@spacefast/common 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (202) hide show
  1. package/README.md +42 -0
  2. package/dist/brand.d.ts +15 -0
  3. package/dist/brand.js +24 -0
  4. package/dist/config/domains.d.ts +30 -0
  5. package/dist/config/domains.js +75 -0
  6. package/dist/config/index.d.ts +1 -0
  7. package/dist/config/index.js +3 -0
  8. package/dist/contracts/abuse.d.ts +93 -0
  9. package/dist/contracts/abuse.js +50 -0
  10. package/dist/contracts/access.d.ts +409 -0
  11. package/dist/contracts/access.js +396 -0
  12. package/dist/contracts/account.d.ts +28 -0
  13. package/dist/contracts/account.js +54 -0
  14. package/dist/contracts/activity.d.ts +118 -0
  15. package/dist/contracts/activity.js +180 -0
  16. package/dist/contracts/analytics.d.ts +56 -0
  17. package/dist/contracts/analytics.js +91 -0
  18. package/dist/contracts/annotations.d.ts +327 -0
  19. package/dist/contracts/annotations.js +234 -0
  20. package/dist/contracts/api-keys.d.ts +517 -0
  21. package/dist/contracts/api-keys.js +235 -0
  22. package/dist/contracts/archives.d.ts +332 -0
  23. package/dist/contracts/archives.js +120 -0
  24. package/dist/contracts/auth.d.ts +86 -0
  25. package/dist/contracts/auth.js +82 -0
  26. package/dist/contracts/beta.d.ts +106 -0
  27. package/dist/contracts/beta.js +104 -0
  28. package/dist/contracts/billing.d.ts +328 -0
  29. package/dist/contracts/billing.js +203 -0
  30. package/dist/contracts/builds.d.ts +504 -0
  31. package/dist/contracts/builds.js +248 -0
  32. package/dist/contracts/channels.d.ts +49 -0
  33. package/dist/contracts/channels.js +51 -0
  34. package/dist/contracts/common.d.ts +238 -0
  35. package/dist/contracts/common.js +175 -0
  36. package/dist/contracts/deployments.d.ts +574 -0
  37. package/dist/contracts/deployments.js +97 -0
  38. package/dist/contracts/device-auth.d.ts +194 -0
  39. package/dist/contracts/device-auth.js +162 -0
  40. package/dist/contracts/domains.d.ts +6115 -0
  41. package/dist/contracts/domains.js +1435 -0
  42. package/dist/contracts/enums.d.ts +196 -0
  43. package/dist/contracts/enums.js +211 -0
  44. package/dist/contracts/error-code-meta.d.ts +1560 -0
  45. package/dist/contracts/error-code-meta.js +400 -0
  46. package/dist/contracts/error-codes.d.ts +13 -0
  47. package/dist/contracts/error-codes.js +416 -0
  48. package/dist/contracts/events.d.ts +398 -0
  49. package/dist/contracts/events.js +320 -0
  50. package/dist/contracts/fast-domain-search.d.ts +19 -0
  51. package/dist/contracts/fast-domain-search.js +22 -0
  52. package/dist/contracts/features.d.ts +240 -0
  53. package/dist/contracts/features.js +406 -0
  54. package/dist/contracts/git.d.ts +288 -0
  55. package/dist/contracts/git.js +116 -0
  56. package/dist/contracts/ids.d.ts +35 -0
  57. package/dist/contracts/ids.js +45 -0
  58. package/dist/contracts/intercom.d.ts +6 -0
  59. package/dist/contracts/intercom.js +5 -0
  60. package/dist/contracts/internal.d.ts +103 -0
  61. package/dist/contracts/internal.js +92 -0
  62. package/dist/contracts/mcp.d.ts +788 -0
  63. package/dist/contracts/mcp.js +161 -0
  64. package/dist/contracts/me.d.ts +81 -0
  65. package/dist/contracts/me.js +104 -0
  66. package/dist/contracts/oauth-resources.d.ts +30 -0
  67. package/dist/contracts/oauth-resources.js +61 -0
  68. package/dist/contracts/operations.d.ts +54 -0
  69. package/dist/contracts/operations.js +14 -0
  70. package/dist/contracts/plan-policy.d.ts +85 -0
  71. package/dist/contracts/plan-policy.js +75 -0
  72. package/dist/contracts/platform.d.ts +359 -0
  73. package/dist/contracts/platform.js +216 -0
  74. package/dist/contracts/push-new.d.ts +156 -0
  75. package/dist/contracts/push-new.js +52 -0
  76. package/dist/contracts/quotas.d.ts +16 -0
  77. package/dist/contracts/quotas.js +36 -0
  78. package/dist/contracts/repository-connections.d.ts +231 -0
  79. package/dist/contracts/repository-connections.js +106 -0
  80. package/dist/contracts/resources.d.ts +529 -0
  81. package/dist/contracts/resources.js +209 -0
  82. package/dist/contracts/routes.d.ts +45 -0
  83. package/dist/contracts/routes.js +31 -0
  84. package/dist/contracts/runtime-api.d.ts +449 -0
  85. package/dist/contracts/runtime-api.js +513 -0
  86. package/dist/contracts/sites.d.ts +393 -0
  87. package/dist/contracts/sites.js +121 -0
  88. package/dist/contracts/slugs.d.ts +31 -0
  89. package/dist/contracts/slugs.js +47 -0
  90. package/dist/contracts/space-config.d.ts +216 -0
  91. package/dist/contracts/space-config.js +237 -0
  92. package/dist/contracts/space-theme.d.ts +25 -0
  93. package/dist/contracts/space-theme.js +49 -0
  94. package/dist/contracts/spaces.d.ts +2760 -0
  95. package/dist/contracts/spaces.js +589 -0
  96. package/dist/contracts/superadmin-activity.d.ts +205 -0
  97. package/dist/contracts/superadmin-activity.js +107 -0
  98. package/dist/contracts/superadmin-emails.d.ts +212 -0
  99. package/dist/contracts/superadmin-emails.js +112 -0
  100. package/dist/contracts/superadmin-queues.d.ts +414 -0
  101. package/dist/contracts/superadmin-queues.js +202 -0
  102. package/dist/contracts/superadmin-runtime.d.ts +27 -0
  103. package/dist/contracts/superadmin-runtime.js +38 -0
  104. package/dist/contracts/superadmin-spaces.d.ts +429 -0
  105. package/dist/contracts/superadmin-spaces.js +82 -0
  106. package/dist/contracts/superadmin-tenants.d.ts +180 -0
  107. package/dist/contracts/superadmin-tenants.js +117 -0
  108. package/dist/contracts/superadmin.d.ts +654 -0
  109. package/dist/contracts/superadmin.js +309 -0
  110. package/dist/contracts/tags.d.ts +1140 -0
  111. package/dist/contracts/tags.js +1050 -0
  112. package/dist/contracts/teams.d.ts +233 -0
  113. package/dist/contracts/teams.js +174 -0
  114. package/dist/contracts/telemetry.d.ts +2 -0
  115. package/dist/contracts/telemetry.js +1 -0
  116. package/dist/contracts/transfers.d.ts +105 -0
  117. package/dist/contracts/transfers.js +48 -0
  118. package/dist/contracts/variables.d.ts +189 -0
  119. package/dist/contracts/variables.js +82 -0
  120. package/dist/contracts/webhooks.d.ts +159 -0
  121. package/dist/contracts/webhooks.js +59 -0
  122. package/dist/contracts/zero.d.ts +1538 -0
  123. package/dist/contracts/zero.js +755 -0
  124. package/dist/docs/agent-prose.d.ts +35 -0
  125. package/dist/docs/agent-prose.js +153 -0
  126. package/dist/docs/agent-setup.d.ts +6 -0
  127. package/dist/docs/agent-setup.js +164 -0
  128. package/dist/docs/agent-solutions.d.ts +110 -0
  129. package/dist/docs/agent-solutions.js +181 -0
  130. package/dist/docs/error-docs.d.ts +12 -0
  131. package/dist/docs/error-docs.js +1601 -0
  132. package/dist/docs/skill-distribution.d.ts +12 -0
  133. package/dist/docs/skill-distribution.js +18 -0
  134. package/dist/domain-exploration.d.ts +108 -0
  135. package/dist/domain-exploration.js +488 -0
  136. package/dist/domain-normalize.d.ts +1 -0
  137. package/dist/domain-normalize.js +14 -0
  138. package/dist/domain-zones.d.ts +1 -0
  139. package/dist/domain-zones.js +5272 -0
  140. package/dist/index.d.ts +1 -0
  141. package/dist/index.js +1 -0
  142. package/dist/utils/access-policy.d.ts +39 -0
  143. package/dist/utils/access-policy.js +232 -0
  144. package/dist/utils/api.d.ts +4 -0
  145. package/dist/utils/api.js +13 -0
  146. package/dist/utils/auth-redirect.d.ts +1 -0
  147. package/dist/utils/auth-redirect.js +48 -0
  148. package/dist/utils/auth.d.ts +5 -0
  149. package/dist/utils/auth.js +13 -0
  150. package/dist/utils/build-settings.d.ts +49 -0
  151. package/dist/utils/build-settings.js +366 -0
  152. package/dist/utils/claim-token.d.ts +1 -0
  153. package/dist/utils/claim-token.js +9 -0
  154. package/dist/utils/collections.d.ts +1 -0
  155. package/dist/utils/collections.js +5 -0
  156. package/dist/utils/concurrency.d.ts +1 -0
  157. package/dist/utils/concurrency.js +18 -0
  158. package/dist/utils/content-type.d.ts +10 -0
  159. package/dist/utils/content-type.js +145 -0
  160. package/dist/utils/error-display.d.ts +7 -0
  161. package/dist/utils/error-display.js +42 -0
  162. package/dist/utils/error.d.ts +1 -0
  163. package/dist/utils/error.js +3 -0
  164. package/dist/utils/generate-space-name.d.ts +14 -0
  165. package/dist/utils/generate-space-name.js +95 -0
  166. package/dist/utils/git-repository.d.ts +5 -0
  167. package/dist/utils/git-repository.js +99 -0
  168. package/dist/utils/guards.d.ts +1 -0
  169. package/dist/utils/guards.js +3 -0
  170. package/dist/utils/publish-detection.d.ts +10 -0
  171. package/dist/utils/publish-detection.js +118 -0
  172. package/dist/utils/publish-policy.d.ts +69 -0
  173. package/dist/utils/publish-policy.js +429 -0
  174. package/dist/utils/query-client.d.ts +7 -0
  175. package/dist/utils/query-client.js +21 -0
  176. package/dist/utils/query-keys.d.ts +75 -0
  177. package/dist/utils/query-keys.js +78 -0
  178. package/dist/utils/runtime-paths.d.ts +7 -0
  179. package/dist/utils/runtime-paths.js +28 -0
  180. package/dist/utils/runtime-upload.d.ts +19 -0
  181. package/dist/utils/runtime-upload.js +27 -0
  182. package/dist/utils/slug.d.ts +5 -0
  183. package/dist/utils/slug.js +13 -0
  184. package/dist/utils/space-config.d.ts +75 -0
  185. package/dist/utils/space-config.js +415 -0
  186. package/dist/utils/space-theme.d.ts +16 -0
  187. package/dist/utils/space-theme.js +89 -0
  188. package/dist/utils/static-runtime-policy.d.ts +17 -0
  189. package/dist/utils/static-runtime-policy.js +103 -0
  190. package/dist/utils/upload-session.d.ts +34 -0
  191. package/dist/utils/upload-session.js +69 -0
  192. package/dist/utils/urls.d.ts +2 -0
  193. package/dist/utils/urls.js +7 -0
  194. package/dist/utils/version-path.d.ts +6 -0
  195. package/dist/utils/version-path.js +51 -0
  196. package/dist/utils/wpcom-auth-redirects.d.ts +14 -0
  197. package/dist/utils/wpcom-auth-redirects.js +49 -0
  198. package/dist/utils/zero-realtime-signature.d.ts +12 -0
  199. package/dist/utils/zero-realtime-signature.js +45 -0
  200. package/dist/vocabulary.d.ts +230 -0
  201. package/dist/vocabulary.js +218 -0
  202. package/package.json +58 -0
