@bedrock-rbx/ocale 0.1.0-beta.1 → 0.1.0-beta.10

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.
Files changed (70) hide show
  1. package/dist/badges.d.mts +86 -3
  2. package/dist/badges.d.mts.map +1 -1
  3. package/dist/badges.mjs +113 -6
  4. package/dist/badges.mjs.map +1 -1
  5. package/dist/data.generated-Cb6g6asv.d.mts +485 -0
  6. package/dist/data.generated-Cb6g6asv.d.mts.map +1 -0
  7. package/dist/developer-products.d.mts +14 -5
  8. package/dist/developer-products.d.mts.map +1 -1
  9. package/dist/developer-products.mjs +5 -5
  10. package/dist/developer-products.mjs.map +1 -1
  11. package/dist/game-passes.d.mts +83 -2
  12. package/dist/game-passes.d.mts.map +1 -1
  13. package/dist/game-passes.mjs +111 -5
  14. package/dist/game-passes.mjs.map +1 -1
  15. package/dist/index.d.mts +75 -64
  16. package/dist/index.d.mts.map +1 -1
  17. package/dist/index.mjs +5 -3
  18. package/dist/locales.d.mts +2 -0
  19. package/dist/locales.mjs +512 -0
  20. package/dist/locales.mjs.map +1 -0
  21. package/dist/luau-execution.d.mts +149 -0
  22. package/dist/luau-execution.d.mts.map +1 -0
  23. package/dist/luau-execution.mjs +164 -0
  24. package/dist/luau-execution.mjs.map +1 -0
  25. package/dist/permission-error-DOVtNq3A.mjs +46 -0
  26. package/dist/permission-error-DOVtNq3A.mjs.map +1 -0
  27. package/dist/places.d.mts +87 -8
  28. package/dist/places.d.mts.map +1 -1
  29. package/dist/places.mjs +58 -69
  30. package/dist/places.mjs.map +1 -1
  31. package/dist/poll-timeout-Dg_QFEqi.mjs +79 -0
  32. package/dist/poll-timeout-Dg_QFEqi.mjs.map +1 -0
  33. package/dist/polling-BMrYajok.d.mts +253 -0
  34. package/dist/polling-BMrYajok.d.mts.map +1 -0
  35. package/dist/polling-helpers-QGjvYq3c.mjs +650 -0
  36. package/dist/polling-helpers-QGjvYq3c.mjs.map +1 -0
  37. package/dist/{price-information-CmpscMc4.mjs → price-information-DIrvwCmd.mjs} +2 -2
  38. package/dist/{price-information-CmpscMc4.mjs.map → price-information-DIrvwCmd.mjs.map} +1 -1
  39. package/dist/rate-limit-BYuizHoD.d.mts +92 -0
  40. package/dist/rate-limit-BYuizHoD.d.mts.map +1 -0
  41. package/dist/{rate-limit-BBU_4xnZ.mjs → rate-limit-D1q2Js-z.mjs} +12 -46
  42. package/dist/rate-limit-D1q2Js-z.mjs.map +1 -0
  43. package/dist/{resource-client-CaS_j3yg.mjs → resource-client-D6Efj9fU.mjs} +95 -15
  44. package/dist/resource-client-D6Efj9fU.mjs.map +1 -0
  45. package/dist/signatures-B5Fojgn0.mjs +59 -0
  46. package/dist/signatures-B5Fojgn0.mjs.map +1 -0
  47. package/dist/storage.d.mts +662 -0
  48. package/dist/storage.d.mts.map +1 -0
  49. package/dist/storage.mjs +858 -0
  50. package/dist/storage.mjs.map +1 -0
  51. package/dist/testing.d.mts +727 -0
  52. package/dist/testing.d.mts.map +1 -0
  53. package/dist/testing.mjs +457 -0
  54. package/dist/testing.mjs.map +1 -0
  55. package/dist/{to-blob-1BtHsDGK.mjs → to-blob-B27VhoRp.mjs} +1 -1
  56. package/dist/{to-blob-1BtHsDGK.mjs.map → to-blob-B27VhoRp.mjs.map} +1 -1
  57. package/dist/{types-YCTsM8Qd.d.mts → types-CwtZT1ek.d.mts} +1 -1
  58. package/dist/{types-YCTsM8Qd.d.mts.map → types-CwtZT1ek.d.mts.map} +1 -1
  59. package/dist/universes.d.mts +38 -18
  60. package/dist/universes.d.mts.map +1 -1
  61. package/dist/universes.mjs +5 -5
  62. package/dist/universes.mjs.map +1 -1
  63. package/dist/{validation-CTZzJhmd.mjs → validation-DkL5KQqz.mjs} +2 -2
  64. package/dist/validation-DkL5KQqz.mjs.map +1 -0
  65. package/dist/wire-CeL6W_V7.d.mts +35 -0
  66. package/dist/wire-CeL6W_V7.d.mts.map +1 -0
  67. package/package.json +8 -3
  68. package/dist/rate-limit-BBU_4xnZ.mjs.map +0 -1
  69. package/dist/resource-client-CaS_j3yg.mjs.map +0 -1
  70. package/dist/validation-CTZzJhmd.mjs.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"polling-BMrYajok.d.mts","names":[],"sources":["../src/domains/cloud-v2/luau-execution-tasks/types.ts","../src/domains/cloud-v2/luau-execution-task-logs/types.ts","../src/resources/luau-execution/polling.ts"],"mappings":";;;;;;AAKA;;UAAiB,sBAAA;EAAA;;;;EAAA,SAKP,WAAA;;WAEA,kBAAA;;WAEA,OAAA;EAiBV;EAAA,SAfU,MAAA;;;;;WAKA,cAAA;;WAEA,UAAA;AAAA;;;;AAsCV;;UA9BiB,yBAAA;EA8BA;;;;EAAA,SAzBP,WAAA;;WAEA,kBAAA;EAiCA;EAAA,SA/BA,OAAA;EAsCO;EAAA,SApCP,MAAA;EAsCK;;;;EAAA,SAjCL,cAAA;EAuCA;EAAA,SArCA,UAAA;EA6CO;EAAA,SA3CP,SAAA;AAAA;;AAsDV;;;;;;UA5CiB,oBAAA;EA4CqB;EAAA,SA1C5B,OAAA;;WAEA,SAAA;;WAEA,MAAA;;WAEA,UAAA;EA4CA;EAAA,SA1CA,SAAA;AAAA;;;;;UAOO,aAAA;;WAEP,GAAA,EAAK,oBAAA;;;AAmEf;;;WA7DU,IAAA;AAAA;;;;;;UAQO,cAAA,SAAuB,qBAAA;;WAE9B,KAAA;AAAA;;;;;;;UASO,YAAA,SAAqB,qBAAA;;;;;;WAM5B,MAAA;IAAA,SAAmB,OAAA,EAAS,aAAA,CAAc,SAAA;EAAA;;WAE1C,KAAA;AAAA;;;;;;ACzGV;UDkHiB,UAAA,SAAmB,qBAAA;;WAE1B,KAAA;IC9GA;;;;;;IAAA,SDqHC,IAAA,0FCtGM;IAAA,SD4GN,OAAA;EAAA;;WAGD,KAAA;AAAA;;;AC7FV;;KDoGY,iBAAA,GAAoB,YAAA,GAAe,UAAA,GAAa,cAAA;;;;;;UAOlD,qBAAA;ECpGA;;;;EAAA,SDyGA,WAAA;EEpIE;;;;AAAqC;EAArC,SF0IF,eAAA;;WAEA,SAAA,GAAY,IAAA;;WAEZ,kBAAA;;WAEA,GAAA,EAAK,oBAAA;;;;;;WAML,cAAA;;WAEA,SAAA,GAAY,IAAA;;WAEZ,IAAA;AAAA;;;;AAhLV;;;UCGiB,kBAAA;;;;;;WAMP,QAAA;;;ADiBV;;WCZU,SAAA;EDYO;EAAA,SCVP,GAAA,EAAK,oBAAA;AAAA;;;;;;UAQE,UAAA;EDsBP;EAAA,SCpBA,UAAA;ED8BO;EAAA,SC5BP,OAAA;ED4BO;;;;EAAA,SCvBP,WAAA;AAAA;;;ADwCV;;;;UC/BiB,OAAA;;WAEP,QAAA,EAAU,aAAA,CAAc,UAAA;;;AD6ClC;;WCxCU,aAAA;AAAA;;;;KC3BE,oBAAA,GAAuB,WAAA,GAAc,cAAA;;UAGvC,WAAA;;WAEA,SAAA,IAAa,OAAA;;WAEb,MAAA,GAAS,WAAA;EF2BnB;EAAA,SEzBU,SAAA;AAAA;;;;;;;;;AF0CV"}
