@astrale-domains/services 0.4.5 → 0.4.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/README.md +278 -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 +463 -0
- package/dist/schema/modules/deployment/classes/cloudflare-deployment.js +30 -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 +189 -0
- package/dist/schema/modules/deployment/classes/deployment.js +56 -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/errors/deployment-hosting-unavailable.d.ts +7 -0
- package/dist/schema/modules/deployment/errors/deployment-hosting-unavailable.js +8 -0
- package/dist/schema/modules/deployment/errors/deployment-label-not-found.d.ts +12 -0
- package/dist/schema/modules/deployment/errors/deployment-label-not-found.js +11 -0
- package/dist/schema/modules/deployment/errors/deployment-not-found.d.ts +10 -0
- package/dist/schema/modules/deployment/errors/deployment-not-found.js +11 -0
- package/dist/schema/modules/deployment/errors/deployment-registry-only.d.ts +11 -0
- package/dist/schema/modules/deployment/errors/deployment-registry-only.js +12 -0
- package/dist/schema/modules/deployment/errors/index.d.ts +4 -0
- package/dist/schema/modules/deployment/errors/index.js +4 -0
- package/dist/schema/modules/deployment/functions/deploy-cloudflare-deployment.d.ts +170 -0
- package/dist/schema/modules/deployment/functions/deploy-cloudflare-deployment.js +14 -0
- package/dist/schema/modules/deployment/functions/describe-deployment-hosting.d.ts +8 -0
- package/dist/schema/modules/deployment/functions/describe-deployment-hosting.js +11 -0
- package/dist/schema/modules/deployment/functions/expire-deployment-previews.d.ts +16 -0
- package/dist/schema/modules/deployment/functions/expire-deployment-previews.js +14 -0
- package/dist/schema/modules/deployment/functions/index.d.ts +11 -0
- package/dist/schema/modules/deployment/functions/index.js +11 -0
- package/dist/schema/modules/deployment/functions/list-cloudflare-deployment-secret-names.d.ts +5 -0
- package/dist/schema/modules/deployment/functions/list-cloudflare-deployment-secret-names.js +4 -0
- package/dist/schema/modules/deployment/functions/list-cloudflare-deployments.d.ts +58 -0
- package/dist/schema/modules/deployment/functions/list-cloudflare-deployments.js +10 -0
- package/dist/schema/modules/deployment/functions/list-deployment-secret-names.d.ts +4 -0
- package/dist/schema/modules/deployment/functions/list-deployment-secret-names.js +6 -0
- package/dist/schema/modules/deployment/functions/read-deployment-last-calls.d.ts +10 -0
- package/dist/schema/modules/deployment/functions/read-deployment-last-calls.js +13 -0
- package/dist/schema/modules/deployment/functions/retain-deployment.d.ts +12 -0
- package/dist/schema/modules/deployment/functions/retain-deployment.js +13 -0
- package/dist/schema/modules/deployment/functions/retire-deployment.d.ts +23 -0
- package/dist/schema/modules/deployment/functions/retire-deployment.js +17 -0
- package/dist/schema/modules/deployment/functions/set-cloudflare-deployment-secret.d.ts +18 -0
- package/dist/schema/modules/deployment/functions/set-cloudflare-deployment-secret.js +7 -0
- package/dist/schema/modules/deployment/functions/set-deployment-secret.d.ts +14 -0
- package/dist/schema/modules/deployment/functions/set-deployment-secret.js +3 -0
- package/dist/schema/modules/deployment/index.d.ts +8 -0
- package/dist/schema/modules/deployment/index.js +6 -0
- package/dist/schema/modules/deployment/policies/act-for-organization.d.ts +6 -0
- package/dist/schema/modules/deployment/policies/act-for-organization.js +10 -0
- package/dist/schema/modules/deployment/policies/index.d.ts +5 -0
- package/dist/schema/modules/deployment/policies/index.js +5 -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 +30 -0
- package/dist/schema/modules/deployment/states/deployment-lifecycle.js +19 -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-hosting.d.ts +94 -0
- package/dist/schema/modules/deployment/types/deployment-hosting.js +19 -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-request.d.ts +161 -0
- package/dist/schema/modules/deployment/types/deployment-request.js +40 -0
- package/dist/schema/modules/deployment/types/deployment-response.d.ts +109 -0
- package/dist/schema/modules/deployment/types/deployment-response.js +36 -0
- package/dist/schema/modules/deployment/types/deployment-retention.d.ts +49 -0
- package/dist/schema/modules/deployment/types/deployment-retention.js +45 -0
- package/dist/schema/modules/deployment/types/deployment-retire.d.ts +30 -0
- package/dist/schema/modules/deployment/types/deployment-retire.js +18 -0
- package/dist/schema/modules/deployment/types/deployment-secret-digest.d.ts +17 -0
- package/dist/schema/modules/deployment/types/deployment-secret-digest.js +14 -0
- package/dist/schema/modules/deployment/types/deployment-secret.d.ts +59 -0
- package/dist/schema/modules/deployment/types/deployment-secret.js +52 -0
- package/dist/schema/modules/deployment/types/deployment-summary.d.ts +165 -0
- package/dist/schema/modules/deployment/types/deployment-summary.js +38 -0
- package/dist/schema/modules/deployment/types/frozen-configuration.d.ts +52 -0
- package/dist/schema/modules/deployment/types/frozen-configuration.js +55 -0
- package/dist/schema/modules/deployment/types/index.d.ts +20 -0
- package/dist/schema/modules/deployment/types/index.js +10 -0
- package/dist/schema/modules/service/classes/cloudflare-worker.d.ts +60 -24
- package/dist/schema/modules/service/classes/service.d.ts +7 -7
- 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 +3 -3
- 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 +22 -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 +740 -23
- package/dist/schema/schema.js +11 -0
- package/package.json +15 -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,157 @@ 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.
|
|
48
|
+
|
|
49
|
+
## Immutable deployments
|
|
50
|
+
|
|
51
|
+
The Admin-hosted Services runtime hosts publishers' releases as immutable deployments, one per
|
|
52
|
+
label, on the publisher's line. Three static `CloudflareDeployment` Methods serve them, and two
|
|
53
|
+
instance Methods rotate one deployment's secrets; any authenticated identity of the Admin instance
|
|
54
|
+
may call them. A Domain Worker serves every Kernel that
|
|
55
|
+
installs it, but deployments are hosted for the Admin instance's Kernel alone
|
|
56
|
+
(`SERVICES_DEPLOYMENT_KERNEL`): its graph is the line registry, while the deployments namespace and
|
|
57
|
+
the routing KV are shared. Any other Kernel finds hosting unavailable before anything is read.
|
|
58
|
+
|
|
59
|
+
- `deploy` takes a `DeploymentRequestV1`: the release's origin, environment, addressing, label,
|
|
60
|
+
build digest, frozen configuration, record fields, Worker bundle and the environment's current
|
|
61
|
+
secrets. It is a non-durable Action, never a Workflow, so no Execution, step result or journal
|
|
62
|
+
entry holds its input. Before any read it recomputes the build digest and the label, admits the
|
|
63
|
+
record with the SDK, and refuses a service binding, a router other than the logical
|
|
64
|
+
`admin-router`, a reserved binding name, or secrets other than exactly the declared ones. Only
|
|
65
|
+
the platform organisation (`SERVICES_PLATFORM_OWNER`) deploys on readable lines.
|
|
66
|
+
- `deploy` then observes the line under the Services Domain credential and proves, on the caller's
|
|
67
|
+
own session, that the caller acts for the organisation it names (`OwnLine` on a held line,
|
|
68
|
+
`ActForOrganization` for a new one) before any Mutation. A new label is created under a graph
|
|
69
|
+
lease. The provider uploads it create-only, with `ASTRALE_BUILD_DIGEST`, `ASTRALE_SETTINGS` (router
|
|
70
|
+
binding `ROUTER`), a signing key Services generates for this deployment alone, and the request's
|
|
71
|
+
secrets. It adopts a script only when resuming a deployment the graph already held from an earlier
|
|
72
|
+
attempt, and only when the script's tags name the same artifact, line and key and this Kernel's
|
|
73
|
+
installation; any other script under the label is another deployment's, refused
|
|
74
|
+
`deployment-conflict`, and its secrets are never written. It checks that the uploaded version
|
|
75
|
+
itself serves before it activates the label through the routing KV `record:<label>`. The graph then records the deployment active with its key id, script etag and
|
|
76
|
+
a keyed HMAC-SHA256 digest of its secrets; no value, private key or version id is stored.
|
|
77
|
+
- the same release again is the same label: `deploy` answers `reused`. Its secrets are the
|
|
78
|
+
environment's current values: when they match the recorded digests it answers `unchanged` and
|
|
79
|
+
writes nothing; otherwise it rewrites the changed values in place on that deployment alone and
|
|
80
|
+
answers `updated` (same script, URL, issuer and key, no new release). Every other deployment of
|
|
81
|
+
the line keeps its own secrets.
|
|
82
|
+
- `setSecret({ name, value })` and `secrets({})` are instance Methods of one `CloudflareDeployment`.
|
|
83
|
+
`setSecret` rewrites one secret in place on that deployment only, and only a name its frozen
|
|
84
|
+
configuration declares (`secret-undeclared` otherwise); there is no `deleteSecret`, since a bound
|
|
85
|
+
name is part of the release, and the signing key never rotates. `secrets` lists the names its
|
|
86
|
+
script binds, never a value. Like `deploy`, any authenticated identity may call them, because a
|
|
87
|
+
publisher holds no `can_use` on Services' Functions and an `authorized` Method requires it of
|
|
88
|
+
every non-Root caller: before anything is read, the Kernel answers `OwnDeployment` for the caller
|
|
89
|
+
on its own session, and any other caller finds no such deployment (`DEPLOYMENT_NOT_FOUND`). If the
|
|
90
|
+
Admin instance ever grants publishers `can_use` on these Methods, they become `authorized` with
|
|
91
|
+
the `OwnDeployment` Policy instead. Both are non-durable Actions, so no Execution, step result or
|
|
92
|
+
journal entry holds a value.
|
|
93
|
+
- a `setSecret` refusal is `{ kind: 'rejected', reason, message, retryAfter? }`.
|
|
94
|
+
`service-unavailable` with `retryAfter` (the deployment is being created, another operation
|
|
95
|
+
holds it, or the provider failed) is retried then; without `retryAfter` the deployment cannot be
|
|
96
|
+
rotated in place (its creation failed, it is retiring or retired, or the script under its label is
|
|
97
|
+
not the recorded one, which is the operator's to inspect), and the message says what can.
|
|
98
|
+
- an in-place rewrite, by `deploy` or `setSecret`, runs under the deployment's graph lease. It
|
|
99
|
+
compares the values with the keyed digests and writes only the changed ones; it first forgets the
|
|
100
|
+
digests of the names it writes and records the new digests only once every write succeeded, so a
|
|
101
|
+
recorded digest always names the value last written. A provider failure answers
|
|
102
|
+
`service-unavailable` with `retryAfter`, and a rerun, with any values, converges. The script is
|
|
103
|
+
first checked to be the recorded one (code hash, artifact tag, key tag, installation tag); a
|
|
104
|
+
rewrite never touches another script. Workers for Platforms keeps the script's name, code hash,
|
|
105
|
+
tags and bindings across a secret write and mints a new provider version, which serves the new
|
|
106
|
+
value a few seconds later (OPS-2 X1): propagation is eventually consistent, and nothing records a
|
|
107
|
+
version id.
|
|
108
|
+
- `hosting` returns the routing domain and how the caller's lines read (readable for the platform
|
|
109
|
+
organisation, opaque otherwise). `list` returns the deployments of the lines the caller holds. It
|
|
110
|
+
reads the held lines under the Services Domain credential, narrowed in the Query to the origin
|
|
111
|
+
and environment asked for, and keeps the lines a batched `Identity.can(OwnLine)` grants the
|
|
112
|
+
caller: a caller-mode read sees none of the lines a caller holds through `extends_with`
|
|
113
|
+
([kernel#1138](https://github.com/astrale-os/kernel/issues/1138), the removal trigger of this
|
|
114
|
+
filter). One listing reads at most 16,384 matching held lines and fails beyond, so a listing
|
|
115
|
+
without an origin is bounded by the platform's held lines. A deployment whose stored record or
|
|
116
|
+
configuration this Services SDK no longer admits, for instance after a stricter decoder, is
|
|
117
|
+
still listed, from the facts Services owns, with its record exactly as stored (typed as JSON for
|
|
118
|
+
that row): the listing never fails on it, and the consumer admits the record itself. Deploy,
|
|
119
|
+
retain, retire, `setSecret`, `secrets` and `expirePreviews` fail closed on such a deployment
|
|
120
|
+
with an undeclared internal error (5000) and write nothing; `lastCalls` answers from its facts.
|
|
121
|
+
- deleting a Service, or an instance and its Services, never addresses a publisher's deployment.
|
|
122
|
+
|
|
123
|
+
Only a runtime whose Environment vars set `SERVICES_DEPLOYMENT_HOST` (the deployments' routing
|
|
124
|
+
domain) hosts deployments; every other runtime answers `hosting-unavailable`. Such a runtime refuses
|
|
125
|
+
to boot without `SERVICES_DEPLOYMENT_KERNEL` (the Admin Kernel's issuer URL),
|
|
126
|
+
`SERVICES_SECRET_DIGEST_KEY` (at least 32 characters, kept for the life of the environment: the
|
|
127
|
+
recorded digests depend on it), the `SERVICE_DEPLOYMENTS` dispatch binding to the environment's
|
|
128
|
+
deployments namespace, and `CLOUDFLARE_SCHEDULE_KV_ID`, the routing KV that activates a label, and
|
|
129
|
+
refuses a `SERVICES_PLATFORM_OWNER` that is not an Identity id. Hosting is declared once, by the
|
|
130
|
+
Environment's `vars` in `astrale.config.ts`: the same vars decide the `SERVICE_DEPLOYMENTS` binding,
|
|
131
|
+
and the configuration refuses a secrets file that sets a hosting var. [Real-Kernel
|
|
132
|
+
proof](tests/kernel/README.md).
|
|
133
|
+
|
|
134
|
+
### Retention and retirement
|
|
135
|
+
|
|
136
|
+
A deployment is a `preview` until the registry Domain marks it `published`; only a preview expires.
|
|
137
|
+
Four more `CloudflareDeployment` Methods manage what stays served. Retirement, retention and
|
|
138
|
+
revival name a deployment by its label, script etag, artifact tag and configuration digest, never
|
|
139
|
+
by a provider version id.
|
|
140
|
+
|
|
141
|
+
- `retire` is the instance Method of the line holder's emergency stop. Any authenticated identity
|
|
142
|
+
may call it, because a publisher holds no `can_use` on Services' Functions and an `authorized`
|
|
143
|
+
Method requires it of every non-Root caller: before anything is read, the Kernel answers
|
|
144
|
+
`OwnDeployment` for the caller on its own session, and any other caller finds no such deployment
|
|
145
|
+
(`DEPLOYMENT_NOT_FOUND`). If the Admin instance ever grants publishers `can_use` on it, it becomes
|
|
146
|
+
`authorized` with the `OwnDeployment` Policy instead. It withdraws the deployment for good in two
|
|
147
|
+
phases. The graph records it `retiring` first, so no deploy reuses it; the same Mutation evicts
|
|
148
|
+
the operation lease of any operation writing the script, such as an in-place rewrite of its
|
|
149
|
+
secrets, which then records nothing. Then the routing KV gets the tombstone
|
|
150
|
+
`retirement:<label>` = `withdrawn`. The dispatcher
|
|
151
|
+
answers a label with a tombstone `DEPLOYMENT_RETIRED` (`410`) and keeps serving its
|
|
152
|
+
`deployment.json` from `record:<label>`, which stays. The first call answers `retiring` with
|
|
153
|
+
`retryAfterMs`. A call 65 seconds after the tombstone, once the dispatcher's retirement probe
|
|
154
|
+
answers `DEPLOYMENT_RETIRED`, deletes the script and its signing key and answers `retired`. A
|
|
155
|
+
withdrawn label is never served again: deploying the same release is refused
|
|
156
|
+
`deployment-retired`.
|
|
157
|
+
- `retain` marks one preview `published`. Only the registry Domain's principal calls it, acting as
|
|
158
|
+
itself; it is the installed, unfrozen Domain whose origin is `SERVICES_REGISTRY_ORIGIN`. Services
|
|
159
|
+
reads the caller's Domain node by id under its own credential, which is why it requires read on
|
|
160
|
+
the Kernel's `Domain` Class; nothing the caller presents decides it. An authenticated caller
|
|
161
|
+
carries Identity ids but no Domain origin, and read on `Identity` does not reach a Domain's node.
|
|
162
|
+
Every instance that installs this Services version grants that read, so Services can read the
|
|
163
|
+
origin and frozen flag of each Domain installed there; only the Admin instance's hosting runtime
|
|
164
|
+
uses it. The requirement goes once the Kernel gives a handler its caller's Domain origin. A line
|
|
165
|
+
holder, or an identity acting for the registry, is refused `DEPLOYMENT_REGISTRY_ONLY`. The mark
|
|
166
|
+
is monotonic and idempotent, and it never undoes a retirement in progress: a preview marked after
|
|
167
|
+
its expiry started still retires, and a redeploy of the same release revives it.
|
|
168
|
+
- `lastCalls` returns the last call of up to 100 labels the caller holds (as the Kernel answers
|
|
169
|
+
`OwnDeployment` on the caller's session), or any labels for the registry; an unknown label and
|
|
170
|
+
another organisation's both answer `DEPLOYMENT_LABEL_NOT_FOUND`. It reads the data points the dispatcher writes per admitted call, through the Analytics
|
|
171
|
+
Engine SQL API, and the last call recorded in the graph. A label nobody called reads `null`. It
|
|
172
|
+
reads only the facts Services recorded, so it answers for a listed deployment whose stored
|
|
173
|
+
record this SDK no longer admits.
|
|
174
|
+
- `expirePreviews` is the registry's pass. A preview expires 30 days after its activation (its
|
|
175
|
+
creation, or its revival) or its last call, whichever is later; every activation records its
|
|
176
|
+
instant, and a pass refuses an active preview without one rather than expire it on its creation. The pass is a plan unless the runtime sets
|
|
177
|
+
`SERVICES_PREVIEW_EXPIRY=enforce` and the caller passes `apply: true`: it answers the `planned`
|
|
178
|
+
labels and retires none. Applied, it retires them in two phases with the tombstone `expired` and
|
|
179
|
+
answers `retired` and `pending` labels; the next pass completes the pending ones. Either way it
|
|
180
|
+
records later calls, so each preview's `expiresAt` follows its traffic. `limit` bounds the
|
|
181
|
+
deployment writes of one pass (64 by default), and retirements come first.
|
|
182
|
+
|
|
183
|
+
An expired label revives. When the same owner deploys the same release (same label, so same
|
|
184
|
+
artifact and configuration) again, the deployment resumes from `retired`. It is uploaded
|
|
185
|
+
create-only with a new signing key, and the activation republishes the same `record:<label>`
|
|
186
|
+
before it removes the `expired` tombstone. An instance that pins the label is served the same
|
|
187
|
+
release digest at the same URL. A `withdrawn` tombstone is never removed.
|
|
188
|
+
|
|
189
|
+
`SERVICES_REGISTRY_ORIGIN` and `SERVICES_PREVIEW_EXPIRY` (`plan`, the default, or `enforce`) are
|
|
190
|
+
Environment vars of a hosting runtime, refused in a secrets file and refused without
|
|
191
|
+
`SERVICES_DEPLOYMENT_HOST`. Without a registry origin no caller is the registry, and `retain` and
|
|
192
|
+
`expirePreviews` are refused. `admin-beta` names `admin.astrale.ai` and keeps expiry a plan.
|
|
193
|
+
Reading last calls needs the API token's Account Analytics Read permission. `pnpm
|
|
194
|
+
provider:deployment-audit` lists the deployments namespace read-only
|
|
195
|
+
([operator](providers/cloudflare/operator/README.md)).
|
|
25
196
|
|
|
26
197
|
The View, CLI, and agent consumers read the named Service Queries directly; there is intentionally
|
|
27
198
|
no list Function wrapping `listServicesQuery`. Deployment, secrets, schedules, logs, and deletion
|
|
@@ -75,13 +246,96 @@ health check. Cloudflare can automatically delete the generated certificate as s
|
|
|
75
246
|
Domain is detached. `restore` recreates the exact domain, waits for active TLS and records the actual
|
|
76
247
|
replacement certificate locator. A `pending` result requires a later retry; it is not completion.
|
|
77
248
|
|
|
78
|
-
The
|
|
79
|
-
`https://services.beta.astrale.ai
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
retained Service
|
|
249
|
+
The consumer runtimes are frozen ([`frozen-environments.json`](./frozen-environments.json)): the
|
|
250
|
+
original R1 runtime at `https://services.beta.astrale.ai`, which 1Pact instances pin and which
|
|
251
|
+
serves that issuer's discovery and keys, `https://services-v2.beta.astrale.ai`, which retains that
|
|
252
|
+
issuer and key, and production at `https://services.astrale.ai`. They keep serving the code they run
|
|
253
|
+
today and no Environment deploys them. Do not uninstall Services or replace a runtime underneath
|
|
254
|
+
installations that still use its Schema. An instance rollback must restore any detached domain
|
|
255
|
+
before reinstalling the original endpoint, and must first be qualified with real retained Service
|
|
256
|
+
data.
|
|
257
|
+
|
|
258
|
+
## Admin-hosted runtime
|
|
259
|
+
|
|
260
|
+
The `admin-beta` Environment is the Services runtime of the Admin instance, the one that hosts
|
|
261
|
+
publishers' deployments outside the instances that install them. It is a Worker of its own,
|
|
262
|
+
`services-domain-admin-beta` at `https://services-admin.beta.astrale.ai`, on the beta data plane the
|
|
263
|
+
Admin instance's Services already manage. Its plain vars name the router Worker
|
|
264
|
+
(`ASTRALE_ROUTER_WORKER`), the routing domain under which deployments are addressed
|
|
265
|
+
(`SERVICES_DEPLOYMENT_HOST`, served by the Services dispatcher), the Admin instance's Kernel, the
|
|
266
|
+
only one it hosts deployments for (`SERVICES_DEPLOYMENT_KERNEL`, `https://admin.eu.beta.astrale.ai/api`),
|
|
267
|
+
and the registry Domain (`SERVICES_REGISTRY_ORIGIN`). These vars are the only declaration of
|
|
268
|
+
hosting: they also bind `SERVICE_DEPLOYMENTS`. `.env.admin-beta` must set
|
|
269
|
+
`SERVICES_SECRET_DIGEST_KEY`, the key of each hosted deployment's secret digest, and the dispatch
|
|
270
|
+
namespace and routing KV the runtime boots with. The runtime keys HMAC-SHA256 with the UTF-8 bytes
|
|
271
|
+
of the digest key as written, never base64-decoded, so the configuration refuses, before any
|
|
272
|
+
deployment effect, a file without them, a digest key shorter than 32 UTF-8 bytes, or a file that
|
|
273
|
+
sets a hosting var. `SERVICES_PLATFORM_OWNER` is not set yet: until it names the platform
|
|
274
|
+
organisation's Identity id on the Admin instance, every line is opaque and a readable deploy is
|
|
275
|
+
refused.
|
|
276
|
+
|
|
277
|
+
It retains the issuer `https://services.beta.astrale.ai` and its signing key, as services-v2 does.
|
|
278
|
+
The Admin instance's Services are bound to that issuer, and the Kernel refuses an issuer change when
|
|
279
|
+
it replaces an installed Domain (`issuer-changed`); neither the Admin Host's Kernel nor the CLI
|
|
280
|
+
offers a consented issuer change yet. The cost: a Worker built from main holds the key that 1Pact's
|
|
281
|
+
installations trust. Keep the key only in managed secret storage and in this Worker's
|
|
282
|
+
`ASTRALE_SIGNING_IDENTITY` secret. The Admin instance moves to an issuer of its own when the
|
|
283
|
+
canonical Admin-hosted runtime replaces this one through a consented issuer change; this Worker and
|
|
284
|
+
its copy of the key are retired after that reinstall.
|
|
285
|
+
|
|
286
|
+
Only the Admin instance installs this runtime; consumer instances keep the Services they pin.
|
|
287
|
+
The operator sets it up once:
|
|
288
|
+
|
|
289
|
+
1. Read what the Admin instance's Services are bound to, read-only:
|
|
290
|
+
`astrale introspect services.astrale.ai -i <admin-instance> --json`. Record `revision` and
|
|
291
|
+
`publication.identity.issuer`, and the frozen runtime whose `/.well-known/astrale/domain.json`
|
|
292
|
+
declares that revision: it is the rollback URL. Go on only if the issuer is
|
|
293
|
+
`https://services.beta.astrale.ai`; any other issuer makes step 6 an issuer change, which the
|
|
294
|
+
Kernel refuses. Check as well that the Admin instance's Kernel issuer is admin-beta's
|
|
295
|
+
`SERVICES_DEPLOYMENT_KERNEL`; otherwise every deploy answers `hosting-unavailable`. Before the
|
|
296
|
+
first readable deploy, read the platform organisation's Identity id there and set it as
|
|
297
|
+
admin-beta's `SERVICES_PLATFORM_OWNER` var in a reviewed change to `astrale.config.ts`.
|
|
298
|
+
2. Create `.env.admin-beta` (mode 600) from `.env.example` with the beta data-plane coordinates the
|
|
299
|
+
Admin instance's Services manage today (account, token, dispatch namespace, routing domain
|
|
300
|
+
`svc.eu.beta.astrale.ai`, schedule KV, dispatcher, zone, Admin target) and a new
|
|
301
|
+
`SERVICES_SECRET_DIGEST_KEY` that no other environment uses, e.g. `openssl rand -base64 32` (32
|
|
302
|
+
random bytes, kept as their 44-character base64 text).
|
|
303
|
+
3. Restore the retained `https://services.beta.astrale.ai` signing identity, the one services-v2 was
|
|
304
|
+
deployed with, from managed secret storage to `.astrale/services-beta-identity.json` (mode 600).
|
|
305
|
+
Never generate a key for this runtime: the frozen R1 Worker publishes the issuer's keys, so a new
|
|
306
|
+
key would never verify. Never leave that key at `.astrale/identity.json`, the development
|
|
307
|
+
Environment's default identity: `pnpm dev` would bind it to development Workers. Check that the
|
|
308
|
+
issuer publishes the restored key:
|
|
309
|
+
|
|
310
|
+
```sh
|
|
311
|
+
node --input-type=module -e '
|
|
312
|
+
const { readFileSync } = await import("node:fs")
|
|
313
|
+
const { kid, x } = JSON.parse(readFileSync(".astrale/services-beta-identity.json", "utf8"))
|
|
314
|
+
const issuer = "https://services.beta.astrale.ai"
|
|
315
|
+
const { jwks_uri } = await (await fetch(`${issuer}/.well-known/openid-configuration`)).json()
|
|
316
|
+
const { keys } = await (await fetch(jwks_uri)).json()
|
|
317
|
+
if (!keys.some((key) => key.kid === kid && key.x === x)) throw new Error("key not published")
|
|
318
|
+
console.log(`issuer publishes kid ${kid}`)
|
|
319
|
+
'
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
4. Deploy once with `pnpm run deploy admin-beta`. It creates only the `services-domain-admin-beta`
|
|
323
|
+
Worker and its route; nothing is installed. Do not run `pnpm provider:bootstrap` or a
|
|
324
|
+
`provider:route-*` command for this runtime: on the beta data plane they redeploy the shared
|
|
325
|
+
dispatcher and DNS routing that serve 1Pact's tenants (see the
|
|
326
|
+
[operator README](./providers/cloudflare/operator/README.md)).
|
|
327
|
+
5. Rehearse step 6 first on a disposable instance whose Host runs the Admin Host's Kernel release and
|
|
328
|
+
whose Services are bound to the same issuer and revision as in step 1, with at least one Service.
|
|
329
|
+
The install must succeed and the Service must stay manageable (list, secrets, logs). Then install
|
|
330
|
+
the step 1 rollback URL there again: if the Kernel refuses it, step 6 is one-way, and that must be
|
|
331
|
+
recorded before step 6 runs.
|
|
332
|
+
6. Install on the Admin instance only, directly:
|
|
333
|
+
`astrale domain install https://services-admin.beta.astrale.ai --direct --allow-identity-override -i <admin-instance>`.
|
|
334
|
+
The only consent is the identity override, because the origin `services.astrale.ai` differs from
|
|
335
|
+
the serving host; the issuer does not change. On any refusal, stop: never uninstall Services on
|
|
336
|
+
the Admin instance to get around it, which would drop the Service records it holds. Never repoint
|
|
337
|
+
Admin's catalog entry for `services.astrale.ai` at this runtime: consumer flows, 1Pact's among
|
|
338
|
+
them, install Services by origin through that entry.
|
|
85
339
|
|
|
86
340
|
## Plain background Service starter
|
|
87
341
|
|
|
@@ -107,8 +361,8 @@ No tooling dependency is added to the Schema runtime or imported from the packag
|
|
|
107
361
|
|
|
108
362
|
Copy `.env.example` to `.env.dev` and fill the Cloudflare values.
|
|
109
363
|
|
|
110
|
-
`pnpm dev` watches and deploys the development Environment remotely. `pnpm
|
|
111
|
-
|
|
364
|
+
`pnpm dev` watches and deploys the development Environment remotely. `pnpm run deploy admin-beta`
|
|
365
|
+
deploys the [Admin-hosted runtime](#admin-hosted-runtime) once. These bootstrap Environments
|
|
112
366
|
are deliberately deploy-only: install the resulting URL on the intended Kernel explicitly.
|
|
113
367
|
Stopping development leaves the remote Worker available. No local Worker or tunnel is started.
|
|
114
368
|
|
|
@@ -123,9 +377,21 @@ pnpm build
|
|
|
123
377
|
pnpm package
|
|
124
378
|
```
|
|
125
379
|
|
|
126
|
-
The deployed module named by `entry` must be present in `modules`.
|
|
127
|
-
|
|
128
|
-
|
|
380
|
+
The deployed module named by `entry` must be present in `modules`. Modules and assets carry
|
|
381
|
+
`content: { encoding: 'identity' | 'gzip', decodedSize, contentBase64 }`; large encoded files use
|
|
382
|
+
`contentBase64Chunks` instead, with each string bounded to 512 KiB. `decodedSize` is the exact original
|
|
383
|
+
byte length. Compression changes transport only: provider uploads and deployment digests use the
|
|
384
|
+
reconstructed bytes. Services validates complete gzip streams (including their checksum), exact sizes,
|
|
385
|
+
and canonical Base64 before any graph or provider operation. Individual decoded files remain bounded
|
|
386
|
+
to 7.5 MiB per module and 12 MiB per asset; all decoded deployment material shares a 32 MiB budget.
|
|
387
|
+
|
|
388
|
+
The previous top-level `contentBase64` and `contentBase64Chunks` fields remain accepted and are
|
|
389
|
+
explicitly deprecated. Roll out Services and install its new schema on consumer instances before
|
|
390
|
+
publishing the compressed SDK adapter. Old SDK clients continue working against the new Services;
|
|
391
|
+
new SDK requests are refused by an old schema without provider effects. The adapter never retries a
|
|
392
|
+
deployment using a different wire representation after an uncertain outcome.
|
|
393
|
+
|
|
394
|
+
Module names are unique and secrets use environment-variable identifiers. Plain and revisioned artifacts are
|
|
129
395
|
distinct modes and cannot replace each other at one Service record. Five-field cron expressions are
|
|
130
396
|
supported when `CLOUDFLARE_SCHEDULE_KV_ID` is configured.
|
|
131
397
|
|
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 { ActForOrganization, CloudflareDeployment, Deployment, DeploymentLine, OwnDeployment, OwnLine, TraverseOwnedLine, TraverseOwnedLineDeployment, deploymentCommit, deploymentHosting, deploymentLabel, deploymentLifecycle, deploymentRecord, deploymentRejection, deploymentRequest, deploymentResponse, deploymentRetention, deploymentRetirement, deploymentSecretDigests, deploymentSecretRejection, deploymentSummary, deployment_on_line, expirePreviewsOutput, frozenConfiguration, lastCallsOutput, listedDeploymentSummary, line_owned_by, MAXIMUM_LAST_CALL_LABELS, MAXIMUM_PREVIEW_EXPIRY_WRITES, retireDeploymentOutput, unadmittedDeploymentSummary, } from './modules/deployment/index.js';
|
|
7
|
+
export type { DeploymentHosting, DeploymentLifecycle, DeploymentLifecycleEvent, DeploymentRecord, DeploymentRejection, DeploymentRejectionReason, DeploymentRequest, DeploymentResponse, DeploymentRetention, DeploymentRetirement, DeploymentSecretDigest, DeploymentSecretRejection, DeploymentSummary, ExpirePreviewsResult, FrozenConfiguration, ListedDeploymentSummary, RetireDeploymentResult, UnadmittedDeploymentSummary, } 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 { ActForOrganization, CloudflareDeployment, Deployment, DeploymentLine, OwnDeployment, OwnLine, TraverseOwnedLine, TraverseOwnedLineDeployment, deploymentCommit, deploymentHosting, deploymentLabel, deploymentLifecycle, deploymentRecord, deploymentRejection, deploymentRequest, deploymentResponse, deploymentRetention, deploymentRetirement, deploymentSecretDigests, deploymentSecretRejection, deploymentSummary, deployment_on_line, expirePreviewsOutput, frozenConfiguration, lastCallsOutput, listedDeploymentSummary, line_owned_by, MAXIMUM_LAST_CALL_LABELS, MAXIMUM_PREVIEW_EXPIRY_WRITES, retireDeploymentOutput, unadmittedDeploymentSummary, } from './modules/deployment/index.js';
|