@@ -0,0 +1,396 @@
1
+ import { z } from "zod";
2
+ // Unified access contracts (internal-docs/stattic-model-plan.html "Section I ·
3
+ // access" + internal-docs/access-management-plan.md).
4
+ //
5
+ // Unified access contracts (the one access & policy lane). The headline
6
+ // simplification: **firewall ⊂ access** — there is exactly one Rule schema, and
7
+ // an anonymous firewall rule is simply a Rule whose `auth` is absent. The
8
+ // runtime enforces a verifiable subset (password secret-compare + token
9
+ // Ed25519/grant-intersection + anonymous firewall); the cloud resolves identity
10
+ // and mints signed tokens. Field names are the spec contract — do not rename.
11
+ // ---------------------------------------------------------------------------
12
+ // 1. Grants
13
+ // ---------------------------------------------------------------------------
14
+ // A grant is a string in a verified token (or a `requiredGrants` entry on a
15
+ // rule). Identity is a string set: the runtime is a verifier and
16
+ // set-intersector — a visitor passes when `grants ∩ requiredGrants ≠ ∅`.
17
+ //
18
+ // Grants are globs. One namespace per kind, with `*` wildcards permitted in
19
+ // `requiredGrants` so a rule can name a class of identities:
20
+ //
21
+ // email:alice@acme.com a single verified email
22
+ // email:*@acme.com any verified email on a domain (glob)
23
+ // team:team_123:member top-level team membership at a role
24
+ // sub-team:sub_123:member enterprise group membership inside a team
25
+ // user:<handle> a specific platform person
26
+ // svc:<tokenId> a service token (CI, agents)
27
+ // ext:{connectionId}:<tag> an owner-defined external grant
28
+ //
29
+ // Tokens signed by an external (BYO) key may only carry grants namespaced to
30
+ // that key (see `accessKeySchema.grantNamespaces`); everything else is dropped
31
+ // before intersection.
32
+ export const grantSchema = z.string().min(1).max(255);
33
+ // Known grant namespace prefixes. Useful for validation/UX; not exhaustive of
34
+ // every future namespace, but covers the documented vocabulary.
35
+ export const GRANT_NAMESPACES = [
36
+ "email:",
37
+ "team:",
38
+ "sub-team:",
39
+ "user:",
40
+ "svc:",
41
+ "ext:",
42
+ // Mint-time-only namespaces (sources the cloud resolves into the above, plus
43
+ // transient grants the runtime mints itself).
44
+ "email-domain:",
45
+ "space:",
46
+ "link:",
47
+ "sso:",
48
+ "pw:", // minted by a form-transport password challenge
49
+ ];
50
+ const GRANT_PATTERN = /^(email|email-domain|team|sub-team|user|svc|ext|space|link|sso|pw):.+$/;
51
+ // Validator for grant globs like "email:*@acme.com", "team:team_123:member",
52
+ // "sub-team:sub_123:member", "user:<h>", "svc:…", "ext:{conn}:…". Returns true when the grant string is a
53
+ // well-formed `namespace:value`. This is advisory (the runtime intersects
54
+ // opaque strings); use it for authoring-surface validation, not enforcement.
55
+ export function isWellFormedGrant(grant) {
56
+ return GRANT_PATTERN.test(grant);
57
+ }
58
+ // A `requiredGrants` entry may contain `*` wildcards; a minted token grant must
59
+ // be concrete (no `*`). Both share `grantSchema`; this narrows the authoring
60
+ // case.
61
+ export const requiredGrantSchema = grantSchema.refine(isWellFormedGrant, {
62
+ message: "grant must be namespaced, e.g. email:*@acme.com, team:team_123:member, sub-team:sub_123:member, user:<h>, svc:…, ext:{conn}:…",
63
+ });
64
+ // ---------------------------------------------------------------------------
65
+ // 2. Issuer registry
66
+ // ---------------------------------------------------------------------------
67
+ // A registered signing key. SSO + BYO-issuer keys are registered once at
68
+ // team/space level; rules reference grants, and a token's grants are dropped
69
+ // unless namespaced to one of `grantNamespaces`. Service tokens are just tokens
70
+ // carrying `svc:` grants signed by a platform key.
71
+ export const accessKeySchema = z.object({
72
+ kid: z.string().min(1).describe("Key id; matches the token header `kid`."),
73
+ alg: z.literal("EdDSA"),
74
+ publicKey: z.string().min(1).describe("base64url-encoded raw Ed25519 public key."),
75
+ // Grants in a token signed by this key are DROPPED unless prefixed by one of
76
+ // these. Platform keys list the platform prefixes
77
+ // (["team:","sub-team:","user:","email:","email-domain:","space:","link:","svc:","sso:"]);
78
+ // external keys list exactly ["ext:{connectionId}:"], bounding a leaked key's
79
+ // blast radius to the rules the owner pointed at it.
80
+ grantNamespaces: z.array(z.string().min(1)).min(1),
81
+ });
82
+ // ---------------------------------------------------------------------------
83
+ // 3. The unified runtime Rule (firewall = a rule with no auth)
84
+ // ---------------------------------------------------------------------------
85
+ // The `auth` object: pass when EITHER the password OR the token leg is
86
+ // satisfied. Folds the old basicAuth / sso / login / composite requirement
87
+ // types into two legs. An absent `auth` makes the rule an anonymous firewall
88
+ // rule (effect applies on match, no credential needed) — this is the sense in
89
+ // which **firewall ⊂ access**.
90
+ export const passwordAuthSchema = z.object({
91
+ // A secret reference (e.g. "secret:site_pw"), never plaintext. The runtime
92
+ // resolves it from serving secrets and compares.
93
+ ref: z.string().min(1),
94
+ // `basic` = stateless HTTP Basic 401 challenge. `form` = renders the password
95
+ // wall, and on success mints a short-lived `pw:` grant cookie.
96
+ transport: z.enum(["basic", "form"]),
97
+ username: z.string().min(1).optional(),
98
+ });
99
+ export const tokenAuthSchema = z.object({
100
+ // ANY-OF: the visitor's verified grants must intersect this set. Entries may
101
+ // be globs (e.g. "email:*@acme.com").
102
+ requiredGrants: z.array(grantSchema).min(1),
103
+ // Issuer keys whose tokens are accepted for this rule. When omitted, the
104
+ // compiler fills in the applicable platform/registered keys. Tokens signed by
105
+ // a key contribute only grants within that key's `grantNamespaces`.
106
+ issuers: z.array(accessKeySchema).optional(),
107
+ // Interactive login surface the runtime 302-redirects an unsatisfied browser
108
+ // visitor to (with an opaque `return=` param). Absent = no interactive login
109
+ // (service-token-only rule) and the runtime denies a browser rather than loop.
110
+ loginUrl: z.string().min(1).optional(),
111
+ // Cookie name the runtime reads the visitor token from (default
112
+ // `stattic_access`); the Authorization Bearer header always takes precedence.
113
+ cookieName: z.string().min(1).optional(),
114
+ });
115
+ export const ruleAuthSchema = z
116
+ .object({
117
+ password: passwordAuthSchema.optional(),
118
+ token: tokenAuthSchema.optional(),
119
+ })
120
+ .refine((a) => a.password !== undefined || a.token !== undefined, {
121
+ message: "auth must specify at least one of `password` or `token`",
122
+ });
123
+ // Match conditions AND together (host AND path AND channel AND ipCidrs AND …).
124
+ // All fields optional; an empty match matches everything in scope.
125
+ export const ruleMatchSchema = z.object({
126
+ host: z.string().min(1).optional(),
127
+ // Glob path pattern: "/docs/**" | "/docs/*" | "/x.html".
128
+ pathPattern: z.string().min(1).optional(),
129
+ // Serving context channel name (e.g. "live", "staging").
130
+ channel: z.string().min(1).optional(),
131
+ // CIDR v4/v6 list; the request IP must fall in one of these.
132
+ ipCidrs: z.array(z.string().min(1)).max(50).optional(),
133
+ // User-agent matcher (e.g. block a crawler, gate an agent).
134
+ agent: z.string().min(1).optional(),
135
+ // ISO 3166-1 alpha-2 country code matcher.
136
+ country: z.string().min(2).max(2).optional(),
137
+ // Single request-header matcher: name + expected value.
138
+ header: z.object({ name: z.string().min(1), value: z.string() }).optional(),
139
+ });
140
+ // The one Rule. `match` (AND) selects requests; `effect` is what happens on
141
+ // match; `auth` (absent = anonymous firewall) gates `challenge`/`allow`.
142
+ export const runtimeRuleSchema = z.object({
143
+ match: ruleMatchSchema.default({}),
144
+ effect: z.enum(["allow", "deny", "challenge"]),
145
+ // Absent = anonymous firewall rule (no credential required). Present = pass
146
+ // when the password OR token leg is satisfied.
147
+ auth: ruleAuthSchema.optional(),
148
+ // Surfaced on a `deny` (X-Spacefast-Reason header) and the rendered platform
149
+ // page so an operator/visitor can tell which rule fired and why.
150
+ reasonCode: z.string().min(1).optional(),
151
+ message: z.string().min(1).optional(),
152
+ });
153
+ // ---------------------------------------------------------------------------
154
+ // 3b. Visitor token (the cloud "mint" half)
155
+ // ---------------------------------------------------------------------------
156
+ // The default cookie the runtime reads a visitor token from when a rule's token
157
+ // leg names no explicit `cookieName` (see access-rules.php
158
+ // `_stattic_unified_token_from_request`). The authorize endpoint sets the
159
+ // minted token under this name so the very next request to the protected host
160
+ // carries it.
161
+ export const ACCESS_TOKEN_COOKIE_NAME = "stattic_access";
162
+ // The header `kid`/`alg` the platform signs visitor tokens with. These match
163
+ // the runtime JWKS key (`stattic-runtime-v1` / EdDSA) so the runtime's
164
+ // JWKS-by-kid verify (access-rules.php) accepts a token the cloud minted. Do
165
+ // NOT introduce a second key system — these constants name the existing one.
166
+ export const ACCESS_TOKEN_KID = "stattic-runtime-v1";
167
+ export const ACCESS_TOKEN_ALG = "EdDSA";
168
+ // The DEDICATED `kid` Cast access tokens are signed under (CAST-NATIVE-PLAN
169
+ // decision D-1). It is published in the SAME JWKS as the runtime key, but is
170
+ // distinct so the runtime's JWKS-by-kid verify (which only accepts
171
+ // `ACCESS_TOKEN_KID`) refuses a Cast token outright, decoupling Cast key
172
+ // rotation from the runtime. Cast selects the verifying key by this `kid`.
173
+ export const CAST_TOKEN_KID = "spacefast-cast-v1";
174
+ // The claim set carried by a minted visitor token. `grants` are concrete
175
+ // (no `*`), `email:`/`user:`/`team:<teamId>:<role>`/`sub-team:<subTeamId>:<role>` namespaced so they survive
176
+ // the platform issuer's `grantNamespaces` filter at the runtime. `aud`, when
177
+ // present, lowercases-binds the token to a single serving host.
178
+ export const accessTokenPayloadSchema = z.object({
179
+ // Subject: the authenticated platform user id the token was minted for.
180
+ sub: z.string().min(1),
181
+ // Concrete (non-glob) grants. The runtime intersects these with a rule's
182
+ // `requiredGrants`; the visitor passes when the intersection is non-empty.
183
+ grants: z.array(grantSchema).default([]),
184
+ // Unix seconds. Mirrors the runtime's exp check (300s leeway).
185
+ exp: z.number().int().nonnegative(),
186
+ nbf: z.number().int().nonnegative().optional(),
187
+ iat: z.number().int().nonnegative().optional(),
188
+ iss: z.string().min(1).optional(),
189
+ // Optional host binding (lowercased) — when set the token is only accepted on
190
+ // that serving host.
191
+ aud: z.string().min(1).optional(),
192
+ });
193
+ // Authorize request: the bounded authenticated-team-member mint path. The
194
+ // caller is already an authenticated session; the body only tunes the mint.
195
+ // `setCookie` (default true) asks the endpoint to also set the access cookie so
196
+ // the next navigation to the protected host is authorized without the client
197
+ // re-attaching the token. `aud` optionally binds the token to one host.
198
+ export const authorizeRequestSchema = z.object({
199
+ setCookie: z.boolean().default(true),
200
+ aud: z.string().min(1).optional(),
201
+ });
202
+ // Authorize response: the signed compact JWT plus its decoded claims (so a
203
+ // caller can show/inspect the grants without re-parsing) and whether the access
204
+ // cookie was set on the response.
205
+ export const authorizeResponseSchema = z.object({
206
+ // The signed compact EdDSA JWT (`header.claims.signature`, base64url).
207
+ token: z.string().min(1),
208
+ // Decoded claims of `token` (echo of what was signed).
209
+ payload: accessTokenPayloadSchema,
210
+ // Unix seconds the token expires at (convenience mirror of `payload.exp`).
211
+ expiresAt: z.number().int().nonnegative(),
212
+ // The cookie name the token was set under, or null when `setCookie` was false.
213
+ cookieName: z.string().min(1).nullable().default(null),
214
+ });
215
+ // ---------------------------------------------------------------------------
216
+ // 3c. Mint-time grant builders (the cloud "resolve identity → grants" half)
217
+ // ---------------------------------------------------------------------------
218
+ // The concrete grant a space invitee carries once they accept: a token with
219
+ // `space:{spaceId}:viewer` intersects the `invited`-audience rule the compiler
220
+ // emits (`requiredGrants: ["space:{spaceId}:viewer"]` + team grants, §6.3).
221
+ // The platform issuer lists the `space:` namespace, so the runtime keeps it.
222
+ export function spaceViewerGrant(spaceId) {
223
+ return `space:${spaceId}:viewer`;
224
+ }
225
+ // The leveled space grant an invited reviewer carries (CAST-NATIVE-PLAN D-2/
226
+ // D-4): `space:{spaceId}:{level}` where level ∈ viewer|commenter|editor. The
227
+ // `space:` namespace is on the platform issuer (resolve.ts `platformIssuer`), so
228
+ // the runtime keeps it; Cast reads the level off the token to key its
229
+ // capability table. `spaceViewerGrant` is the `viewer` special case kept for the
230
+ // accepted-invite path; this is the general leveled form the reviewer people
231
+ // layer reconciles and the Cast mint carries.
232
+ export function spaceLevelGrant(spaceId, level) {
233
+ return `space:${spaceId}:${level}`;
234
+ }
235
+ // The concrete grant a share-link holder carries: a token with `link:{linkId}`
236
+ // intersects the `shareLinks`-audience rule whose `requiredGrants` the compiler
237
+ // fills from the ACTIVE link rows (§6.4). Revoking the link recompiles it out
238
+ // and the token goes inert. The platform issuer lists the `link:` namespace.
239
+ export function shareLinkGrant(linkId) {
240
+ return `link:${linkId}`;
241
+ }
242
+ // ---------------------------------------------------------------------------
243
+ // 3d. Invite + share-link mint surface (request/response contracts)
244
+ // ---------------------------------------------------------------------------
245
+ //
246
+ // ADDITIVE / NOT-YET-WIRED: the request/response shapes for the invite and
247
+ // share-link minting endpoints described in access-management-plan.md §6.3/§6.4
248
+ // and §9. The persistence (the `spaceInvites` / `shareLinks` tables, magic-token
249
+ // hashing, accept/create/revoke routes, the recompile-on-revoke step, and the
250
+ // request-access loop) needs DB migrations + email and is specified in
251
+ // internal-docs/invite-minting-plan.md — these schemas are the contract that
252
+ // plan's endpoints will validate against, safe to land first.
253
+ // `POST /v1/spaces/:id/invites` body (§6.3). Invites a single email as a space
254
+ // viewer. The email is lowercased + NFC-normalized server-side before storage.
255
+ export const inviteCreateRequestSchema = z.object({
256
+ email: z.string().email(),
257
+ // Optional invite-link validity in days (default 7d at the route).
258
+ expiresInDays: z.number().int().positive().max(365).optional(),
259
+ // Optional note shown in the invite email.
260
+ message: z.string().max(300).optional(),
261
+ });
262
+ // A pending/accepted/revoked invite as surfaced to owners. The magic token is
263
+ // NEVER returned — only its lifecycle. `id` is `sin_…`.
264
+ export const spaceInviteSchema = z.object({
265
+ id: z.string().min(1),
266
+ spaceId: z.string().min(1),
267
+ email: z.string().email(),
268
+ status: z.enum(["pending", "accepted", "revoked", "expired"]),
269
+ // The viewer grant this invite mints on acceptance — surfaced so the owner can
270
+ // see exactly what it grants (`space:{spaceId}:viewer`).
271
+ grant: z.string().min(1),
272
+ invitedBy: z.string().min(1).nullable().default(null),
273
+ expiresAt: z.string().min(1).nullable().default(null),
274
+ acceptedAt: z.string().min(1).nullable().default(null),
275
+ revokedAt: z.string().min(1).nullable().default(null),
276
+ createdAt: z.string().min(1),
277
+ });
278
+ // `POST /v1/spaces/:id/share-links` body (§6.4). Creates an "anyone with the
279
+ // link" grant scoped to a path prefix, with an optional expiry + label.
280
+ export const shareLinkCreateRequestSchema = z.object({
281
+ // "/" = the whole space. Must be an absolute, backslash-free path.
282
+ pathPrefix: z
283
+ .string()
284
+ .regex(/^\/[^\\]*$/)
285
+ .default("/"),
286
+ // Absent = a non-expiring link.
287
+ expiresAt: z.string().min(1).optional(),
288
+ label: z.string().max(120).optional(),
289
+ });
290
+ // A share link as surfaced to owners. `url` (the token-bearing URL) is returned
291
+ // ONLY on the create response (the runtime trades `?stattic_share=` for a
292
+ // cookie once); list/read responses omit it and show only the lifecycle. `id`
293
+ // is `lnk_…`; `grant` is `link:{id}`.
294
+ export const shareLinkSchema = z.object({
295
+ id: z.string().min(1),
296
+ spaceId: z.string().min(1),
297
+ pathPrefix: z.string().min(1),
298
+ label: z.string().nullable().default(null),
299
+ grant: z.string().min(1),
300
+ // The token-bearing URL — present only on create; null on list/read.
301
+ url: z.string().min(1).nullable().default(null),
302
+ createdBy: z.string().min(1).nullable().default(null),
303
+ expiresAt: z.string().min(1).nullable().default(null),
304
+ revokedAt: z.string().min(1).nullable().default(null),
305
+ createdAt: z.string().min(1),
306
+ });
307
+ // ---------------------------------------------------------------------------
308
+ // 4. Lanes / nouns (additive types only — not wired)
309
+ // ---------------------------------------------------------------------------
310
+ // A channel is a named serving lane (e.g. "live", "staging") pointing at a
311
+ // version, with promote/rollback history.
312
+ export const channelSchema = z.object({
313
+ name: z.string().min(1),
314
+ versionId: z.string().min(1),
315
+ // Newest-first promote/rollback log: which version this channel pointed at.
316
+ history: z
317
+ .array(z.object({
318
+ versionId: z.string().min(1),
319
+ at: z.string().min(1).describe("ISO 8601 timestamp."),
320
+ }))
321
+ .default([]),
322
+ });
323
+ // Content-lane serving config (scalar, field-ownership / SSA semantics). No
324
+ // `spa` toggle — that mode is gone; a SPA is expressed as a `fallback`.
325
+ export const servingConfigSchema = z.object({
326
+ // Directory index document (e.g. "index.html").
327
+ index: z.string().min(1).optional(),
328
+ // Single fallback document served when no file/route matches (replaces the
329
+ // old `spa` boolean).
330
+ fallback: z.string().min(1).optional(),
331
+ // Whether directory listings are rendered when there is no index.
332
+ listing: z.boolean().optional(),
333
+ });
334
+ // The policy-lane document: an ordered, additive list of unified Rules. This is
335
+ // the firewall+access lane (own version + rollback, independent of content).
336
+ export const policyDocSchema = z.object({
337
+ rules: z.array(runtimeRuleSchema).default([]),
338
+ });
339
+ // ---------------------------------------------------------------------------
340
+ // 5. Storage + resolution shapes (additive)
341
+ // ---------------------------------------------------------------------------
342
+ // The CLOUD-stored policy for one space. This is the persisted, versioned form
343
+ // of the policy lane: an ordered list of unified Rules plus a monotonic
344
+ // `version` so the lane can promote/rollback independently of content (mirrors
345
+ // `channelSchema.history`). `version` is bumped on every write; a write that
346
+ // supplies a stale `version` is a lost-update and is rejected by the resolver.
347
+ //
348
+ // Provenance: these are the "cloud" rules. They are merged with any "file"
349
+ // rules compiled from the space's `sf.jsonc` (which travel + roll back
350
+ // WITH a content version) to produce the effective policy — see
351
+ // `effectiveRuleSchema` / `effectivePolicySchema`.
352
+ export const spacePolicySchema = z.object({
353
+ // Ordered, additive Rules (first-match-wins at serving compile time). Same
354
+ // unified Rule the runtime verifies; an absent `auth` is an anonymous
355
+ // firewall rule (firewall ⊂ access).
356
+ rules: z.array(runtimeRuleSchema).default([]),
357
+ // Monotonic lane version. Starts at 1 on first write; every accepted write
358
+ // increments it. Used for optimistic concurrency (lost-update rejection) and
359
+ // for rollback to a prior lane revision.
360
+ version: z.number().int().nonnegative().default(0),
361
+ });
362
+ // Where an effective rule came from. `platform` = composed by the cloud from
363
+ // platform state (plan window, abuse/ban/billing) and PREPENDED above every
364
+ // user-authored rule so a platform decision always wins first-match-wins; the
365
+ // user can NEVER author a `platform` rule. `file` = compiled from the space's
366
+ // `sf.jsonc` (timeless, rolls back with the content version). `cloud` =
367
+ // the stored `spacePolicySchema` lane (incident interventions, password walls
368
+ // set via the API/CLI, etc.). Provenance is surfaced so an operator reading the
369
+ // effective policy can tell which surface to edit to change a given rule.
370
+ export const ruleSourceSchema = z.enum(["platform", "file", "cloud"]);
371
+ // A provenance-annotated effective Rule: the unified `runtimeRuleSchema` plus
372
+ // the `source` it was contributed by and the `order` it occupies in the
373
+ // resolved, first-match-wins list. This is the READ shape returned by the
374
+ // effective-policy resolver — never stored. `order` is the 0-based index in the
375
+ // flattened effective list (file rules then cloud rules, or whatever order the
376
+ // resolver composes), letting a caller reconstruct match precedence.
377
+ export const effectiveRuleSchema = runtimeRuleSchema.extend({
378
+ source: ruleSourceSchema,
379
+ order: z.number().int().nonnegative(),
380
+ });
381
+ // The resolved effective policy for a space: the flattened, provenance-tagged
382
+ // rule list plus the `cloudVersion` (the `spacePolicySchema.version` the cloud
383
+ // rules were resolved from) so a reader can detect drift / pin a write against
384
+ // the revision it observed. `fileVersion` is the content version id the `file`
385
+ // rules were compiled from (null when the space has no compiled file rules).
386
+ export const effectivePolicySchema = z.object({
387
+ rules: z.array(effectiveRuleSchema).default([]),
388
+ cloudVersion: z.number().int().nonnegative().default(0),
389
+ fileVersion: z.string().min(1).nullable().default(null),
390
+ // Serving-secret map (name -> value) the resolved rules reference by
391
+ // `auth.password.ref` = "secret:<name>". Today this carries the space
392
+ // password's bcrypt verifier hash, keyed so the runtime resolves it from
393
+ // `serving['secrets']` and `password_verify`s against it. Never contains
394
+ // plaintext the visitor types — only stored verifier hashes / shared secrets.
395
+ secrets: z.record(z.string().min(1), z.string().min(1)).default({}),
396
+ });
@@ -0,0 +1,28 @@
1
+ import { z } from "zod";
2
+ export declare const accessTokenScope: z.ZodEnum<{
3
+ "account:read": "account:read";
4
+ "account:write": "account:write";
5
+ "team:read": "team:read";
6
+ "team:write": "team:write";
7
+ "space:read": "space:read";
8
+ "space:write": "space:write";
9
+ "domain:read": "domain:read";
10
+ "domain:write": "domain:write";
11
+ }>;
12
+ export type AccessTokenScope = z.infer<typeof accessTokenScope>;
13
+ export declare const ACCESS_TOKEN_SCOPE_DEFINITIONS: {
14
+ value: AccessTokenScope;
15
+ label: string;
16
+ description: string;
17
+ }[];
18
+ export declare const DEFAULT_ACCESS_TOKEN_SCOPES: AccessTokenScope[];
19
+ export type AuthSession = {
20
+ session: {
21
+ id: string;
22
+ };
23
+ user: {
24
+ id: string;
25
+ email?: string | null | undefined;
26
+ name?: string | null | undefined;
27
+ };
28
+ };
@@ -0,0 +1,54 @@
1
+ import { z } from "zod";
2
+ export const accessTokenScope = z.enum([
3
+ "account:read",
4
+ "account:write",
5
+ "team:read",
6
+ "team:write",
7
+ "space:read",
8
+ "space:write",
9
+ "domain:read",
10
+ "domain:write",
11
+ ]);
12
+ export const ACCESS_TOKEN_SCOPE_DEFINITIONS = [
13
+ {
14
+ value: "account:read",
15
+ label: "Read account",
16
+ description: "View account details, active sessions, and existing access tokens.",
17
+ },
18
+ {
19
+ value: "account:write",
20
+ label: "Manage account",
21
+ description: "Update account settings and revoke or create account-scoped credentials.",
22
+ },
23
+ {
24
+ value: "team:read",
25
+ label: "Read teams",
26
+ description: "View team membership, billing, activity, secrets, and settings.",
27
+ },
28
+ {
29
+ value: "team:write",
30
+ label: "Manage teams",
31
+ description: "Change team settings and manage members, invitations, or secrets.",
32
+ },
33
+ {
34
+ value: "space:read",
35
+ label: "Read spaces",
36
+ description: "View spaces, versions, diagnostics, variables, and runtime status.",
37
+ },
38
+ {
39
+ value: "space:write",
40
+ label: "Manage spaces",
41
+ description: "Create, update, publish, and delete spaces, versions, or variables.",
42
+ },
43
+ {
44
+ value: "domain:read",
45
+ label: "Read domains",
46
+ description: "Inspect custom domains, DNS state, and assignment details.",
47
+ },
48
+ {
49
+ value: "domain:write",
50
+ label: "Manage domains",
51
+ description: "Attach, update, verify, or remove space and team domains.",
52
+ },
53
+ ];
54
+ export const DEFAULT_ACCESS_TOKEN_SCOPES = ["account:read"];
@@ -0,0 +1,118 @@
1
+ import { z } from "zod";
2
+ export declare const ACTIVITY_EVENT_CODES: readonly ["space.created", "space.claimed", "space.transferred", "space.moved", "space.expired", "space.disabled", "space.enabled", "space.deleted", "space.config_updated", "space.password_updated", "version.created", "version.ready", "version.warning", "version.failed", "version.expired", "version.canceled", "version.deleted", "version.retention_warning", "version.retention_deleted", "channel.promoted", "build.created", "build.succeeded", "build.failed", "build.canceled", "build.skipped", "domain.created", "domain.verified", "domain.verification_failed", "domain.control_lost", "domain.dns_updated", "domain.nameservers_updated", "domain.registration_purchased", "domain.registration_renewed", "domain.registration_expiring", "domain.registration_expired", "domain.transfer_in_started", "domain.transfer_out_started", "domain.deleted", "binding.created", "binding.activated", "binding.blocked", "binding.deleted", "transfer.requested", "transfer.confirmed", "transfer.completed", "transfer.canceled", "transfer.expired", "transfer.failed", "variable.updated", "variable.deleted", "api_key.created", "api_key.updated", "api_key.revoked", "webhook.created", "webhook.updated", "webhook.secret_rotated", "webhook.disabled", "team.updated", "team.member_added", "team.member_removed", "team.member_role_updated", "team.builds_deploys_quota_exceeded", "tenant.past_due", "tenant.suspended", "tenant.reactivated", "tenant.deleted", "export.ready", "export.failed", "import.ready", "import.failed", "annotation.token_minted", "annotation.created", "annotation.comment_created", "annotation.resolved", "annotation.reopened", "annotation.archived", "abuse_report.created", "abuse_report.updated", "claim.blocked_takedown", "user.created", "user.signed_in", "user.deleted", "user.impersonation_started", "user.impersonation_stopped", "user.two_factor_enabled", "user.two_factor_disabled"];
3
+ export type ActivityEventCode = (typeof ACTIVITY_EVENT_CODES)[number];
4
+ export declare function isActivityEventCode(value: string): value is ActivityEventCode;
5
+ export declare function isValidActivityEventFilter(filter: string): boolean;
6
+ export declare function matchesActivityEventFilters(filters: readonly string[], code: string): boolean;
7
+ export declare const activityActorSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
8
+ type: z.ZodLiteral<"user">;
9
+ id: z.ZodString;
10
+ }, z.core.$strip>, z.ZodObject<{
11
+ type: z.ZodLiteral<"api_key">;
12
+ id: z.ZodString;
13
+ }, z.core.$strip>, z.ZodObject<{
14
+ type: z.ZodLiteral<"oauth_client">;
15
+ id: z.ZodString;
16
+ }, z.core.$strip>, z.ZodObject<{
17
+ type: z.ZodLiteral<"anonymous_claim">;
18
+ id: z.ZodString;
19
+ }, z.core.$strip>, z.ZodObject<{
20
+ type: z.ZodLiteral<"system">;
21
+ id: z.ZodString;
22
+ }, z.core.$strip>], "type">;
23
+ export declare const activityPrincipalSchema: z.ZodObject<{
24
+ tenantId: z.ZodString;
25
+ principalType: z.ZodEnum<{
26
+ external: "external";
27
+ team: "team";
28
+ }>;
29
+ principalId: z.ZodString;
30
+ }, z.core.$strip>;
31
+ export declare const activityEventSchema: z.ZodObject<{
32
+ id: z.ZodString;
33
+ sequence: z.ZodNumber;
34
+ tenantId: z.ZodString;
35
+ principal: z.ZodNullable<z.ZodObject<{
36
+ tenantId: z.ZodString;
37
+ principalType: z.ZodEnum<{
38
+ external: "external";
39
+ team: "team";
40
+ }>;
41
+ principalId: z.ZodString;
42
+ }, z.core.$strip>>;
43
+ spaceId: z.ZodNullable<z.ZodString>;
44
+ actor: z.ZodDiscriminatedUnion<[z.ZodObject<{
45
+ type: z.ZodLiteral<"user">;
46
+ id: z.ZodString;
47
+ }, z.core.$strip>, z.ZodObject<{
48
+ type: z.ZodLiteral<"api_key">;
49
+ id: z.ZodString;
50
+ }, z.core.$strip>, z.ZodObject<{
51
+ type: z.ZodLiteral<"oauth_client">;
52
+ id: z.ZodString;
53
+ }, z.core.$strip>, z.ZodObject<{
54
+ type: z.ZodLiteral<"anonymous_claim">;
55
+ id: z.ZodString;
56
+ }, z.core.$strip>, z.ZodObject<{
57
+ type: z.ZodLiteral<"system">;
58
+ id: z.ZodString;
59
+ }, z.core.$strip>], "type">;
60
+ code: z.ZodString;
61
+ message: z.ZodString;
62
+ details: z.ZodNullable<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
63
+ createdAt: z.ZodString;
64
+ }, z.core.$strip>;
65
+ export declare const activityQuerySchema: z.ZodObject<{
66
+ limit: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
67
+ cursor: z.ZodOptional<z.ZodString>;
68
+ principalType: z.ZodOptional<z.ZodEnum<{
69
+ external: "external";
70
+ team: "team";
71
+ }>>;
72
+ principalId: z.ZodOptional<z.ZodString>;
73
+ spaceId: z.ZodOptional<z.ZodString>;
74
+ code: z.ZodOptional<z.ZodString>;
75
+ since: z.ZodOptional<z.ZodString>;
76
+ until: z.ZodOptional<z.ZodString>;
77
+ }, z.core.$strip>;
78
+ export declare const activityListResponseSchema: z.ZodObject<{
79
+ data: z.ZodArray<z.ZodObject<{
80
+ id: z.ZodString;
81
+ sequence: z.ZodNumber;
82
+ tenantId: z.ZodString;
83
+ principal: z.ZodNullable<z.ZodObject<{
84
+ tenantId: z.ZodString;
85
+ principalType: z.ZodEnum<{
86
+ external: "external";
87
+ team: "team";
88
+ }>;
89
+ principalId: z.ZodString;
90
+ }, z.core.$strip>>;
91
+ spaceId: z.ZodNullable<z.ZodString>;
92
+ actor: z.ZodDiscriminatedUnion<[z.ZodObject<{
93
+ type: z.ZodLiteral<"user">;
94
+ id: z.ZodString;
95
+ }, z.core.$strip>, z.ZodObject<{
96
+ type: z.ZodLiteral<"api_key">;
97
+ id: z.ZodString;
98
+ }, z.core.$strip>, z.ZodObject<{
99
+ type: z.ZodLiteral<"oauth_client">;
100
+ id: z.ZodString;
101
+ }, z.core.$strip>, z.ZodObject<{
102
+ type: z.ZodLiteral<"anonymous_claim">;
103
+ id: z.ZodString;
104
+ }, z.core.$strip>, z.ZodObject<{
105
+ type: z.ZodLiteral<"system">;
106
+ id: z.ZodString;
107
+ }, z.core.$strip>], "type">;
108
+ code: z.ZodString;
109
+ message: z.ZodString;
110
+ details: z.ZodNullable<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
111
+ createdAt: z.ZodString;
112
+ }, z.core.$strip>>;
113
+ pagination: z.ZodObject<{
114
+ nextCursor: z.ZodNullable<z.ZodString>;
115
+ hasMore: z.ZodBoolean;
116
+ }, z.core.$strip>;
117
+ }, z.core.$strip>;
118
+ export type ActivityEvent = z.infer<typeof activityEventSchema>;