@@ -0,0 +1,650 @@
1
+ import { r as ApiError } from "./rate-limit-D1q2Js-z.mjs";
2
+ import { n as PollAbortedError, t as PollTimeoutError } from "./poll-timeout-Dg_QFEqi.mjs";
3
+ import { t as ValidationError } from "./validation-DkL5KQqz.mjs";
4
+ import { a as IDEMPOTENT_METHOD_DEFAULTS, c as isDateTimeString, i as CREATE_METHOD_DEFAULTS, n as okRequest, o as defaultRetryDelay, s as isRecord } from "./resource-client-D6Efj9fU.mjs";
5
+ //#region src/domains/cloud-v2/luau-execution-task-logs/builders.ts
6
+ /**
7
+ * Builds a `GET` request for the Open Cloud "list Luau execution session
8
+ * task logs" endpoint. The endpoint requires the maximal x-aep-resource
9
+ * path shape (universe, place, version, session, task), so the supplied
10
+ * ref must include `versionId` and `sessionId`; refs extracted from the
11
+ * narrower path formats are rejected with a {@link ValidationError}.
12
+ *
13
+ * The `view` query parameter is hard-coded to `STRUCTURED` so callers
14
+ * always receive typed structured messages. No public `view` parameter
15
+ * is exposed.
16
+ *
17
+ * @param parameters - Task ref, and optional `pageSize` and `pageToken`
18
+ * pagination controls.
19
+ * @returns A success result wrapping the request, or a
20
+ * {@link ValidationError} when the ref is missing `versionId` or
21
+ * `sessionId`.
22
+ */
23
+ function buildListLogsRequest(parameters) {
24
+ const { pageSize, pageToken, ref } = parameters;
25
+ const { placeId, sessionId, taskId, universeId, versionId } = ref;
26
+ if (versionId === void 0) return {
27
+ err: new ValidationError("Task ref is missing versionId; cannot list logs", { code: "incomplete_ref" }),
28
+ success: false
29
+ };
30
+ if (sessionId === void 0) return {
31
+ err: new ValidationError("Task ref is missing sessionId; cannot list logs", { code: "incomplete_ref" }),
32
+ success: false
33
+ };
34
+ return {
35
+ data: {
36
+ method: "GET",
37
+ url: `${`/cloud/v2/universes/${universeId}/places/${placeId}/versions/${versionId}/luau-execution-sessions/${sessionId}/tasks/${taskId}/logs`}?${buildQuery(pageSize, pageToken).toString()}`
38
+ },
39
+ success: true
40
+ };
41
+ }
42
+ function buildQuery(pageSize, pageToken) {
43
+ const query = new URLSearchParams({ view: "STRUCTURED" });
44
+ if (pageSize !== void 0) query.append("maxPageSize", String(pageSize));
45
+ if (pageToken !== void 0) query.append("pageToken", pageToken);
46
+ return query;
47
+ }
48
+ /**
49
+ * Per-second request ceiling for listing Luau execution task logs,
50
+ * sourced from `x-roblox-rate-limits.perApiKeyOwner` on the
51
+ * `Cloud_ListLuauExecutionSessionTaskLogs` operation (45 requests per
52
+ * minute per API key owner).
53
+ */
54
+ const LIST_LOGS_OPERATION_LIMIT = Object.freeze({
55
+ maxPerSecond: 45 / 60,
56
+ operationKey: "luau-execution-task-logs.list"
57
+ });
58
+ /**
59
+ * Scopes required to list Luau execution task logs, sourced from
60
+ * `x-roblox-scopes` on the list-logs operation in the vendored OpenAPI
61
+ * schema. Surfaced via the `requiredScopes` field of the per-method
62
+ * spec so a 401 or 403 ApiError is upgraded to a `PermissionError`
63
+ * naming the missing scope. Only `:read` is required as the
64
+ * minimum-privilege scope for this read-only operation.
65
+ */
66
+ const LIST_LOGS_REQUIRED_SCOPES = Object.freeze(["universe.place.luau-execution-session:read"]);
67
+ //#endregion
68
+ //#region src/domains/cloud-v2/luau-execution-task-logs/parsers.ts
69
+ const MALFORMED_LOGS_MESSAGE = "Malformed list-luau-execution-task-logs response";
70
+ /**
71
+ * Parses a successful Open Cloud list-luau-execution-task-logs response
72
+ * body into the public {@link LogPage} shape. Chunks are flattened into
73
+ * a single ordered array of {@link LogMessage} values. The
74
+ * `MESSAGE_TYPE_UNSPECIFIED` sentinel is rejected.
75
+ *
76
+ * @param response - The full {@link HttpResponse} from the Open Cloud API.
77
+ * @returns A success result wrapping the parsed {@link LogPage}, or an
78
+ * {@link ApiError} when the body does not match a supported shape.
79
+ */
80
+ function parseListLogsResponse(response) {
81
+ const { body, status: statusCode } = response;
82
+ if (!isRecord(body)) return malformed$1(statusCode);
83
+ const rawChunks = body["luauExecutionSessionTaskLogs"] ?? void 0;
84
+ if (!isOptionalLogChunks(rawChunks)) return malformed$1(statusCode);
85
+ const rawToken = body["nextPageToken"] ?? void 0;
86
+ if (rawToken !== void 0 && typeof rawToken !== "string") return malformed$1(statusCode);
87
+ const messages = [];
88
+ for (const chunk of rawChunks ?? []) for (const wireMessage of chunk.structuredMessages ?? []) messages.push({
89
+ createTime: wireMessage.createTime,
90
+ message: wireMessage.message,
91
+ messageType: wireMessage.messageType
92
+ });
93
+ return {
94
+ data: {
95
+ messages,
96
+ nextPageToken: rawToken
97
+ },
98
+ success: true
99
+ };
100
+ }
101
+ function isAcceptedMessageType(value) {
102
+ return value === "OUTPUT" || value === "INFO" || value === "WARNING" || value === "ERROR";
103
+ }
104
+ function isLogMessageWire(value) {
105
+ return isRecord(value) && typeof value["createTime"] === "string" && typeof value["message"] === "string" && isAcceptedMessageType(value["messageType"]);
106
+ }
107
+ function isOptionalStructuredMessages(value) {
108
+ return value === void 0 || Array.isArray(value) && value.every((item) => isLogMessageWire(item));
109
+ }
110
+ function isLogChunkWire(value) {
111
+ return isRecord(value) && isOptionalStructuredMessages(value["structuredMessages"]);
112
+ }
113
+ function isOptionalLogChunks(value) {
114
+ return value === void 0 || Array.isArray(value) && value.every((item) => isLogChunkWire(item));
115
+ }
116
+ function malformed$1(statusCode) {
117
+ return {
118
+ err: new ApiError(MALFORMED_LOGS_MESSAGE, { statusCode }),
119
+ success: false
120
+ };
121
+ }
122
+ //#endregion
123
+ //#region src/domains/cloud-v2/luau-execution-task-logs/specs.ts
124
+ function makeSpec$1(spec) {
125
+ return Object.freeze(spec);
126
+ }
127
+ /**
128
+ * Per-method dispatch spec for listing the structured log messages
129
+ * produced by a Luau execution task. Frozen at module scope so both
130
+ * the top-level `LuauExecutionClient` and the `luauExecution` Operation
131
+ * Group on `PlacesClient` share the same instance reference.
132
+ */
133
+ const LIST_LOGS_SPEC = makeSpec$1({
134
+ buildRequest: buildListLogsRequest,
135
+ methodDefaults: IDEMPOTENT_METHOD_DEFAULTS,
136
+ methodKind: "idempotent",
137
+ operationLimit: LIST_LOGS_OPERATION_LIMIT,
138
+ parse: parseListLogsResponse,
139
+ requiredScopes: LIST_LOGS_REQUIRED_SCOPES
140
+ });
141
+ //#endregion
142
+ //#region src/domains/cloud-v2/luau-execution-tasks/builders.ts
143
+ const JSON_HEADERS = { "content-type": "application/json" };
144
+ /**
145
+ * Builds a `POST` request for the Open Cloud "create Luau execution
146
+ * session task" endpoint, targeting the place's head version. Serializes
147
+ * `timeoutSeconds` into the wire's duration string format (`"<n>s"`)
148
+ * when supplied.
149
+ *
150
+ * @param parameters - Universe and place identifiers, the script body,
151
+ * and an optional `timeoutSeconds`.
152
+ * @returns A pure {@link HttpRequest} describing the submit call.
153
+ */
154
+ function buildSubmitAtHeadRequest(parameters) {
155
+ const { placeId, universeId } = parameters;
156
+ return {
157
+ body: buildSubmitBody(parameters),
158
+ headers: JSON_HEADERS,
159
+ method: "POST",
160
+ url: `/cloud/v2/universes/${universeId}/places/${placeId}/luau-execution-session-tasks`
161
+ };
162
+ }
163
+ /**
164
+ * Builds a `POST` request for the Open Cloud "create Luau execution
165
+ * session task" endpoint, targeting a specific place version. Differs
166
+ * from {@link buildSubmitAtHeadRequest} only in URL shape: the path
167
+ * includes the `versions/{versionId}` segment so the script runs
168
+ * against that exact place version instead of the live head.
169
+ *
170
+ * @param parameters - Universe, place, and version identifiers, the
171
+ * script body, and an optional `timeoutSeconds`.
172
+ * @returns A pure {@link HttpRequest} describing the submit call.
173
+ */
174
+ function buildSubmitAtVersionRequest(parameters) {
175
+ const { placeId, universeId, versionId } = parameters;
176
+ return {
177
+ body: buildSubmitBody(parameters),
178
+ headers: JSON_HEADERS,
179
+ method: "POST",
180
+ url: `/cloud/v2/universes/${universeId}/places/${placeId}/versions/${versionId}/luau-execution-session-tasks`
181
+ };
182
+ }
183
+ /**
184
+ * Builds a `GET` request for the Open Cloud "read Luau execution session
185
+ * task" endpoint. The endpoint accepts only the maximal x-aep-resource
186
+ * path shape (universe, place, version, session, task), so the supplied
187
+ * ref must include `versionId` and `sessionId`; refs extracted from the
188
+ * narrower path formats are rejected with a {@link ValidationError}.
189
+ *
190
+ * @param parameters - Task ref and optional view selector. When `view`
191
+ * is omitted, no `?view=` query is sent and the server applies its
192
+ * own default (`BASIC`).
193
+ * @returns A success result wrapping the request, or a
194
+ * {@link ValidationError} when the ref is missing `versionId` or
195
+ * `sessionId`.
196
+ */
197
+ function buildGetRequest(parameters) {
198
+ const { ref, view } = parameters;
199
+ const { placeId, sessionId, taskId, universeId, versionId } = ref;
200
+ if (versionId === void 0) return {
201
+ err: new ValidationError("Task ref is missing versionId; cannot GET", { code: "incomplete_ref" }),
202
+ success: false
203
+ };
204
+ if (sessionId === void 0) return {
205
+ err: new ValidationError("Task ref is missing sessionId; cannot GET", { code: "incomplete_ref" }),
206
+ success: false
207
+ };
208
+ const base = `/cloud/v2/universes/${universeId}/places/${placeId}/versions/${versionId}/luau-execution-sessions/${sessionId}/tasks/${taskId}`;
209
+ return {
210
+ data: {
211
+ method: "GET",
212
+ url: view === void 0 ? base : `${base}?view=${view}`
213
+ },
214
+ success: true
215
+ };
216
+ }
217
+ function buildSubmitBody(parameters) {
218
+ const { binaryInput, enableBinaryOutput: shouldEnableBinaryOutput, script, timeoutSeconds } = parameters;
219
+ const body = { script };
220
+ if (timeoutSeconds !== void 0) body["timeout"] = `${timeoutSeconds}s`;
221
+ if (binaryInput !== void 0) body["binaryInput"] = binaryInput;
222
+ if (shouldEnableBinaryOutput !== void 0) body["enableBinaryOutput"] = shouldEnableBinaryOutput;
223
+ return body;
224
+ }
225
+ //#endregion
226
+ //#region src/domains/cloud-v2/luau-execution-tasks/operations.ts
227
+ const SUBMIT_PER_MINUTE = 40;
228
+ const GET_PER_MINUTE = 200;
229
+ const SECONDS_PER_MINUTE = 60;
230
+ /**
231
+ * Per-second request ceiling for submitting a Luau execution task,
232
+ * sourced from `x-roblox-rate-limits.perApiKeyOwner` on the
233
+ * `Cloud_CreateLuauExecutionSessionTask__Using_Universes` operation
234
+ * (40 requests per minute per API key owner). The two URL shapes
235
+ * (head and version) share this queue because Roblox attributes both
236
+ * to the same per-minute quota.
237
+ */
238
+ const SUBMIT_OPERATION_LIMIT = Object.freeze({
239
+ maxPerSecond: SUBMIT_PER_MINUTE / SECONDS_PER_MINUTE,
240
+ operationKey: "luau-execution-tasks.submit"
241
+ });
242
+ /**
243
+ * Per-second request ceiling for fetching a Luau execution task,
244
+ * sourced from `x-roblox-rate-limits.perApiKeyOwner` on the
245
+ * `Cloud_GetLuauExecutionSessionTask` operation (200 requests per
246
+ * minute per API key owner).
247
+ */
248
+ const GET_OPERATION_LIMIT = Object.freeze({
249
+ maxPerSecond: GET_PER_MINUTE / SECONDS_PER_MINUTE,
250
+ operationKey: "luau-execution-tasks.get"
251
+ });
252
+ /**
253
+ * Scopes required to submit a Luau execution task, sourced from
254
+ * `x-roblox-scopes` on the create operation in the vendored OpenAPI
255
+ * schema. Surfaced via the `requiredScopes` field of the per-method
256
+ * spec so a 401 or 403 ApiError is upgraded to a `PermissionError`
257
+ * naming the missing scope.
258
+ */
259
+ const SUBMIT_REQUIRED_SCOPES = Object.freeze(["universe.place.luau-execution-session:write"]);
260
+ /**
261
+ * Scopes required to fetch a Luau execution task, sourced from
262
+ * `x-roblox-scopes` on the get operation. The `:write` scope also
263
+ * grants read in upstream auth, but we surface only `:read` here as
264
+ * the minimum-privilege requirement for this method.
265
+ */
266
+ const GET_REQUIRED_SCOPES = Object.freeze(["universe.place.luau-execution-session:read"]);
267
+ //#endregion
268
+ //#region src/domains/cloud-v2/luau-execution-tasks/parsers.ts
269
+ const MALFORMED_TASK_MESSAGE = "Malformed luau-execution-session-task response";
270
+ const PATH_PATTERN = /^universes\/(\d+)\/places\/(\d+)(?:\/versions\/(\d+))?(?:\/luau-execution-sessions\/([^/]+)\/tasks\/([^/]+)|\/luau-execution-session-tasks\/([^/]+))$/;
271
+ /**
272
+ * Parses a successful Open Cloud `LuauExecutionSessionTask` response
273
+ * body into the public {@link LuauExecutionTask} discriminated union.
274
+ * Handles every supported task state (in-progress, COMPLETE, FAILED)
275
+ * across all four x-aep-resource path shapes the server returns.
276
+ *
277
+ * @param response - The full {@link HttpResponse} from the Open Cloud
278
+ * API.
279
+ * @returns A success result wrapping the parsed task, or an
280
+ * {@link ApiError} when the body or path do not match a supported
281
+ * shape.
282
+ */
283
+ function parseLuauExecutionTaskResponse(response) {
284
+ const { body, status: statusCode } = response;
285
+ if (!isLuauExecutionTaskWire(body)) return malformed(statusCode);
286
+ const ref = parseTaskRef(body.path);
287
+ if (ref === void 0) return malformed(statusCode);
288
+ const timeoutSeconds = parseTimeoutSeconds(body.timeout);
289
+ const createdAt = parseOptionalDate(body.createTime);
290
+ const updatedAt = parseOptionalDate(body.updateTime);
291
+ if (body.state === "COMPLETE") return parseCompleteTask({
292
+ body,
293
+ createdAt,
294
+ ref,
295
+ statusCode,
296
+ timeoutSeconds,
297
+ updatedAt
298
+ });
299
+ if (body.state === "FAILED") return parseFailedTask({
300
+ body,
301
+ createdAt,
302
+ ref,
303
+ statusCode,
304
+ timeoutSeconds,
305
+ updatedAt
306
+ });
307
+ return parseInProgressTask({
308
+ body,
309
+ createdAt,
310
+ ref,
311
+ state: body.state,
312
+ statusCode,
313
+ timeoutSeconds,
314
+ updatedAt
315
+ });
316
+ }
317
+ function isAcceptedWireState(state) {
318
+ return state === "QUEUED" || state === "PROCESSING" || state === "CANCELLED" || state === "COMPLETE" || state === "FAILED";
319
+ }
320
+ function isErrorWireCode(code) {
321
+ return code === "SCRIPT_ERROR" || code === "DEADLINE_EXCEEDED" || code === "OUTPUT_SIZE_LIMIT_EXCEEDED" || code === "INTERNAL_ERROR";
322
+ }
323
+ function isErrorWire(value) {
324
+ return isRecord(value) && isErrorWireCode(value["code"]) && typeof value["message"] === "string";
325
+ }
326
+ function isOptionalErrorWire(value) {
327
+ return value === void 0 || isErrorWire(value);
328
+ }
329
+ function isOutputWire(value) {
330
+ return isRecord(value) && Array.isArray(value["results"]);
331
+ }
332
+ function isOptionalOutputWire(value) {
333
+ return value === void 0 || isOutputWire(value);
334
+ }
335
+ function isOptionalString(value) {
336
+ return value === void 0 || typeof value === "string";
337
+ }
338
+ function isOptionalBoolean(value) {
339
+ return value === void 0 || typeof value === "boolean";
340
+ }
341
+ function isOptionalDateTimeString(value) {
342
+ return value === void 0 || isDateTimeString(value);
343
+ }
344
+ function isLuauExecutionTaskWire(body) {
345
+ return isRecord(body) && typeof body["path"] === "string" && isOptionalDateTimeString(body["createTime"]) && isOptionalDateTimeString(body["updateTime"]) && isAcceptedWireState(body["state"]) && typeof body["user"] === "string" && isOptionalOutputWire(body["output"]) && isOptionalErrorWire(body["error"]) && isOptionalDurationWire(body["timeout"]) && isOptionalString(body["binaryInput"]) && isOptionalBoolean(body["enableBinaryOutput"]) && isOptionalString(body["binaryOutputUri"]);
346
+ }
347
+ function parseOptionalDate(value) {
348
+ return value === void 0 ? void 0 : new Date(value);
349
+ }
350
+ const DURATION_PATTERN = /^(\d+)s$/;
351
+ function isOptionalDurationWire(value) {
352
+ return value === void 0 || typeof value === "string" && DURATION_PATTERN.test(value);
353
+ }
354
+ function parseTimeoutSeconds(value) {
355
+ if (value === void 0) return;
356
+ const seconds = DURATION_PATTERN.exec(value)?.[1];
357
+ if (seconds === void 0) return;
358
+ return Number.parseInt(seconds, 10);
359
+ }
360
+ function malformed(statusCode) {
361
+ return {
362
+ err: new ApiError(MALFORMED_TASK_MESSAGE, { statusCode }),
363
+ success: false
364
+ };
365
+ }
366
+ function parseInProgressTask(args) {
367
+ const { body, createdAt, ref, state, timeoutSeconds, updatedAt } = args;
368
+ return {
369
+ data: {
370
+ binaryInput: body.binaryInput,
371
+ binaryOutputUri: body.binaryOutputUri,
372
+ createdAt,
373
+ enableBinaryOutput: body.enableBinaryOutput,
374
+ ref,
375
+ state,
376
+ timeoutSeconds,
377
+ updatedAt,
378
+ user: body.user
379
+ },
380
+ success: true
381
+ };
382
+ }
383
+ function parseCompleteTask(args) {
384
+ const { body, createdAt, ref, statusCode, timeoutSeconds, updatedAt } = args;
385
+ if (body.output === void 0) return malformed(statusCode);
386
+ return {
387
+ data: {
388
+ binaryInput: body.binaryInput,
389
+ binaryOutputUri: body.binaryOutputUri,
390
+ createdAt,
391
+ enableBinaryOutput: body.enableBinaryOutput,
392
+ output: { results: body.output.results },
393
+ ref,
394
+ state: "COMPLETE",
395
+ timeoutSeconds,
396
+ updatedAt,
397
+ user: body.user
398
+ },
399
+ success: true
400
+ };
401
+ }
402
+ function parseFailedTask(args) {
403
+ const { body, createdAt, ref, statusCode, timeoutSeconds, updatedAt } = args;
404
+ if (body.error === void 0) return malformed(statusCode);
405
+ return {
406
+ data: {
407
+ binaryInput: body.binaryInput,
408
+ binaryOutputUri: body.binaryOutputUri,
409
+ createdAt,
410
+ enableBinaryOutput: body.enableBinaryOutput,
411
+ error: {
412
+ code: body.error.code,
413
+ message: body.error.message
414
+ },
415
+ ref,
416
+ state: "FAILED",
417
+ timeoutSeconds,
418
+ updatedAt,
419
+ user: body.user
420
+ },
421
+ success: true
422
+ };
423
+ }
424
+ function parseTaskRef(path) {
425
+ const match = PATH_PATTERN.exec(path);
426
+ if (match === null) return;
427
+ const [, universeId, placeId, versionId, sessionId, sessionTaskId, plainTaskId] = match;
428
+ const taskId = sessionTaskId ?? plainTaskId;
429
+ if (universeId === void 0 || placeId === void 0 || taskId === void 0) return;
430
+ return {
431
+ placeId,
432
+ sessionId,
433
+ taskId,
434
+ universeId,
435
+ versionId
436
+ };
437
+ }
438
+ //#endregion
439
+ //#region src/domains/cloud-v2/luau-execution-tasks/specs.ts
440
+ function makeSpec(spec) {
441
+ return Object.freeze(spec);
442
+ }
443
+ /**
444
+ * Per-method dispatch spec for submitting a Luau execution task at a
445
+ * place's head version. Frozen at module scope so both the top-level
446
+ * `LuauExecutionClient` and the `luauExecution` Operation Group on
447
+ * `PlacesClient` share the same instance reference.
448
+ */
449
+ const SUBMIT_HEAD_SPEC = makeSpec({
450
+ buildRequest: (parameters) => okRequest(buildSubmitAtHeadRequest(parameters)),
451
+ methodDefaults: CREATE_METHOD_DEFAULTS,
452
+ methodKind: "create",
453
+ operationLimit: SUBMIT_OPERATION_LIMIT,
454
+ parse: parseLuauExecutionTaskResponse,
455
+ requiredScopes: SUBMIT_REQUIRED_SCOPES
456
+ });
457
+ /**
458
+ * Per-method dispatch spec for submitting a Luau execution task at a
459
+ * specific place version. Shares the rate-limit queue and required
460
+ * scope set with {@link SUBMIT_HEAD_SPEC} because Roblox attributes
461
+ * both URL shapes to one per-minute quota.
462
+ */
463
+ const SUBMIT_VERSION_SPEC = makeSpec({
464
+ buildRequest: (parameters) => okRequest(buildSubmitAtVersionRequest(parameters)),
465
+ methodDefaults: CREATE_METHOD_DEFAULTS,
466
+ methodKind: "create",
467
+ operationLimit: SUBMIT_OPERATION_LIMIT,
468
+ parse: parseLuauExecutionTaskResponse,
469
+ requiredScopes: SUBMIT_REQUIRED_SCOPES
470
+ });
471
+ /**
472
+ * Per-method dispatch spec for fetching a Luau execution task. Uses
473
+ * idempotent retry semantics (429 and 5xx both retried) so reads
474
+ * recover transparently from transient server errors.
475
+ */
476
+ const GET_SPEC = makeSpec({
477
+ buildRequest: buildGetRequest,
478
+ methodDefaults: IDEMPOTENT_METHOD_DEFAULTS,
479
+ methodKind: "idempotent",
480
+ operationLimit: GET_OPERATION_LIMIT,
481
+ parse: parseLuauExecutionTaskResponse,
482
+ requiredScopes: GET_REQUIRED_SCOPES
483
+ });
484
+ const ABORTED = Symbol("poll-aborted");
485
+ /**
486
+ * Core polling loop. Calls `deps.fetch()` repeatedly, sleeping
487
+ * `pollDelay(attempt)` ms between iterations, until a terminal state
488
+ * is observed, the wall-clock budget is exhausted, or an `AbortSignal`
489
+ * fires. Returns the terminal task on success.
490
+ *
491
+ * @param deps - Injected fetch, now, and sleep callbacks.
492
+ * @param options - Optional poll delay, timeout, and abort signal.
493
+ * @returns The terminal task, or an error if aborted, timed out, or the transport fails.
494
+ */
495
+ async function pollUntilDoneCore(deps, options = {}) {
496
+ const timeoutMs = options.timeoutMs ?? 3e5;
497
+ const pollDelay = options.pollDelay ?? defaultRetryDelay;
498
+ const sig = options.signal;
499
+ const startedAt = deps.now();
500
+ if (sig?.aborted === true) return abortedResult(sig);
501
+ let lastTask;
502
+ for (let attempt = 0;; attempt += 1) {
503
+ if (deps.now() - startedAt >= timeoutMs) return {
504
+ err: makeTimeout(lastTask, timeoutMs),
505
+ success: false
506
+ };
507
+ const iteration = await pollIteration({
508
+ delayMs: pollDelay(attempt),
509
+ deps,
510
+ signal: sig
511
+ });
512
+ if (iteration.done) return iteration.result;
513
+ lastTask = iteration.task;
514
+ }
515
+ }
516
+ function makeAborted(signal) {
517
+ return new PollAbortedError("Polling was aborted", { reason: signal?.reason });
518
+ }
519
+ function abortedResult(signal) {
520
+ return {
521
+ err: makeAborted(signal),
522
+ success: false
523
+ };
524
+ }
525
+ function isTerminal(task) {
526
+ return task.state === "COMPLETE" || task.state === "FAILED" || task.state === "CANCELLED";
527
+ }
528
+ function abortObserver(signal) {
529
+ const { promise, resolve } = Promise.withResolvers();
530
+ function onAbort() {
531
+ resolve(ABORTED);
532
+ }
533
+ signal.addEventListener("abort", onAbort);
534
+ function cleanup() {
535
+ signal.removeEventListener("abort", onAbort);
536
+ }
537
+ return {
538
+ cleanup,
539
+ promise
540
+ };
541
+ }
542
+ async function raceWithAbort(promise, signal) {
543
+ if (signal === void 0) return promise;
544
+ if (signal.aborted) return ABORTED;
545
+ const observer = abortObserver(signal);
546
+ try {
547
+ return await Promise.race([promise, observer.promise]);
548
+ } finally {
549
+ observer.cleanup();
550
+ }
551
+ }
552
+ async function sleepWithAbort(options) {
553
+ const { ms, signal, sleep } = options;
554
+ return await raceWithAbort(sleep(ms), signal) === ABORTED;
555
+ }
556
+ async function pollIteration(options) {
557
+ const { delayMs, deps, signal } = options;
558
+ const fetchResult = await raceWithAbort(deps.fetch(), signal);
559
+ if (fetchResult === ABORTED) return {
560
+ done: true,
561
+ result: abortedResult(signal)
562
+ };
563
+ if (!fetchResult.success) return {
564
+ done: true,
565
+ result: fetchResult
566
+ };
567
+ if (isTerminal(fetchResult.data)) return {
568
+ done: true,
569
+ result: {
570
+ data: fetchResult.data,
571
+ success: true
572
+ }
573
+ };
574
+ if (await sleepWithAbort({
575
+ ms: delayMs,
576
+ signal,
577
+ sleep: deps.sleep
578
+ })) return {
579
+ done: true,
580
+ result: abortedResult(signal)
581
+ };
582
+ return {
583
+ done: false,
584
+ task: fetchResult.data
585
+ };
586
+ }
587
+ function makeTimeout(task, timeoutMs) {
588
+ return new PollTimeoutError(`Polling timed out after ${timeoutMs} ms`, {
589
+ lastObservedTask: task,
590
+ timeoutMs
591
+ });
592
+ }
593
+ //#endregion
594
+ //#region src/resources/luau-execution/polling-helpers.ts
595
+ /**
596
+ * Builds the {@link PollDeps} bundle used by {@link pollUntilDoneCore},
597
+ * closing over the supplied {@link ResourceClient}, task ref, and
598
+ * per-request options so the core loop stays narrow.
599
+ *
600
+ * @param inner - The {@link ResourceClient} that issues each `tasks.get` call.
601
+ * @param args - The polling options and the task ref to fetch on every iteration.
602
+ * @returns A {@link PollDeps} bundle wiring `fetch`, `now`, and `sleep`.
603
+ */
604
+ function buildPollDeps(inner, args) {
605
+ return {
606
+ fetch: async () => {
607
+ return inner.execute({
608
+ options: args.options,
609
+ parameters: {
610
+ ref: args.ref,
611
+ view: "BASIC"
612
+ },
613
+ spec: GET_SPEC
614
+ });
615
+ },
616
+ now: Date.now,
617
+ sleep: inner.sleep
618
+ };
619
+ }
620
+ /**
621
+ * Submits a Luau execution task and polls it to a terminal state.
622
+ * Dispatches to the head-version or specific-version submit spec based on
623
+ * the presence of `versionId`, then delegates to {@link pollUntilDoneCore}.
624
+ *
625
+ * @param inner - The {@link ResourceClient} that issues submit and poll calls.
626
+ * @param args - The polling options and submit parameters.
627
+ * @returns A {@link Result} wrapping the terminal {@link LuauExecutionTask}, or
628
+ * the {@link OpenCloudError} that caused submit or polling to fail.
629
+ */
630
+ async function submitAndPoll(inner, args) {
631
+ const { options, parameters } = args;
632
+ const submitResult = await ("versionId" in parameters ? inner.execute({
633
+ options,
634
+ parameters,
635
+ spec: SUBMIT_VERSION_SPEC
636
+ }) : inner.execute({
637
+ options,
638
+ parameters,
639
+ spec: SUBMIT_HEAD_SPEC
640
+ }));
641
+ if (!submitResult.success) return submitResult;
642
+ return pollUntilDoneCore(buildPollDeps(inner, {
643
+ options,
644
+ ref: submitResult.data.ref
645
+ }), options);
646
+ }
647
+ //#endregion
648
+ export { SUBMIT_HEAD_SPEC as a, GET_SPEC as i, submitAndPoll as n, SUBMIT_VERSION_SPEC as o, pollUntilDoneCore as r, LIST_LOGS_SPEC as s, buildPollDeps as t };
649
+
650
+ //# sourceMappingURL=polling-helpers-QGjvYq3c.mjs.map