@bedrock-rbx/ocale 0.1.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,245 @@
1
+ import { d as OpenCloudError, i as OpenCloudClientOptions, l as Result, s as RequestOptions } from "./types-YCTsM8Qd.mjs";
2
+
3
+ //#region src/domains/developer-products/products/types.d.ts
4
+ /**
5
+ * Pricing feature flags that can be enabled on a developer product. Values
6
+ * mirror the Open Cloud `DeveloperProducts.PricingFeature` enum.
7
+ */
8
+ type DeveloperProductPricingFeature = "Invalid" | "PriceOptimization" | "RegionalPricing" | "UserFixedPrice";
9
+ /**
10
+ * Public shape of a developer product's pricing configuration.
11
+ */
12
+ interface DeveloperProductPrice {
13
+ /** Default Robux price; `undefined` when no default price is configured. */
14
+ readonly defaultPriceInRobux: number | undefined;
15
+ /** Pricing feature flags currently enabled on this developer product. */
16
+ readonly enabledFeatures: ReadonlyArray<DeveloperProductPricingFeature>;
17
+ }
18
+ /**
19
+ * A Roblox developer product as exposed to SDK consumers. Fields use
20
+ * DX-friendly names and types (stringified IDs, `Date` timestamps) rather
21
+ * than the raw wire representation.
22
+ */
23
+ interface DeveloperProduct {
24
+ /** Stringified developer product ID. The API returns an int64; always use this. */
25
+ readonly id: string;
26
+ /** Display name of the developer product. */
27
+ readonly name: string;
28
+ /** ISO timestamp at which the developer product was created, as a `Date`. */
29
+ readonly createdAt: Date;
30
+ /** Consumer-facing description shown on the storefront. */
31
+ readonly description: string;
32
+ /** Icon image asset ID as a string; `undefined` when no icon is uploaded. */
33
+ readonly iconImageAssetId: string | undefined;
34
+ /** Whether the developer product is currently purchasable. */
35
+ readonly isForSale: boolean;
36
+ /** Whether the developer product is locked from configuration changes. */
37
+ readonly isImmutable: boolean;
38
+ /** Pricing configuration; `undefined` when pricing is not yet set. */
39
+ readonly price: DeveloperProductPrice | undefined;
40
+ /** Whether the developer product appears on the external store page. */
41
+ readonly storePageEnabled: boolean;
42
+ /** Stringified ID of the universe that owns the developer product. */
43
+ readonly universeId: string;
44
+ /** ISO timestamp of the most recent update, as a `Date`. */
45
+ readonly updatedAt: Date;
46
+ }
47
+ /**
48
+ * Parameters for creating a new developer product under a universe.
49
+ */
50
+ interface CreateDeveloperProductParameters {
51
+ /** Display name of the new developer product. */
52
+ readonly name: string;
53
+ /** Optional consumer-facing description shown on the storefront. */
54
+ readonly description?: string;
55
+ /** Optional icon image uploaded with the new developer product. */
56
+ readonly imageFile?: Blob | Uint8Array;
57
+ /** Whether the developer product should be purchasable immediately. */
58
+ readonly isForSale?: boolean;
59
+ /** Whether regional pricing should be enabled at creation time. */
60
+ readonly isRegionalPricingEnabled?: boolean;
61
+ /** Optional default price in Robux at creation time. */
62
+ readonly price?: number;
63
+ /** Stringified ID of the universe that owns the developer product. */
64
+ readonly universeId: string;
65
+ }
66
+ /**
67
+ * Parameters for reading a single developer product by ID.
68
+ */
69
+ interface GetDeveloperProductParameters {
70
+ /** Stringified ID of the developer product to retrieve. */
71
+ readonly productId: string;
72
+ /** Stringified ID of the universe that owns the developer product. */
73
+ readonly universeId: string;
74
+ }
75
+ /**
76
+ * Parameters for partially updating an existing developer product. Every
77
+ * field except the identifiers is optional; omitted fields are not included
78
+ * in the multipart PATCH body so the server leaves their current values
79
+ * untouched.
80
+ */
81
+ interface UpdateDeveloperProductParameters {
82
+ /** Optional new display name. */
83
+ readonly name?: string;
84
+ /** Optional new consumer-facing description. */
85
+ readonly description?: string;
86
+ /** Optional replacement icon image upload. */
87
+ readonly imageFile?: Blob | Uint8Array;
88
+ /** Optional flag toggling whether the product is purchasable. */
89
+ readonly isForSale?: boolean;
90
+ /** Optional flag toggling regional pricing. */
91
+ readonly isRegionalPricingEnabled?: boolean;
92
+ /** Optional new default price in Robux. */
93
+ readonly price?: number;
94
+ /** Stringified ID of the developer product to update. */
95
+ readonly productId: string;
96
+ /** Optional flag toggling visibility on the external store page. */
97
+ readonly storePageEnabled?: boolean;
98
+ /** Stringified ID of the universe that owns the developer product. */
99
+ readonly universeId: string;
100
+ }
101
+ //#endregion
102
+ //#region src/domains/game-internationalization/developer-product-icon/types.d.ts
103
+ /**
104
+ * Parameters for uploading or replacing the per-locale icon registered
105
+ * against a developer product. A subsequent upload for the same
106
+ * `(productId, languageCode)` pair replaces the existing icon for that
107
+ * locale.
108
+ */
109
+ interface UploadDeveloperProductIconParameters {
110
+ /** Image bytes to upload. PNG and JPEG are accepted by the server. */
111
+ readonly image: Blob | Uint8Array;
112
+ /** BCP-47 language code the icon is being uploaded for (e.g. `fr-fr`). */
113
+ readonly languageCode: string;
114
+ /** Stringified ID of the developer product whose icon is being uploaded. */
115
+ readonly productId: string;
116
+ }
117
+ //#endregion
118
+ //#region src/domains/game-internationalization/developer-product-name-description/types.d.ts
119
+ /**
120
+ * Parameters for updating the per-locale name and/or description registered
121
+ * against a developer product. Both `name` and `description` are optional;
122
+ * fields omitted from the call are not included in the JSON body so the
123
+ * server leaves the existing value for that locale untouched.
124
+ */
125
+ interface UpdateDeveloperProductNameDescriptionParameters {
126
+ /** Replacement display name for the supplied locale. */
127
+ readonly name?: string;
128
+ /** Replacement description for the supplied locale. */
129
+ readonly description?: string;
130
+ /** BCP-47 language code being updated (e.g. `fr-fr`). */
131
+ readonly languageCode: string;
132
+ /** Stringified ID of the developer product whose localization is being updated. */
133
+ readonly productId: string;
134
+ }
135
+ //#endregion
136
+ //#region src/resources/developer-products/client.d.ts
137
+ interface DeveloperProductLocalizationHandle {
138
+ /**
139
+ * Updates the per-locale display name and/or description registered against
140
+ * a developer product. Either `name`, `description`, or both may be
141
+ * supplied; omitted fields are not forwarded so the server leaves the
142
+ * existing value for that locale untouched. Mirrors the upstream `200 OK`
143
+ * echo body as `undefined` data.
144
+ *
145
+ * @param parameters - Product and language identifiers plus the optional
146
+ * replacement values.
147
+ * @param options - Optional per-request overrides.
148
+ * @returns A success {@link Result} with no payload, or the
149
+ * {@link OpenCloudError} that caused the request to fail.
150
+ */
151
+ updateNameDescription: (parameters: UpdateDeveloperProductNameDescriptionParameters, options?: RequestOptions) => Promise<Result<undefined, OpenCloudError>>;
152
+ /**
153
+ * Uploads or replaces the per-locale icon for a developer product. A
154
+ * subsequent upload for the same `(productId, languageCode)` pair replaces
155
+ * the existing icon for that locale. Does not retry on 5xx so a duplicate
156
+ * upload cannot be created if the server fails mid-write.
157
+ *
158
+ * @param parameters - Product and language identifiers plus the image
159
+ * bytes to upload.
160
+ * @param options - Optional per-request overrides.
161
+ * @returns A success {@link Result} with no payload, or the
162
+ * {@link OpenCloudError} that caused the request to fail.
163
+ */
164
+ uploadIcon: (parameters: UploadDeveloperProductIconParameters, options?: RequestOptions) => Promise<Result<undefined, OpenCloudError>>;
165
+ }
166
+ /**
167
+ * Public client for the Roblox Open Cloud Developer Products API.
168
+ *
169
+ * Wires request builders, the injected {@link OpenCloudClientOptions.httpClient}, and response
170
+ * parsers into a single ergonomic surface. Every method returns a
171
+ * {@link Result} so callers handle failure explicitly; no thrown
172
+ * `OpenCloudError` ever escapes the client.
173
+ *
174
+ * ```ts
175
+ * import { DeveloperProductsClient } from "@bedrock-rbx/ocale/developer-products";
176
+ *
177
+ * const client = new DeveloperProductsClient({ apiKey: process.env.ROBLOX_API_KEY! });
178
+ *
179
+ * const result = await client.get({
180
+ * universeId: "1234567890",
181
+ * productId: "9876543210",
182
+ * });
183
+ *
184
+ * if (result.success) {
185
+ * console.log(`${result.data.name} (${result.data.id})`);
186
+ * } else {
187
+ * console.error(result.err.message);
188
+ * }
189
+ * ```
190
+ */
191
+ declare class DeveloperProductsClient {
192
+ #private;
193
+ /**
194
+ * Operation Group exposing per-locale localization Operations
195
+ * (`updateNameDescription`, `uploadIcon`) backed by the
196
+ * `legacy-game-internationalization` domain. Source-language values
197
+ * remain on {@link DeveloperProductsClient.update}; methods on this
198
+ * group set per-locale overlays on top. Shares the parent client's
199
+ * HTTP, rate-limit, and retry plumbing.
200
+ */
201
+ readonly localization: DeveloperProductLocalizationHandle;
202
+ /**
203
+ * Creates a new {@link DeveloperProductsClient}. Configuration is frozen
204
+ * on construction; per-request overrides are accepted on each method.
205
+ *
206
+ * @param options - Client-level configuration including the API key.
207
+ */
208
+ constructor(options: OpenCloudClientOptions);
209
+ /**
210
+ * Creates a new developer product under the supplied universe.
211
+ *
212
+ * @param parameters - Creation fields including the universe and product name.
213
+ * @param options - Optional per-request overrides.
214
+ * @returns A {@link Result} wrapping the parsed {@link DeveloperProduct} or
215
+ * the {@link OpenCloudError} that caused the request to fail.
216
+ */
217
+ create(parameters: CreateDeveloperProductParameters, options?: RequestOptions): Promise<Result<DeveloperProduct, OpenCloudError>>;
218
+ /**
219
+ * Reads a single developer product by ID.
220
+ *
221
+ * @param parameters - Universe and product identifiers.
222
+ * @param options - Optional per-request overrides (e.g. A different
223
+ * {@link OpenCloudClientOptions.apiKey} for this call only).
224
+ * @returns A {@link Result} wrapping the parsed {@link DeveloperProduct} or
225
+ * the {@link OpenCloudError} that caused the request to fail.
226
+ */
227
+ get(parameters: GetDeveloperProductParameters, options?: RequestOptions): Promise<Result<DeveloperProduct, OpenCloudError>>;
228
+ /**
229
+ * Partially updates an existing developer product. Mirrors the upstream
230
+ * `204 No Content` response: a successful update yields `undefined` data.
231
+ * Callers that need the post-update state (for example to observe a
232
+ * server-derived `updatedTimestamp`) chain {@link DeveloperProductsClient.get}
233
+ * themselves so the GET only fires when actually needed.
234
+ *
235
+ * @param parameters - The universe and product identifiers and the
236
+ * fields to update. Only fields explicitly provided are forwarded.
237
+ * @param options - Optional per-request overrides.
238
+ * @returns A success {@link Result} with no payload, or the
239
+ * {@link OpenCloudError} that caused the request to fail.
240
+ */
241
+ update(parameters: UpdateDeveloperProductParameters, options?: RequestOptions): Promise<Result<undefined, OpenCloudError>>;
242
+ }
243
+ //#endregion
244
+ export { type CreateDeveloperProductParameters, type DeveloperProduct, type DeveloperProductPrice, type DeveloperProductPricingFeature, DeveloperProductsClient, type GetDeveloperProductParameters, type UpdateDeveloperProductNameDescriptionParameters, type UpdateDeveloperProductParameters, type UploadDeveloperProductIconParameters };
245
+ //# sourceMappingURL=developer-products.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"developer-products.d.mts","names":[],"sources":["../src/domains/developer-products/products/types.ts","../src/domains/game-internationalization/developer-product-icon/types.ts","../src/domains/game-internationalization/developer-product-name-description/types.ts","../src/resources/developer-products/client.ts"],"mappings":";;;;;;AAIA;KAAY,8BAAA;;;;UASK,qBAAA;EAAA;EAAA,SAEP,mBAAA;EAEiB;EAAA,SAAjB,eAAA,EAAiB,aAAA,CAAc,8BAAA;AAAA;;;;;AAQzC;UAAiB,gBAAA;;WAEP,EAAA;;WAEA,IAAA;;WAEA,SAAA,EAAW,IAAA;;WAEX,WAAA;;WAEA,gBAAA;;WAEA,SAAA;;WAEA,WAAA;;WAEA,KAAA,EAAO,qBAAA;;WAEP,gBAAA;;WAEA,UAAA;;WAEA,SAAA,EAAW,IAAA;AAAA;;;;UAMJ,gCAAA;;WAEP,IAAA;;WAEA,WAAA;;WAEA,SAAA,GAAY,IAAA,GAAO,UAAA;;WAEnB,SAAA;;WAEA,wBAAA;EAUV;EAAA,SARU,KAAA;;WAEA,UAAA;AAAA;AAmBV;;;AAAA,UAbiB,6BAAA;;WAEP,SAAA;;WAEA,UAAA;AAAA;;;;;;;UASO,gCAAA;EAkBP;EAAA,SAhBA,IAAA;;WAEA,WAAA;ECpFV;EAAA,SDsFU,SAAA,GAAY,IAAA,GAAO,UAAA;;WAEnB,SAAA;;WAEA,wBAAA;;WAEA,KAAA;;WAEA,SAAA;ECxFA;EAAA,SD0FA,gBAAA;;WAEA,UAAA;AAAA;;;;;;AApGV;;;UCEiB,oCAAA;EDFL;EAAA,SCIF,KAAA,EAAO,IAAA,GAAO,UAAA;EDKP;EAAA,SCHP,YAAA;EDOiB;EAAA,SCLjB,SAAA;AAAA;;;;;;ADRV;;;UEEiB,+CAAA;EFFL;EAAA,SEIF,IAAA;EFKO;EAAA,SEHP,WAAA;EFOiB;EAAA,SELjB,YAAA;;WAEA,SAAA;AAAA;;;UC8EA,kCAAA;EHxFE;AASZ;;;;;;;;;;AAYA;;EGiFC,qBAAA,GACC,UAAA,EAAY,+CAAA,EACZ,OAAA,GAAU,cAAA,KACN,OAAA,CAAQ,MAAA,YAAkB,cAAA;;;;;;;;;;;;;EAa/B,UAAA,GACC,UAAA,EAAY,oCAAA,EACZ,OAAA,GAAU,cAAA,KACN,OAAA,CAAQ,MAAA,YAAkB,cAAA;AAAA;;;;;;;;AHxEhC;;;;;;;;;;;;;;;AAoBA;;;cGgFa,uBAAA;EAAA;EHnEb;;;;;;;;EAAA,SG8EiB,YAAA,EAAc,kCAAA;;;;;;;EAQ9B,WAAA,CAAY,OAAA,EAAS,sBAAA;EHpEZ;;;;AClGV;;;;EEmLC,MAAA,CACC,UAAA,EAAY,gCAAA,EACZ,OAAA,GAAU,cAAA,GACR,OAAA,CAAQ,MAAA,CAAO,gBAAA,EAAkB,cAAA;;;;;;;;;;EAapC,GAAA,CACC,UAAA,EAAY,6BAAA,EACZ,OAAA,GAAU,cAAA,GACR,OAAA,CAAQ,MAAA,CAAO,gBAAA,EAAkB,cAAA;EDtMpB;;;;;;;;;;;;AC8BW;EAyL3B,MAAA,CACC,UAAA,EAAY,gCAAA,EACZ,OAAA,GAAU,cAAA,GACR,OAAA,CAAQ,MAAA,YAAkB,cAAA;AAAA"}
@@ -0,0 +1,388 @@
1
+ import { i as ApiError } from "./rate-limit-BBU_4xnZ.mjs";
2
+ import { t as toBlob } from "./to-blob-1BtHsDGK.mjs";
3
+ import { a as IDEMPOTENT_METHOD_DEFAULTS, i as CREATE_METHOD_DEFAULTS, n as okRequest, o as isRecord, r as parseEmptyResponse, t as ResourceClient } from "./resource-client-CaS_j3yg.mjs";
4
+ import { n as isPriceInformationLike, t as copyPriceInformation } from "./price-information-CmpscMc4.mjs";
5
+ //#region src/domains/developer-products/products/builders.ts
6
+ /**
7
+ * Builds a `GET` request for the Open Cloud "read developer product"
8
+ * endpoint.
9
+ *
10
+ * @param parameters - Universe and product identifiers to interpolate into
11
+ * the URL.
12
+ * @returns A pure {@link HttpRequest} describing the read call.
13
+ */
14
+ function buildGetRequest(parameters) {
15
+ return {
16
+ method: "GET",
17
+ url: `/developer-products/v2/universes/${parameters.universeId}/developer-products/${parameters.productId}/creator`
18
+ };
19
+ }
20
+ /**
21
+ * Builds a `POST` request for the Open Cloud "create developer product"
22
+ * endpoint.
23
+ *
24
+ * @param parameters - Fields describing the new developer product; optional
25
+ * values omitted here are left off the multipart payload entirely.
26
+ * @returns A pure {@link HttpRequest} describing the create call.
27
+ */
28
+ function buildCreateRequest(parameters) {
29
+ const body = new FormData();
30
+ body.append("name", parameters.name);
31
+ if (parameters.description !== void 0) body.append("description", parameters.description);
32
+ if (parameters.isForSale !== void 0) body.append("isForSale", String(parameters.isForSale));
33
+ if (parameters.price !== void 0) body.append("price", String(parameters.price));
34
+ if (parameters.isRegionalPricingEnabled !== void 0) body.append("isRegionalPricingEnabled", String(parameters.isRegionalPricingEnabled));
35
+ if (parameters.imageFile !== void 0) body.append("imageFile", toBlob(parameters.imageFile));
36
+ return {
37
+ body,
38
+ method: "POST",
39
+ url: `/developer-products/v2/universes/${parameters.universeId}/developer-products`
40
+ };
41
+ }
42
+ /**
43
+ * Builds a `PATCH` request for the Open Cloud "update developer product"
44
+ * endpoint. Every field on `parameters` except the identifiers is optional;
45
+ * omitted fields are not appended to the multipart body so the server leaves
46
+ * them unchanged.
47
+ *
48
+ * @param parameters - Identifiers plus fields to update.
49
+ * @returns A pure {@link HttpRequest} describing the update call.
50
+ */
51
+ function buildUpdateRequest$1(parameters) {
52
+ const body = new FormData();
53
+ if (parameters.name !== void 0) body.append("name", parameters.name);
54
+ if (parameters.description !== void 0) body.append("description", parameters.description);
55
+ if (parameters.isForSale !== void 0) body.append("isForSale", String(parameters.isForSale));
56
+ if (parameters.price !== void 0) body.append("price", String(parameters.price));
57
+ if (parameters.isRegionalPricingEnabled !== void 0) body.append("isRegionalPricingEnabled", String(parameters.isRegionalPricingEnabled));
58
+ if (parameters.storePageEnabled !== void 0) body.append("storePageEnabled", String(parameters.storePageEnabled));
59
+ if (parameters.imageFile !== void 0) body.append("imageFile", toBlob(parameters.imageFile));
60
+ return {
61
+ body,
62
+ method: "PATCH",
63
+ url: `/developer-products/v2/universes/${parameters.universeId}/developer-products/${parameters.productId}`
64
+ };
65
+ }
66
+ //#endregion
67
+ //#region src/domains/developer-products/products/operations.ts
68
+ /**
69
+ * Per-second request ceiling for reading a single developer product, from
70
+ * the Open Cloud OpenAPI schema.
71
+ */
72
+ const GET_OPERATION_LIMIT = Object.freeze({
73
+ maxPerSecond: 10,
74
+ operationKey: "developer-products.get"
75
+ });
76
+ /**
77
+ * Per-second request ceiling for creating a developer product, from the
78
+ * Open Cloud OpenAPI schema.
79
+ */
80
+ const CREATE_OPERATION_LIMIT = Object.freeze({
81
+ maxPerSecond: 3,
82
+ operationKey: "developer-products.create"
83
+ });
84
+ /**
85
+ * Per-second request ceiling for updating a developer product, from the
86
+ * Open Cloud OpenAPI schema. Keyed independently from
87
+ * {@link CREATE_OPERATION_LIMIT} so create and update do not share a queue,
88
+ * since Roblox does not document the per-minute quota as shared between
89
+ * the POST and PATCH endpoints.
90
+ */
91
+ const UPDATE_OPERATION_LIMIT = Object.freeze({
92
+ maxPerSecond: 3,
93
+ operationKey: "developer-products.update"
94
+ });
95
+ /**
96
+ * Scopes the API key or OAuth token must carry to read a developer product,
97
+ * sourced from `x-roblox-scopes` on the `DeveloperProducts_GetDeveloperProductConfigV2`
98
+ * operation in the vendored OpenAPI schema.
99
+ */
100
+ const GET_REQUIRED_SCOPES = Object.freeze(["developer-product:read"]);
101
+ /**
102
+ * Scopes the API key or OAuth token must carry to create or update a developer
103
+ * product, sourced from `x-roblox-scopes` on the
104
+ * `DeveloperProducts_CreateDeveloperProductV2` and
105
+ * `DeveloperProducts_UpdateDeveloperProductV2` operations in the vendored
106
+ * OpenAPI schema.
107
+ */
108
+ const WRITE_REQUIRED_SCOPES = Object.freeze(["developer-product:write"]);
109
+ //#endregion
110
+ //#region src/domains/developer-products/products/parsers.ts
111
+ /**
112
+ * Parses a successful Developer Products API response into the public
113
+ * `DeveloperProduct` shape, returning a `Result` so callers can handle
114
+ * malformed payloads without exceptions.
115
+ *
116
+ * @param response - The full {@link HttpResponse} from the Open Cloud API.
117
+ * The status code is included on the returned `ApiError` when validation
118
+ * fails; the headers are available for future parsers that need them.
119
+ * @returns A success result wrapping the converted `DeveloperProduct`, or
120
+ * an `ApiError` when the body does not match the wire schema.
121
+ */
122
+ function parseDeveloperProductResponse(response) {
123
+ const { body, status: statusCode } = response;
124
+ if (!isDeveloperProductConfigV2(body)) return {
125
+ err: new ApiError("Malformed developer product response", { statusCode }),
126
+ success: false
127
+ };
128
+ const priceWire = body.priceInformation ?? void 0;
129
+ const iconAssetId = body.iconImageAssetId ?? void 0;
130
+ return {
131
+ data: {
132
+ id: String(body.productId),
133
+ name: body.name,
134
+ createdAt: new Date(body.createdTimestamp),
135
+ description: body.description,
136
+ iconImageAssetId: iconAssetId === void 0 ? void 0 : String(iconAssetId),
137
+ isForSale: body.isForSale,
138
+ isImmutable: body.isImmutable,
139
+ price: priceWire === void 0 ? void 0 : copyPriceInformation(priceWire),
140
+ storePageEnabled: body.storePageEnabled,
141
+ universeId: String(body.universeId),
142
+ updatedAt: new Date(body.updatedTimestamp)
143
+ },
144
+ success: true
145
+ };
146
+ }
147
+ function hasRequiredPrimitiveFields(body) {
148
+ return typeof body["productId"] === "number" && body["productId"] !== 0 && typeof body["universeId"] === "number" && typeof body["name"] === "string" && typeof body["description"] === "string" && typeof body["isForSale"] === "boolean" && typeof body["isImmutable"] === "boolean" && typeof body["storePageEnabled"] === "boolean" && typeof body["createdTimestamp"] === "string" && typeof body["updatedTimestamp"] === "string";
149
+ }
150
+ function isPricingFeatureWire(value) {
151
+ return value === "Invalid" || value === "PriceOptimization" || value === "RegionalPricing" || value === "UserFixedPrice";
152
+ }
153
+ function isDeveloperProductConfigV2(body) {
154
+ if (!isRecord(body)) return false;
155
+ if (!hasRequiredPrimitiveFields(body)) return false;
156
+ const iconImageAssetId = body["iconImageAssetId"] ?? void 0;
157
+ if (iconImageAssetId !== void 0 && typeof iconImageAssetId !== "number") return false;
158
+ const price = body["priceInformation"] ?? void 0;
159
+ if (price !== void 0 && !isPriceInformationLike(price, isPricingFeatureWire)) return false;
160
+ return true;
161
+ }
162
+ //#endregion
163
+ //#region src/domains/game-internationalization/developer-product-icon/builders.ts
164
+ /**
165
+ * Builds a `POST` request for the localized "upload developer-product icon"
166
+ * endpoint. A successful upload replaces any existing icon for the same
167
+ * `(productId, languageCode)` pair.
168
+ *
169
+ * @param parameters - Product and language identifiers plus the image bytes
170
+ * to upload.
171
+ * @returns A pure {@link HttpRequest} describing the upload call.
172
+ */
173
+ function buildUploadIconRequest(parameters) {
174
+ const body = new FormData();
175
+ body.append("Files", toBlob(parameters.image));
176
+ return {
177
+ body,
178
+ method: "POST",
179
+ url: `/legacy-game-internationalization/v1/developer-products/${parameters.productId}/icons/language-codes/${parameters.languageCode}`
180
+ };
181
+ }
182
+ //#endregion
183
+ //#region src/domains/game-internationalization/developer-product-name-description/builders.ts
184
+ /**
185
+ * Builds a `PATCH` request for the localized "update developer-product
186
+ * name/description" endpoint. Either `name`, `description`, or both may be
187
+ * supplied; omitted fields are not included in the JSON body so the server
188
+ * leaves the existing value for that locale untouched.
189
+ *
190
+ * @param parameters - Product and language identifiers plus the optional
191
+ * replacement values.
192
+ * @returns A pure {@link HttpRequest} describing the update call.
193
+ */
194
+ function buildUpdateRequest(parameters) {
195
+ const body = {};
196
+ if (parameters.name !== void 0) body["name"] = parameters.name;
197
+ if (parameters.description !== void 0) body["description"] = parameters.description;
198
+ return {
199
+ body,
200
+ method: "PATCH",
201
+ url: `/legacy-game-internationalization/v1/developer-products/${parameters.productId}/name-description/language-codes/${parameters.languageCode}`
202
+ };
203
+ }
204
+ //#endregion
205
+ //#region src/domains/game-internationalization/developer-product-name-description/operations.ts
206
+ /**
207
+ * Per-second request ceiling for every developer-product localization
208
+ * Operation. The legacy `gameinternationalization` service caps each API key
209
+ * at 100 requests per minute *shared across the entire service* (see the
210
+ * `x-roblox-rate-limits` extension on every operation in the vendored Open
211
+ * Cloud spec), so all developer-product localization methods queue against
212
+ * the same operation key.
213
+ */
214
+ const LOCALIZATION_OPERATION_LIMIT = Object.freeze({
215
+ maxPerSecond: 100 / 60,
216
+ operationKey: "developer-product-localization"
217
+ });
218
+ /**
219
+ * Scopes required for every developer-product localization operation, sourced
220
+ * from `x-roblox-scopes` on the legacy `gameinternationalization`
221
+ * developer-product endpoints in the vendored OpenAPI schema.
222
+ */
223
+ const LOCALIZATION_REQUIRED_SCOPES = Object.freeze(["legacy-developer-product:manage"]);
224
+ //#endregion
225
+ //#region src/resources/developer-products/client.ts
226
+ function makeSpec(spec) {
227
+ return Object.freeze(spec);
228
+ }
229
+ const CREATE_SPEC = makeSpec({
230
+ buildRequest: (parameters) => okRequest(buildCreateRequest(parameters)),
231
+ methodDefaults: CREATE_METHOD_DEFAULTS,
232
+ methodKind: "create",
233
+ operationLimit: CREATE_OPERATION_LIMIT,
234
+ parse: parseDeveloperProductResponse,
235
+ requiredScopes: WRITE_REQUIRED_SCOPES
236
+ });
237
+ const GET_SPEC = makeSpec({
238
+ buildRequest: (parameters) => okRequest(buildGetRequest(parameters)),
239
+ methodDefaults: IDEMPOTENT_METHOD_DEFAULTS,
240
+ methodKind: "idempotent",
241
+ operationLimit: GET_OPERATION_LIMIT,
242
+ parse: parseDeveloperProductResponse,
243
+ requiredScopes: GET_REQUIRED_SCOPES
244
+ });
245
+ const UPDATE_SPEC = makeSpec({
246
+ buildRequest: (parameters) => okRequest(buildUpdateRequest$1(parameters)),
247
+ methodDefaults: IDEMPOTENT_METHOD_DEFAULTS,
248
+ methodKind: "idempotent",
249
+ operationLimit: UPDATE_OPERATION_LIMIT,
250
+ parse: parseEmptyResponse,
251
+ requiredScopes: WRITE_REQUIRED_SCOPES
252
+ });
253
+ const UPDATE_NAME_DESCRIPTION_SPEC = makeSpec({
254
+ buildRequest: (parameters) => okRequest(buildUpdateRequest(parameters)),
255
+ methodDefaults: IDEMPOTENT_METHOD_DEFAULTS,
256
+ methodKind: "idempotent",
257
+ operationLimit: LOCALIZATION_OPERATION_LIMIT,
258
+ parse: parseEmptyResponse,
259
+ requiredScopes: LOCALIZATION_REQUIRED_SCOPES
260
+ });
261
+ const UPLOAD_ICON_SPEC = makeSpec({
262
+ buildRequest: (parameters) => okRequest(buildUploadIconRequest(parameters)),
263
+ methodDefaults: CREATE_METHOD_DEFAULTS,
264
+ methodKind: "create",
265
+ operationLimit: LOCALIZATION_OPERATION_LIMIT,
266
+ parse: parseEmptyResponse,
267
+ requiredScopes: LOCALIZATION_REQUIRED_SCOPES
268
+ });
269
+ /**
270
+ * Public client for the Roblox Open Cloud Developer Products API.
271
+ *
272
+ * Wires request builders, the injected {@link OpenCloudClientOptions.httpClient}, and response
273
+ * parsers into a single ergonomic surface. Every method returns a
274
+ * {@link Result} so callers handle failure explicitly; no thrown
275
+ * `OpenCloudError` ever escapes the client.
276
+ *
277
+ * ```ts
278
+ * import { DeveloperProductsClient } from "@bedrock-rbx/ocale/developer-products";
279
+ *
280
+ * const client = new DeveloperProductsClient({ apiKey: process.env.ROBLOX_API_KEY! });
281
+ *
282
+ * const result = await client.get({
283
+ * universeId: "1234567890",
284
+ * productId: "9876543210",
285
+ * });
286
+ *
287
+ * if (result.success) {
288
+ * console.log(`${result.data.name} (${result.data.id})`);
289
+ * } else {
290
+ * console.error(result.err.message);
291
+ * }
292
+ * ```
293
+ */
294
+ var DeveloperProductsClient = class {
295
+ #inner;
296
+ /**
297
+ * Operation Group exposing per-locale localization Operations
298
+ * (`updateNameDescription`, `uploadIcon`) backed by the
299
+ * `legacy-game-internationalization` domain. Source-language values
300
+ * remain on {@link DeveloperProductsClient.update}; methods on this
301
+ * group set per-locale overlays on top. Shares the parent client's
302
+ * HTTP, rate-limit, and retry plumbing.
303
+ */
304
+ localization;
305
+ /**
306
+ * Creates a new {@link DeveloperProductsClient}. Configuration is frozen
307
+ * on construction; per-request overrides are accepted on each method.
308
+ *
309
+ * @param options - Client-level configuration including the API key.
310
+ */
311
+ constructor(options) {
312
+ this.#inner = new ResourceClient(options);
313
+ this.localization = createLocalizationHandle(this.#inner);
314
+ }
315
+ /**
316
+ * Creates a new developer product under the supplied universe.
317
+ *
318
+ * @param parameters - Creation fields including the universe and product name.
319
+ * @param options - Optional per-request overrides.
320
+ * @returns A {@link Result} wrapping the parsed {@link DeveloperProduct} or
321
+ * the {@link OpenCloudError} that caused the request to fail.
322
+ */
323
+ async create(parameters, options) {
324
+ return this.#inner.execute({
325
+ options,
326
+ parameters,
327
+ spec: CREATE_SPEC
328
+ });
329
+ }
330
+ /**
331
+ * Reads a single developer product by ID.
332
+ *
333
+ * @param parameters - Universe and product identifiers.
334
+ * @param options - Optional per-request overrides (e.g. A different
335
+ * {@link OpenCloudClientOptions.apiKey} for this call only).
336
+ * @returns A {@link Result} wrapping the parsed {@link DeveloperProduct} or
337
+ * the {@link OpenCloudError} that caused the request to fail.
338
+ */
339
+ async get(parameters, options) {
340
+ return this.#inner.execute({
341
+ options,
342
+ parameters,
343
+ spec: GET_SPEC
344
+ });
345
+ }
346
+ /**
347
+ * Partially updates an existing developer product. Mirrors the upstream
348
+ * `204 No Content` response: a successful update yields `undefined` data.
349
+ * Callers that need the post-update state (for example to observe a
350
+ * server-derived `updatedTimestamp`) chain {@link DeveloperProductsClient.get}
351
+ * themselves so the GET only fires when actually needed.
352
+ *
353
+ * @param parameters - The universe and product identifiers and the
354
+ * fields to update. Only fields explicitly provided are forwarded.
355
+ * @param options - Optional per-request overrides.
356
+ * @returns A success {@link Result} with no payload, or the
357
+ * {@link OpenCloudError} that caused the request to fail.
358
+ */
359
+ async update(parameters, options) {
360
+ return this.#inner.execute({
361
+ options,
362
+ parameters,
363
+ spec: UPDATE_SPEC
364
+ });
365
+ }
366
+ };
367
+ function createLocalizationHandle(inner) {
368
+ return {
369
+ async updateNameDescription(parameters, options) {
370
+ return inner.execute({
371
+ options,
372
+ parameters,
373
+ spec: UPDATE_NAME_DESCRIPTION_SPEC
374
+ });
375
+ },
376
+ async uploadIcon(parameters, options) {
377
+ return inner.execute({
378
+ options,
379
+ parameters,
380
+ spec: UPLOAD_ICON_SPEC
381
+ });
382
+ }
383
+ };
384
+ }
385
+ //#endregion
386
+ export { DeveloperProductsClient };
387
+
388
+ //# sourceMappingURL=developer-products.mjs.map