Add Extensions endpoints to API
This commit is contained in:
parent
1557797545
commit
5cab3e31b0
|
@ -15,6 +15,7 @@ import (
|
||||||
"go.fifitido.net/twitch/api/conduit"
|
"go.fifitido.net/twitch/api/conduit"
|
||||||
"go.fifitido.net/twitch/api/entitlements"
|
"go.fifitido.net/twitch/api/entitlements"
|
||||||
"go.fifitido.net/twitch/api/eventsub"
|
"go.fifitido.net/twitch/api/eventsub"
|
||||||
|
"go.fifitido.net/twitch/api/extensions"
|
||||||
)
|
)
|
||||||
|
|
||||||
const HelixBaseUrl = "https://api.twitch.tv/helix"
|
const HelixBaseUrl = "https://api.twitch.tv/helix"
|
||||||
|
@ -33,6 +34,7 @@ type API struct {
|
||||||
Conduit *conduit.Conduit
|
Conduit *conduit.Conduit
|
||||||
CCLS *ccls.CCLS
|
CCLS *ccls.CCLS
|
||||||
Entitlements *entitlements.Entitlements
|
Entitlements *entitlements.Entitlements
|
||||||
|
Extensions *extensions.Extensions
|
||||||
EventSub *eventsub.EventSub
|
EventSub *eventsub.EventSub
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,6 +56,7 @@ func New() *API {
|
||||||
Conduit: conduit.New(client, baseUrl),
|
Conduit: conduit.New(client, baseUrl),
|
||||||
CCLS: ccls.New(client, baseUrl),
|
CCLS: ccls.New(client, baseUrl),
|
||||||
Entitlements: entitlements.New(client, baseUrl),
|
Entitlements: entitlements.New(client, baseUrl),
|
||||||
|
Extensions: extensions.New(client, baseUrl),
|
||||||
EventSub: eventsub.New(client, baseUrl),
|
EventSub: eventsub.New(client, baseUrl),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
package extensions
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
|
||||||
|
"github.com/google/go-querystring/query"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CreateExtensionSecretParams struct {
|
||||||
|
// The ID of the extension to apply the shared secret to.
|
||||||
|
ExtensionID string `url:"extension_id"`
|
||||||
|
|
||||||
|
// The amount of time, in seconds, to delay activating the secret.
|
||||||
|
// The delay should provide enough time for instances of the extension to gracefully switch over to the new secret.
|
||||||
|
// The minimum delay is 300 seconds (5 minutes).
|
||||||
|
// The default is 300 seconds.
|
||||||
|
Delay *int `url:"delay"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CreateExtensionSecretResponse struct {
|
||||||
|
// A list that contains the newly added secrets.
|
||||||
|
Data []ExtensionSecrets `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates a shared secret used to sign and verify JWT tokens.
|
||||||
|
// Creating a new secret removes the current secrets from service.
|
||||||
|
// Use this function only when you are ready to use the new secret it returns.
|
||||||
|
//
|
||||||
|
// Requires a signed JSON Web Token (JWT) created by an EBS. For signing requirements,
|
||||||
|
// see Signing the JWT: https://dev.twitch.tv/docs/extensions/building/#signing-the-jwt
|
||||||
|
// The signed JWT must include the role, user_id, and exp fields
|
||||||
|
// (see JWT Schema: https://dev.twitch.tv/docs/extensions/reference/#jwt-schema).
|
||||||
|
// The role field must be set to external.
|
||||||
|
func (c *Extensions) CreateExtensionSecret(ctx context.Context, params *CreateExtensionSecretParams) (*CreateExtensionSecretResponse, error) {
|
||||||
|
v, _ := query.Values(params)
|
||||||
|
endpoint := c.baseUrl.ResolveReference(&url.URL{Path: "extensions/jwt/secrets", RawQuery: v.Encode()})
|
||||||
|
|
||||||
|
req, err := http.NewRequestWithContext(ctx, http.MethodPost, endpoint.String(), nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := c.client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
|
||||||
|
var data CreateExtensionSecretResponse
|
||||||
|
if err := json.NewDecoder(res.Body).Decode(&data); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &data, nil
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
package extensions
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Extensions struct {
|
||||||
|
client *http.Client
|
||||||
|
baseUrl *url.URL
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(client *http.Client, baseUrl *url.URL) *Extensions {
|
||||||
|
return &Extensions{
|
||||||
|
client: client,
|
||||||
|
baseUrl: baseUrl,
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
package extensions
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
|
||||||
|
"github.com/google/go-querystring/query"
|
||||||
|
)
|
||||||
|
|
||||||
|
type GetExtensionBitsProductsParams struct {
|
||||||
|
// A Boolean value that determines whether to include disabled or expired Bits products in the response. The default is false.
|
||||||
|
ShouldIncludeAll *bool `url:"should_include_all,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type GetExtensionBitsProductsResponse struct {
|
||||||
|
// A list that contains the specified Bits products.
|
||||||
|
Data []BitsProduct `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gets the list of Bits products that belongs to the extension. The client ID in the app access token identifies the extension.
|
||||||
|
//
|
||||||
|
// Requires an app access token. The client ID in the app access token must be the extension’s client ID.
|
||||||
|
func (c *Extensions) GetExtensionBitsProducts(ctx context.Context, params *GetExtensionBitsProductsParams) (*GetExtensionBitsProductsResponse, error) {
|
||||||
|
v, _ := query.Values(params)
|
||||||
|
endpoint := c.baseUrl.ResolveReference(&url.URL{Path: "bits/extensions", RawQuery: v.Encode()})
|
||||||
|
|
||||||
|
req, err := http.NewRequestWithContext(ctx, http.MethodGet, endpoint.String(), nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := c.client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
|
||||||
|
var data GetExtensionBitsProductsResponse
|
||||||
|
if err := json.NewDecoder(res.Body).Decode(&data); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &data, nil
|
||||||
|
}
|
|
@ -0,0 +1,81 @@
|
||||||
|
package extensions
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
|
||||||
|
"github.com/google/go-querystring/query"
|
||||||
|
)
|
||||||
|
|
||||||
|
type GetExtensionConfigurationSegmentParams struct {
|
||||||
|
// The ID of the broadcaster that installed the extension.
|
||||||
|
// This parameter is required if you set the segment parameter to broadcaster or developer.
|
||||||
|
// Do not specify this parameter if you set segment to global.
|
||||||
|
BroadcasterID *string `url:"broadcaster_id,omitempty"`
|
||||||
|
|
||||||
|
// The ID of the extension that contains the configuration segment you want to get.
|
||||||
|
ExtensionID string `url:"extension_id"`
|
||||||
|
|
||||||
|
// The type of configuration segment to get. Possible case-sensitive values are:
|
||||||
|
//
|
||||||
|
// broadcaster, developer, global
|
||||||
|
//
|
||||||
|
// You may specify one or more segments. To specify multiple segments, include the segment parameter for each segment to get.
|
||||||
|
// For example, segment=broadcaster&segment=developer. Ignores duplicate segments.
|
||||||
|
Segment []ConfigurationSegment `url:"segment"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type GetExtensionConfigurationSegmentResponse struct {
|
||||||
|
// The list of requested configuration segments.
|
||||||
|
// The list is returned in the same order that you specified the list of segments in the request.
|
||||||
|
Data []ConfigurationSegmentData `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ConfigurationSegmentData struct {
|
||||||
|
// The type of segment.
|
||||||
|
Segment ConfigurationSegment `json:"segment"`
|
||||||
|
|
||||||
|
// The ID of the broadcaster that installed the extension.
|
||||||
|
// The object includes this field only if the segment query parameter is set to developer or broadcaster.
|
||||||
|
BroadcasterID *string `json:"broadcaster_id,omitempty"`
|
||||||
|
|
||||||
|
// The contents of the segment. This string may be a plain-text string or a string-encoded JSON object.
|
||||||
|
Content string `json:"content"`
|
||||||
|
|
||||||
|
// The version number that identifies this definition of the segment’s data.
|
||||||
|
Version string `json:"version"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gets the specified configuration segment from the specified extension.
|
||||||
|
//
|
||||||
|
// Rate Limits: You may retrieve each segment a maximum of 20 times per minute.
|
||||||
|
//
|
||||||
|
// Requires a signed JSON Web Token (JWT) created by an EBS. For signing requirements,
|
||||||
|
// see Signing the JWT: https://dev.twitch.tv/docs/extensions/building/#signing-the-jwt
|
||||||
|
// The signed JWT must include the role, user_id, and exp fields
|
||||||
|
// (see JWT Schema: https://dev.twitch.tv/docs/extensions/reference/#jwt-schema).
|
||||||
|
// The role field must be set to external.
|
||||||
|
func (c *Extensions) GetExtensionConfigurationSegment(ctx context.Context, params *GetExtensionConfigurationSegmentParams) (*GetExtensionConfigurationSegmentResponse, error) {
|
||||||
|
v, _ := query.Values(params)
|
||||||
|
endpoint := c.baseUrl.ResolveReference(&url.URL{Path: "extensions/configurations", RawQuery: v.Encode()})
|
||||||
|
|
||||||
|
req, err := http.NewRequestWithContext(ctx, http.MethodGet, endpoint.String(), nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := c.client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
|
||||||
|
var data GetExtensionConfigurationSegmentResponse
|
||||||
|
if err := json.NewDecoder(res.Body).Decode(&data); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &data, nil
|
||||||
|
}
|
|
@ -0,0 +1,73 @@
|
||||||
|
package extensions
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
|
||||||
|
"github.com/google/go-querystring/query"
|
||||||
|
"go.fifitido.net/twitch/api/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
type GetExtensionLiveChannelsParams struct {
|
||||||
|
// The ID of the extension to get. Returns the list of broadcasters that are live and that have installed or activated this extension.
|
||||||
|
ExtensionID string `url:"extension_id"`
|
||||||
|
|
||||||
|
// The maximum number of items to return per page in the response. The minimum page size is 1 item per page and the maximum is 100 items per page. The default is 20.
|
||||||
|
First *int `url:"first,omitempty"`
|
||||||
|
|
||||||
|
// The cursor used to get the next page of results. The pagination field in the response contains the cursor’s value.
|
||||||
|
// Read More: https://dev.twitch.tv/docs/api/guide#pagination
|
||||||
|
After *types.Cursor `url:"after,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type GetExtensionLiveChannelsResponse struct {
|
||||||
|
// The list of broadcasters that are streaming live and that have installed or activated the extension.
|
||||||
|
Data []ExtensionLiveChannel `json:"data"`
|
||||||
|
|
||||||
|
// The cursor used to get the next page of results. The pagination field in the response contains the cursor’s value.
|
||||||
|
// Read More: https://dev.twitch.tv/docs/api/guide#pagination
|
||||||
|
Pagination types.Pagination `json:"pagination"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ExtensionLiveChannel struct {
|
||||||
|
// The ID of the broadcaster that is streaming live and has installed or activated the extension.
|
||||||
|
BroadcasterID string `json:"broadcaster_id"`
|
||||||
|
// The broadcaster’s display name.
|
||||||
|
BroadcasterName string `json:"broadcaster_name"`
|
||||||
|
// The name of the category or game being streamed.
|
||||||
|
GameName string `json:"game_name"`
|
||||||
|
// The ID of the category or game being streamed.
|
||||||
|
GameID string `json:"game_id"`
|
||||||
|
// The title of the broadcaster’s stream. May be an empty string if not specified.
|
||||||
|
Title string `json:"title"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gets a list of broadcasters that are streaming live and have installed or activated the extension.
|
||||||
|
//
|
||||||
|
// It may take a few minutes for the list to include or remove broadcasters that have recently gone live or stopped broadcasting.
|
||||||
|
//
|
||||||
|
// Requires an app access token or user access token.
|
||||||
|
func (c *Extensions) GetExtensionLiveChannels(ctx context.Context, params *GetExtensionLiveChannelsParams) (*GetExtensionLiveChannelsResponse, error) {
|
||||||
|
v, _ := query.Values(params)
|
||||||
|
endpoint := c.baseUrl.ResolveReference(&url.URL{Path: "extensions/live", RawQuery: v.Encode()})
|
||||||
|
|
||||||
|
req, err := http.NewRequestWithContext(ctx, http.MethodGet, endpoint.String(), nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := c.client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
|
||||||
|
var response GetExtensionLiveChannelsResponse
|
||||||
|
if err := json.NewDecoder(res.Body).Decode(&response); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &response, nil
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
package extensions
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
)
|
||||||
|
|
||||||
|
type GetExtensionSecretsResponse struct {
|
||||||
|
// The list of shared secrets that the extension created.
|
||||||
|
Data []ExtensionSecrets `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gets an extension’s list of shared secrets.
|
||||||
|
//
|
||||||
|
// Requires a signed JSON Web Token (JWT) created by an EBS. For signing requirements,
|
||||||
|
// see Signing the JWT: https://dev.twitch.tv/docs/extensions/building/#signing-the-jwt
|
||||||
|
// The signed JWT must include the role, user_id, and exp fields
|
||||||
|
// (see JWT Schema: https://dev.twitch.tv/docs/extensions/reference/#jwt-schema).
|
||||||
|
// The role field must be set to external.
|
||||||
|
func (c *Extensions) GetExtensionSecrets(ctx context.Context, extensionID string) (*GetExtensionSecretsResponse, error) {
|
||||||
|
endpoint := c.baseUrl.ResolveReference(&url.URL{Path: "extensions/jwt/secrets", RawQuery: "extension_id=" + extensionID})
|
||||||
|
|
||||||
|
req, err := http.NewRequestWithContext(ctx, http.MethodGet, endpoint.String(), nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := c.client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
|
||||||
|
var data GetExtensionSecretsResponse
|
||||||
|
if err := json.NewDecoder(res.Body).Decode(&data); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &data, nil
|
||||||
|
}
|
|
@ -0,0 +1,54 @@
|
||||||
|
package extensions
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
|
||||||
|
"github.com/google/go-querystring/query"
|
||||||
|
)
|
||||||
|
|
||||||
|
type GetExtensionsParams struct {
|
||||||
|
// The ID of the extension to get.
|
||||||
|
ExtensionID string `url:"extension_id"`
|
||||||
|
|
||||||
|
// The version of the extension to get. If not specified, it returns the latest, released version.
|
||||||
|
// If you don’t have a released version, you must specify a version; otherwise, the list is empty.
|
||||||
|
ExtensionVersion *string `url:"extension_version,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type GetExtensionsResponse struct {
|
||||||
|
// A list that contains the specified extension.
|
||||||
|
Data []Extension `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gets information about an extension.
|
||||||
|
//
|
||||||
|
// Requires a signed JSON Web Token (JWT) created by an EBS. For signing requirements,
|
||||||
|
// see Signing the JWT: https://dev.twitch.tv/docs/extensions/building/#signing-the-jwt
|
||||||
|
// The signed JWT must include the role, user_id, and exp fields
|
||||||
|
// (see JWT Schema: https://dev.twitch.tv/docs/extensions/reference/#jwt-schema).
|
||||||
|
// The role field must be set to external.
|
||||||
|
func (c *Extensions) GetExtensions(ctx context.Context, params *GetExtensionsParams) (*GetExtensionsResponse, error) {
|
||||||
|
v, _ := query.Values(params)
|
||||||
|
endpoint := c.baseUrl.ResolveReference(&url.URL{Path: "extensions", RawQuery: v.Encode()})
|
||||||
|
|
||||||
|
req, err := http.NewRequestWithContext(ctx, http.MethodGet, endpoint.String(), nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := c.client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
|
||||||
|
var data GetExtensionsResponse
|
||||||
|
if err := json.NewDecoder(res.Body).Decode(&data); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &data, nil
|
||||||
|
}
|
|
@ -0,0 +1,49 @@
|
||||||
|
package extensions
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
|
||||||
|
"github.com/google/go-querystring/query"
|
||||||
|
)
|
||||||
|
|
||||||
|
type GetReleasedExtensionsParams struct {
|
||||||
|
// The ID of the extension to get.
|
||||||
|
ExtensionID string `url:"extension_id"`
|
||||||
|
|
||||||
|
// The version of the extension to get. If not specified, it returns the latest, released version.
|
||||||
|
ExtensionVersion *string `url:"extension_version,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type GetReleasedExtensionsResponse struct {
|
||||||
|
// A list that contains the specified extension.
|
||||||
|
Data []Extension `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gets information about a released extension. Returns the extension if its state is Released.
|
||||||
|
//
|
||||||
|
// Requires an app access token or user access token.
|
||||||
|
func (c *Extensions) GetReleasedExtensions(ctx context.Context, params *GetReleasedExtensionsParams) (*GetReleasedExtensionsResponse, error) {
|
||||||
|
v, _ := query.Values(params)
|
||||||
|
endpoint := c.baseUrl.ResolveReference(&url.URL{Path: "extensions/released", RawQuery: v.Encode()})
|
||||||
|
|
||||||
|
req, err := http.NewRequestWithContext(ctx, http.MethodGet, endpoint.String(), nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := c.client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
|
||||||
|
var data GetReleasedExtensionsResponse
|
||||||
|
if err := json.NewDecoder(res.Body).Decode(&data); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &data, nil
|
||||||
|
}
|
|
@ -0,0 +1,221 @@
|
||||||
|
package extensions
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
type ConfigurationSegment string
|
||||||
|
|
||||||
|
const (
|
||||||
|
ConfigurationSegmentBroadcaster ConfigurationSegment = "broadcaster"
|
||||||
|
ConfigurationSegmentDeveloper ConfigurationSegment = "developer"
|
||||||
|
ConfigurationSegmentGlobal ConfigurationSegment = "global"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ExtensionSecrets struct {
|
||||||
|
// The version number that identifies this definition of the secret’s data.
|
||||||
|
FormatVersion int `json:"format_version"`
|
||||||
|
|
||||||
|
// The list of secrets.
|
||||||
|
Secrets []ExtensionSecret `json:"secrets"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ExtensionSecret struct {
|
||||||
|
// The raw secret that you use with JWT encoding.
|
||||||
|
Content string `json:"content"`
|
||||||
|
|
||||||
|
// The UTC date and time (in RFC3339 format) that you may begin using this secret to sign a JWT.
|
||||||
|
ActiveAt time.Time `json:"active_at"`
|
||||||
|
|
||||||
|
// The UTC date and time (in RFC3339 format) that you must stop using this secret to decode a JWT.
|
||||||
|
ExpiresAt time.Time `json:"expires_at"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ConfigurationLocation string
|
||||||
|
|
||||||
|
const (
|
||||||
|
// The Extensions Configuration Service hosts the configuration.
|
||||||
|
ConfigurationLocationHosted ConfigurationLocation = "hosted"
|
||||||
|
|
||||||
|
// The Extension Backend Service (EBS) hosts the configuration.
|
||||||
|
ConfigurationLocationCustom ConfigurationLocation = "custom"
|
||||||
|
|
||||||
|
// The extension doesn't require configuration.
|
||||||
|
ConfigurationLocationNone ConfigurationLocation = "none"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ExtensionState string
|
||||||
|
|
||||||
|
const (
|
||||||
|
ExtensionStateApproved ExtensionState = "Approved"
|
||||||
|
ExtensionStateAssetsUploaded ExtensionState = "AssetsUploaded"
|
||||||
|
ExtensionStateDeleted ExtensionState = "Deleted"
|
||||||
|
ExtensionStateDeprecated ExtensionState = "Deprecated"
|
||||||
|
ExtensionStateInReview ExtensionState = "InReview"
|
||||||
|
ExtensionStateInTest ExtensionState = "InTest"
|
||||||
|
ExtensionStatePendingAction ExtensionState = "PendingAction"
|
||||||
|
ExtensionStateRejected ExtensionState = "Rejected"
|
||||||
|
ExtensionStateReleased ExtensionState = "Released"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Extension struct {
|
||||||
|
// The name of the user or organization that owns the extension
|
||||||
|
AuthorName string `json:"author_name"`
|
||||||
|
|
||||||
|
// A boolean value that determines whether the extension has features that use bits.
|
||||||
|
// Is true if the extension has features that use bits.
|
||||||
|
HasBits bool `json:"has_bits"`
|
||||||
|
|
||||||
|
// A boolean value that determines whether a user can install the extension on their channel.
|
||||||
|
// Is true if the user can install the extension on their channel.
|
||||||
|
CanInstall bool `json:"can_install"`
|
||||||
|
|
||||||
|
// The location of where the extension’s configuration is stored.
|
||||||
|
ConfigurationLocation ConfigurationLocation `json:"configuration_location"`
|
||||||
|
|
||||||
|
// A longer description of the extension. It appears on the details page.
|
||||||
|
Description string `json:"description"`
|
||||||
|
|
||||||
|
// A URL to the extension's Terms of Service.
|
||||||
|
EulaTosUrl string `json:"eula_tos_url"`
|
||||||
|
|
||||||
|
// A boolean value that determines whether the extension can communicate with the installed channel's chat.
|
||||||
|
// Is true if the extension can communicate with the installed channel's chat room.
|
||||||
|
HasChatSupport bool `json:"has_chat_support"`
|
||||||
|
|
||||||
|
// A URL to the default icon that's displayed in the Extensions directory.
|
||||||
|
IconUrl string `json:"icon_url"`
|
||||||
|
|
||||||
|
// A dictionary that contains URLs to different sizes of the default icon.
|
||||||
|
// The dictionary’s key identifies the icon’s size (for example, 24x24), and the dictionary’s value contains the URL to the icon.
|
||||||
|
IconUrls map[string]string `json:"icon_urls"`
|
||||||
|
|
||||||
|
// The extension’s ID.
|
||||||
|
ID string `json:"id"`
|
||||||
|
|
||||||
|
// The extension’s state.
|
||||||
|
State ExtensionState `json:"state"`
|
||||||
|
|
||||||
|
// Indicates whether the extension can view the user’s subscription level on the channel that the extension is installed on.
|
||||||
|
// Possible values are:
|
||||||
|
//
|
||||||
|
// none — The extension can't view the user’s subscription level.
|
||||||
|
//
|
||||||
|
// optional — The extension can view the user’s subscription level.
|
||||||
|
SubscriptionsSupportLevel string `json:"subscriptions_support_level"`
|
||||||
|
|
||||||
|
// A short description of the extension that streamers see when hovering over the discovery splash screen in the Extensions manager.
|
||||||
|
Summary string `json:"summary"`
|
||||||
|
|
||||||
|
// The email address that users use to get support for the extension.
|
||||||
|
SupportEmail string `json:"support_email"`
|
||||||
|
|
||||||
|
// The extension’s version number.
|
||||||
|
Version string `json:"version"`
|
||||||
|
|
||||||
|
// A brief description displayed on the channel to explain how the extension works.
|
||||||
|
ViewerSummary string `json:"viewer_summary"`
|
||||||
|
|
||||||
|
// Describes all views-related information such as how the extension is displayed on mobile devices.
|
||||||
|
Views struct {
|
||||||
|
// Describes how the extension is displayed on mobile devices.
|
||||||
|
Mobile struct {
|
||||||
|
// The HTML file that is shown to viewers on mobile devices. This page is presented to viewers as a panel behind the chat area of the mobile app.
|
||||||
|
ViewerUrl string `json:"viewer_url"`
|
||||||
|
} `json:"mobile"`
|
||||||
|
|
||||||
|
// Describes how the extension is rendered if the extension may be activated as a panel extension.
|
||||||
|
Panel struct {
|
||||||
|
// The HTML file that is shown to viewers when the extension is activated as a panel extension.
|
||||||
|
ViewerUrl string `json:"viewer_url"`
|
||||||
|
|
||||||
|
// The height, in pixels, of the panel component that the extension is rendered in.
|
||||||
|
Height int `json:"height"`
|
||||||
|
|
||||||
|
// A Boolean value that determines whether the extension can link to non-Twitch domains.
|
||||||
|
CanLinkExternalContent bool `json:"can_link_external_content"`
|
||||||
|
} `json:"panel"`
|
||||||
|
|
||||||
|
// Describes how the extension is rendered if the extension may be activated as a video-overlay extension.
|
||||||
|
VideoOverlay struct {
|
||||||
|
// The HTML file that is shown to viewers when the extension is activated as a video-overlay extension.
|
||||||
|
ViewerUrl string `json:"viewer_url"`
|
||||||
|
|
||||||
|
// A Boolean value that determines whether the extension can link to non-Twitch domains.
|
||||||
|
CanLinkExternalContent bool `json:"can_link_external_content"`
|
||||||
|
} `json:"video_overlay"`
|
||||||
|
|
||||||
|
// Describes how the extension is rendered if the extension may be activated as a video-component extension.
|
||||||
|
VideoComponent struct {
|
||||||
|
// The HTML file that is shown to viewers when the extension is activated as a video-component extension.
|
||||||
|
ViewerUrl string `json:"viewer_url"`
|
||||||
|
|
||||||
|
// The width value of the ratio (width : height) which determines the extension’s width,
|
||||||
|
// and how the extension’s iframe will resize in different video player environments.
|
||||||
|
AspectRatioX int `json:"aspect_ratio_x"`
|
||||||
|
|
||||||
|
// The height value of the ratio (width : height) which determines the extension’s height,
|
||||||
|
// and how the extension’s iframe will resize in different video player environments.
|
||||||
|
AspectRatioY int `json:"aspect_ratio_y"`
|
||||||
|
|
||||||
|
// A Boolean value that determines whether to apply CSS zoom.
|
||||||
|
// If true, a CSS zoom is applied such that the size of the extension is variable but the inner dimensions are fixed based on Scale Pixels.
|
||||||
|
// This allows your extension to render as if it is of fixed width and height.
|
||||||
|
// If false, the inner dimensions of the extension iframe are variable, meaning your extension must implement responsiveness.
|
||||||
|
Autoscale bool `json:"autoscale"`
|
||||||
|
|
||||||
|
// The base width, in pixels, of the extension to use when scaling (see autoscale). This value is ignored if autoscale is false.
|
||||||
|
ScalePixels int `json:"scale_pixels"`
|
||||||
|
|
||||||
|
// The height as a percent of the maximum height of a video component extension. Values are between 1% - 100%.
|
||||||
|
TargetHeight int `json:"target_height"`
|
||||||
|
|
||||||
|
// A boolean value that determines whether the extension can link to non-Twitch domains.
|
||||||
|
CanLinkExternalContent bool `json:"can_link_external_content"`
|
||||||
|
} `json:"video_component"`
|
||||||
|
|
||||||
|
// Describes the view that is shown to broadcasters while they are configuring your extension within the Extension Manager.
|
||||||
|
Config struct {
|
||||||
|
// The HTML file that is shown to broadcasters while they are configuring your extension within the Extension Manager.
|
||||||
|
ViewerUrl string `json:"viewer_url"`
|
||||||
|
|
||||||
|
// A Boolean value that determines whether the extension can link to non-Twitch domains.
|
||||||
|
CanLinkExternalContent bool `json:"can_link_external_content"`
|
||||||
|
} `json:"config"`
|
||||||
|
} `json:"views"`
|
||||||
|
|
||||||
|
// Allowlisted configuration URLs for displaying the extension
|
||||||
|
// (the allowlist is configured on Twitch’s developer site under the Extensions -> Extension -> Version -> Capabilities).
|
||||||
|
AllowlistedConfigUrls []string `json:"allowlisted_config_urls"`
|
||||||
|
|
||||||
|
// Allowlisted panel URLs for displaying the extension
|
||||||
|
// (the allowlist is configured on Twitch’s developer site under the Extensions -> Extension -> Version -> Capabilities).
|
||||||
|
AllowlistedPanelUrls []string `json:"allowlisted_panel_urls"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type BitsProduct struct {
|
||||||
|
// The product’s SKU. The SKU is unique across an extension’s products.
|
||||||
|
SKU string `json:"sku"`
|
||||||
|
|
||||||
|
// An object that contains the product’s cost information.
|
||||||
|
Cost struct {
|
||||||
|
// The product’s price.
|
||||||
|
Amount int `json:"amount"`
|
||||||
|
|
||||||
|
// The type of currency. Possible values are:
|
||||||
|
//
|
||||||
|
// bits
|
||||||
|
Type string `json:"type"`
|
||||||
|
} `json:"cost"`
|
||||||
|
|
||||||
|
// A Boolean value that indicates whether the product is in development. If true, the product is not available for public use.
|
||||||
|
InDevelopment bool `json:"in_development"`
|
||||||
|
|
||||||
|
// The product’s name as displayed in the extension.
|
||||||
|
DisplayName string `json:"display_name"`
|
||||||
|
|
||||||
|
// The date and time, in RFC3339 format, when the product expires.
|
||||||
|
Expiration time.Time `json:"expiration"`
|
||||||
|
|
||||||
|
// A Boolean value that determines whether Bits product purchase events are broadcast to all instances of an extension on a channel.
|
||||||
|
// The events are broadcast via the onTransactionComplete helper callback. Is true if the event is broadcast to all instances.
|
||||||
|
IsBroadcast bool `json:"is_broadcast"`
|
||||||
|
}
|
|
@ -0,0 +1,58 @@
|
||||||
|
package extensions
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SendExtensionChatMessageRequest struct {
|
||||||
|
// The message. The message may contain a maximum of 280 characters.
|
||||||
|
Text string `json:"text"`
|
||||||
|
|
||||||
|
// The ID of the extension that’s sending the chat message.
|
||||||
|
ExtensionID string `json:"extension_id"`
|
||||||
|
|
||||||
|
// The extension’s version number.
|
||||||
|
ExtensionVersion string `json:"extension_version"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sends a message to the specified broadcaster’s chat room.
|
||||||
|
// The extension’s name is used as the username for the message in the chat room.
|
||||||
|
// To send a chat message, your extension must enable Chat Capabilities (under your extension’s Capabilities tab).
|
||||||
|
//
|
||||||
|
// Rate Limits: You may send a maximum of 12 messages per minute per channel.
|
||||||
|
//
|
||||||
|
// Requires a signed JSON Web Token (JWT) created by an EBS. For signing requirements,
|
||||||
|
// see Signing the JWT: https://dev.twitch.tv/docs/extensions/building/#signing-the-jwt
|
||||||
|
// The signed JWT must include the role, user_id, and exp fields
|
||||||
|
// (see JWT Schema: https://dev.twitch.tv/docs/extensions/reference/#jwt-schema).
|
||||||
|
// The role field must be set to external.
|
||||||
|
func (c *Extensions) SendExtensionChatMessage(ctx context.Context, broadcasterID string, body *SendExtensionChatMessageRequest) error {
|
||||||
|
endpoint := c.baseUrl.ResolveReference(&url.URL{Path: "extensions/chat", RawQuery: "broadcaster_id=" + broadcasterID})
|
||||||
|
|
||||||
|
r, w := io.Pipe()
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
if err := json.NewEncoder(w).Encode(body); err != nil {
|
||||||
|
w.CloseWithError(err)
|
||||||
|
} else {
|
||||||
|
w.Close()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
req, err := http.NewRequestWithContext(ctx, http.MethodPost, endpoint.String(), r)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := c.client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -0,0 +1,69 @@
|
||||||
|
package extensions
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SendExtensionPubsubMessageRequest struct {
|
||||||
|
// The target of the message. Possible values are:
|
||||||
|
//
|
||||||
|
// broadcast
|
||||||
|
// global
|
||||||
|
// whisper-<user-id>
|
||||||
|
//
|
||||||
|
// If is_global_broadcast is true, you must set this field to global. The broadcast and global values are mutually exclusive; specify only one of them.
|
||||||
|
Target []string `json:"target"`
|
||||||
|
|
||||||
|
// The ID of the broadcaster to send the message to. Don’t include this field if is_global_broadcast is set to true.
|
||||||
|
BroadcasterID *string `json:"broadcaster_id,omitempty"`
|
||||||
|
|
||||||
|
// A Boolean value that determines whether the message should be sent to all channels where your extension is active. Set to true if the message should be sent to all channels. The default is false.
|
||||||
|
IsGlobalBroadcast *bool `json:"is_global_broadcast,omitempty"`
|
||||||
|
|
||||||
|
// The message to send. The message can be a plain-text string or a string-encoded JSON object. The message is limited to a maximum of 5 KB.
|
||||||
|
Message string `json:"message"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sends a message to one or more viewers. You can send messages to a specific channel or to all channels where your extension is active. This endpoint uses the same mechanism as the send JavaScript helper function used to send messages.
|
||||||
|
//
|
||||||
|
// Rate Limits: You may send a maximum of 100 messages per minute per combination of extension client ID and broadcaster ID.
|
||||||
|
//
|
||||||
|
// Requires a signed JSON Web Token (JWT) created by an EBS. For signing requirements,
|
||||||
|
// see Signing the JWT: https://dev.twitch.tv/docs/extensions/building/#signing-the-jwt
|
||||||
|
// The signed JWT must include the role, user_id, and exp fields
|
||||||
|
// (see JWT Schema: https://dev.twitch.tv/docs/extensions/reference/#jwt-schema).
|
||||||
|
// along with the channel_id and pubsub_perms fields. The role field must be set to external.
|
||||||
|
//
|
||||||
|
// To send the message to a specific channel, set the channel_id field in the JWT to the channel’s ID and set the pubsub_perms.send array to broadcast.
|
||||||
|
//
|
||||||
|
// To send the message to all channels on which your extension is active, set the channel_id field to all and set the pubsub_perms.send array to global.
|
||||||
|
func (c *Extensions) SendExtensionPubsubMessage(ctx context.Context, body *SendExtensionPubsubMessageRequest) error {
|
||||||
|
endpoint := c.baseUrl.ResolveReference(&url.URL{Path: "extensions/pubsub"})
|
||||||
|
|
||||||
|
r, w := io.Pipe()
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
if err := json.NewEncoder(w).Encode(body); err != nil {
|
||||||
|
w.CloseWithError(err)
|
||||||
|
} else {
|
||||||
|
w.Close()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
req, err := http.NewRequestWithContext(ctx, http.MethodPost, endpoint.String(), r)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := c.client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -0,0 +1,65 @@
|
||||||
|
package extensions
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SetExtensionConfigurationSegmentRequest struct {
|
||||||
|
// The ID of the extension to update.
|
||||||
|
ExtensionID string `json:"extension_id"`
|
||||||
|
|
||||||
|
// The configuration segment to update.
|
||||||
|
Segment ConfigurationSegment `json:"segment"`
|
||||||
|
|
||||||
|
// The ID of the broadcaster that installed the extension.
|
||||||
|
// Include this field only if the segment is set to developer or broadcaster.
|
||||||
|
BroadcasterID *string `json:"broadcaster_id,omitempty"`
|
||||||
|
|
||||||
|
// The contents of the segment.
|
||||||
|
// This string may be a plain-text string or a string-encoded JSON object.
|
||||||
|
Content *string `json:"content,omitempty"`
|
||||||
|
|
||||||
|
// The version number that identifies this definition of the segment’s data.
|
||||||
|
// If not specified, the latest definition is updated.
|
||||||
|
Version *string `json:"version,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Updates a configuration segment. The segment is limited to 5 KB. Extensions that are active on a channel do not receive the updated configuration.
|
||||||
|
//
|
||||||
|
// Rate Limits: You may update the configuration a maximum of 20 times per minute.
|
||||||
|
//
|
||||||
|
// Requires a signed JSON Web Token (JWT) created by an EBS. For signing requirements,
|
||||||
|
// see Signing the JWT: https://dev.twitch.tv/docs/extensions/building/#signing-the-jwt
|
||||||
|
// The signed JWT must include the role, user_id, and exp fields
|
||||||
|
// (see JWT Schema: https://dev.twitch.tv/docs/extensions/reference/#jwt-schema).
|
||||||
|
// The role field must be set to external.
|
||||||
|
func (c *Extensions) SetExtensionConfigurationSegment(ctx context.Context, body *SetExtensionConfigurationSegmentRequest) error {
|
||||||
|
endpoint := c.baseUrl.ResolveReference(&url.URL{Path: "extensions/configurations"})
|
||||||
|
|
||||||
|
r, w := io.Pipe()
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
if err := json.NewEncoder(w).Encode(body); err != nil {
|
||||||
|
w.CloseWithError(err)
|
||||||
|
} else {
|
||||||
|
w.Close()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
req, err := http.NewRequestWithContext(ctx, http.MethodPut, endpoint.String(), r)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := c.client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -0,0 +1,59 @@
|
||||||
|
package extensions
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SetExtensionRequiredConfigurationRequest struct {
|
||||||
|
// The ID of the extension to update.
|
||||||
|
ExtensionID string `json:"extension_id"`
|
||||||
|
|
||||||
|
// The version of the extension to update.
|
||||||
|
ExtensionVersion string `json:"extension_version"`
|
||||||
|
|
||||||
|
// The required_configuration string to use with the extension.
|
||||||
|
RequiredConfiguration string `json:"required_configuration"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Updates the extension’s required_configuration string.
|
||||||
|
// Use this endpoint if your extension requires the broadcaster to configure the extension before activating it
|
||||||
|
// (to require configuration, you must select Custom/My Own Service in Extension Capabilities).
|
||||||
|
// For more information,
|
||||||
|
// see Required Configurations: https://dev.twitch.tv/docs/extensions/building#required-configurations
|
||||||
|
// and Setting Required Configuration: https://dev.twitch.tv/docs/extensions/building#setting-required-configuration-with-the-configuration-service-optional
|
||||||
|
//
|
||||||
|
// Requires a signed JSON Web Token (JWT) created by an EBS. For signing requirements,
|
||||||
|
// see Signing the JWT: https://dev.twitch.tv/docs/extensions/building/#signing-the-jwt
|
||||||
|
// The signed JWT must include the role, user_id, and exp fields
|
||||||
|
// (see JWT Schema: https://dev.twitch.tv/docs/extensions/reference/#jwt-schema).
|
||||||
|
// Set the role field to external and the user_id field to the ID of the user that owns the extension.
|
||||||
|
func (c *Extensions) SetExtensionRequiredConfiguration(ctx context.Context, broadcasterID string, body *SetExtensionRequiredConfigurationRequest) error {
|
||||||
|
endpoint := c.baseUrl.ResolveReference(&url.URL{Path: "extensions/required_configuration", RawQuery: "broadcaster_id=" + broadcasterID})
|
||||||
|
|
||||||
|
r, w := io.Pipe()
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
if err := json.NewEncoder(w).Encode(body); err != nil {
|
||||||
|
w.CloseWithError(err)
|
||||||
|
} else {
|
||||||
|
w.Close()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
req, err := http.NewRequestWithContext(ctx, http.MethodPut, endpoint.String(), r)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := c.client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -0,0 +1,84 @@
|
||||||
|
package extensions
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UpdateExtensionBitsProductRequest struct {
|
||||||
|
// The product's SKU. The SKU must be unique within an extension. The product's SKU cannot be changed.
|
||||||
|
// The SKU may contain only alphanumeric characters, dashes (-), underscores (_), and periods (.) and is limited to a maximum of 255 characters. No spaces.
|
||||||
|
SKU string `json:"sku"`
|
||||||
|
|
||||||
|
// An object that contains the product's cost information.
|
||||||
|
Cost struct {
|
||||||
|
// The product's price.
|
||||||
|
Amount int `json:"amount"`
|
||||||
|
|
||||||
|
// The type of currency. Possible values are:
|
||||||
|
//
|
||||||
|
// bits
|
||||||
|
Type string `json:"type"`
|
||||||
|
} `json:"cost"`
|
||||||
|
|
||||||
|
// The product's name as displayed in the extension. The maximum length is 255 characters.
|
||||||
|
DisplayName string `json:"display_name"`
|
||||||
|
|
||||||
|
// A Boolean value that indicates whether the product is in development.
|
||||||
|
// Set to true if the product is in development and not available for public use.
|
||||||
|
// The default is false.
|
||||||
|
InDevelopment *bool `json:"in_development"`
|
||||||
|
|
||||||
|
// The date and time, in RFC3339 format, when the product expires.
|
||||||
|
Expiration *time.Time `json:"expiration"`
|
||||||
|
|
||||||
|
// A Boolean value that determines whether Bits product purchase events are broadcast to all instances of the extension on a channel.
|
||||||
|
// The events are broadcast via the onTransactionComplete helper callback. The default is false.
|
||||||
|
IsBroadcast *bool `json:"is_broadcast"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type UpdateExtensionBitsProductResponse struct {
|
||||||
|
// A list of Bits products that the extension created. The list is in ascending SKU order.
|
||||||
|
// The list is empty if the extension hasn't created any products or they're all expired or disabled.
|
||||||
|
Data []BitsProduct `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adds or updates a Bits product that the extension created.
|
||||||
|
// If the SKU doesn’t exist, the product is added. You may update all fields except the sku field.
|
||||||
|
//
|
||||||
|
// Requires an app access token. The client ID in the app access token must match the extension’s client ID.
|
||||||
|
func (c *Extensions) UpdateExtensionBitsProduct(ctx context.Context, body *UpdateExtensionBitsProductRequest) (*UpdateExtensionBitsProductResponse, error) {
|
||||||
|
endpoint := c.baseUrl.ResolveReference(&url.URL{Path: "bits/extensions"})
|
||||||
|
|
||||||
|
r, w := io.Pipe()
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
if err := json.NewEncoder(w).Encode(body); err != nil {
|
||||||
|
w.CloseWithError(err)
|
||||||
|
} else {
|
||||||
|
w.Close()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
req, err := http.NewRequestWithContext(ctx, http.MethodPut, endpoint.String(), r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := c.client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
|
||||||
|
var data UpdateExtensionBitsProductResponse
|
||||||
|
if err := json.NewDecoder(res.Body).Decode(&data); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &data, nil
|
||||||
|
}
|
Loading…
Reference in New Issue