@bedrock-rbx/ocale 0.1.0-beta.2 → 0.1.0-beta.3

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 (49) hide show
  1. package/dist/badges.d.mts +2 -2
  2. package/dist/badges.mjs +3 -3
  3. package/dist/{data.generated-BtkDGH8C.d.mts → data.generated-DOaDx6J0.d.mts} +1 -1
  4. package/dist/{data.generated-BtkDGH8C.d.mts.map → data.generated-DOaDx6J0.d.mts.map} +1 -1
  5. package/dist/developer-products.d.mts +2 -2
  6. package/dist/developer-products.mjs +4 -4
  7. package/dist/game-passes.d.mts +2 -2
  8. package/dist/game-passes.mjs +4 -4
  9. package/dist/index.d.mts +92 -3
  10. package/dist/index.d.mts.map +1 -1
  11. package/dist/index.mjs +3 -2
  12. package/dist/{is-date-time-string-Cuf1TaSC.mjs → is-date-time-string-Ds8Ew-Xa.mjs} +1 -1
  13. package/dist/{is-date-time-string-Cuf1TaSC.mjs.map → is-date-time-string-Ds8Ew-Xa.mjs.map} +1 -1
  14. package/dist/locales.d.mts +1 -1
  15. package/dist/luau-execution.d.mts +93 -6
  16. package/dist/luau-execution.d.mts.map +1 -1
  17. package/dist/luau-execution.mjs +115 -3
  18. package/dist/luau-execution.mjs.map +1 -1
  19. package/dist/places.d.mts +46 -6
  20. package/dist/places.d.mts.map +1 -1
  21. package/dist/places.mjs +23 -4
  22. package/dist/places.mjs.map +1 -1
  23. package/dist/poll-timeout-BdUcWv52.mjs +79 -0
  24. package/dist/poll-timeout-BdUcWv52.mjs.map +1 -0
  25. package/dist/{types-BZ0959rh.d.mts → polling-Cc50rgl6.d.mts} +106 -2
  26. package/dist/polling-Cc50rgl6.d.mts.map +1 -0
  27. package/dist/polling-helpers-BVkmr6C7.mjs +636 -0
  28. package/dist/polling-helpers-BVkmr6C7.mjs.map +1 -0
  29. package/dist/{price-information-s7DY0GV2.mjs → price-information-DFf89abd.mjs} +2 -2
  30. package/dist/{price-information-s7DY0GV2.mjs.map → price-information-DFf89abd.mjs.map} +1 -1
  31. package/dist/{rate-limit-DzHBFwps.d.mts → rate-limit-BSbFNSGT.d.mts} +2 -2
  32. package/dist/{rate-limit-DzHBFwps.d.mts.map → rate-limit-BSbFNSGT.d.mts.map} +1 -1
  33. package/dist/{resource-client-Wi4Mwqy5.mjs → resource-client-opC6BUkL.mjs} +10 -2
  34. package/dist/{resource-client-Wi4Mwqy5.mjs.map → resource-client-opC6BUkL.mjs.map} +1 -1
  35. package/dist/storage.d.mts +7 -1
  36. package/dist/storage.d.mts.map +1 -1
  37. package/dist/storage.mjs +2 -2
  38. package/dist/{to-blob-1BtHsDGK.mjs → to-blob-DHN7UoM8.mjs} +1 -1
  39. package/dist/{to-blob-1BtHsDGK.mjs.map → to-blob-DHN7UoM8.mjs.map} +1 -1
  40. package/dist/{types-Cp8w8uwA.d.mts → types-DUzm6maA.d.mts} +1 -1
  41. package/dist/{types-Cp8w8uwA.d.mts.map → types-DUzm6maA.d.mts.map} +1 -1
  42. package/dist/universes.d.mts +2 -2
  43. package/dist/universes.mjs +4 -4
  44. package/dist/{validation-b7KAoEio.mjs → validation-VImVHzxg.mjs} +1 -1
  45. package/dist/{validation-b7KAoEio.mjs.map → validation-VImVHzxg.mjs.map} +1 -1
  46. package/package.json +1 -1
  47. package/dist/specs-Co6qYp_E.mjs +0 -309
  48. package/dist/specs-Co6qYp_E.mjs.map +0 -1
  49. package/dist/types-BZ0959rh.d.mts.map +0 -1
