@intentius/chant-lexicon-fly 0.89.0 → 0.90.0
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.
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/integrity.json +3 -3
- package/dist/manifest.json +1 -1
- package/dist/op/activities/emulator-images.d.ts +13 -0
- package/dist/op/activities/emulator-images.d.ts.map +1 -1
- package/dist/op/activities/index.d.ts +4 -2
- package/dist/op/activities/index.d.ts.map +1 -1
- package/dist/op/activities/sprite-services.d.ts +158 -0
- package/dist/op/activities/sprite-services.d.ts.map +1 -0
- package/dist/op/activities/sprites-contract.d.ts +17 -1
- package/dist/op/activities/sprites-contract.d.ts.map +1 -1
- package/dist/op/activities/sprites-emulator.d.ts +12 -0
- package/dist/op/activities/sprites-emulator.d.ts.map +1 -1
- package/dist/op/activities/sprites-fake.d.ts +4 -0
- package/dist/op/activities/sprites-fake.d.ts.map +1 -1
- package/dist/op/activities/sprites.d.ts +53 -0
- package/dist/op/activities/sprites.d.ts.map +1 -1
- package/dist/op/builders.d.ts +20 -1
- package/dist/op/builders.d.ts.map +1 -1
- package/dist/skills/chant-fly-sprites.md +4 -2
- package/package.json +2 -2
- package/src/index.ts +9 -0
- package/src/op/activities/emulator-images.ts +14 -0
- package/src/op/activities/index.ts +34 -0
- package/src/op/activities/sprite-config.test.ts +19 -0
- package/src/op/activities/sprite-services.docker.integration.test.ts +87 -0
- package/src/op/activities/sprite-services.test.ts +263 -0
- package/src/op/activities/sprite-services.ts +311 -0
- package/src/op/activities/sprites-contract.test.ts +15 -4
- package/src/op/activities/sprites-contract.ts +24 -6
- package/src/op/activities/sprites-emulator.ts +52 -1
- package/src/op/activities/sprites-fake.ts +57 -8
- package/src/op/activities/sprites.test.ts +102 -0
- package/src/op/activities/sprites.ts +108 -7
- package/src/op/builders.ts +28 -1
- package/src/skills/chant-fly-sprites.md +4 -2
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { describe, test, expect } from "vitest";
|
|
2
2
|
import {
|
|
3
3
|
resolveSpritesEndpoint,
|
|
4
|
+
resolveSpritesToken,
|
|
4
5
|
DEFAULT_SPRITES_BASE_URL,
|
|
5
6
|
accumulateExecFrames,
|
|
6
7
|
parseCheckpointNdjson,
|
|
@@ -13,6 +14,8 @@ import {
|
|
|
13
14
|
spriteRestore,
|
|
14
15
|
listCheckpoints,
|
|
15
16
|
spriteDestroy,
|
|
17
|
+
spriteDelete,
|
|
18
|
+
spriteUrl,
|
|
16
19
|
type SpritesHttp,
|
|
17
20
|
type Checkpoint,
|
|
18
21
|
} from "./sprites";
|
|
@@ -141,6 +144,50 @@ describe("resolveSpritesEndpoint (S3)", () => {
|
|
|
141
144
|
test("default is real Sprites", () => {
|
|
142
145
|
expect(resolveSpritesEndpoint({}, {} as NodeJS.ProcessEnv)).toBe(DEFAULT_SPRITES_BASE_URL);
|
|
143
146
|
});
|
|
147
|
+
|
|
148
|
+
// #2711 — the studio and wisp call it SPRITES_API_URL.
|
|
149
|
+
test("SPRITES_API_URL alias when SPRITES_BASE_URL is unset", () => {
|
|
150
|
+
expect(resolveSpritesEndpoint({}, { SPRITES_API_URL: "http://alias:9000" } as NodeJS.ProcessEnv)).toBe(
|
|
151
|
+
"http://alias:9000",
|
|
152
|
+
);
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
test("SPRITES_BASE_URL wins over SPRITES_API_URL", () => {
|
|
156
|
+
expect(
|
|
157
|
+
resolveSpritesEndpoint(
|
|
158
|
+
{},
|
|
159
|
+
{ SPRITES_BASE_URL: "http://base:1", SPRITES_API_URL: "http://alias:2" } as NodeJS.ProcessEnv,
|
|
160
|
+
),
|
|
161
|
+
).toBe("http://base:1");
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
describe("resolveSpritesToken (#2711)", () => {
|
|
166
|
+
test("explicit arg wins", () => {
|
|
167
|
+
expect(resolveSpritesToken("arg-token", { SPRITES_API_TOKEN: "env" } as NodeJS.ProcessEnv)).toBe("arg-token");
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
test("SPRITES_API_TOKEN env when no arg", () => {
|
|
171
|
+
expect(resolveSpritesToken(undefined, { SPRITES_API_TOKEN: "env-token" } as NodeJS.ProcessEnv)).toBe(
|
|
172
|
+
"env-token",
|
|
173
|
+
);
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
test("SPRITE_TOKEN alias when SPRITES_API_TOKEN is unset", () => {
|
|
177
|
+
expect(resolveSpritesToken(undefined, { SPRITE_TOKEN: "alias-token" } as NodeJS.ProcessEnv)).toBe(
|
|
178
|
+
"alias-token",
|
|
179
|
+
);
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
test("SPRITES_API_TOKEN wins over SPRITE_TOKEN", () => {
|
|
183
|
+
expect(
|
|
184
|
+
resolveSpritesToken(undefined, { SPRITES_API_TOKEN: "orig", SPRITE_TOKEN: "alias" } as NodeJS.ProcessEnv),
|
|
185
|
+
).toBe("orig");
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
test("undefined when nothing is set", () => {
|
|
189
|
+
expect(resolveSpritesToken(undefined, {} as NodeJS.ProcessEnv)).toBeUndefined();
|
|
190
|
+
});
|
|
144
191
|
});
|
|
145
192
|
|
|
146
193
|
// ── Command tokenizing + exec WS url ──────────────────────────────────────────
|
|
@@ -263,6 +310,61 @@ describe("spriteDestroy", () => {
|
|
|
263
310
|
});
|
|
264
311
|
});
|
|
265
312
|
|
|
313
|
+
describe("spriteDelete (#2711)", () => {
|
|
314
|
+
test("is spriteDestroy under another name — same DELETE, same idempotence", async () => {
|
|
315
|
+
expect(spriteDelete).toBe(spriteDestroy);
|
|
316
|
+
const { http, calls } = recorder(() => ({ status: 200, text: "{}" }));
|
|
317
|
+
await spriteDelete({ id: "task-1", endpoint: "http://x" }, undefined, http);
|
|
318
|
+
expect(calls[0].method).toBe("DELETE");
|
|
319
|
+
expect(calls[0].url).toBe("http://x/v1/sprites/task-1");
|
|
320
|
+
});
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
describe("spriteUrl (#2711)", () => {
|
|
324
|
+
test("GETs /v1/sprites/{id} and returns its url", async () => {
|
|
325
|
+
const { http, calls } = recorder(() => ({ status: 200, text: JSON.stringify({ url: "http://h/s/task-1" }) }));
|
|
326
|
+
const res = await spriteUrl({ id: "task-1", endpoint: "http://x" }, undefined, http);
|
|
327
|
+
expect(res).toEqual({ url: "http://h/s/task-1" });
|
|
328
|
+
expect(calls[0].method).toBe("GET");
|
|
329
|
+
expect(calls[0].url).toBe("http://x/v1/sprites/task-1");
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
test("throws when the sprite has no url", async () => {
|
|
333
|
+
const { http } = recorder(() => ({ status: 200, text: "{}" }));
|
|
334
|
+
await expect(spriteUrl({ id: "task-1", endpoint: "http://x" }, undefined, http)).rejects.toThrow(/no url/);
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
test("with a path: returns immediately once the check answers 2xx", async () => {
|
|
338
|
+
let checks = 0;
|
|
339
|
+
const { http, calls } = recorder((method, url) => {
|
|
340
|
+
if (method === "GET" && url === "http://x/v1/sprites/task-1") {
|
|
341
|
+
return { status: 200, text: JSON.stringify({ url: "http://h/s/task-1" }) };
|
|
342
|
+
}
|
|
343
|
+
checks += 1;
|
|
344
|
+
return { status: checks < 2 ? 503 : 200, text: "" };
|
|
345
|
+
});
|
|
346
|
+
const res = await spriteUrl(
|
|
347
|
+
{ id: "task-1", endpoint: "http://x", path: "/", intervalMs: 1 },
|
|
348
|
+
undefined,
|
|
349
|
+
http,
|
|
350
|
+
);
|
|
351
|
+
expect(res).toEqual({ url: "http://h/s/task-1" });
|
|
352
|
+
expect(checks).toBe(2); // one 503, then 200
|
|
353
|
+
expect(calls.at(-1)?.url).toBe("http://h/s/task-1/");
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
test("with a path: throws once timeoutMs elapses without a match", async () => {
|
|
357
|
+
const { http } = recorder((method, url) =>
|
|
358
|
+
url === "http://x/v1/sprites/task-1"
|
|
359
|
+
? { status: 200, text: JSON.stringify({ url: "http://h/s/task-1" }) }
|
|
360
|
+
: { status: 503, text: "nothing is answering" },
|
|
361
|
+
);
|
|
362
|
+
await expect(
|
|
363
|
+
spriteUrl({ id: "task-1", endpoint: "http://x", path: "/", timeoutMs: 5, intervalMs: 1 }, undefined, http),
|
|
364
|
+
).rejects.toThrow(/did not answer/);
|
|
365
|
+
});
|
|
366
|
+
});
|
|
367
|
+
|
|
266
368
|
// ── Bearer header on the default client ───────────────────────────────────────
|
|
267
369
|
|
|
268
370
|
describe("defaultSpritesHttp bearer header", () => {
|
|
@@ -20,6 +20,13 @@
|
|
|
20
20
|
* S3: endpoint override via `SPRITES_BASE_URL` (an explicit `endpoint` arg wins,
|
|
21
21
|
* then the env, then the real Sprites base), so the same Op targets real Sprites
|
|
22
22
|
* or the in-process fake with no code change.
|
|
23
|
+
*
|
|
24
|
+
* #2711: the studio and wisp's own docs call these `SPRITES_API_URL` and
|
|
25
|
+
* `SPRITE_TOKEN` rather than `SPRITES_BASE_URL`/`SPRITES_API_TOKEN`. Both
|
|
26
|
+
* pairs are accepted — `resolveSpritesEndpoint`/`resolveSpritesToken` read the
|
|
27
|
+
* alias when the original name is unset, with the original always winning
|
|
28
|
+
* when both are present, so an existing deployment is never surprised by the
|
|
29
|
+
* alias taking over.
|
|
23
30
|
*/
|
|
24
31
|
|
|
25
32
|
// `ws` is loaded inside spriteExec, not at the top. It is a CommonJS package
|
|
@@ -27,6 +34,8 @@
|
|
|
27
34
|
// ESM, where that require throws. The top-level import put it on the path of
|
|
28
35
|
// every project that imports the lexicon and needs the run fallback (#2613).
|
|
29
36
|
|
|
37
|
+
import { sleep } from "@intentius/chant/op";
|
|
38
|
+
|
|
30
39
|
export const DEFAULT_SPRITES_BASE_URL = "https://api.sprites.dev";
|
|
31
40
|
|
|
32
41
|
// ── Pure helpers (unit-testable without http/ws) ──────────────────────────────
|
|
@@ -41,15 +50,27 @@ export function resolveSpritesEndpoint(
|
|
|
41
50
|
args: { endpoint?: string } = {},
|
|
42
51
|
env: NodeJS.ProcessEnv = process.env,
|
|
43
52
|
): string {
|
|
44
|
-
const base = args.endpoint || env.SPRITES_BASE_URL || DEFAULT_SPRITES_BASE_URL;
|
|
53
|
+
const base = args.endpoint || env.SPRITES_BASE_URL || env.SPRITES_API_URL || DEFAULT_SPRITES_BASE_URL;
|
|
45
54
|
return base.replace(/\/$/, "");
|
|
46
55
|
}
|
|
47
56
|
|
|
57
|
+
/**
|
|
58
|
+
* Resolve the bearer token (#2711): an explicit `token` arg wins, then
|
|
59
|
+
* `SPRITES_API_TOKEN`, then its alias `SPRITE_TOKEN`. Pure — mirrors
|
|
60
|
+
* `resolveSpritesEndpoint`.
|
|
61
|
+
*/
|
|
62
|
+
export function resolveSpritesToken(
|
|
63
|
+
token: string | undefined = undefined,
|
|
64
|
+
env: NodeJS.ProcessEnv = process.env,
|
|
65
|
+
): string | undefined {
|
|
66
|
+
return token ?? env.SPRITES_API_TOKEN ?? env.SPRITE_TOKEN;
|
|
67
|
+
}
|
|
68
|
+
|
|
48
69
|
const spritesUrl = (base: string): string => `${base}/v1/sprites`;
|
|
49
|
-
const
|
|
70
|
+
const spriteResourceUrl = (base: string, id: string): string => `${spritesUrl(base)}/${encodeURIComponent(id)}`;
|
|
50
71
|
// Create uses REST JSON; exec is the control WebSocket below; checkpoints are NDJSON.
|
|
51
|
-
const spriteCheckpointUrl = (base: string, id: string): string => `${
|
|
52
|
-
const spriteCheckpointsUrl = (base: string, id: string): string => `${
|
|
72
|
+
const spriteCheckpointUrl = (base: string, id: string): string => `${spriteResourceUrl(base, id)}/checkpoint`;
|
|
73
|
+
const spriteCheckpointsUrl = (base: string, id: string): string => `${spriteResourceUrl(base, id)}/checkpoints`;
|
|
53
74
|
const spriteCheckpointRestoreUrl = (base: string, id: string, cp: string): string =>
|
|
54
75
|
`${spriteCheckpointsUrl(base, id)}/${encodeURIComponent(cp)}/restore`;
|
|
55
76
|
|
|
@@ -354,7 +375,7 @@ export function defaultSpritesHttp(token?: string, fetchImpl: typeof fetch = fet
|
|
|
354
375
|
return async (method, url, body, headers, signal) => {
|
|
355
376
|
const h: Record<string, string> = { ...headers };
|
|
356
377
|
if (body !== undefined) h["content-type"] = "application/json";
|
|
357
|
-
const tok = token
|
|
378
|
+
const tok = resolveSpritesToken(token);
|
|
358
379
|
if (tok) h["authorization"] = `Bearer ${tok}`;
|
|
359
380
|
const res = await fetchImpl(url, {
|
|
360
381
|
method,
|
|
@@ -393,7 +414,7 @@ export async function spriteCreate(
|
|
|
393
414
|
export async function spriteExec(args: SpriteExecArgs, signal?: AbortSignal): Promise<SpriteExecResult> {
|
|
394
415
|
const base = resolveSpritesEndpoint(args);
|
|
395
416
|
const url = spriteExecWsUrl(base, args.id, args.cmd);
|
|
396
|
-
const token = args.token
|
|
417
|
+
const token = resolveSpritesToken(args.token);
|
|
397
418
|
const headers: Record<string, string> = {};
|
|
398
419
|
if (token) headers.Authorization = `Bearer ${token}`;
|
|
399
420
|
const { default: WebSocket } = await import("ws");
|
|
@@ -522,10 +543,90 @@ export async function spriteDestroy(
|
|
|
522
543
|
http: SpritesHttp = defaultSpritesHttp(args.token),
|
|
523
544
|
): Promise<Record<string, never>> {
|
|
524
545
|
const base = resolveSpritesEndpoint(args);
|
|
525
|
-
const res = await http("DELETE",
|
|
546
|
+
const res = await http("DELETE", spriteResourceUrl(base, args.id), undefined, undefined, signal);
|
|
526
547
|
if (res.status >= 300 && res.status !== 404) {
|
|
527
548
|
throw new Error(`sprite ${args.id} destroy failed (${res.status}): ${res.text}`);
|
|
528
549
|
}
|
|
529
550
|
console.log(`destroyed: sprite/${args.id} (${base})`);
|
|
530
551
|
return {};
|
|
531
552
|
}
|
|
553
|
+
|
|
554
|
+
/**
|
|
555
|
+
* Delete the sprite (#2711) — the same idempotent `DELETE /v1/sprites/{id}` as
|
|
556
|
+
* `spriteDestroy`, under the name spritzer, wisp and the other lexicons'
|
|
557
|
+
* delete activities (`awsDelete`, `gcpDelete`, `azDelete`) use. A literal
|
|
558
|
+
* alias, not a reimplementation, so the two names can never drift: an Op
|
|
559
|
+
* authored against either resolves to the same call. `spriteDestroy` stays —
|
|
560
|
+
* it is the name every existing Op, example and the `op-verb-class` registry
|
|
561
|
+
* already depend on.
|
|
562
|
+
*/
|
|
563
|
+
export const spriteDelete = spriteDestroy;
|
|
564
|
+
export type SpriteDeleteArgs = SpriteDestroyArgs;
|
|
565
|
+
|
|
566
|
+
export interface SpriteUrlArgs {
|
|
567
|
+
/** Target sprite id. */
|
|
568
|
+
id: string;
|
|
569
|
+
/**
|
|
570
|
+
* Wait until this path on the sprite's URL answers, instead of returning
|
|
571
|
+
* the URL immediately. Unset (default): no wait, just resolve the URL.
|
|
572
|
+
*/
|
|
573
|
+
path?: string;
|
|
574
|
+
/** Expected status while waiting. Default: any 2xx. */
|
|
575
|
+
status?: number;
|
|
576
|
+
/** Max time to wait for `path` to answer, ms. Default: `10000`. */
|
|
577
|
+
timeoutMs?: number;
|
|
578
|
+
/** Delay between polls, ms. Default: `500`. */
|
|
579
|
+
intervalMs?: number;
|
|
580
|
+
endpoint?: string;
|
|
581
|
+
token?: string;
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
export interface SpriteUrlResult {
|
|
585
|
+
url: string;
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
/**
|
|
589
|
+
* Resolve the sprite's URL (#2711) — `spriteCreate` returns it too, but
|
|
590
|
+
* nothing until now exposed it on its own (for a later phase that only has
|
|
591
|
+
* the sprite `id`) or waited on it. `GET /v1/sprites/{id}` for the URL; with
|
|
592
|
+
* `path` set, polls `GET {url}{path}` until `status` (default any 2xx) or
|
|
593
|
+
* `timeoutMs` runs out — the box's door/hud/chud services take a moment to
|
|
594
|
+
* bind their `http_port` after `spriteServiceStart`.
|
|
595
|
+
*/
|
|
596
|
+
export async function spriteUrl(
|
|
597
|
+
args: SpriteUrlArgs,
|
|
598
|
+
signal?: AbortSignal,
|
|
599
|
+
http: SpritesHttp = defaultSpritesHttp(args.token),
|
|
600
|
+
): Promise<SpriteUrlResult> {
|
|
601
|
+
const base = resolveSpritesEndpoint(args);
|
|
602
|
+
const res = await http("GET", spriteResourceUrl(base, args.id), undefined, undefined, signal);
|
|
603
|
+
if (res.status >= 300) throw new Error(`sprite ${args.id} url lookup failed (${res.status}): ${res.text}`);
|
|
604
|
+
const url = (safeJson(res.text) as { url?: string } | undefined)?.url;
|
|
605
|
+
if (!url) throw new Error(`sprite ${args.id} has no url`);
|
|
606
|
+
|
|
607
|
+
if (args.path !== undefined) {
|
|
608
|
+
const timeoutMs = args.timeoutMs ?? 10_000;
|
|
609
|
+
const intervalMs = args.intervalMs ?? 500;
|
|
610
|
+
const target = `${url}${args.path}`;
|
|
611
|
+
const deadline = Date.now() + timeoutMs;
|
|
612
|
+
let lastErr = "";
|
|
613
|
+
for (;;) {
|
|
614
|
+
if (signal?.aborted) throw new Error(`sprite ${args.id} url wait aborted`);
|
|
615
|
+
try {
|
|
616
|
+
const check = await http("GET", target, undefined, undefined, signal);
|
|
617
|
+
const ok = args.status !== undefined ? check.status === args.status : check.status >= 200 && check.status < 300;
|
|
618
|
+
if (ok) {
|
|
619
|
+
console.log(`url: sprite/${args.id} answers on ${target} (${check.status})`);
|
|
620
|
+
return { url };
|
|
621
|
+
}
|
|
622
|
+
lastErr = `status ${check.status} (want ${args.status ?? "2xx"})`;
|
|
623
|
+
} catch (e) {
|
|
624
|
+
lastErr = e instanceof Error ? e.message : String(e);
|
|
625
|
+
}
|
|
626
|
+
if (Date.now() >= deadline) throw new Error(`sprite ${args.id} url ${target} did not answer: ${lastErr}`);
|
|
627
|
+
await sleep(intervalMs, signal);
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
return { url };
|
|
632
|
+
}
|
package/src/op/builders.ts
CHANGED
|
@@ -28,9 +28,18 @@
|
|
|
28
28
|
|
|
29
29
|
import { activity, type NamedActivityStep, type WithStepRefs } from "@intentius/chant/op";
|
|
30
30
|
import type { ActivityStep } from "@intentius/chant/op";
|
|
31
|
-
import type { SpriteCreateArgs, SpriteExecArgs, SpriteCheckpointArgs, SpriteRestoreArgs, ListCheckpointsArgs, SpriteDestroyArgs } from "./activities/sprites";
|
|
31
|
+
import type { SpriteCreateArgs, SpriteExecArgs, SpriteCheckpointArgs, SpriteRestoreArgs, ListCheckpointsArgs, SpriteDestroyArgs, SpriteDeleteArgs, SpriteUrlArgs } from "./activities/sprites";
|
|
32
32
|
import type { SpriteWriteFileArgs, SpriteReadFileArgs, SpriteListDirArgs, SpriteRemoveArgs } from "./activities/sprite-fs";
|
|
33
33
|
import type { SpriteApplyNetworkPolicyArgs, SpriteApplyServicesArgs } from "./activities/sprite-config";
|
|
34
|
+
import type {
|
|
35
|
+
SpriteServiceCreateArgs,
|
|
36
|
+
SpriteServiceGetArgs,
|
|
37
|
+
SpriteServiceListArgs,
|
|
38
|
+
SpriteServiceStartArgs,
|
|
39
|
+
SpriteServiceStopArgs,
|
|
40
|
+
SpriteServiceDeleteArgs,
|
|
41
|
+
SpriteServiceLogsArgs,
|
|
42
|
+
} from "./activities/sprite-services";
|
|
34
43
|
import type { SpriteTaskCreateArgs, SpriteTaskRefreshArgs, SpriteTaskReleaseArgs } from "./activities/sprite-tasks";
|
|
35
44
|
import type { SpritesUpArgs, SpritesDownArgs } from "./activities/sprites-emulator";
|
|
36
45
|
|
|
@@ -75,6 +84,10 @@ export const spriteRestore = spriteStep<SpriteRestoreArgs>("spriteRestore", "lon
|
|
|
75
84
|
export const listCheckpoints = spriteStep<ListCheckpointsArgs>("listCheckpoints", "fastIdempotent");
|
|
76
85
|
/** Destroy a sprite — the fully typed twin of core's `spriteDestroy`. Defaults to the `fastIdempotent` profile. */
|
|
77
86
|
export const spriteDestroy = spriteStep<SpriteDestroyArgs>("spriteDestroy", "fastIdempotent");
|
|
87
|
+
/** Delete a sprite (#2711; alias of `spriteDestroy`). Defaults to the `fastIdempotent` profile. */
|
|
88
|
+
export const spriteDelete = spriteStep<SpriteDeleteArgs>("spriteDelete", "fastIdempotent");
|
|
89
|
+
/** Resolve a sprite's URL, optionally waiting until a path on it answers (#2711). Defaults to the `fastIdempotent` profile. */
|
|
90
|
+
export const spriteUrl = spriteStep<SpriteUrlArgs>("spriteUrl", "fastIdempotent");
|
|
78
91
|
/** Write a file into a sprite — the fully typed twin of core's `spriteWriteFile`. Defaults to the `fastIdempotent` profile. */
|
|
79
92
|
export const spriteWriteFile = spriteStep<SpriteWriteFileArgs>("spriteWriteFile", "fastIdempotent");
|
|
80
93
|
/** Read a file from a sprite — the fully typed twin of core's `spriteReadFile`. Defaults to the `fastIdempotent` profile. */
|
|
@@ -87,6 +100,20 @@ export const spriteRemove = spriteStep<SpriteRemoveArgs>("spriteRemove", "fastId
|
|
|
87
100
|
export const spriteApplyNetworkPolicy = spriteStep<SpriteApplyNetworkPolicyArgs>("spriteApplyNetworkPolicy", "fastIdempotent");
|
|
88
101
|
/** Reconcile a sprite's background services — the fully typed twin of core's `spriteApplyServices`. Defaults to the `fastIdempotent` profile. */
|
|
89
102
|
export const spriteApplyServices = spriteStep<SpriteApplyServicesArgs>("spriteApplyServices", "fastIdempotent");
|
|
103
|
+
/** Create-and-start one background service (#2711) — the single-service primitive underneath `spriteApplyServices`. Defaults to the `longInfra` profile (the create+start NDJSON round trip). */
|
|
104
|
+
export const spriteServiceCreate = spriteStep<SpriteServiceCreateArgs>("spriteServiceCreate", "longInfra");
|
|
105
|
+
/** Get one background service's definition and live state (#2711). Defaults to the `fastIdempotent` profile. */
|
|
106
|
+
export const spriteServiceGet = spriteStep<SpriteServiceGetArgs>("spriteServiceGet", "fastIdempotent");
|
|
107
|
+
/** List a sprite's background services (#2711). Defaults to the `fastIdempotent` profile. */
|
|
108
|
+
export const spriteServiceList = spriteStep<SpriteServiceListArgs>("spriteServiceList", "fastIdempotent");
|
|
109
|
+
/** Start a stopped background service (#2711). Defaults to the `longInfra` profile (the NDJSON round trip). */
|
|
110
|
+
export const spriteServiceStart = spriteStep<SpriteServiceStartArgs>("spriteServiceStart", "longInfra");
|
|
111
|
+
/** Stop a running background service (#2711). Defaults to the `fastIdempotent` profile. */
|
|
112
|
+
export const spriteServiceStop = spriteStep<SpriteServiceStopArgs>("spriteServiceStop", "fastIdempotent");
|
|
113
|
+
/** Delete a background service, idempotent (#2711). Defaults to the `fastIdempotent` profile. */
|
|
114
|
+
export const spriteServiceDelete = spriteStep<SpriteServiceDeleteArgs>("spriteServiceDelete", "fastIdempotent");
|
|
115
|
+
/** Read a background service's log tail (#2711). Defaults to the `fastIdempotent` profile. */
|
|
116
|
+
export const spriteServiceLogs = spriteStep<SpriteServiceLogsArgs>("spriteServiceLogs", "fastIdempotent");
|
|
90
117
|
/** Create a keep-alive task — the fully typed twin of core's `spriteTaskCreate`. Defaults to the `fastIdempotent` profile. */
|
|
91
118
|
export const spriteTaskCreate = spriteStep<SpriteTaskCreateArgs>("spriteTaskCreate", "fastIdempotent");
|
|
92
119
|
/** Refresh a keep-alive task's expiry — the fully typed twin of core's `spriteTaskRefresh`. Defaults to the `fastIdempotent` profile. */
|
|
@@ -78,7 +78,7 @@ When the `Run` phase's command exits non-zero, `spriteExec` throws, the phase fa
|
|
|
78
78
|
|
|
79
79
|
## Targeting the emulator or real Sprites
|
|
80
80
|
|
|
81
|
-
The activities resolve their endpoint in this order: an explicit `endpoint` arg, then `SPRITES_BASE_URL`, then the real Sprites base. The same Op targets an emulator or real Sprites with no code change. The default `fetch` client adds `Authorization: Bearer
|
|
81
|
+
The activities resolve their endpoint in this order: an explicit `endpoint` arg, then `SPRITES_BASE_URL`, then its alias `SPRITES_API_URL` (the name the studio and wisp's own docs use), then the real Sprites base. The same Op targets an emulator or real Sprites with no code change. The default `fetch` client adds `Authorization: Bearer <token>` when a token is set — `SPRITES_API_TOKEN`, or its alias `SPRITE_TOKEN` — the emulator ignores it. Either alias is read only when the original name is unset, so an existing deployment using `SPRITES_BASE_URL`/`SPRITES_API_TOKEN` is unaffected.
|
|
82
82
|
|
|
83
83
|
```bash
|
|
84
84
|
# Point at a self-hosted or in-process emulator.
|
|
@@ -105,9 +105,11 @@ The same lexicon ships more Sprite primitives, all imported from `@intentius/cha
|
|
|
105
105
|
|--------|-----------|-----|
|
|
106
106
|
| Filesystem (#848) | `spriteWriteFile` / `spriteReadFile` / `spriteListDir` / `spriteRemove` | stage an input file and read a result out without shelling `spriteExec` + `cat` |
|
|
107
107
|
| Config reconcile (#849) | `spriteApplyNetworkPolicy` / `spriteApplyServices` | reconcile a Sprite's egress allowlist and background services against typed config (validated before any HTTP; a whole-object replace for policy, create-or-update by name for services) |
|
|
108
|
+
| Services (#2711) | `spriteServiceCreate` / `spriteServiceGet` / `spriteServiceList` / `spriteServiceStart` / `spriteServiceStop` / `spriteServiceDelete` / `spriteServiceLogs` | the single-service primitives underneath `spriteApplyServices` — create-and-start one long-lived service (a box's door, hud or chud), inspect or list what's running, stop/start or delete one by name, read its log tail |
|
|
109
|
+
| Sprite URL / delete (#2711) | `spriteUrl` / `spriteDelete` | resolve a Sprite's URL, optionally waiting until a path on it answers; delete the Sprite (`spriteDelete` is `spriteDestroy` under the name spritzer/wisp and the other lexicons' delete activities use — same call, either name) |
|
|
108
110
|
| Keep-alive (#847) | `spriteTaskCreate` / `spriteTaskRefresh` / `spriteTaskRelease` | hold a Sprite active for a session so it will not pause; a session past the 1-hour task cap refreshes on an interval |
|
|
109
111
|
|
|
110
|
-
These are still runtime-orchestration primitives, not declarable resources — a Sprite has no desired-state create body to reconcile.
|
|
112
|
+
These are still runtime-orchestration primitives, not declarable resources — a Sprite has no desired-state create body to reconcile. Services created directly with `spriteServiceCreate` are what a box's `spritzer` preset provisions door/hud/chud on (arugula-salad/studio#27) — the same wire surface as `sprite-env services` inside the sprite, spritzer 0.6.0's container mode, and wisp.
|
|
111
113
|
|
|
112
114
|
## Where it fits
|
|
113
115
|
|