@astrale-domains/services 0.4.5 → 0.4.6
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/README.md +121 -12
- package/dist/schema/index.d.ts +2 -0
- package/dist/schema/index.js +1 -0
- package/dist/schema/modules/deployment/classes/cloudflare-deployment.d.ts +97 -0
- package/dist/schema/modules/deployment/classes/cloudflare-deployment.js +10 -0
- package/dist/schema/modules/deployment/classes/deployment-line.d.ts +23 -0
- package/dist/schema/modules/deployment/classes/deployment-line.js +24 -0
- package/dist/schema/modules/deployment/classes/deployment-on-line.d.ts +17 -0
- package/dist/schema/modules/deployment/classes/deployment-on-line.js +11 -0
- package/dist/schema/modules/deployment/classes/deployment.d.ts +98 -0
- package/dist/schema/modules/deployment/classes/deployment.js +32 -0
- package/dist/schema/modules/deployment/classes/index.d.ts +5 -0
- package/dist/schema/modules/deployment/classes/index.js +5 -0
- package/dist/schema/modules/deployment/classes/line-owned-by.d.ts +26 -0
- package/dist/schema/modules/deployment/classes/line-owned-by.js +19 -0
- package/dist/schema/modules/deployment/index.d.ts +6 -0
- package/dist/schema/modules/deployment/index.js +4 -0
- package/dist/schema/modules/deployment/policies/index.d.ts +4 -0
- package/dist/schema/modules/deployment/policies/index.js +4 -0
- package/dist/schema/modules/deployment/policies/own-deployment.d.ts +2 -0
- package/dist/schema/modules/deployment/policies/own-deployment.js +12 -0
- package/dist/schema/modules/deployment/policies/own-line.d.ts +5 -0
- package/dist/schema/modules/deployment/policies/own-line.js +10 -0
- package/dist/schema/modules/deployment/policies/traverse-owned-line-deployment.d.ts +2 -0
- package/dist/schema/modules/deployment/policies/traverse-owned-line-deployment.js +7 -0
- package/dist/schema/modules/deployment/policies/traverse-owned-line.d.ts +2 -0
- package/dist/schema/modules/deployment/policies/traverse-owned-line.js +7 -0
- package/dist/schema/modules/deployment/states/deployment-lifecycle.d.ts +27 -0
- package/dist/schema/modules/deployment/states/deployment-lifecycle.js +17 -0
- package/dist/schema/modules/deployment/states/index.d.ts +2 -0
- package/dist/schema/modules/deployment/states/index.js +1 -0
- package/dist/schema/modules/deployment/types/deployment-record.d.ts +35 -0
- package/dist/schema/modules/deployment/types/deployment-record.js +31 -0
- package/dist/schema/modules/deployment/types/deployment-retention.d.ts +13 -0
- package/dist/schema/modules/deployment/types/deployment-retention.js +5 -0
- package/dist/schema/modules/deployment/types/index.d.ts +4 -0
- package/dist/schema/modules/deployment/types/index.js +2 -0
- package/dist/schema/modules/service/classes/cloudflare-worker.d.ts +56 -20
- package/dist/schema/modules/service/classes/service.d.ts +9 -9
- package/dist/schema/modules/service/functions/delete-service-secret.d.ts +1 -1
- package/dist/schema/modules/service/functions/delete-service.d.ts +1 -1
- package/dist/schema/modules/service/functions/delete-worker-secret.d.ts +1 -1
- package/dist/schema/modules/service/functions/delete-worker.d.ts +1 -1
- package/dist/schema/modules/service/functions/deploy-cloudflare-worker.d.ts +37 -1
- package/dist/schema/modules/service/functions/list-service-logs.d.ts +1 -1
- package/dist/schema/modules/service/functions/list-service-schedules.d.ts +1 -1
- package/dist/schema/modules/service/functions/list-service-secret-names.d.ts +1 -1
- package/dist/schema/modules/service/functions/list-worker-logs.d.ts +1 -1
- package/dist/schema/modules/service/functions/list-worker-schedules.d.ts +1 -1
- package/dist/schema/modules/service/functions/list-worker-secret-names.d.ts +1 -1
- package/dist/schema/modules/service/functions/migrate-worker-ingress.d.ts +1 -1
- package/dist/schema/modules/service/functions/replace-service-schedules.d.ts +1 -1
- package/dist/schema/modules/service/functions/replace-worker-schedules.d.ts +1 -1
- package/dist/schema/modules/service/functions/set-service-secret.d.ts +1 -1
- package/dist/schema/modules/service/functions/set-worker-secret.d.ts +1 -1
- package/dist/schema/modules/service/index.d.ts +2 -2
- package/dist/schema/modules/service/index.js +1 -1
- package/dist/schema/modules/service/types/content/index.d.ts +1 -0
- package/dist/schema/modules/service/types/content/index.js +1 -0
- package/dist/schema/modules/service/types/content/limits.d.ts +7 -0
- package/dist/schema/modules/service/types/content/limits.js +7 -0
- package/dist/schema/modules/service/types/deploy-cloudflare-worker.d.ts +110 -0
- package/dist/schema/modules/service/types/index.d.ts +2 -1
- package/dist/schema/modules/service/types/index.js +1 -1
- package/dist/schema/modules/service/types/legacy/service-deployment-content.js +15 -0
- package/dist/schema/modules/service/types/service-deployment-artifact-module.d.ts +23 -0
- package/dist/schema/modules/service/types/service-deployment-artifact-module.js +5 -3
- package/dist/schema/modules/service/types/service-deployment-assets.d.ts +36 -0
- package/dist/schema/modules/service/types/service-deployment-assets.js +5 -3
- package/dist/schema/modules/service/types/service-deployment-content.d.ts +18 -11
- package/dist/schema/modules/service/types/service-deployment-content.js +17 -8
- package/dist/schema/schema.d.ts +308 -35
- package/dist/schema/schema.js +10 -0
- package/package.json +10 -11
package/README.md
CHANGED
|
@@ -11,6 +11,26 @@ protocols behind neutral SDK Integrations and stores only admitted lifecycle evi
|
|
|
11
11
|
- Owners may be Shell users, local Kernel roots, or application/CI identities. Services requires only
|
|
12
12
|
the Kernel Schema; a Shell installation is not required to deploy. Ownership
|
|
13
13
|
remains exact-subject scoped, and existing Shell-user ownership edges remain valid.
|
|
14
|
+
- a `DeploymentLine` is one `(origin, environment)`, named by its SDK fingerprint. `line_owned_by`
|
|
15
|
+
gives it to at most one organisation Identity, first come. Members and CI identities read the
|
|
16
|
+
line and its deployments through Kernel `extends_with` (`OwnLine`, `OwnDeployment`). A line is
|
|
17
|
+
never reassigned. Deleting its deployments, the organisation's Services or the organisation
|
|
18
|
+
itself leaves the line refused to every other organisation (`line-owned-elsewhere`). Only an
|
|
19
|
+
operator transfer moves the holder Edge.
|
|
20
|
+
- the line Queries, `admitDeploymentLine` and the deployment Mutations run under the Services
|
|
21
|
+
Domain credential and trust the organisation they are given. Under a caller's credential the
|
|
22
|
+
Policies hide a foreign line, which would read as a free one. Their caller must first prove that
|
|
23
|
+
the requesting identity is that organisation or acts for it: `Identity.can` on `OwnLine` for a
|
|
24
|
+
held line, the identity itself or its `extends_with` for a registration.
|
|
25
|
+
- each `Deployment` (`CloudflareDeployment`) sits on one line through `deployment_on_line` and is
|
|
26
|
+
visible to whoever holds that line. A deployment is recorded only while its organisation holds
|
|
27
|
+
the line. Its label must name the line, and its record must name the line's origin and
|
|
28
|
+
environment. [Real-Kernel proof](tests/kernel/README.md).
|
|
29
|
+
- an operator deleting an organisation that holds lines deletes its `line_owned_by` Edges in the
|
|
30
|
+
same Mutation: the Kernel deletes a Node only together with every incident Edge. Its lines stay
|
|
31
|
+
registered with no holder and are refused to every organisation. A transfer is a root
|
|
32
|
+
`createEdge` of `line_owned_by` from the line to the new organisation; a line has one holder at
|
|
33
|
+
most.
|
|
14
34
|
- secret values stay write-only at Cloudflare and never enter Astrale mutations or graph state.
|
|
15
35
|
- schedules remain provider state; only the owner may read or replace them.
|
|
16
36
|
- logs are remote evidence admitted by the Cloudflare Provider before a Workflow returns them.
|
|
@@ -22,6 +42,9 @@ protocols behind neutral SDK Integrations and stores only admitted lifecycle evi
|
|
|
22
42
|
- the provider supplies `WORKER_URL` as the Service's canonical HTTPS URL to both candidate and
|
|
23
43
|
public Workers. It is reserved provider metadata, not a caller variable or secret. Applications
|
|
24
44
|
therefore keep one issuer even when requests arrive over HTTP or through a dispatcher alias.
|
|
45
|
+
- `ASTRALE_BUILD_DIGEST` is reserved the same way: a Worker's build digest is bound by its host,
|
|
46
|
+
never by its author, so Services refuses it as a caller variable or secret on every deployment
|
|
47
|
+
path and in secret management.
|
|
25
48
|
|
|
26
49
|
The View, CLI, and agent consumers read the named Service Queries directly; there is intentionally
|
|
27
50
|
no list Function wrapping `listServicesQuery`. Deployment, secrets, schedules, logs, and deletion
|
|
@@ -75,13 +98,87 @@ health check. Cloudflare can automatically delete the generated certificate as s
|
|
|
75
98
|
Domain is detached. `restore` recreates the exact domain, waits for active TLS and records the actual
|
|
76
99
|
replacement certificate locator. A `pending` result requires a later retry; it is not completion.
|
|
77
100
|
|
|
78
|
-
The
|
|
79
|
-
`https://services.beta.astrale.ai
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
retained Service
|
|
101
|
+
The consumer runtimes are frozen ([`frozen-environments.json`](./frozen-environments.json)): the
|
|
102
|
+
original R1 runtime at `https://services.beta.astrale.ai`, which 1Pact instances pin and which
|
|
103
|
+
serves that issuer's discovery and keys, `https://services-v2.beta.astrale.ai`, which retains that
|
|
104
|
+
issuer and key, and production at `https://services.astrale.ai`. They keep serving the code they run
|
|
105
|
+
today and no Environment deploys them. Do not uninstall Services or replace a runtime underneath
|
|
106
|
+
installations that still use its Schema. An instance rollback must restore any detached domain
|
|
107
|
+
before reinstalling the original endpoint, and must first be qualified with real retained Service
|
|
108
|
+
data.
|
|
109
|
+
|
|
110
|
+
## Admin-hosted runtime
|
|
111
|
+
|
|
112
|
+
The `admin-beta` Environment is the Services runtime of the Admin instance, the one that hosts
|
|
113
|
+
publishers' deployments outside the instances that install them. It is a Worker of its own,
|
|
114
|
+
`services-domain-admin-beta` at `https://services-admin.beta.astrale.ai`, on the beta data plane the
|
|
115
|
+
Admin instance's Services already manage. Its plain vars name the router Worker
|
|
116
|
+
(`ASTRALE_ROUTER_WORKER`), the routing domain under which deployments are addressed
|
|
117
|
+
(`SERVICES_DEPLOYMENT_HOST`, served by the Services dispatcher) and the registry Domain
|
|
118
|
+
(`SERVICES_REGISTRY_ORIGIN`). `.env.admin-beta` must set `SERVICES_SECRET_DIGEST_KEY`, the key of
|
|
119
|
+
each hosted deployment's secret digest. The runtime keys HMAC-SHA256 with the UTF-8 bytes of the value
|
|
120
|
+
as written, never base64-decoded, so the configuration refuses, before any deployment effect, a file
|
|
121
|
+
without it or with a value shorter than 32 UTF-8 bytes.
|
|
122
|
+
|
|
123
|
+
It retains the issuer `https://services.beta.astrale.ai` and its signing key, as services-v2 does.
|
|
124
|
+
The Admin instance's Services are bound to that issuer, and the Kernel refuses an issuer change when
|
|
125
|
+
it replaces an installed Domain (`issuer-changed`); neither the Admin Host's Kernel nor the CLI
|
|
126
|
+
offers a consented issuer change yet. The cost: a Worker built from main holds the key that 1Pact's
|
|
127
|
+
installations trust. Keep the key only in managed secret storage and in this Worker's
|
|
128
|
+
`ASTRALE_SIGNING_IDENTITY` secret. The Admin instance moves to an issuer of its own when the
|
|
129
|
+
canonical Admin-hosted runtime replaces this one through a consented issuer change; this Worker and
|
|
130
|
+
its copy of the key are retired after that reinstall.
|
|
131
|
+
|
|
132
|
+
Only the Admin instance installs this runtime; consumer instances keep the Services they pin.
|
|
133
|
+
The operator sets it up once:
|
|
134
|
+
|
|
135
|
+
1. Read what the Admin instance's Services are bound to, read-only:
|
|
136
|
+
`astrale introspect services.astrale.ai -i <admin-instance> --json`. Record `revision` and
|
|
137
|
+
`publication.identity.issuer`, and the frozen runtime whose `/.well-known/astrale/domain.json`
|
|
138
|
+
declares that revision: it is the rollback URL. Go on only if the issuer is
|
|
139
|
+
`https://services.beta.astrale.ai`; any other issuer makes step 6 an issuer change, which the
|
|
140
|
+
Kernel refuses.
|
|
141
|
+
2. Create `.env.admin-beta` (mode 600) from `.env.example` with the beta data-plane coordinates the
|
|
142
|
+
Admin instance's Services manage today (account, token, dispatch namespace, routing domain
|
|
143
|
+
`svc.eu.beta.astrale.ai`, schedule KV, dispatcher, zone, Admin target) and a new
|
|
144
|
+
`SERVICES_SECRET_DIGEST_KEY` that no other environment uses, e.g. `openssl rand -base64 32` (32
|
|
145
|
+
random bytes, kept as their 44-character base64 text).
|
|
146
|
+
3. Restore the retained `https://services.beta.astrale.ai` signing identity, the one services-v2 was
|
|
147
|
+
deployed with, from managed secret storage to `.astrale/services-beta-identity.json` (mode 600).
|
|
148
|
+
Never generate a key for this runtime: the frozen R1 Worker publishes the issuer's keys, so a new
|
|
149
|
+
key would never verify. Never leave that key at `.astrale/identity.json`, the development
|
|
150
|
+
Environment's default identity: `pnpm dev` would bind it to development Workers. Check that the
|
|
151
|
+
issuer publishes the restored key:
|
|
152
|
+
|
|
153
|
+
```sh
|
|
154
|
+
node --input-type=module -e '
|
|
155
|
+
const { readFileSync } = await import("node:fs")
|
|
156
|
+
const { kid, x } = JSON.parse(readFileSync(".astrale/services-beta-identity.json", "utf8"))
|
|
157
|
+
const issuer = "https://services.beta.astrale.ai"
|
|
158
|
+
const { jwks_uri } = await (await fetch(`${issuer}/.well-known/openid-configuration`)).json()
|
|
159
|
+
const { keys } = await (await fetch(jwks_uri)).json()
|
|
160
|
+
if (!keys.some((key) => key.kid === kid && key.x === x)) throw new Error("key not published")
|
|
161
|
+
console.log(`issuer publishes kid ${kid}`)
|
|
162
|
+
'
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
4. Deploy once with `pnpm run deploy admin-beta`. It creates only the `services-domain-admin-beta`
|
|
166
|
+
Worker and its route; nothing is installed. Do not run `pnpm provider:bootstrap` or a
|
|
167
|
+
`provider:route-*` command for this runtime: on the beta data plane they redeploy the shared
|
|
168
|
+
dispatcher and DNS routing that serve 1Pact's tenants (see the
|
|
169
|
+
[operator README](./providers/cloudflare/operator/README.md)).
|
|
170
|
+
5. Rehearse step 6 first on a disposable instance whose Host runs the Admin Host's Kernel release and
|
|
171
|
+
whose Services are bound to the same issuer and revision as in step 1, with at least one Service.
|
|
172
|
+
The install must succeed and the Service must stay manageable (list, secrets, logs). Then install
|
|
173
|
+
the step 1 rollback URL there again: if the Kernel refuses it, step 6 is one-way, and that must be
|
|
174
|
+
recorded before step 6 runs.
|
|
175
|
+
6. Install on the Admin instance only, directly:
|
|
176
|
+
`astrale domain install https://services-admin.beta.astrale.ai --direct --allow-identity-override -i <admin-instance>`.
|
|
177
|
+
The only consent is the identity override, because the origin `services.astrale.ai` differs from
|
|
178
|
+
the serving host; the issuer does not change. On any refusal, stop: never uninstall Services on
|
|
179
|
+
the Admin instance to get around it, which would drop the Service records it holds. Never repoint
|
|
180
|
+
Admin's catalog entry for `services.astrale.ai` at this runtime: consumer flows, 1Pact's among
|
|
181
|
+
them, install Services by origin through that entry.
|
|
85
182
|
|
|
86
183
|
## Plain background Service starter
|
|
87
184
|
|
|
@@ -107,8 +204,8 @@ No tooling dependency is added to the Schema runtime or imported from the packag
|
|
|
107
204
|
|
|
108
205
|
Copy `.env.example` to `.env.dev` and fill the Cloudflare values.
|
|
109
206
|
|
|
110
|
-
`pnpm dev` watches and deploys the development Environment remotely. `pnpm
|
|
111
|
-
|
|
207
|
+
`pnpm dev` watches and deploys the development Environment remotely. `pnpm run deploy admin-beta`
|
|
208
|
+
deploys the [Admin-hosted runtime](#admin-hosted-runtime) once. These bootstrap Environments
|
|
112
209
|
are deliberately deploy-only: install the resulting URL on the intended Kernel explicitly.
|
|
113
210
|
Stopping development leaves the remote Worker available. No local Worker or tunnel is started.
|
|
114
211
|
|
|
@@ -123,9 +220,21 @@ pnpm build
|
|
|
123
220
|
pnpm package
|
|
124
221
|
```
|
|
125
222
|
|
|
126
|
-
The deployed module named by `entry` must be present in `modules`.
|
|
127
|
-
|
|
128
|
-
|
|
223
|
+
The deployed module named by `entry` must be present in `modules`. Modules and assets carry
|
|
224
|
+
`content: { encoding: 'identity' | 'gzip', decodedSize, contentBase64 }`; large encoded files use
|
|
225
|
+
`contentBase64Chunks` instead, with each string bounded to 512 KiB. `decodedSize` is the exact original
|
|
226
|
+
byte length. Compression changes transport only: provider uploads and deployment digests use the
|
|
227
|
+
reconstructed bytes. Services validates complete gzip streams (including their checksum), exact sizes,
|
|
228
|
+
and canonical Base64 before any graph or provider operation. Individual decoded files remain bounded
|
|
229
|
+
to 7.5 MiB per module and 12 MiB per asset; all decoded deployment material shares a 32 MiB budget.
|
|
230
|
+
|
|
231
|
+
The previous top-level `contentBase64` and `contentBase64Chunks` fields remain accepted and are
|
|
232
|
+
explicitly deprecated. Roll out Services and install its new schema on consumer instances before
|
|
233
|
+
publishing the compressed SDK adapter. Old SDK clients continue working against the new Services;
|
|
234
|
+
new SDK requests are refused by an old schema without provider effects. The adapter never retries a
|
|
235
|
+
deployment using a different wire representation after an uncertain outcome.
|
|
236
|
+
|
|
237
|
+
Module names are unique and secrets use environment-variable identifiers. Plain and revisioned artifacts are
|
|
129
238
|
distinct modes and cannot replace each other at one Service record. Five-field cron expressions are
|
|
130
239
|
supported when `CLOUDFLARE_SCHEDULE_KV_ID` is configured.
|
|
131
240
|
|
package/dist/schema/index.d.ts
CHANGED
|
@@ -3,3 +3,5 @@ export type { ServicesDomain, ServicesSchema } from './schema.js';
|
|
|
3
3
|
export { artifact, artifactModule, assetBundle, assetFile, deployServiceInput, deployServiceOutput, resourceLimits, revisionedDeployment, } from './modules/service/index.js';
|
|
4
4
|
export type { ArtifactModule, AssetBundle, DeployServiceInput, DeployServiceOutput, ResourceLimits, } from './modules/service/index.js';
|
|
5
5
|
export { CloudflareWorker, OwnService, Service, TraverseOwnedService, service_owned_by, } from './modules/service/index.js';
|
|
6
|
+
export { CloudflareDeployment, Deployment, DeploymentLine, OwnDeployment, OwnLine, TraverseOwnedLine, TraverseOwnedLineDeployment, deploymentCommit, deploymentLifecycle, deploymentRecord, deploymentRetention, deploymentRetirement, deployment_on_line, line_owned_by, } from './modules/deployment/index.js';
|
|
7
|
+
export type { DeploymentLifecycle, DeploymentLifecycleEvent, DeploymentRecord, DeploymentRetention, DeploymentRetirement, } from './modules/deployment/index.js';
|
package/dist/schema/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
export { schema } from './schema.js';
|
|
2
2
|
export { artifact, artifactModule, assetBundle, assetFile, deployServiceInput, deployServiceOutput, resourceLimits, revisionedDeployment, } from './modules/service/index.js';
|
|
3
3
|
export { CloudflareWorker, OwnService, Service, TraverseOwnedService, service_owned_by, } from './modules/service/index.js';
|
|
4
|
+
export { CloudflareDeployment, Deployment, DeploymentLine, OwnDeployment, OwnLine, TraverseOwnedLine, TraverseOwnedLineDeployment, deploymentCommit, deploymentLifecycle, deploymentRecord, deploymentRetention, deploymentRetirement, deployment_on_line, line_owned_by, } from './modules/deployment/index.js';
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
export declare const CloudflareDeployment: import("@astrale-os/sdk/schema").AuthoredNodeClass<{
|
|
2
|
+
readonly description: "One Deployment uploaded as the Workers for Platforms script its label names.";
|
|
3
|
+
readonly icon: import("@astrale-os/sdk/schema").ClassIcon;
|
|
4
|
+
readonly extends: readonly [import("@astrale-os/sdk/schema").AuthoredNodeClass<{
|
|
5
|
+
readonly abstract: true;
|
|
6
|
+
readonly description: "One immutable deployment of a release on a publisher line.";
|
|
7
|
+
readonly icon: import("@astrale-os/sdk/schema").ClassIcon;
|
|
8
|
+
readonly extends: readonly [import("@astrale-os/sdk/schema").KernelClass<"Timestamped">];
|
|
9
|
+
readonly properties: {
|
|
10
|
+
label: import("zod").ZodString;
|
|
11
|
+
url: import("zod").ZodString;
|
|
12
|
+
state: import("@astrale-os/sdk/schema").StateProperty<import("@astrale-os/sdk/schema").StateMachine<{
|
|
13
|
+
readonly deploying: {
|
|
14
|
+
readonly activate: "active";
|
|
15
|
+
readonly fail: "failed";
|
|
16
|
+
};
|
|
17
|
+
readonly active: {
|
|
18
|
+
readonly retire: "retiring";
|
|
19
|
+
};
|
|
20
|
+
readonly retiring: {
|
|
21
|
+
readonly completeRetirement: "retired";
|
|
22
|
+
};
|
|
23
|
+
readonly retired: {
|
|
24
|
+
readonly revive: "deploying";
|
|
25
|
+
};
|
|
26
|
+
readonly failed: {
|
|
27
|
+
readonly retry: "deploying";
|
|
28
|
+
};
|
|
29
|
+
}, "deploying">, {
|
|
30
|
+
required?: boolean;
|
|
31
|
+
description?: string;
|
|
32
|
+
}>;
|
|
33
|
+
retention: import("zod").ZodEnum<{
|
|
34
|
+
preview: "preview";
|
|
35
|
+
published: "published";
|
|
36
|
+
}>;
|
|
37
|
+
record: import("zod").ZodObject<{
|
|
38
|
+
format: import("zod").ZodLiteral<"astrale.deployment-record">;
|
|
39
|
+
version: import("zod").ZodLiteral<1>;
|
|
40
|
+
origin: import("zod").ZodString;
|
|
41
|
+
environment: import("zod").ZodString;
|
|
42
|
+
releaseDigest: import("zod").ZodString;
|
|
43
|
+
buildDigest: import("zod").ZodString;
|
|
44
|
+
schemaRevision: import("zod").ZodString;
|
|
45
|
+
configuration: import("zod").ZodString;
|
|
46
|
+
providerScript: import("zod").ZodString;
|
|
47
|
+
commit: import("zod").ZodNullable<import("zod").ZodObject<{
|
|
48
|
+
sha: import("zod").ZodString;
|
|
49
|
+
dirty: import("zod").ZodBoolean;
|
|
50
|
+
base: import("zod").ZodOptional<import("zod").ZodObject<{
|
|
51
|
+
version: import("zod").ZodString;
|
|
52
|
+
distance: import("zod").ZodNumber;
|
|
53
|
+
}, import("zod/v4/core").$strict>>;
|
|
54
|
+
}, import("zod/v4/core").$strict>>;
|
|
55
|
+
}, import("zod/v4/core").$strict>;
|
|
56
|
+
signingKeyId: import("@astrale-os/sdk/schema").AuthoredProperty<import("zod").ZodString, {
|
|
57
|
+
readonly required: false;
|
|
58
|
+
}>;
|
|
59
|
+
lastCallAt: import("@astrale-os/sdk/schema").AuthoredProperty<Readonly<{
|
|
60
|
+
readonly type: 'string';
|
|
61
|
+
readonly 'x-astrale-value-kind': 'instant';
|
|
62
|
+
}>, {
|
|
63
|
+
readonly required: false;
|
|
64
|
+
}>;
|
|
65
|
+
expiresAt: import("@astrale-os/sdk/schema").AuthoredProperty<Readonly<{
|
|
66
|
+
readonly type: 'string';
|
|
67
|
+
readonly 'x-astrale-value-kind': 'instant';
|
|
68
|
+
}>, {
|
|
69
|
+
readonly required: false;
|
|
70
|
+
}>;
|
|
71
|
+
retiredAt: import("@astrale-os/sdk/schema").AuthoredProperty<Readonly<{
|
|
72
|
+
readonly type: 'string';
|
|
73
|
+
readonly 'x-astrale-value-kind': 'instant';
|
|
74
|
+
}>, {
|
|
75
|
+
readonly required: false;
|
|
76
|
+
}>;
|
|
77
|
+
retirement: import("@astrale-os/sdk/schema").AuthoredProperty<import("zod").ZodEnum<{
|
|
78
|
+
expired: "expired";
|
|
79
|
+
withdrawn: "withdrawn";
|
|
80
|
+
}>, {
|
|
81
|
+
readonly required: false;
|
|
82
|
+
}>;
|
|
83
|
+
operationReceipt: import("@astrale-os/sdk/schema").AuthoredProperty<import("zod").ZodString, {
|
|
84
|
+
readonly required: false;
|
|
85
|
+
}>;
|
|
86
|
+
operationExpiresAt: import("@astrale-os/sdk/schema").AuthoredProperty<Readonly<{
|
|
87
|
+
readonly type: 'string';
|
|
88
|
+
readonly 'x-astrale-value-kind': 'instant';
|
|
89
|
+
}>, {
|
|
90
|
+
readonly required: false;
|
|
91
|
+
}>;
|
|
92
|
+
};
|
|
93
|
+
}>];
|
|
94
|
+
readonly policies: {
|
|
95
|
+
read: () => import("@astrale-os/sdk/schema").Policy;
|
|
96
|
+
};
|
|
97
|
+
}>;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { classIcon, nodeClass } from '@astrale-os/sdk/schema';
|
|
2
|
+
import { CloudUpload } from '@astrale-os/sdk/schema/icons';
|
|
3
|
+
import { OwnDeployment } from '../policies/own-deployment.js';
|
|
4
|
+
import { Deployment } from './deployment.js';
|
|
5
|
+
export const CloudflareDeployment = nodeClass({
|
|
6
|
+
description: 'One Deployment uploaded as the Workers for Platforms script its label names.',
|
|
7
|
+
icon: classIcon.lucide(CloudUpload),
|
|
8
|
+
extends: [Deployment],
|
|
9
|
+
policies: { read: () => OwnDeployment },
|
|
10
|
+
});
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/**
|
|
3
|
+
* The line every deployment of one origin in one environment shares. The first organisation that
|
|
4
|
+
* deploys on it holds it, and only an operator transfer gives it to another: it stays registered
|
|
5
|
+
* and refused to every other organisation after its organisation, that organisation's Services or
|
|
6
|
+
* every deployment on it are deleted.
|
|
7
|
+
*/
|
|
8
|
+
export declare const DeploymentLine: import("@astrale-os/sdk/schema").AuthoredNodeClass<{
|
|
9
|
+
readonly description: "The deployment line of one origin in one environment, held by one organisation.";
|
|
10
|
+
readonly icon: import("@astrale-os/sdk/schema").ClassIcon;
|
|
11
|
+
readonly extends: readonly [import("@astrale-os/sdk/schema").KernelClass<"Timestamped">];
|
|
12
|
+
readonly properties: {
|
|
13
|
+
origin: z.ZodString;
|
|
14
|
+
environment: z.ZodString;
|
|
15
|
+
/** The 16-character fingerprint of `(origin, environment)`; it alone identifies the line. */
|
|
16
|
+
fingerprint: z.ZodString;
|
|
17
|
+
/** How the line reads in its deployments' labels: readable, or the fingerprint alone. */
|
|
18
|
+
line: z.ZodString;
|
|
19
|
+
};
|
|
20
|
+
readonly policies: {
|
|
21
|
+
read: () => import("@astrale-os/sdk/schema").Policy;
|
|
22
|
+
};
|
|
23
|
+
}>;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { classIcon, fullMatch, K, nodeClass } from '@astrale-os/sdk/schema';
|
|
2
|
+
import { GitBranch } from '@astrale-os/sdk/schema/icons';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
import { OwnLine } from '../policies/own-line.js';
|
|
5
|
+
/**
|
|
6
|
+
* The line every deployment of one origin in one environment shares. The first organisation that
|
|
7
|
+
* deploys on it holds it, and only an operator transfer gives it to another: it stays registered
|
|
8
|
+
* and refused to every other organisation after its organisation, that organisation's Services or
|
|
9
|
+
* every deployment on it are deleted.
|
|
10
|
+
*/
|
|
11
|
+
export const DeploymentLine = nodeClass({
|
|
12
|
+
description: 'The deployment line of one origin in one environment, held by one organisation.',
|
|
13
|
+
icon: classIcon.lucide(GitBranch),
|
|
14
|
+
extends: [K.classes.Timestamped],
|
|
15
|
+
properties: {
|
|
16
|
+
origin: z.string().min(1).max(253),
|
|
17
|
+
environment: z.string().min(1).max(63),
|
|
18
|
+
/** The 16-character fingerprint of `(origin, environment)`; it alone identifies the line. */
|
|
19
|
+
fingerprint: z.string().check(fullMatch('[a-z2-7]{16}')),
|
|
20
|
+
/** How the line reads in its deployments' labels: readable, or the fingerprint alone. */
|
|
21
|
+
line: z.string().min(16).max(40),
|
|
22
|
+
},
|
|
23
|
+
policies: { read: () => OwnLine },
|
|
24
|
+
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/** The line one deployment was made on; a deployment never moves to another line. */
|
|
2
|
+
export declare const deployment_on_line: import("@astrale-os/sdk/schema").DirectedEdgeClass<{
|
|
3
|
+
readonly depth: 0;
|
|
4
|
+
readonly abstract: false;
|
|
5
|
+
readonly extends: readonly [];
|
|
6
|
+
readonly properties: never;
|
|
7
|
+
readonly source: {
|
|
8
|
+
readonly as: "deployment";
|
|
9
|
+
readonly outgoing: "1";
|
|
10
|
+
};
|
|
11
|
+
readonly target: {
|
|
12
|
+
readonly as: "line";
|
|
13
|
+
readonly incoming: "0..*";
|
|
14
|
+
};
|
|
15
|
+
readonly constraints: Record<never, never>;
|
|
16
|
+
readonly effectiveProperties: never;
|
|
17
|
+
}>;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { edgeClass } from '@astrale-os/sdk/schema';
|
|
2
|
+
import { TraverseOwnedLineDeployment } from '../policies/traverse-owned-line-deployment.js';
|
|
3
|
+
import { DeploymentLine } from './deployment-line.js';
|
|
4
|
+
import { Deployment } from './deployment.js';
|
|
5
|
+
/** The line one deployment was made on; a deployment never moves to another line. */
|
|
6
|
+
export const deployment_on_line = edgeClass.directed({
|
|
7
|
+
description: 'The deployment line one Deployment belongs to.',
|
|
8
|
+
source: { as: 'deployment', accepts: [() => Deployment], outgoing: '1' },
|
|
9
|
+
target: { as: 'line', accepts: [() => DeploymentLine], incoming: '0..*' },
|
|
10
|
+
policies: { traverse: () => TraverseOwnedLineDeployment },
|
|
11
|
+
});
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/**
|
|
3
|
+
* One immutable deployment of a release: one build in one environment with its frozen
|
|
4
|
+
* configuration, served by one script at its own URL. It never changes code; a new release is a
|
|
5
|
+
* new deployment on the same line.
|
|
6
|
+
*/
|
|
7
|
+
export declare const Deployment: import("@astrale-os/sdk/schema").AuthoredNodeClass<{
|
|
8
|
+
readonly abstract: true;
|
|
9
|
+
readonly description: "One immutable deployment of a release on a publisher line.";
|
|
10
|
+
readonly icon: import("@astrale-os/sdk/schema").ClassIcon;
|
|
11
|
+
readonly extends: readonly [import("@astrale-os/sdk/schema").KernelClass<"Timestamped">];
|
|
12
|
+
readonly properties: {
|
|
13
|
+
/** `<line>-<content16>`, the DNS label and provider script name of this deployment. */
|
|
14
|
+
label: z.ZodString;
|
|
15
|
+
url: z.ZodString;
|
|
16
|
+
state: import("@astrale-os/sdk/schema").StateProperty<import("@astrale-os/sdk/schema").StateMachine<{
|
|
17
|
+
readonly deploying: {
|
|
18
|
+
readonly activate: "active";
|
|
19
|
+
readonly fail: "failed";
|
|
20
|
+
};
|
|
21
|
+
readonly active: {
|
|
22
|
+
readonly retire: "retiring";
|
|
23
|
+
};
|
|
24
|
+
readonly retiring: {
|
|
25
|
+
readonly completeRetirement: "retired";
|
|
26
|
+
};
|
|
27
|
+
readonly retired: {
|
|
28
|
+
readonly revive: "deploying";
|
|
29
|
+
};
|
|
30
|
+
readonly failed: {
|
|
31
|
+
readonly retry: "deploying";
|
|
32
|
+
};
|
|
33
|
+
}, "deploying">, {
|
|
34
|
+
required?: boolean;
|
|
35
|
+
description?: string;
|
|
36
|
+
}>;
|
|
37
|
+
retention: z.ZodEnum<{
|
|
38
|
+
preview: "preview";
|
|
39
|
+
published: "published";
|
|
40
|
+
}>;
|
|
41
|
+
record: z.ZodObject<{
|
|
42
|
+
format: z.ZodLiteral<"astrale.deployment-record">;
|
|
43
|
+
version: z.ZodLiteral<1>;
|
|
44
|
+
origin: z.ZodString;
|
|
45
|
+
environment: z.ZodString;
|
|
46
|
+
releaseDigest: z.ZodString;
|
|
47
|
+
buildDigest: z.ZodString;
|
|
48
|
+
schemaRevision: z.ZodString;
|
|
49
|
+
configuration: z.ZodString;
|
|
50
|
+
providerScript: z.ZodString;
|
|
51
|
+
commit: z.ZodNullable<z.ZodObject<{
|
|
52
|
+
sha: z.ZodString;
|
|
53
|
+
dirty: z.ZodBoolean;
|
|
54
|
+
base: z.ZodOptional<z.ZodObject<{
|
|
55
|
+
version: z.ZodString;
|
|
56
|
+
distance: z.ZodNumber;
|
|
57
|
+
}, z.core.$strict>>;
|
|
58
|
+
}, z.core.$strict>>;
|
|
59
|
+
}, z.core.$strict>;
|
|
60
|
+
signingKeyId: import("@astrale-os/sdk/schema").AuthoredProperty<z.ZodString, {
|
|
61
|
+
readonly required: false;
|
|
62
|
+
}>;
|
|
63
|
+
lastCallAt: import("@astrale-os/sdk/schema").AuthoredProperty<Readonly<{
|
|
64
|
+
readonly type: 'string';
|
|
65
|
+
readonly 'x-astrale-value-kind': 'instant';
|
|
66
|
+
}>, {
|
|
67
|
+
readonly required: false;
|
|
68
|
+
}>;
|
|
69
|
+
expiresAt: import("@astrale-os/sdk/schema").AuthoredProperty<Readonly<{
|
|
70
|
+
readonly type: 'string';
|
|
71
|
+
readonly 'x-astrale-value-kind': 'instant';
|
|
72
|
+
}>, {
|
|
73
|
+
readonly required: false;
|
|
74
|
+
}>;
|
|
75
|
+
retiredAt: import("@astrale-os/sdk/schema").AuthoredProperty<Readonly<{
|
|
76
|
+
readonly type: 'string';
|
|
77
|
+
readonly 'x-astrale-value-kind': 'instant';
|
|
78
|
+
}>, {
|
|
79
|
+
readonly required: false;
|
|
80
|
+
}>;
|
|
81
|
+
retirement: import("@astrale-os/sdk/schema").AuthoredProperty<z.ZodEnum<{
|
|
82
|
+
expired: "expired";
|
|
83
|
+
withdrawn: "withdrawn";
|
|
84
|
+
}>, {
|
|
85
|
+
readonly required: false;
|
|
86
|
+
}>;
|
|
87
|
+
/** The graph lease of the provider operation in flight on this deployment. */
|
|
88
|
+
operationReceipt: import("@astrale-os/sdk/schema").AuthoredProperty<z.ZodString, {
|
|
89
|
+
readonly required: false;
|
|
90
|
+
}>;
|
|
91
|
+
operationExpiresAt: import("@astrale-os/sdk/schema").AuthoredProperty<Readonly<{
|
|
92
|
+
readonly type: 'string';
|
|
93
|
+
readonly 'x-astrale-value-kind': 'instant';
|
|
94
|
+
}>, {
|
|
95
|
+
readonly required: false;
|
|
96
|
+
}>;
|
|
97
|
+
};
|
|
98
|
+
}>;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { classIcon, K, nodeClass, property, schema as valueSchema, stateProperty, } from '@astrale-os/sdk/schema';
|
|
2
|
+
import { Rocket } from '@astrale-os/sdk/schema/icons';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
import { deploymentLifecycle } from '../states/index.js';
|
|
5
|
+
import { deploymentRecord, deploymentRetention, deploymentRetirement } from '../types/index.js';
|
|
6
|
+
/**
|
|
7
|
+
* One immutable deployment of a release: one build in one environment with its frozen
|
|
8
|
+
* configuration, served by one script at its own URL. It never changes code; a new release is a
|
|
9
|
+
* new deployment on the same line.
|
|
10
|
+
*/
|
|
11
|
+
export const Deployment = nodeClass({
|
|
12
|
+
abstract: true,
|
|
13
|
+
description: 'One immutable deployment of a release on a publisher line.',
|
|
14
|
+
icon: classIcon.lucide(Rocket),
|
|
15
|
+
extends: [K.classes.Timestamped],
|
|
16
|
+
properties: {
|
|
17
|
+
/** `<line>-<content16>`, the DNS label and provider script name of this deployment. */
|
|
18
|
+
label: z.string().min(33).max(57),
|
|
19
|
+
url: z.string().min(1).max(2_048),
|
|
20
|
+
state: stateProperty(deploymentLifecycle),
|
|
21
|
+
retention: deploymentRetention,
|
|
22
|
+
record: deploymentRecord,
|
|
23
|
+
signingKeyId: property(z.string().min(1).max(128), { required: false }),
|
|
24
|
+
lastCallAt: property(valueSchema.values.instant, { required: false }),
|
|
25
|
+
expiresAt: property(valueSchema.values.instant, { required: false }),
|
|
26
|
+
retiredAt: property(valueSchema.values.instant, { required: false }),
|
|
27
|
+
retirement: property(deploymentRetirement, { required: false }),
|
|
28
|
+
/** The graph lease of the provider operation in flight on this deployment. */
|
|
29
|
+
operationReceipt: property(z.string().min(1).max(128), { required: false }),
|
|
30
|
+
operationExpiresAt: property(valueSchema.values.instant, { required: false }),
|
|
31
|
+
},
|
|
32
|
+
});
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { CloudflareDeployment } from './cloudflare-deployment.js';
|
|
2
|
+
export { Deployment } from './deployment.js';
|
|
3
|
+
export { DeploymentLine } from './deployment-line.js';
|
|
4
|
+
export { deployment_on_line } from './deployment-on-line.js';
|
|
5
|
+
export { line_owned_by } from './line-owned-by.js';
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { CloudflareDeployment } from './cloudflare-deployment.js';
|
|
2
|
+
export { Deployment } from './deployment.js';
|
|
3
|
+
export { DeploymentLine } from './deployment-line.js';
|
|
4
|
+
export { deployment_on_line } from './deployment-on-line.js';
|
|
5
|
+
export { line_owned_by } from './line-owned-by.js';
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The organisation holding one deployment line: an Identity of the Admin instance, a Shell User
|
|
3
|
+
* or Group, whose members and CI identities act for it through `extends_with`. A line outlives
|
|
4
|
+
* this Edge: deleting its organisation removes the Edge and leaves the line held by nobody until
|
|
5
|
+
* an operator transfer.
|
|
6
|
+
*
|
|
7
|
+
* Hence at most one holder, not exactly one: the Kernel deletes a Node only together with every
|
|
8
|
+
* incident Edge, so a required holder would make the organisation undeletable unless its lines
|
|
9
|
+
* went with it, and a deleted line would free its fingerprint for another organisation.
|
|
10
|
+
*/
|
|
11
|
+
export declare const line_owned_by: import("@astrale-os/sdk/schema").DirectedEdgeClass<{
|
|
12
|
+
readonly depth: 0;
|
|
13
|
+
readonly abstract: false;
|
|
14
|
+
readonly extends: readonly [];
|
|
15
|
+
readonly properties: never;
|
|
16
|
+
readonly source: {
|
|
17
|
+
readonly as: "line";
|
|
18
|
+
readonly outgoing: "0..1";
|
|
19
|
+
};
|
|
20
|
+
readonly target: {
|
|
21
|
+
readonly as: "owner";
|
|
22
|
+
readonly incoming: "0..*";
|
|
23
|
+
};
|
|
24
|
+
readonly constraints: Record<never, never>;
|
|
25
|
+
readonly effectiveProperties: never;
|
|
26
|
+
}>;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { edgeClass, K } from '@astrale-os/sdk/schema';
|
|
2
|
+
import { TraverseOwnedLine } from '../policies/traverse-owned-line.js';
|
|
3
|
+
import { DeploymentLine } from './deployment-line.js';
|
|
4
|
+
/**
|
|
5
|
+
* The organisation holding one deployment line: an Identity of the Admin instance, a Shell User
|
|
6
|
+
* or Group, whose members and CI identities act for it through `extends_with`. A line outlives
|
|
7
|
+
* this Edge: deleting its organisation removes the Edge and leaves the line held by nobody until
|
|
8
|
+
* an operator transfer.
|
|
9
|
+
*
|
|
10
|
+
* Hence at most one holder, not exactly one: the Kernel deletes a Node only together with every
|
|
11
|
+
* incident Edge, so a required holder would make the organisation undeletable unless its lines
|
|
12
|
+
* went with it, and a deleted line would free its fingerprint for another organisation.
|
|
13
|
+
*/
|
|
14
|
+
export const line_owned_by = edgeClass.directed({
|
|
15
|
+
description: 'The organisation that holds one deployment line.',
|
|
16
|
+
source: { as: 'line', accepts: [() => DeploymentLine], outgoing: '0..1' },
|
|
17
|
+
target: { as: 'owner', accepts: [K.classes.Identity], incoming: '0..*' },
|
|
18
|
+
policies: { traverse: () => TraverseOwnedLine },
|
|
19
|
+
});
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { CloudflareDeployment, Deployment, DeploymentLine, deployment_on_line, line_owned_by, } from './classes/index.js';
|
|
2
|
+
export { OwnDeployment, OwnLine, TraverseOwnedLine, TraverseOwnedLineDeployment, } from './policies/index.js';
|
|
3
|
+
export { deploymentLifecycle } from './states/index.js';
|
|
4
|
+
export type { DeploymentLifecycle, DeploymentLifecycleEvent } from './states/index.js';
|
|
5
|
+
export { deploymentCommit, deploymentRecord, deploymentRetention, deploymentRetirement, } from './types/index.js';
|
|
6
|
+
export type { DeploymentRecord, DeploymentRetention, DeploymentRetirement } from './types/index.js';
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { CloudflareDeployment, Deployment, DeploymentLine, deployment_on_line, line_owned_by, } from './classes/index.js';
|
|
2
|
+
export { OwnDeployment, OwnLine, TraverseOwnedLine, TraverseOwnedLineDeployment, } from './policies/index.js';
|
|
3
|
+
export { deploymentLifecycle } from './states/index.js';
|
|
4
|
+
export { deploymentCommit, deploymentRecord, deploymentRetention, deploymentRetirement, } from './types/index.js';
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { policy } from '@astrale-os/sdk/schema';
|
|
2
|
+
import { DeploymentLine } from '../classes/deployment-line.js';
|
|
3
|
+
import { deployment_on_line } from '../classes/deployment-on-line.js';
|
|
4
|
+
import { line_owned_by } from '../classes/line-owned-by.js';
|
|
5
|
+
/** A deployment belongs to whoever holds its line; it carries no owner of its own. */
|
|
6
|
+
export const OwnDeployment = policy({
|
|
7
|
+
description: 'The subject holds the deployment line this Deployment was made on.',
|
|
8
|
+
match: ({ allOf, edge, exists, object, subject }) => exists(({ node }) => {
|
|
9
|
+
const line = node(() => DeploymentLine);
|
|
10
|
+
return allOf(edge({ source: object, class: () => deployment_on_line, target: line }), edge({ source: line, class: () => line_owned_by, target: subject }));
|
|
11
|
+
}),
|
|
12
|
+
});
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { policy } from '@astrale-os/sdk/schema';
|
|
2
|
+
import { line_owned_by } from '../classes/line-owned-by.js';
|
|
3
|
+
/**
|
|
4
|
+
* The organisation holding a line, and every Identity that acts for it: a member or a CI identity
|
|
5
|
+
* reaches it through its `extends_with` composition, never through a second rule here.
|
|
6
|
+
*/
|
|
7
|
+
export const OwnLine = policy({
|
|
8
|
+
description: 'The subject holds this deployment line.',
|
|
9
|
+
match: ({ edge, object, subject }) => edge({ source: object, class: () => line_owned_by, target: subject }),
|
|
10
|
+
});
|