@@ -0,0 +1,636 @@
1
+ import { i as ApiError } from "./rate-limit-CKfuhxT1.mjs";
2
+ import { n as PollAbortedError, t as PollTimeoutError } from "./poll-timeout-BdUcWv52.mjs";
3
+ import { t as ValidationError } from "./validation-VImVHzxg.mjs";
4
+ import { a as IDEMPOTENT_METHOD_DEFAULTS, i as CREATE_METHOD_DEFAULTS, n as okRequest, o as defaultRetryDelay, s as isRecord } from "./resource-client-opC6BUkL.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 (!isListLogsResponseWire(body)) return malformed$1(statusCode);
83
+ const chunks = body.luauExecutionSessionTaskLogs ?? [];
84
+ const messages = [];
85
+ for (const chunk of chunks) for (const wireMessage of chunk.structuredMessages ?? []) messages.push({
86
+ createTime: wireMessage.createTime,
87
+ message: wireMessage.message,
88
+ messageType: wireMessage.messageType
89
+ });
90
+ return {
91
+ data: {
92
+ messages,
93
+ nextPageToken: body.nextPageToken
94
+ },
95
+ success: true
96
+ };
97
+ }
98
+ function isAcceptedMessageType(value) {
99
+ return value === "OUTPUT" || value === "INFO" || value === "WARNING" || value === "ERROR";
100
+ }
101
+ function isLogMessageWire(value) {
102
+ return isRecord(value) && typeof value["createTime"] === "string" && typeof value["message"] === "string" && isAcceptedMessageType(value["messageType"]);
103
+ }
104
+ function isOptionalStructuredMessages(value) {
105
+ return value === void 0 || Array.isArray(value) && value.every((item) => isLogMessageWire(item));
106
+ }
107
+ function isLogChunkWire(value) {
108
+ return isRecord(value) && isOptionalStructuredMessages(value["structuredMessages"]);
109
+ }
110
+ function isOptionalLogChunks(value) {
111
+ return value === void 0 || Array.isArray(value) && value.every((item) => isLogChunkWire(item));
112
+ }
113
+ function isListLogsResponseWire(body) {
114
+ return isRecord(body) && isOptionalLogChunks(body["luauExecutionSessionTaskLogs"]) && (body["nextPageToken"] === void 0 || typeof body["nextPageToken"] === "string");
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
+ if (body.state === "COMPLETE") return parseCompleteTask({
290
+ body,
291
+ ref,
292
+ statusCode,
293
+ timeoutSeconds
294
+ });
295
+ if (body.state === "FAILED") return parseFailedTask({
296
+ body,
297
+ ref,
298
+ statusCode,
299
+ timeoutSeconds
300
+ });
301
+ return parseInProgressTask({
302
+ body,
303
+ ref,
304
+ state: body.state,
305
+ statusCode,
306
+ timeoutSeconds
307
+ });
308
+ }
309
+ function isAcceptedWireState(state) {
310
+ return state === "QUEUED" || state === "PROCESSING" || state === "CANCELLED" || state === "COMPLETE" || state === "FAILED";
311
+ }
312
+ function isErrorWireCode(code) {
313
+ return code === "SCRIPT_ERROR" || code === "DEADLINE_EXCEEDED" || code === "OUTPUT_SIZE_LIMIT_EXCEEDED" || code === "INTERNAL_ERROR";
314
+ }
315
+ function isErrorWire(value) {
316
+ return isRecord(value) && isErrorWireCode(value["code"]) && typeof value["message"] === "string";
317
+ }
318
+ function isOptionalErrorWire(value) {
319
+ return value === void 0 || isErrorWire(value);
320
+ }
321
+ function isOutputWire(value) {
322
+ return isRecord(value) && Array.isArray(value["results"]);
323
+ }
324
+ function isOptionalOutputWire(value) {
325
+ return value === void 0 || isOutputWire(value);
326
+ }
327
+ function isOptionalString(value) {
328
+ return value === void 0 || typeof value === "string";
329
+ }
330
+ function isOptionalBoolean(value) {
331
+ return value === void 0 || typeof value === "boolean";
332
+ }
333
+ function isLuauExecutionTaskWire(body) {
334
+ return isRecord(body) && typeof body["path"] === "string" && typeof body["createTime"] === "string" && typeof body["updateTime"] === "string" && 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"]);
335
+ }
336
+ const DURATION_PATTERN = /^(\d+)s$/;
337
+ function isOptionalDurationWire(value) {
338
+ return value === void 0 || typeof value === "string" && DURATION_PATTERN.test(value);
339
+ }
340
+ function parseTimeoutSeconds(value) {
341
+ if (value === void 0) return;
342
+ const seconds = DURATION_PATTERN.exec(value)?.[1];
343
+ if (seconds === void 0) return;
344
+ return Number.parseInt(seconds, 10);
345
+ }
346
+ function malformed(statusCode) {
347
+ return {
348
+ err: new ApiError(MALFORMED_TASK_MESSAGE, { statusCode }),
349
+ success: false
350
+ };
351
+ }
352
+ function parseInProgressTask(args) {
353
+ const { body, ref, state, timeoutSeconds } = args;
354
+ return {
355
+ data: {
356
+ binaryInput: body.binaryInput,
357
+ binaryOutputUri: body.binaryOutputUri,
358
+ createdAt: new Date(body.createTime),
359
+ enableBinaryOutput: body.enableBinaryOutput,
360
+ ref,
361
+ state,
362
+ timeoutSeconds,
363
+ updatedAt: new Date(body.updateTime),
364
+ user: body.user
365
+ },
366
+ success: true
367
+ };
368
+ }
369
+ function parseCompleteTask(args) {
370
+ const { body, ref, statusCode, timeoutSeconds } = args;
371
+ if (body.output === void 0) return malformed(statusCode);
372
+ return {
373
+ data: {
374
+ binaryInput: body.binaryInput,
375
+ binaryOutputUri: body.binaryOutputUri,
376
+ createdAt: new Date(body.createTime),
377
+ enableBinaryOutput: body.enableBinaryOutput,
378
+ output: { results: body.output.results },
379
+ ref,
380
+ state: "COMPLETE",
381
+ timeoutSeconds,
382
+ updatedAt: new Date(body.updateTime),
383
+ user: body.user
384
+ },
385
+ success: true
386
+ };
387
+ }
388
+ function parseFailedTask(args) {
389
+ const { body, ref, statusCode, timeoutSeconds } = args;
390
+ if (body.error === void 0) return malformed(statusCode);
391
+ return {
392
+ data: {
393
+ binaryInput: body.binaryInput,
394
+ binaryOutputUri: body.binaryOutputUri,
395
+ createdAt: new Date(body.createTime),
396
+ enableBinaryOutput: body.enableBinaryOutput,
397
+ error: {
398
+ code: body.error.code,
399
+ message: body.error.message
400
+ },
401
+ ref,
402
+ state: "FAILED",
403
+ timeoutSeconds,
404
+ updatedAt: new Date(body.updateTime),
405
+ user: body.user
406
+ },
407
+ success: true
408
+ };
409
+ }
410
+ function parseTaskRef(path) {
411
+ const match = PATH_PATTERN.exec(path);
412
+ if (match === null) return;
413
+ const [, universeId, placeId, versionId, sessionId, sessionTaskId, plainTaskId] = match;
414
+ const taskId = sessionTaskId ?? plainTaskId;
415
+ if (universeId === void 0 || placeId === void 0 || taskId === void 0) return;
416
+ return {
417
+ placeId,
418
+ sessionId,
419
+ taskId,
420
+ universeId,
421
+ versionId
422
+ };
423
+ }
424
+ //#endregion
425
+ //#region src/domains/cloud-v2/luau-execution-tasks/specs.ts
426
+ function makeSpec(spec) {
427
+ return Object.freeze(spec);
428
+ }
429
+ /**
430
+ * Per-method dispatch spec for submitting a Luau execution task at a
431
+ * place's head version. Frozen at module scope so both the top-level
432
+ * `LuauExecutionClient` and the `luauExecution` Operation Group on
433
+ * `PlacesClient` share the same instance reference.
434
+ */
435
+ const SUBMIT_HEAD_SPEC = makeSpec({
436
+ buildRequest: (parameters) => okRequest(buildSubmitAtHeadRequest(parameters)),
437
+ methodDefaults: CREATE_METHOD_DEFAULTS,
438
+ methodKind: "create",
439
+ operationLimit: SUBMIT_OPERATION_LIMIT,
440
+ parse: parseLuauExecutionTaskResponse,
441
+ requiredScopes: SUBMIT_REQUIRED_SCOPES
442
+ });
443
+ /**
444
+ * Per-method dispatch spec for submitting a Luau execution task at a
445
+ * specific place version. Shares the rate-limit queue and required
446
+ * scope set with {@link SUBMIT_HEAD_SPEC} because Roblox attributes
447
+ * both URL shapes to one per-minute quota.
448
+ */
449
+ const SUBMIT_VERSION_SPEC = makeSpec({
450
+ buildRequest: (parameters) => okRequest(buildSubmitAtVersionRequest(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 fetching a Luau execution task. Uses
459
+ * idempotent retry semantics (429 and 5xx both retried) so reads
460
+ * recover transparently from transient server errors.
461
+ */
462
+ const GET_SPEC = makeSpec({
463
+ buildRequest: buildGetRequest,
464
+ methodDefaults: IDEMPOTENT_METHOD_DEFAULTS,
465
+ methodKind: "idempotent",
466
+ operationLimit: GET_OPERATION_LIMIT,
467
+ parse: parseLuauExecutionTaskResponse,
468
+ requiredScopes: GET_REQUIRED_SCOPES
469
+ });
470
+ const ABORTED = Symbol("poll-aborted");
471
+ /**
472
+ * Core polling loop. Calls `deps.fetch()` repeatedly, sleeping
473
+ * `pollDelay(attempt)` ms between iterations, until a terminal state
474
+ * is observed, the wall-clock budget is exhausted, or an `AbortSignal`
475
+ * fires. Returns the terminal task on success.
476
+ *
477
+ * @param deps - Injected fetch, now, and sleep callbacks.
478
+ * @param options - Optional poll delay, timeout, and abort signal.
479
+ * @returns The terminal task, or an error if aborted, timed out, or the transport fails.
480
+ */
481
+ async function pollUntilDoneCore(deps, options = {}) {
482
+ const timeoutMs = options.timeoutMs ?? 3e5;
483
+ const pollDelay = options.pollDelay ?? defaultRetryDelay;
484
+ const sig = options.signal;
485
+ const startedAt = deps.now();
486
+ if (sig?.aborted === true) return abortedResult(sig);
487
+ let lastTask;
488
+ for (let attempt = 0;; attempt += 1) {
489
+ if (deps.now() - startedAt >= timeoutMs) return {
490
+ err: makeTimeout(lastTask, timeoutMs),
491
+ success: false
492
+ };
493
+ const iteration = await pollIteration({
494
+ delayMs: pollDelay(attempt),
495
+ deps,
496
+ signal: sig
497
+ });
498
+ if (iteration.done) return iteration.result;
499
+ lastTask = iteration.task;
500
+ }
501
+ }
502
+ function makeAborted(signal) {
503
+ return new PollAbortedError("Polling was aborted", { reason: signal?.reason });
504
+ }
505
+ function abortedResult(signal) {
506
+ return {
507
+ err: makeAborted(signal),
508
+ success: false
509
+ };
510
+ }
511
+ function isTerminal(task) {
512
+ return task.state === "COMPLETE" || task.state === "FAILED" || task.state === "CANCELLED";
513
+ }
514
+ function abortObserver(signal) {
515
+ const { promise, resolve } = Promise.withResolvers();
516
+ function onAbort() {
517
+ resolve(ABORTED);
518
+ }
519
+ signal.addEventListener("abort", onAbort);
520
+ function cleanup() {
521
+ signal.removeEventListener("abort", onAbort);
522
+ }
523
+ return {
524
+ cleanup,
525
+ promise
526
+ };
527
+ }
528
+ async function raceWithAbort(promise, signal) {
529
+ if (signal === void 0) return promise;
530
+ if (signal.aborted) return ABORTED;
531
+ const observer = abortObserver(signal);
532
+ try {
533
+ return await Promise.race([promise, observer.promise]);
534
+ } finally {
535
+ observer.cleanup();
536
+ }
537
+ }
538
+ async function sleepWithAbort(options) {
539
+ const { ms, signal, sleep } = options;
540
+ return await raceWithAbort(sleep(ms), signal) === ABORTED;
541
+ }
542
+ async function pollIteration(options) {
543
+ const { delayMs, deps, signal } = options;
544
+ const fetchResult = await raceWithAbort(deps.fetch(), signal);
545
+ if (fetchResult === ABORTED) return {
546
+ done: true,
547
+ result: abortedResult(signal)
548
+ };
549
+ if (!fetchResult.success) return {
550
+ done: true,
551
+ result: fetchResult
552
+ };
553
+ if (isTerminal(fetchResult.data)) return {
554
+ done: true,
555
+ result: {
556
+ data: fetchResult.data,
557
+ success: true
558
+ }
559
+ };
560
+ if (await sleepWithAbort({
561
+ ms: delayMs,
562
+ signal,
563
+ sleep: deps.sleep
564
+ })) return {
565
+ done: true,
566
+ result: abortedResult(signal)
567
+ };
568
+ return {
569
+ done: false,
570
+ task: fetchResult.data
571
+ };
572
+ }
573
+ function makeTimeout(task, timeoutMs) {
574
+ return new PollTimeoutError(`Polling timed out after ${timeoutMs} ms`, {
575
+ lastObservedTask: task,
576
+ timeoutMs
577
+ });
578
+ }
579
+ //#endregion
580
+ //#region src/resources/luau-execution/polling-helpers.ts
581
+ /**
582
+ * Builds the {@link PollDeps} bundle used by {@link pollUntilDoneCore},
583
+ * closing over the supplied {@link ResourceClient}, task ref, and
584
+ * per-request options so the core loop stays narrow.
585
+ *
586
+ * @param inner - The {@link ResourceClient} that issues each `tasks.get` call.
587
+ * @param args - The polling options and the task ref to fetch on every iteration.
588
+ * @returns A {@link PollDeps} bundle wiring `fetch`, `now`, and `sleep`.
589
+ */
590
+ function buildPollDeps(inner, args) {
591
+ return {
592
+ fetch: async () => {
593
+ return inner.execute({
594
+ options: args.options,
595
+ parameters: {
596
+ ref: args.ref,
597
+ view: "BASIC"
598
+ },
599
+ spec: GET_SPEC
600
+ });
601
+ },
602
+ now: Date.now,
603
+ sleep: inner.sleep
604
+ };
605
+ }
606
+ /**
607
+ * Submits a Luau execution task and polls it to a terminal state.
608
+ * Dispatches to the head-version or specific-version submit spec based on
609
+ * the presence of `versionId`, then delegates to {@link pollUntilDoneCore}.
610
+ *
611
+ * @param inner - The {@link ResourceClient} that issues submit and poll calls.
612
+ * @param args - The polling options and submit parameters.
613
+ * @returns A {@link Result} wrapping the terminal {@link LuauExecutionTask}, or
614
+ * the {@link OpenCloudError} that caused submit or polling to fail.
615
+ */
616
+ async function submitAndPoll(inner, args) {
617
+ const { options, parameters } = args;
618
+ const submitResult = await ("versionId" in parameters ? inner.execute({
619
+ options,
620
+ parameters,
621
+ spec: SUBMIT_VERSION_SPEC
622
+ }) : inner.execute({
623
+ options,
624
+ parameters,
625
+ spec: SUBMIT_HEAD_SPEC
626
+ }));
627
+ if (!submitResult.success) return submitResult;
628
+ return pollUntilDoneCore(buildPollDeps(inner, {
629
+ options,
630
+ ref: submitResult.data.ref
631
+ }), options);
632
+ }
633
+ //#endregion
634
+ 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 };
635
+
636
+ //# sourceMappingURL=polling-helpers-BVkmr6C7.mjs.map