@intentius/chant-lexicon-fly 0.18.6 → 0.18.7
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/op/activities/index.d.ts +6 -0
- package/dist/op/activities/index.d.ts.map +1 -1
- package/dist/op/activities/sprite-config.d.ts +91 -0
- package/dist/op/activities/sprite-config.d.ts.map +1 -0
- package/dist/op/activities/sprite-fs.d.ts +96 -0
- package/dist/op/activities/sprite-fs.d.ts.map +1 -0
- package/dist/op/activities/sprite-tasks.d.ts +54 -0
- package/dist/op/activities/sprite-tasks.d.ts.map +1 -0
- package/dist/op/activities/sprites-fake.d.ts +37 -0
- package/dist/op/activities/sprites-fake.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/index.ts +9 -0
- package/src/op/activities/index.ts +56 -0
- package/src/op/activities/sprite-config.test.ts +159 -0
- package/src/op/activities/sprite-config.ts +246 -0
- package/src/op/activities/sprite-fs.test.ts +136 -0
- package/src/op/activities/sprite-fs.ts +217 -0
- package/src/op/activities/sprite-tasks.test.ts +165 -0
- package/src/op/activities/sprite-tasks.ts +91 -0
- package/src/op/activities/sprites-fake.ts +201 -2
- package/src/skills/chant-fly-sprites.md +14 -0
package/dist/index.d.ts
CHANGED
|
@@ -4,6 +4,6 @@ export { Fly, Region, OrgSlug, AppName, PseudoParameter } from "./pseudo.js";
|
|
|
4
4
|
export { FLY_METADATA_OWNERSHIP_KEYS } from "./ownership.js";
|
|
5
5
|
export { flyDeploy, flapsUp, flapsDown, flyApplyStep, LOCAL_FLAPS_ENDPOINT } from "./composites/fly-deploy.js";
|
|
6
6
|
export type { FlyDeployOpts, FlyApplyStepOpts, FlapsStepOpts } from "./composites/fly-deploy.js";
|
|
7
|
-
export { spriteCreate, spriteExec, spriteCheckpoint, spriteRestore, listCheckpoints, spriteDestroy, spritesUp, spritesDown, } from "@intentius/chant/op";
|
|
7
|
+
export { spriteCreate, spriteExec, spriteCheckpoint, spriteRestore, listCheckpoints, spriteDestroy, spriteWriteFile, spriteReadFile, spriteListDir, spriteRemove, spriteApplyNetworkPolicy, spriteApplyServices, spriteTaskCreate, spriteTaskRefresh, spriteTaskRelease, spritesUp, spritesDown, } from "@intentius/chant/op";
|
|
8
8
|
export * from "./generated/index.js";
|
|
9
9
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAGrC,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAI7C,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAG1E,OAAO,EAAE,2BAA2B,EAAE,MAAM,aAAa,CAAC;AAK1D,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAC5G,YAAY,EAAE,aAAa,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAM9F,OAAO,EACL,YAAY,EACZ,UAAU,EACV,gBAAgB,EAChB,aAAa,EACb,eAAe,EACf,aAAa,EACb,SAAS,EACT,WAAW,GACZ,MAAM,qBAAqB,CAAC;AAK7B,cAAc,mBAAmB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAGrC,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAI7C,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAG1E,OAAO,EAAE,2BAA2B,EAAE,MAAM,aAAa,CAAC;AAK1D,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAC5G,YAAY,EAAE,aAAa,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAM9F,OAAO,EACL,YAAY,EACZ,UAAU,EACV,gBAAgB,EAChB,aAAa,EACb,eAAe,EACf,aAAa,EACb,eAAe,EACf,cAAc,EACd,aAAa,EACb,YAAY,EACZ,wBAAwB,EACxB,mBAAmB,EACnB,gBAAgB,EAChB,iBAAiB,EACjB,iBAAiB,EACjB,SAAS,EACT,WAAW,GACZ,MAAM,qBAAqB,CAAC;AAK7B,cAAc,mBAAmB,CAAC"}
|
|
@@ -11,6 +11,12 @@ export { flapsUp, flapsDown, flapsRunCommand, flapsRmCommand, flapsExistsCommand
|
|
|
11
11
|
export type { FlapsUpArgs, FlapsDownArgs } from "./flaps.js";
|
|
12
12
|
export { spriteCreate, spriteExec, spriteCheckpoint, spriteRestore, listCheckpoints, spriteDestroy, resolveSpritesEndpoint, defaultSpritesHttp, spriteCreateBody, parseCreateResponse, accumulateExecFrames, parseCheckpointNdjson, pickCheckpointByComment, splitCommand, spriteExecWsUrl, DEFAULT_SPRITES_BASE_URL, } from "./sprites.js";
|
|
13
13
|
export type { SpritesHttp, SpriteCreateArgs, SpriteCreateResult, SpriteExecArgs, SpriteExecResult, SpriteCheckpointArgs, SpriteCheckpointResult, SpriteRestoreArgs, ListCheckpointsArgs, Checkpoint, SpriteDestroyArgs, } from "./sprites.js";
|
|
14
|
+
export { spriteWriteFile, spriteReadFile, spriteListDir, spriteRemove, spriteFsUrl, defaultSpritesRawHttp, } from "./sprite-fs.js";
|
|
15
|
+
export type { SpritesRawHttp, SpriteWriteFileArgs, SpriteReadFileArgs, SpriteReadFileResult, SpriteListDirArgs, SpriteDirEntry, SpriteRemoveArgs, } from "./sprite-fs.js";
|
|
16
|
+
export { spriteApplyNetworkPolicy, spriteApplyServices, validateNetworkRules, networkRulesEqual, validateServices, serviceConfigEqual, } from "./sprite-config.js";
|
|
17
|
+
export type { NetworkRule, SpriteApplyNetworkPolicyArgs, SpriteApplyNetworkPolicyResult, ServiceSpec, SpriteApplyServicesArgs, SpriteApplyServicesResult, } from "./sprite-config.js";
|
|
18
|
+
export { spriteTaskCreate, spriteTaskRefresh, spriteTaskRelease, spriteTasksUrl, spriteTaskUrl, } from "./sprite-tasks.js";
|
|
19
|
+
export type { SpriteTaskCreateArgs, SpriteTaskRefreshArgs, SpriteTaskReleaseArgs, } from "./sprite-tasks.js";
|
|
14
20
|
export { spritesUp, spritesDown, spritesRunCommand, spritesRmCommand, spritesExistsCommand, spritesHealthUrl, spritesEndpoint, } from "./sprites-emulator.js";
|
|
15
21
|
export type { SpritesUpArgs, SpritesDownArgs } from "./sprites-emulator.js";
|
|
16
22
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/op/activities/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EACL,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,YAAY,EACZ,cAAc,EACd,SAAS,EACT,YAAY,EACZ,aAAa,EACb,cAAc,EACd,YAAY,EACZ,YAAY,EACZ,SAAS,EACT,eAAe,EACf,SAAS,EACT,YAAY,EACZ,gBAAgB,EAChB,iBAAiB,EACjB,UAAU,EACV,kBAAkB,EAClB,YAAY,EACZ,WAAW,EACX,eAAe,EACf,cAAc,EACd,sBAAsB,EACtB,kBAAkB,GACnB,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,YAAY,EAAE,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAIlH,OAAO,EACL,OAAO,EACP,SAAS,EACT,eAAe,EACf,cAAc,EACd,kBAAkB,EAClB,cAAc,EACd,aAAa,GACd,MAAM,SAAS,CAAC;AACjB,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAQ1D,OAAO,EACL,YAAY,EACZ,UAAU,EACV,gBAAgB,EAChB,aAAa,EACb,eAAe,EACf,aAAa,EACb,sBAAsB,EACtB,kBAAkB,EAClB,gBAAgB,EAChB,mBAAmB,EACnB,oBAAoB,EACpB,qBAAqB,EACrB,uBAAuB,EACvB,YAAY,EACZ,eAAe,EACf,wBAAwB,GACzB,MAAM,WAAW,CAAC;AACnB,YAAY,EACV,WAAW,EACX,gBAAgB,EAChB,kBAAkB,EAClB,cAAc,EACd,gBAAgB,EAChB,oBAAoB,EACpB,sBAAsB,EACtB,iBAAiB,EACjB,mBAAmB,EACnB,UAAU,EACV,iBAAiB,GAClB,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/op/activities/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EACL,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,YAAY,EACZ,cAAc,EACd,SAAS,EACT,YAAY,EACZ,aAAa,EACb,cAAc,EACd,YAAY,EACZ,YAAY,EACZ,SAAS,EACT,eAAe,EACf,SAAS,EACT,YAAY,EACZ,gBAAgB,EAChB,iBAAiB,EACjB,UAAU,EACV,kBAAkB,EAClB,YAAY,EACZ,WAAW,EACX,eAAe,EACf,cAAc,EACd,sBAAsB,EACtB,kBAAkB,GACnB,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,YAAY,EAAE,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAIlH,OAAO,EACL,OAAO,EACP,SAAS,EACT,eAAe,EACf,cAAc,EACd,kBAAkB,EAClB,cAAc,EACd,aAAa,GACd,MAAM,SAAS,CAAC;AACjB,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAQ1D,OAAO,EACL,YAAY,EACZ,UAAU,EACV,gBAAgB,EAChB,aAAa,EACb,eAAe,EACf,aAAa,EACb,sBAAsB,EACtB,kBAAkB,EAClB,gBAAgB,EAChB,mBAAmB,EACnB,oBAAoB,EACpB,qBAAqB,EACrB,uBAAuB,EACvB,YAAY,EACZ,eAAe,EACf,wBAAwB,GACzB,MAAM,WAAW,CAAC;AACnB,YAAY,EACV,WAAW,EACX,gBAAgB,EAChB,kBAAkB,EAClB,cAAc,EACd,gBAAgB,EAChB,oBAAoB,EACpB,sBAAsB,EACtB,iBAAiB,EACjB,mBAAmB,EACnB,UAAU,EACV,iBAAiB,GAClB,MAAM,WAAW,CAAC;AAInB,OAAO,EACL,eAAe,EACf,cAAc,EACd,aAAa,EACb,YAAY,EACZ,WAAW,EACX,qBAAqB,GACtB,MAAM,aAAa,CAAC;AACrB,YAAY,EACV,cAAc,EACd,mBAAmB,EACnB,kBAAkB,EAClB,oBAAoB,EACpB,iBAAiB,EACjB,cAAc,EACd,gBAAgB,GACjB,MAAM,aAAa,CAAC;AAMrB,OAAO,EACL,wBAAwB,EACxB,mBAAmB,EACnB,oBAAoB,EACpB,iBAAiB,EACjB,gBAAgB,EAChB,kBAAkB,GACnB,MAAM,iBAAiB,CAAC;AACzB,YAAY,EACV,WAAW,EACX,4BAA4B,EAC5B,8BAA8B,EAC9B,WAAW,EACX,uBAAuB,EACvB,yBAAyB,GAC1B,MAAM,iBAAiB,CAAC;AAIzB,OAAO,EACL,gBAAgB,EAChB,iBAAiB,EACjB,iBAAiB,EACjB,cAAc,EACd,aAAa,GACd,MAAM,gBAAgB,CAAC;AACxB,YAAY,EACV,oBAAoB,EACpB,qBAAqB,EACrB,qBAAqB,GACtB,MAAM,gBAAgB,CAAC;AAMxB,OAAO,EACL,SAAS,EACT,WAAW,EACX,iBAAiB,EACjB,gBAAgB,EAChB,oBAAoB,EACpB,gBAAgB,EAChB,eAAe,GAChB,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sprite config reconcile activities (#849) — the two pieces of genuine
|
|
3
|
+
* desired-state a Sprite carries: its outbound network policy and its background
|
|
4
|
+
* services. Unlike the sprite itself (an Op primitive with no reconcilable
|
|
5
|
+
* create body), these are set after create and persist across cold boots, so
|
|
6
|
+
* chant reconciles typed config against the live Sprite — the `flyApply`
|
|
7
|
+
* plan→CRUD pattern scoped to one Sprite, not a declarable resource.
|
|
8
|
+
*
|
|
9
|
+
* Both use the JSON `SpritesHttp` client from `sprites.ts`; endpoint + bearer
|
|
10
|
+
* resolution is shared. Validation is pure and runs before any HTTP (invalid
|
|
11
|
+
* rules / a `needs` cycle throw up front), so a bad config fails the step
|
|
12
|
+
* cleanly rather than half-applying.
|
|
13
|
+
*
|
|
14
|
+
* Scope (v1): network policy is a whole-object replace (converges by
|
|
15
|
+
* construction); services reconcile is additive + update (create-or-update each
|
|
16
|
+
* desired service, optionally start). Owned-only prune of stale services is out
|
|
17
|
+
* of scope — the documented Services REST surface exposes no delete.
|
|
18
|
+
*/
|
|
19
|
+
import { type SpritesHttp } from "./sprites.js";
|
|
20
|
+
/** One outbound rule. Ordered — specificity is positional, so order is significant. */
|
|
21
|
+
export interface NetworkRule {
|
|
22
|
+
domain: string;
|
|
23
|
+
action: "allow" | "deny";
|
|
24
|
+
}
|
|
25
|
+
export interface SpriteApplyNetworkPolicyArgs {
|
|
26
|
+
id: string;
|
|
27
|
+
/** The complete desired ruleset (whole-object replace). */
|
|
28
|
+
rules: NetworkRule[];
|
|
29
|
+
endpoint?: string;
|
|
30
|
+
token?: string;
|
|
31
|
+
}
|
|
32
|
+
export interface SpriteApplyNetworkPolicyResult {
|
|
33
|
+
/** True when the live policy differed and was replaced; false when already converged. */
|
|
34
|
+
changed: boolean;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Validate a ruleset: every rule needs a non-empty `domain` and an `allow`/`deny`
|
|
38
|
+
* `action`. Pure; throws on the first offender.
|
|
39
|
+
*/
|
|
40
|
+
export declare function validateNetworkRules(rules: NetworkRule[]): void;
|
|
41
|
+
/** Order-sensitive equality of two rulesets (position is significant). Pure. */
|
|
42
|
+
export declare function networkRulesEqual(a: NetworkRule[], b: NetworkRule[]): boolean;
|
|
43
|
+
/**
|
|
44
|
+
* Reconcile a Sprite's outbound network policy. GET the live ruleset, and POST
|
|
45
|
+
* the desired set only when it differs (`GET`/`POST /policy/network`). Returns
|
|
46
|
+
* whether a change was applied.
|
|
47
|
+
*/
|
|
48
|
+
export declare function spriteApplyNetworkPolicy(args: SpriteApplyNetworkPolicyArgs, signal?: AbortSignal, http?: SpritesHttp): Promise<SpriteApplyNetworkPolicyResult>;
|
|
49
|
+
/** A desired background service. Keyed by `name`; PUT is create-or-update. */
|
|
50
|
+
export interface ServiceSpec {
|
|
51
|
+
name: string;
|
|
52
|
+
cmd: string;
|
|
53
|
+
args?: string[];
|
|
54
|
+
env?: Record<string, string>;
|
|
55
|
+
dir?: string;
|
|
56
|
+
/** Names of services that must start first. */
|
|
57
|
+
needs?: string[];
|
|
58
|
+
/** Route the Sprite's public URL to this port. */
|
|
59
|
+
http_port?: number;
|
|
60
|
+
}
|
|
61
|
+
export interface SpriteApplyServicesArgs {
|
|
62
|
+
id: string;
|
|
63
|
+
services: ServiceSpec[];
|
|
64
|
+
/** Start each service after applying (in dependency order). Default: false. */
|
|
65
|
+
start?: boolean;
|
|
66
|
+
endpoint?: string;
|
|
67
|
+
token?: string;
|
|
68
|
+
}
|
|
69
|
+
export interface SpriteApplyServicesResult {
|
|
70
|
+
/** Names that were created or updated (converged services are skipped). */
|
|
71
|
+
applied: string[];
|
|
72
|
+
/** Names that were started (empty unless `start`). */
|
|
73
|
+
started: string[];
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Validate a service set: names are unique, every `needs` target exists, and the
|
|
77
|
+
* dependency graph is acyclic. Pure; throws on the first violation. Returns the
|
|
78
|
+
* names in a valid start order (dependencies first).
|
|
79
|
+
*/
|
|
80
|
+
export declare function validateServices(services: ServiceSpec[]): string[];
|
|
81
|
+
/** Comparable service config (the fields the reconcile diffs on). Pure. */
|
|
82
|
+
export declare function serviceConfigEqual(a: Partial<ServiceSpec>, b: Partial<ServiceSpec>): boolean;
|
|
83
|
+
/**
|
|
84
|
+
* Reconcile a Sprite's background services (additive + update). Lists the live
|
|
85
|
+
* services, then `PUT`s each desired service that is new or changed
|
|
86
|
+
* (create-or-update by name); when `start` is set, `POST .../start`s them in
|
|
87
|
+
* dependency order. Converged services are skipped. Owned-only prune is out of
|
|
88
|
+
* scope (no delete in the Services REST surface).
|
|
89
|
+
*/
|
|
90
|
+
export declare function spriteApplyServices(args: SpriteApplyServicesArgs, signal?: AbortSignal, http?: SpritesHttp): Promise<SpriteApplyServicesResult>;
|
|
91
|
+
//# sourceMappingURL=sprite-config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sprite-config.d.ts","sourceRoot":"","sources":["../../../src/op/activities/sprite-config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAA8C,KAAK,WAAW,EAAE,MAAM,WAAW,CAAC;AAYzF,uFAAuF;AACvF,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,OAAO,GAAG,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,4BAA4B;IAC3C,EAAE,EAAE,MAAM,CAAC;IACX,2DAA2D;IAC3D,KAAK,EAAE,WAAW,EAAE,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,8BAA8B;IAC7C,yFAAyF;IACzF,OAAO,EAAE,OAAO,CAAC;CAClB;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,WAAW,EAAE,GAAG,IAAI,CAS/D;AAED,gFAAgF;AAChF,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,WAAW,EAAE,EAAE,CAAC,EAAE,WAAW,EAAE,GAAG,OAAO,CAG7E;AAKD;;;;GAIG;AACH,wBAAsB,wBAAwB,CAC5C,IAAI,EAAE,4BAA4B,EAClC,MAAM,CAAC,EAAE,WAAW,EACpB,IAAI,GAAE,WAA4C,GACjD,OAAO,CAAC,8BAA8B,CAAC,CAiBzC;AAID,8EAA8E;AAC9E,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,+CAA+C;IAC/C,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,kDAAkD;IAClD,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,uBAAuB;IACtC,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,+EAA+E;IAC/E,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,yBAAyB;IACxC,2EAA2E;IAC3E,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,sDAAsD;IACtD,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,WAAW,EAAE,GAAG,MAAM,EAAE,CA0BlE;AAED,2EAA2E;AAC3E,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,GAAG,OAAO,CAW5F;AAkBD;;;;;;GAMG;AACH,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,uBAAuB,EAC7B,MAAM,CAAC,EAAE,WAAW,EACpB,IAAI,GAAE,WAA4C,GACjD,OAAO,CAAC,yBAAyB,CAAC,CAsCpC"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sprite filesystem activities (#848) — imperative file-I/O primitives over the
|
|
3
|
+
* Sprites filesystem API (`/v1/sprites/{id}/fs/*`). Same category as the
|
|
4
|
+
* lifecycle activities in `sprites.ts`: runtime-orchestration primitives, no
|
|
5
|
+
* desired state. They let an Op stage an input file into a sprite and read a
|
|
6
|
+
* result out without shelling it through `spriteExec` + `cat`/`tee`.
|
|
7
|
+
*
|
|
8
|
+
* read/write move raw file bytes in the body (not JSON), so these use a small
|
|
9
|
+
* raw HTTP client (`SpritesRawHttp`) rather than the JSON `SpritesHttp` the
|
|
10
|
+
* lifecycle activities use; path/mode/mkdir/recursive ride as query params.
|
|
11
|
+
* Endpoint + bearer resolution mirror `sprites.ts` — an explicit `endpoint` /
|
|
12
|
+
* `token` wins, then `SPRITES_BASE_URL` / `SPRITES_API_TOKEN`.
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* Build a `/v1/sprites/{id}/fs/{op}?...` URL. `params` values that are undefined
|
|
16
|
+
* or empty are dropped so the query only carries what the caller set. Pure.
|
|
17
|
+
*/
|
|
18
|
+
export declare function spriteFsUrl(base: string, id: string, op: "read" | "write" | "list" | "delete", params: Record<string, string | boolean | undefined>): string;
|
|
19
|
+
/**
|
|
20
|
+
* Injectable raw HTTP client — like `SpritesHttp` but the body is sent verbatim
|
|
21
|
+
* (a file's bytes as a string), not JSON-encoded, and the response `text` is the
|
|
22
|
+
* raw body. Tests inject a fake; the default hits `fetch`.
|
|
23
|
+
*/
|
|
24
|
+
export type SpritesRawHttp = (method: string, url: string, body?: string, headers?: Record<string, string>, signal?: AbortSignal) => Promise<{
|
|
25
|
+
status: number;
|
|
26
|
+
text: string;
|
|
27
|
+
}>;
|
|
28
|
+
/**
|
|
29
|
+
* Default `fetch`-based raw client. Sends the body as-is with an
|
|
30
|
+
* `application/octet-stream` content-type and `Authorization: Bearer <token>`
|
|
31
|
+
* when a token is set (real Sprites); the fake ignores the token. The token
|
|
32
|
+
* defaults to `SPRITES_API_TOKEN` at call time. `fetchImpl` is injectable.
|
|
33
|
+
*/
|
|
34
|
+
export declare function defaultSpritesRawHttp(token?: string, fetchImpl?: typeof fetch): SpritesRawHttp;
|
|
35
|
+
export interface SpriteWriteFileArgs {
|
|
36
|
+
/** Target sprite id (the `name` passed to `spriteCreate`). */
|
|
37
|
+
id: string;
|
|
38
|
+
/** Absolute path (or relative to `workingDir`) to write. */
|
|
39
|
+
path: string;
|
|
40
|
+
/** File contents. */
|
|
41
|
+
content: string;
|
|
42
|
+
/** Octal file mode, e.g. `"0644"`. */
|
|
43
|
+
mode?: string;
|
|
44
|
+
/** Create missing parent directories. */
|
|
45
|
+
mkdir?: boolean;
|
|
46
|
+
/** Base directory for a relative `path`. */
|
|
47
|
+
workingDir?: string;
|
|
48
|
+
endpoint?: string;
|
|
49
|
+
token?: string;
|
|
50
|
+
}
|
|
51
|
+
export interface SpriteReadFileArgs {
|
|
52
|
+
id: string;
|
|
53
|
+
path: string;
|
|
54
|
+
workingDir?: string;
|
|
55
|
+
endpoint?: string;
|
|
56
|
+
token?: string;
|
|
57
|
+
}
|
|
58
|
+
export interface SpriteReadFileResult {
|
|
59
|
+
content: string;
|
|
60
|
+
}
|
|
61
|
+
export interface SpriteListDirArgs {
|
|
62
|
+
id: string;
|
|
63
|
+
path: string;
|
|
64
|
+
workingDir?: string;
|
|
65
|
+
endpoint?: string;
|
|
66
|
+
token?: string;
|
|
67
|
+
}
|
|
68
|
+
/** One directory entry. `type` is `file` or `dir`. */
|
|
69
|
+
export interface SpriteDirEntry {
|
|
70
|
+
name: string;
|
|
71
|
+
type: "file" | "dir";
|
|
72
|
+
size?: number;
|
|
73
|
+
}
|
|
74
|
+
export interface SpriteRemoveArgs {
|
|
75
|
+
id: string;
|
|
76
|
+
path: string;
|
|
77
|
+
/** Remove a directory and its contents. */
|
|
78
|
+
recursive?: boolean;
|
|
79
|
+
/** Perform the delete as root. */
|
|
80
|
+
asRoot?: boolean;
|
|
81
|
+
workingDir?: string;
|
|
82
|
+
endpoint?: string;
|
|
83
|
+
token?: string;
|
|
84
|
+
}
|
|
85
|
+
/** Write a file into the sprite. `PUT /v1/sprites/{id}/fs/write` with raw body. */
|
|
86
|
+
export declare function spriteWriteFile(args: SpriteWriteFileArgs, signal?: AbortSignal, http?: SpritesRawHttp): Promise<Record<string, never>>;
|
|
87
|
+
/** Read a file from the sprite. `GET /v1/sprites/{id}/fs/read` → raw body. */
|
|
88
|
+
export declare function spriteReadFile(args: SpriteReadFileArgs, signal?: AbortSignal, http?: SpritesRawHttp): Promise<SpriteReadFileResult>;
|
|
89
|
+
/** List a directory in the sprite. `GET /v1/sprites/{id}/fs/list` → entry array. */
|
|
90
|
+
export declare function spriteListDir(args: SpriteListDirArgs, signal?: AbortSignal, http?: SpritesRawHttp): Promise<SpriteDirEntry[]>;
|
|
91
|
+
/**
|
|
92
|
+
* Remove a path in the sprite. `DELETE /v1/sprites/{id}/fs/delete`. Idempotent:
|
|
93
|
+
* a 404 (already gone) is a no-op, matching `rm -f` and the destroy activity.
|
|
94
|
+
*/
|
|
95
|
+
export declare function spriteRemove(args: SpriteRemoveArgs, signal?: AbortSignal, http?: SpritesRawHttp): Promise<Record<string, never>>;
|
|
96
|
+
//# sourceMappingURL=sprite-fs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sprite-fs.d.ts","sourceRoot":"","sources":["../../../src/op/activities/sprite-fs.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sprite keep-alive Tasks activities (#847) — a hold that prevents a Sprite from
|
|
3
|
+
* pausing while a session runs. While at least one task exists the Sprite stays
|
|
4
|
+
* active; the hold is refreshed on an interval and released on exit.
|
|
5
|
+
*
|
|
6
|
+
* Per the Sprites docs a task carries an `expire` (seconds or a duration string
|
|
7
|
+
* like `"5m"`/`"1h"`) with a **1-hour max per task**, so a session longer than
|
|
8
|
+
* that must refresh. The recommended shape is a short expiry refreshed on a
|
|
9
|
+
* shorter interval — 5-minute expiry / 60-second refresh — released on exit.
|
|
10
|
+
*
|
|
11
|
+
* These are the three primitives, not a magic looping hold: a phased Op creates
|
|
12
|
+
* the task around a session (`spriteTaskCreate`) and releases it after (in the
|
|
13
|
+
* happy path and in `onFailure`). A worker whose session can outlast the 1-hour
|
|
14
|
+
* cap wraps its own run in a `spriteTaskRefresh` loop (that ambient loop lives in
|
|
15
|
+
* the long-running caller, not a single serializable activity — a phased Op has
|
|
16
|
+
* no single step to hang it on). `spriteTaskRelease` is idempotent so a crash
|
|
17
|
+
* still frees the Sprite (and the task auto-expires if the release never lands).
|
|
18
|
+
*
|
|
19
|
+
* The task REST path is provisional (S6, #766); it mirrors the other endpoints'
|
|
20
|
+
* `/v1/sprites/{id}/...` shape. URL building is a pure helper so the path can
|
|
21
|
+
* move without touching callers.
|
|
22
|
+
*/
|
|
23
|
+
import { type SpritesHttp } from "./sprites.js";
|
|
24
|
+
/** The task REST base for a sprite. Pure. */
|
|
25
|
+
export declare function spriteTasksUrl(base: string, id: string): string;
|
|
26
|
+
export declare function spriteTaskUrl(base: string, id: string, name: string): string;
|
|
27
|
+
export interface SpriteTaskCreateArgs {
|
|
28
|
+
id: string;
|
|
29
|
+
/** Task name (the key later refresh/release use). */
|
|
30
|
+
name: string;
|
|
31
|
+
/** Expiry: seconds (number) or a duration string (`"5m"`, `"1h"`). Max 1h. */
|
|
32
|
+
expire?: number | string;
|
|
33
|
+
endpoint?: string;
|
|
34
|
+
token?: string;
|
|
35
|
+
}
|
|
36
|
+
export interface SpriteTaskRefreshArgs extends SpriteTaskCreateArgs {
|
|
37
|
+
}
|
|
38
|
+
export interface SpriteTaskReleaseArgs {
|
|
39
|
+
id: string;
|
|
40
|
+
name: string;
|
|
41
|
+
endpoint?: string;
|
|
42
|
+
token?: string;
|
|
43
|
+
}
|
|
44
|
+
/** Create a keep-alive task. `POST /v1/sprites/{id}/tasks`. */
|
|
45
|
+
export declare function spriteTaskCreate(args: SpriteTaskCreateArgs, signal?: AbortSignal, http?: SpritesHttp): Promise<{
|
|
46
|
+
name: string;
|
|
47
|
+
}>;
|
|
48
|
+
/** Refresh a task's expiry. `PUT /v1/sprites/{id}/tasks/{name}`. */
|
|
49
|
+
export declare function spriteTaskRefresh(args: SpriteTaskRefreshArgs, signal?: AbortSignal, http?: SpritesHttp): Promise<{
|
|
50
|
+
name: string;
|
|
51
|
+
}>;
|
|
52
|
+
/** Release a task (idempotent; a 404 means already gone). `DELETE /v1/sprites/{id}/tasks/{name}`. */
|
|
53
|
+
export declare function spriteTaskRelease(args: SpriteTaskReleaseArgs, signal?: AbortSignal, http?: SpritesHttp): Promise<Record<string, never>>;
|
|
54
|
+
//# sourceMappingURL=sprite-tasks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sprite-tasks.d.ts","sourceRoot":"","sources":["../../../src/op/activities/sprite-tasks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,EAA8C,KAAK,WAAW,EAAE,MAAM,WAAW,CAAC;AAEzF,6CAA6C;AAC7C,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAE/D;AACD,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAE5E;AAED,MAAM,WAAW,oBAAoB;IACnC,EAAE,EAAE,MAAM,CAAC;IACX,qDAAqD;IACrD,IAAI,EAAE,MAAM,CAAC;IACb,8EAA8E;IAC9E,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,qBAAsB,SAAQ,oBAAoB;CAAG;AAEtE,MAAM,WAAW,qBAAqB;IACpC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,+DAA+D;AAC/D,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,oBAAoB,EAC1B,MAAM,CAAC,EAAE,WAAW,EACpB,IAAI,GAAE,WAA4C,GACjD,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAM3B;AAED,oEAAoE;AACpE,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,qBAAqB,EAC3B,MAAM,CAAC,EAAE,WAAW,EACpB,IAAI,GAAE,WAA4C,GACjD,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAM3B;AAED,qGAAqG;AACrG,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,qBAAqB,EAC3B,MAAM,CAAC,EAAE,WAAW,EACpB,IAAI,GAAE,WAA4C,GACjD,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAOhC"}
|
|
@@ -26,6 +26,21 @@ interface StoredCheckpoint {
|
|
|
26
26
|
is_auto: boolean;
|
|
27
27
|
fs: Record<string, string>;
|
|
28
28
|
}
|
|
29
|
+
interface StoredService {
|
|
30
|
+
name: string;
|
|
31
|
+
cmd: string;
|
|
32
|
+
args?: string[];
|
|
33
|
+
env?: Record<string, string>;
|
|
34
|
+
dir?: string;
|
|
35
|
+
needs?: string[];
|
|
36
|
+
http_port?: number;
|
|
37
|
+
state: {
|
|
38
|
+
name: string;
|
|
39
|
+
pid: number;
|
|
40
|
+
status: string;
|
|
41
|
+
started_at?: string;
|
|
42
|
+
};
|
|
43
|
+
}
|
|
29
44
|
interface SpriteState {
|
|
30
45
|
id: string;
|
|
31
46
|
status: SpriteStatus;
|
|
@@ -37,6 +52,18 @@ interface SpriteState {
|
|
|
37
52
|
/** Monotonic version counter for `v<N>` ids. */
|
|
38
53
|
version: number;
|
|
39
54
|
policy?: unknown;
|
|
55
|
+
/** Outbound network policy (whole-object replace via /policy/network). */
|
|
56
|
+
netPolicy: Array<{
|
|
57
|
+
domain: string;
|
|
58
|
+
action: string;
|
|
59
|
+
}>;
|
|
60
|
+
/** Background services keyed by name (create-or-update via PUT). */
|
|
61
|
+
services: Record<string, StoredService>;
|
|
62
|
+
/** Keep-alive tasks keyed by name; while any exists the sprite stays active. */
|
|
63
|
+
tasks: Record<string, {
|
|
64
|
+
name: string;
|
|
65
|
+
expire?: number | string;
|
|
66
|
+
}>;
|
|
40
67
|
}
|
|
41
68
|
interface ExecResult {
|
|
42
69
|
stdout: string;
|
|
@@ -50,6 +77,16 @@ interface ExecResult {
|
|
|
50
77
|
* `;` run in order; the exit code is the last segment's (shell `;` semantics).
|
|
51
78
|
*/
|
|
52
79
|
export declare function fakeExec(sprite: SpriteState, cmd: string): ExecResult;
|
|
80
|
+
/**
|
|
81
|
+
* Immediate children of `dir` in a flat `path → contents` map: a key
|
|
82
|
+
* `${dir}/name` is a file; `${dir}/name/...` contributes the dir `name` once.
|
|
83
|
+
* Pure — the filesystem-list model for the fake.
|
|
84
|
+
*/
|
|
85
|
+
export declare function fakeListDir(fs: Record<string, string>, dir: string): Array<{
|
|
86
|
+
name: string;
|
|
87
|
+
type: "file" | "dir";
|
|
88
|
+
size?: number;
|
|
89
|
+
}>;
|
|
53
90
|
/**
|
|
54
91
|
* Start the in-process Sprites fake on an ephemeral port. Returns its base
|
|
55
92
|
* `url` (feed it to `SPRITES_BASE_URL`) and a `close()`.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sprites-fake.d.ts","sourceRoot":"","sources":["../../../src/op/activities/sprites-fake.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAMH,KAAK,YAAY,GAAG,UAAU,GAAG,SAAS,GAAG,QAAQ,GAAG,WAAW,CAAC;AAEpE,UAAU,gBAAgB;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;IACjB,EAAE,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC5B;AAED,UAAU,WAAW;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,YAAY,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,yCAAyC;IACzC,EAAE,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC3B,kFAAkF;IAClF,WAAW,EAAE,gBAAgB,EAAE,CAAC;IAChC,gDAAgD;IAChD,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"sprites-fake.d.ts","sourceRoot":"","sources":["../../../src/op/activities/sprites-fake.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAMH,KAAK,YAAY,GAAG,UAAU,GAAG,SAAS,GAAG,QAAQ,GAAG,WAAW,CAAC;AAEpE,UAAU,gBAAgB;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;IACjB,EAAE,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC5B;AAED,UAAU,aAAa;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAC3E;AAED,UAAU,WAAW;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,YAAY,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,yCAAyC;IACzC,EAAE,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC3B,kFAAkF;IAClF,WAAW,EAAE,gBAAgB,EAAE,CAAC;IAChC,gDAAgD;IAChD,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,0EAA0E;IAC1E,SAAS,EAAE,KAAK,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACrD,oEAAoE;IACpE,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IACxC,gFAAgF;IAChF,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,CAAC,CAAC;CACnE;AAED,UAAU,UAAU;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,MAAM,EAAE,WAAW,EAAE,GAAG,EAAE,MAAM,GAAG,UAAU,CA6CrE;AA4CD;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,EAAE,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,GAAG,KAAK,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAgBjI;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,IAAI,OAAO,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;CAAE,CAAC,CA+TpF"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@intentius/chant-lexicon-fly",
|
|
3
|
-
"version": "0.18.
|
|
3
|
+
"version": "0.18.7",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"files": [
|
|
6
6
|
"src/",
|
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
"typescript": "^5.9.3"
|
|
58
58
|
},
|
|
59
59
|
"peerDependencies": {
|
|
60
|
-
"@intentius/chant": "^0.18.
|
|
60
|
+
"@intentius/chant": "^0.18.7"
|
|
61
61
|
},
|
|
62
62
|
"description": "Google Cloud lexicon for chant — declarative IaC in TypeScript",
|
|
63
63
|
"license": "Apache-2.0",
|
package/src/index.ts
CHANGED
|
@@ -28,6 +28,15 @@ export {
|
|
|
28
28
|
spriteRestore,
|
|
29
29
|
listCheckpoints,
|
|
30
30
|
spriteDestroy,
|
|
31
|
+
spriteWriteFile,
|
|
32
|
+
spriteReadFile,
|
|
33
|
+
spriteListDir,
|
|
34
|
+
spriteRemove,
|
|
35
|
+
spriteApplyNetworkPolicy,
|
|
36
|
+
spriteApplyServices,
|
|
37
|
+
spriteTaskCreate,
|
|
38
|
+
spriteTaskRefresh,
|
|
39
|
+
spriteTaskRelease,
|
|
31
40
|
spritesUp,
|
|
32
41
|
spritesDown,
|
|
33
42
|
} from "@intentius/chant/op";
|
|
@@ -85,6 +85,62 @@ export type {
|
|
|
85
85
|
SpriteDestroyArgs,
|
|
86
86
|
} from "./sprites";
|
|
87
87
|
|
|
88
|
+
// Sprite filesystem activities (#848) — imperative file I/O over the fs API.
|
|
89
|
+
// `loadActivities(["fly"])` binds these; the step builders live in core.
|
|
90
|
+
export {
|
|
91
|
+
spriteWriteFile,
|
|
92
|
+
spriteReadFile,
|
|
93
|
+
spriteListDir,
|
|
94
|
+
spriteRemove,
|
|
95
|
+
spriteFsUrl,
|
|
96
|
+
defaultSpritesRawHttp,
|
|
97
|
+
} from "./sprite-fs";
|
|
98
|
+
export type {
|
|
99
|
+
SpritesRawHttp,
|
|
100
|
+
SpriteWriteFileArgs,
|
|
101
|
+
SpriteReadFileArgs,
|
|
102
|
+
SpriteReadFileResult,
|
|
103
|
+
SpriteListDirArgs,
|
|
104
|
+
SpriteDirEntry,
|
|
105
|
+
SpriteRemoveArgs,
|
|
106
|
+
} from "./sprite-fs";
|
|
107
|
+
|
|
108
|
+
// Sprite config reconcile activities (#849) — the desired-state a Sprite carries:
|
|
109
|
+
// its outbound network policy and its background services. `loadActivities(["fly"])`
|
|
110
|
+
// binds these; the step builders live in core. Apply-activities, not a declarable
|
|
111
|
+
// resource — a Sprite has no build→plan→apply pipeline.
|
|
112
|
+
export {
|
|
113
|
+
spriteApplyNetworkPolicy,
|
|
114
|
+
spriteApplyServices,
|
|
115
|
+
validateNetworkRules,
|
|
116
|
+
networkRulesEqual,
|
|
117
|
+
validateServices,
|
|
118
|
+
serviceConfigEqual,
|
|
119
|
+
} from "./sprite-config";
|
|
120
|
+
export type {
|
|
121
|
+
NetworkRule,
|
|
122
|
+
SpriteApplyNetworkPolicyArgs,
|
|
123
|
+
SpriteApplyNetworkPolicyResult,
|
|
124
|
+
ServiceSpec,
|
|
125
|
+
SpriteApplyServicesArgs,
|
|
126
|
+
SpriteApplyServicesResult,
|
|
127
|
+
} from "./sprite-config";
|
|
128
|
+
|
|
129
|
+
// Sprite keep-alive Tasks activities (#847) — a hold that stops a Sprite pausing
|
|
130
|
+
// mid-session. `loadActivities(["fly"])` binds these; step builders live in core.
|
|
131
|
+
export {
|
|
132
|
+
spriteTaskCreate,
|
|
133
|
+
spriteTaskRefresh,
|
|
134
|
+
spriteTaskRelease,
|
|
135
|
+
spriteTasksUrl,
|
|
136
|
+
spriteTaskUrl,
|
|
137
|
+
} from "./sprite-tasks";
|
|
138
|
+
export type {
|
|
139
|
+
SpriteTaskCreateArgs,
|
|
140
|
+
SpriteTaskRefreshArgs,
|
|
141
|
+
SpriteTaskReleaseArgs,
|
|
142
|
+
} from "./sprite-tasks";
|
|
143
|
+
|
|
88
144
|
// spritzer (the Sprites API emulator) Docker lifecycle — the twin of mudflaps
|
|
89
145
|
// above. `spritesUp`/`spritesDown` resolve by name so an Op can boot/tear down
|
|
90
146
|
// the emulator as a modeled step; the sprite activities target it via
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import { describe, test, expect, beforeAll, afterAll } from "vitest";
|
|
2
|
+
import { loadActivities, type ActivityFn } from "@intentius/chant/op";
|
|
3
|
+
import { createSpritesFake } from "./sprites-fake";
|
|
4
|
+
import { spriteCreate as createImpl } from "./sprites";
|
|
5
|
+
import {
|
|
6
|
+
spriteApplyNetworkPolicy,
|
|
7
|
+
spriteApplyServices,
|
|
8
|
+
validateNetworkRules,
|
|
9
|
+
networkRulesEqual,
|
|
10
|
+
validateServices,
|
|
11
|
+
serviceConfigEqual,
|
|
12
|
+
type NetworkRule,
|
|
13
|
+
type ServiceSpec,
|
|
14
|
+
} from "./sprite-config";
|
|
15
|
+
|
|
16
|
+
// Config reconcile (#849) — pure validators + end-to-end against the in-process
|
|
17
|
+
// fake (S7), no Docker. Network policy is a whole-object replace; services are
|
|
18
|
+
// additive + update, started in dependency order.
|
|
19
|
+
|
|
20
|
+
let fake: { url: string; close(): Promise<void> };
|
|
21
|
+
let prevBaseUrl: string | undefined;
|
|
22
|
+
|
|
23
|
+
beforeAll(async () => {
|
|
24
|
+
fake = await createSpritesFake();
|
|
25
|
+
prevBaseUrl = process.env.SPRITES_BASE_URL;
|
|
26
|
+
process.env.SPRITES_BASE_URL = fake.url;
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
afterAll(async () => {
|
|
30
|
+
if (prevBaseUrl === undefined) delete process.env.SPRITES_BASE_URL;
|
|
31
|
+
else process.env.SPRITES_BASE_URL = prevBaseUrl;
|
|
32
|
+
await fake?.close();
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
async function inspect(id: string): Promise<{
|
|
36
|
+
netPolicy: NetworkRule[];
|
|
37
|
+
services: Record<string, { name: string; needs?: string[]; state: { status: string } }>;
|
|
38
|
+
}> {
|
|
39
|
+
const res = await fetch(`${fake.url}/v1/sprites/${id}`);
|
|
40
|
+
return (await res.json()) as never;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
describe("network policy validators (pure)", () => {
|
|
44
|
+
test("validateNetworkRules rejects a bad action / empty domain", () => {
|
|
45
|
+
expect(() => validateNetworkRules([{ domain: "", action: "allow" }])).toThrow(/missing domain/);
|
|
46
|
+
expect(() => validateNetworkRules([{ domain: "x", action: "nope" as never }])).toThrow(/allow.*deny/);
|
|
47
|
+
expect(() => validateNetworkRules([{ domain: "github.com", action: "allow" }])).not.toThrow();
|
|
48
|
+
});
|
|
49
|
+
test("networkRulesEqual is order-sensitive", () => {
|
|
50
|
+
const a: NetworkRule[] = [{ domain: "a", action: "allow" }, { domain: "b", action: "deny" }];
|
|
51
|
+
expect(networkRulesEqual(a, [...a])).toBe(true);
|
|
52
|
+
expect(networkRulesEqual(a, [a[1], a[0]])).toBe(false);
|
|
53
|
+
expect(networkRulesEqual(a, [a[0]])).toBe(false);
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
describe("service validators (pure)", () => {
|
|
58
|
+
test("validateServices returns a dependency-first order", () => {
|
|
59
|
+
const svcs: ServiceSpec[] = [
|
|
60
|
+
{ name: "web", cmd: "run-web", needs: ["db"] },
|
|
61
|
+
{ name: "db", cmd: "run-db" },
|
|
62
|
+
];
|
|
63
|
+
expect(validateServices(svcs)).toEqual(["db", "web"]);
|
|
64
|
+
});
|
|
65
|
+
test("rejects a dangling needs and a cycle and a duplicate", () => {
|
|
66
|
+
expect(() => validateServices([{ name: "web", cmd: "x", needs: ["db"] }])).toThrow(/not defined/);
|
|
67
|
+
expect(() =>
|
|
68
|
+
validateServices([
|
|
69
|
+
{ name: "a", cmd: "x", needs: ["b"] },
|
|
70
|
+
{ name: "b", cmd: "x", needs: ["a"] },
|
|
71
|
+
]),
|
|
72
|
+
).toThrow(/cycle/);
|
|
73
|
+
expect(() =>
|
|
74
|
+
validateServices([
|
|
75
|
+
{ name: "a", cmd: "x" },
|
|
76
|
+
{ name: "a", cmd: "y" },
|
|
77
|
+
]),
|
|
78
|
+
).toThrow(/duplicate/);
|
|
79
|
+
});
|
|
80
|
+
test("serviceConfigEqual ignores undefined-vs-empty noise", () => {
|
|
81
|
+
expect(serviceConfigEqual({ cmd: "x" }, { cmd: "x", args: [], env: {} })).toBe(true);
|
|
82
|
+
expect(serviceConfigEqual({ cmd: "x", http_port: 80 }, { cmd: "x" })).toBe(false);
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
describe("spriteApplyNetworkPolicy reconcile", () => {
|
|
87
|
+
test("applies once, converges on re-apply, replaces on change", async () => {
|
|
88
|
+
await createImpl({ name: "np-1", endpoint: fake.url });
|
|
89
|
+
const rules: NetworkRule[] = [
|
|
90
|
+
{ domain: "*.github.com", action: "allow" },
|
|
91
|
+
{ domain: "*", action: "deny" },
|
|
92
|
+
];
|
|
93
|
+
expect((await spriteApplyNetworkPolicy({ id: "np-1", rules, endpoint: fake.url })).changed).toBe(true);
|
|
94
|
+
expect((await inspect("np-1")).netPolicy).toEqual(rules);
|
|
95
|
+
|
|
96
|
+
// Idempotent: same ruleset → no change.
|
|
97
|
+
expect((await spriteApplyNetworkPolicy({ id: "np-1", rules, endpoint: fake.url })).changed).toBe(false);
|
|
98
|
+
|
|
99
|
+
// Changed ruleset → replaced.
|
|
100
|
+
const tighter: NetworkRule[] = [{ domain: "github.com", action: "allow" }, { domain: "*", action: "deny" }];
|
|
101
|
+
expect((await spriteApplyNetworkPolicy({ id: "np-1", rules: tighter, endpoint: fake.url })).changed).toBe(true);
|
|
102
|
+
expect((await inspect("np-1")).netPolicy).toEqual(tighter);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
test("invalid rules throw before any HTTP", async () => {
|
|
106
|
+
await expect(
|
|
107
|
+
spriteApplyNetworkPolicy({ id: "np-1", rules: [{ domain: "", action: "allow" }], endpoint: fake.url }),
|
|
108
|
+
).rejects.toThrow(/missing domain/);
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
describe("spriteApplyServices reconcile", () => {
|
|
113
|
+
test("creates services, starts them in dependency order, converges on re-apply", async () => {
|
|
114
|
+
await createImpl({ name: "svc-1", endpoint: fake.url });
|
|
115
|
+
const services: ServiceSpec[] = [
|
|
116
|
+
{ name: "web", cmd: "run-web", needs: ["db"], http_port: 8080 },
|
|
117
|
+
{ name: "db", cmd: "run-db" },
|
|
118
|
+
];
|
|
119
|
+
const r1 = await spriteApplyServices({ id: "svc-1", services, start: true, endpoint: fake.url });
|
|
120
|
+
expect(new Set(r1.applied)).toEqual(new Set(["web", "db"]));
|
|
121
|
+
// Started dependency-first.
|
|
122
|
+
expect(r1.started).toEqual(["db", "web"]);
|
|
123
|
+
|
|
124
|
+
const state = await inspect("svc-1");
|
|
125
|
+
expect(Object.keys(state.services).sort()).toEqual(["db", "web"]);
|
|
126
|
+
expect(state.services.web.state.status).toBe("running");
|
|
127
|
+
|
|
128
|
+
// Re-apply unchanged → nothing applied.
|
|
129
|
+
const r2 = await spriteApplyServices({ id: "svc-1", services, endpoint: fake.url });
|
|
130
|
+
expect(r2.applied).toEqual([]);
|
|
131
|
+
|
|
132
|
+
// Change one → only it is re-applied.
|
|
133
|
+
const changed = services.map((s) => (s.name === "web" ? { ...s, http_port: 9090 } : s));
|
|
134
|
+
const r3 = await spriteApplyServices({ id: "svc-1", services: changed, endpoint: fake.url });
|
|
135
|
+
expect(r3.applied).toEqual(["web"]);
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
test("a dependency cycle throws before any HTTP", async () => {
|
|
139
|
+
await createImpl({ name: "svc-2", endpoint: fake.url });
|
|
140
|
+
await expect(
|
|
141
|
+
spriteApplyServices({
|
|
142
|
+
id: "svc-2",
|
|
143
|
+
services: [
|
|
144
|
+
{ name: "a", cmd: "x", needs: ["b"] },
|
|
145
|
+
{ name: "b", cmd: "x", needs: ["a"] },
|
|
146
|
+
],
|
|
147
|
+
endpoint: fake.url,
|
|
148
|
+
}),
|
|
149
|
+
).rejects.toThrow(/cycle/);
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
describe("config activities resolve by name", () => {
|
|
154
|
+
test("loadActivities([\"fly\"]) exposes the reconcile activities", async () => {
|
|
155
|
+
const activities: Map<string, ActivityFn> = await loadActivities(["fly"]);
|
|
156
|
+
expect(typeof activities.get("spriteApplyNetworkPolicy")).toBe("function");
|
|
157
|
+
expect(typeof activities.get("spriteApplyServices")).toBe("function");
|
|
158
|
+
});
|
|
159
|
+
});
|