@spacefast/common 0.0.12 → 0.0.17

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 (189) hide show
  1. package/dist/agents/client-registry.d.ts +22 -0
  2. package/dist/agents/client-registry.js +41 -0
  3. package/dist/agents/connect-targets.d.ts +51 -6
  4. package/dist/agents/connect-targets.js +93 -28
  5. package/dist/brand.d.ts +0 -11
  6. package/dist/brand.js +0 -20
  7. package/dist/config/domains.d.ts +15 -6
  8. package/dist/config/domains.js +24 -10
  9. package/dist/config/postgres-budget.d.ts +3 -0
  10. package/dist/config/postgres-budget.js +6 -1
  11. package/dist/config/postgres-budget.json +2 -1
  12. package/dist/contracts/abuse.js +1 -1
  13. package/dist/contracts/access.d.ts +486 -1196
  14. package/dist/contracts/access.js +323 -1054
  15. package/dist/contracts/activity.d.ts +1 -1
  16. package/dist/contracts/activity.js +11 -15
  17. package/dist/contracts/api-keys.d.ts +16 -0
  18. package/dist/contracts/api-keys.js +11 -9
  19. package/dist/contracts/archives.d.ts +1 -2
  20. package/dist/contracts/archives.js +15 -17
  21. package/dist/contracts/beta.js +1 -1
  22. package/dist/contracts/builds.js +14 -14
  23. package/dist/contracts/channels.js +2 -2
  24. package/dist/contracts/comments.d.ts +143 -99
  25. package/dist/contracts/comments.js +194 -79
  26. package/dist/contracts/common.d.ts +12 -12
  27. package/dist/contracts/common.js +33 -30
  28. package/dist/contracts/continuation.js +5 -5
  29. package/dist/contracts/countries.js +2 -7
  30. package/dist/contracts/data-source-routes.d.ts +20 -0
  31. package/dist/contracts/data-source-routes.js +15 -0
  32. package/dist/contracts/device-auth.d.ts +13 -9
  33. package/dist/contracts/device-auth.js +12 -12
  34. package/dist/contracts/docs.d.ts +10 -10
  35. package/dist/contracts/domains.js +39 -33
  36. package/dist/contracts/enums.d.ts +4 -14
  37. package/dist/contracts/enums.js +3 -10
  38. package/dist/contracts/error-code-meta.d.ts +122 -56
  39. package/dist/contracts/error-code-meta.js +43 -19
  40. package/dist/contracts/error-codes.d.ts +7 -4
  41. package/dist/contracts/error-codes.js +48 -24
  42. package/dist/contracts/events.d.ts +22 -15
  43. package/dist/contracts/events.js +33 -5
  44. package/dist/contracts/execution.d.ts +238 -0
  45. package/dist/contracts/execution.js +309 -0
  46. package/dist/contracts/feature-lifecycle.d.ts +39 -188
  47. package/dist/contracts/feature-lifecycle.js +52 -196
  48. package/dist/contracts/features.d.ts +13 -115
  49. package/dist/contracts/features.js +5 -35
  50. package/dist/contracts/functions.d.ts +597 -0
  51. package/dist/contracts/functions.js +475 -0
  52. package/dist/contracts/grants.d.ts +1175 -0
  53. package/dist/contracts/grants.js +783 -0
  54. package/dist/contracts/ids.d.ts +7 -5
  55. package/dist/contracts/ids.js +7 -7
  56. package/dist/contracts/internal.js +2 -2
  57. package/dist/contracts/mcp.d.ts +17 -556
  58. package/dist/contracts/mcp.js +9 -103
  59. package/dist/contracts/me.js +3 -4
  60. package/dist/contracts/notifications.d.ts +108 -0
  61. package/dist/contracts/notifications.js +54 -0
  62. package/dist/contracts/oauth-resources.d.ts +22 -5
  63. package/dist/contracts/oauth-resources.js +23 -2
  64. package/dist/contracts/operations.d.ts +0 -48
  65. package/dist/contracts/operations.js +0 -19
  66. package/dist/contracts/pages.d.ts +10 -14
  67. package/dist/contracts/pages.js +17 -21
  68. package/dist/contracts/plan-policy.d.ts +1 -8
  69. package/dist/contracts/plan-policy.js +1 -4
  70. package/dist/contracts/platform.d.ts +78 -30
  71. package/dist/contracts/platform.js +69 -20
  72. package/dist/contracts/problem-document.d.ts +14 -0
  73. package/dist/contracts/problem-document.js +35 -0
  74. package/dist/contracts/push-new.d.ts +41 -2
  75. package/dist/contracts/push-new.js +4 -0
  76. package/dist/contracts/quotas.d.ts +0 -1
  77. package/dist/contracts/quotas.js +0 -5
  78. package/dist/contracts/repository-connections.d.ts +1 -1
  79. package/dist/contracts/resources.d.ts +16 -71
  80. package/dist/contracts/resources.js +13 -16
  81. package/dist/contracts/runtime-api.d.ts +666 -303
  82. package/dist/contracts/runtime-api.js +272 -113
  83. package/dist/contracts/runtime-app.d.ts +168 -0
  84. package/dist/contracts/runtime-app.js +42 -0
  85. package/dist/contracts/runtime-db.d.ts +424 -0
  86. package/dist/contracts/runtime-db.js +108 -0
  87. package/dist/contracts/runtime-storage.d.ts +120 -0
  88. package/dist/contracts/runtime-storage.js +40 -0
  89. package/dist/contracts/sf-config-v1.d.ts +54 -1
  90. package/dist/contracts/sf-config-v1.js +2 -2
  91. package/dist/contracts/sites.d.ts +6 -0
  92. package/dist/contracts/sites.js +30 -11
  93. package/dist/contracts/space-config.d.ts +91 -121
  94. package/dist/contracts/space-config.js +464 -42
  95. package/dist/contracts/spaces.d.ts +300 -171
  96. package/dist/contracts/spaces.js +128 -98
  97. package/dist/contracts/superadmin-emails.d.ts +2 -2
  98. package/dist/contracts/superadmin-spaces.d.ts +26 -130
  99. package/dist/contracts/superadmin-spaces.js +22 -0
  100. package/dist/contracts/superadmin-tenants.js +4 -4
  101. package/dist/contracts/superadmin.d.ts +4 -0
  102. package/dist/contracts/superadmin.js +14 -1
  103. package/dist/contracts/tags.d.ts +6 -6
  104. package/dist/contracts/tags.js +1 -1
  105. package/dist/contracts/teams.d.ts +9 -9
  106. package/dist/contracts/teams.js +25 -16
  107. package/dist/contracts/theme-json.js +1 -1
  108. package/dist/contracts/transfers.d.ts +0 -1
  109. package/dist/contracts/transfers.js +4 -4
  110. package/dist/contracts/variables.js +3 -3
  111. package/dist/contracts/zero.d.ts +384 -596
  112. package/dist/contracts/zero.js +167 -299
  113. package/dist/dashboard-paths/index.d.ts +18 -3
  114. package/dist/dashboard-paths/index.js +19 -0
  115. package/dist/docs/agent-handoff-document.d.ts +2 -2
  116. package/dist/docs/agent-handoff-document.js +8 -7
  117. package/dist/docs/agent-prose.d.ts +22 -3
  118. package/dist/docs/agent-prose.js +227 -55
  119. package/dist/docs/agent-setup.d.ts +14 -11
  120. package/dist/docs/agent-setup.js +289 -61
  121. package/dist/docs/agent-solutions.d.ts +6 -6
  122. package/dist/docs/agent-solutions.js +24 -22
  123. package/dist/docs/catalog.d.ts +53 -98
  124. package/dist/docs/catalog.js +90 -117
  125. package/dist/docs/error-docs.js +304 -236
  126. package/dist/docs/skill-distribution.d.ts +2 -0
  127. package/dist/docs/skill-distribution.js +7 -4
  128. package/dist/docs/skills.d.ts +546 -0
  129. package/dist/docs/skills.js +340 -0
  130. package/dist/utils/auth-redirect.d.ts +1 -3
  131. package/dist/utils/auth-redirect.js +1 -21
  132. package/dist/utils/browser-credential.d.ts +19 -0
  133. package/dist/utils/browser-credential.js +62 -0
  134. package/dist/utils/build-settings.d.ts +2 -0
  135. package/dist/utils/build-settings.js +61 -9
  136. package/dist/utils/comment-avatars.d.ts +7 -0
  137. package/dist/utils/comment-avatars.js +42 -0
  138. package/dist/utils/content-type.d.ts +3 -3
  139. package/dist/utils/content-type.js +38 -61
  140. package/dist/utils/credential-policy.d.ts +1 -1
  141. package/dist/utils/credential-policy.js +4 -0
  142. package/dist/utils/domain-diagnostics.d.ts +5 -5
  143. package/dist/utils/domain-diagnostics.js +21 -10
  144. package/dist/utils/egress-policy.fixtures.json +1 -1
  145. package/dist/utils/grants.d.ts +53 -0
  146. package/dist/utils/grants.js +160 -0
  147. package/dist/utils/local-space-state.d.ts +78 -4
  148. package/dist/utils/local-space-state.js +384 -82
  149. package/dist/utils/one-shot-replay.d.ts +14 -0
  150. package/dist/utils/one-shot-replay.js +21 -0
  151. package/dist/utils/page-preview.d.ts +7 -0
  152. package/dist/utils/page-preview.js +9 -0
  153. package/dist/utils/pages.d.ts +2 -5
  154. package/dist/utils/pages.js +64 -33
  155. package/dist/utils/publish-form-data.d.ts +22 -0
  156. package/dist/utils/publish-form-data.js +26 -0
  157. package/dist/utils/publish-policy.d.ts +34 -4
  158. package/dist/utils/publish-policy.js +149 -62
  159. package/dist/utils/query-keys.d.ts +8 -10
  160. package/dist/utils/query-keys.js +14 -10
  161. package/dist/utils/runtime-paths.d.ts +3 -0
  162. package/dist/utils/runtime-paths.js +7 -0
  163. package/dist/utils/secure-local-file.d.ts +73 -0
  164. package/dist/utils/secure-local-file.js +1373 -0
  165. package/dist/utils/space-config.d.ts +17 -4
  166. package/dist/utils/space-config.js +151 -8
  167. package/dist/utils/static-runtime-policy.d.ts +5 -0
  168. package/dist/utils/static-runtime-policy.js +54 -10
  169. package/dist/utils/storage-policy.d.ts +20 -0
  170. package/dist/utils/storage-policy.fixtures.json +174 -0
  171. package/dist/utils/storage-policy.js +193 -0
  172. package/dist/utils/upload-session.d.ts +15 -1
  173. package/dist/utils/upload-session.js +68 -2
  174. package/dist/utils/version-file-browser.d.ts +13 -0
  175. package/dist/utils/version-file-browser.js +59 -0
  176. package/package.json +20 -1
  177. package/dist/contracts/mounts.d.ts +0 -142
  178. package/dist/contracts/mounts.js +0 -56
  179. package/dist/utils/access-grant.d.ts +0 -14
  180. package/dist/utils/access-grant.js +0 -88
  181. package/dist/utils/access-match.d.ts +0 -46
  182. package/dist/utils/access-match.fixtures.json +0 -513
  183. package/dist/utils/access-match.js +0 -312
  184. package/dist/utils/access-verdict.fixtures.json +0 -421
  185. package/dist/utils/asset-fingerprint.d.ts +0 -53
  186. package/dist/utils/asset-fingerprint.js +0 -574
  187. package/dist/utils/sf-config-v1.d.ts +0 -2
  188. package/dist/utils/sf-config-v1.fixtures.json +0 -9
  189. package/dist/utils/sf-config-v1.js +0 -551
@@ -1,421 +0,0 @@
1
- {
2
- "_comment": "Shared corpus for the simulate<->runtime verdict drift guard (access-plan §8/X-9). Asserted against the PHP pure kernel (_spacefast_evaluate_policy, runtime/engine/runtime/access-rules.php) in apps/control-plane/src/runtime/php-policy-parity.test.ts and against apps/control-plane/src/access/simulate.ts's simulateAccess in apps/control-plane/src/runtime/access-verdict-parity.test.ts. `rules` is a raw RuntimeRule[] (no source/order provenance). `context` carries only the 4 fields simulate.ts's SimulateRequest supports (host/path/ip/country) plus `now` for expiry. `grants` mirrors what a real visitor token would carry but is restricted to 0-or-1 `email:` entries (simulate.ts's own simplification — it only ever mints an `email:` grant); `identified` is `grants.length > 0`, matching simulateAccess. `expected` is the {ruleId, effect, satisfied} verdict tuple both sides must agree on.",
3
- "verdicts": [
4
- {
5
- "name": "first-match wins: anonymous deny before a later allow-all",
6
- "rules": [
7
- { "id": "r1", "match": { "pathPattern": "/admin/**" }, "effect": "deny" },
8
- { "id": "r2", "match": {}, "effect": "allow" }
9
- ],
10
- "context": {
11
- "host": "acme.example.com",
12
- "path": "/admin/x",
13
- "ip": "1.2.3.4",
14
- "country": "US"
15
- },
16
- "grants": [],
17
- "identified": false,
18
- "now": 1770000000,
19
- "expected": { "ruleId": "r1", "effect": "deny", "satisfied": true }
20
- },
21
- {
22
- "name": "first match: satisfied allow wins over a later deny",
23
- "rules": [
24
- {
25
- "id": "r1",
26
- "match": {},
27
- "effect": "allow",
28
- "auth": { "requiredGrants": ["email:carol@acme.com"] }
29
- },
30
- { "id": "r2", "match": {}, "effect": "deny" }
31
- ],
32
- "context": { "host": "acme.example.com", "path": "/", "ip": "", "country": "" },
33
- "grants": ["email:carol@acme.com"],
34
- "identified": true,
35
- "now": 1,
36
- "expected": { "ruleId": "r1", "effect": "allow", "satisfied": true }
37
- },
38
- {
39
- "name": "expired deny rule is skipped, falls through to public allow",
40
- "rules": [
41
- { "id": "r1", "match": {}, "effect": "deny", "expiresAt": 1000 },
42
- { "id": "r2", "match": {}, "effect": "allow" }
43
- ],
44
- "context": { "host": "acme.example.com", "path": "/", "ip": "", "country": "" },
45
- "grants": [],
46
- "identified": false,
47
- "now": 2000,
48
- "expected": { "ruleId": "r2", "effect": "allow", "satisfied": true }
49
- },
50
- {
51
- "name": "not-yet-expired rule (expiresAt > now) still applies",
52
- "rules": [{ "id": "r1", "match": {}, "effect": "deny", "expiresAt": 2001 }],
53
- "context": { "host": "acme.example.com", "path": "/", "ip": "", "country": "" },
54
- "grants": [],
55
- "identified": false,
56
- "now": 2000,
57
- "expected": { "ruleId": "r1", "effect": "deny", "satisfied": true }
58
- },
59
- {
60
- "name": "expiresAt == now is expired at the boundary (falls through to public allow)",
61
- "rules": [{ "id": "r1", "match": {}, "effect": "deny", "expiresAt": 2000 }],
62
- "context": { "host": "acme.example.com", "path": "/", "ip": "", "country": "" },
63
- "grants": [],
64
- "identified": false,
65
- "now": 2000,
66
- "expected": { "ruleId": null, "effect": "allow", "satisfied": true }
67
- },
68
- {
69
- "name": "challenge unsatisfied + identified visitor becomes deny (X-32 never re-challenge)",
70
- "rules": [
71
- {
72
- "id": "r1",
73
- "match": {},
74
- "effect": "challenge",
75
- "auth": { "requiredGrants": ["team:t1:member"] }
76
- }
77
- ],
78
- "context": { "host": "acme.example.com", "path": "/", "ip": "", "country": "" },
79
- "grants": ["email:carol@acme.com"],
80
- "identified": true,
81
- "now": 1,
82
- "expected": { "ruleId": "r1", "effect": "deny", "satisfied": false }
83
- },
84
- {
85
- "name": "challenge unsatisfied + anonymous stays a challenge",
86
- "rules": [
87
- {
88
- "id": "r1",
89
- "match": {},
90
- "effect": "challenge",
91
- "auth": { "requiredGrants": ["team:t1:member"] }
92
- }
93
- ],
94
- "context": { "host": "acme.example.com", "path": "/", "ip": "", "country": "" },
95
- "grants": [],
96
- "identified": false,
97
- "now": 1,
98
- "expected": { "ruleId": "r1", "effect": "challenge", "satisfied": false }
99
- },
100
- {
101
- "name": "challenge satisfied becomes allow",
102
- "rules": [
103
- {
104
- "id": "r1",
105
- "match": {},
106
- "effect": "challenge",
107
- "auth": { "requiredGrants": ["email:carol@acme.com"] }
108
- }
109
- ],
110
- "context": { "host": "acme.example.com", "path": "/", "ip": "", "country": "" },
111
- "grants": ["email:carol@acme.com"],
112
- "identified": true,
113
- "now": 1,
114
- "expected": { "ruleId": "r1", "effect": "allow", "satisfied": true }
115
- },
116
- {
117
- "name": "allow rule unsatisfied keeps scanning to default public allow",
118
- "rules": [
119
- {
120
- "id": "r1",
121
- "match": {},
122
- "effect": "allow",
123
- "auth": { "requiredGrants": ["email:carol@acme.com"] }
124
- }
125
- ],
126
- "context": { "host": "acme.example.com", "path": "/", "ip": "", "country": "" },
127
- "grants": [],
128
- "identified": false,
129
- "now": 1,
130
- "expected": { "ruleId": null, "effect": "allow", "satisfied": true }
131
- },
132
- {
133
- "name": "deny rule unsatisfied keeps scanning to default public allow",
134
- "rules": [
135
- {
136
- "id": "r1",
137
- "match": {},
138
- "effect": "deny",
139
- "auth": { "requiredGrants": ["email:carol@acme.com"] }
140
- }
141
- ],
142
- "context": { "host": "acme.example.com", "path": "/", "ip": "", "country": "" },
143
- "grants": [],
144
- "identified": false,
145
- "now": 1,
146
- "expected": { "ruleId": null, "effect": "allow", "satisfied": true }
147
- },
148
- {
149
- "name": "deny rule satisfied denies immediately",
150
- "rules": [
151
- {
152
- "id": "r1",
153
- "match": {},
154
- "effect": "deny",
155
- "auth": { "requiredGrants": ["email:mallory@acme.com"] }
156
- }
157
- ],
158
- "context": { "host": "acme.example.com", "path": "/", "ip": "", "country": "" },
159
- "grants": ["email:mallory@acme.com"],
160
- "identified": true,
161
- "now": 1,
162
- "expected": { "ruleId": "r1", "effect": "deny", "satisfied": true }
163
- },
164
- {
165
- "name": "host mismatch falls through to public allow",
166
- "rules": [{ "id": "r1", "match": { "host": "other.example.com" }, "effect": "deny" }],
167
- "context": { "host": "acme.example.com", "path": "/", "ip": "", "country": "" },
168
- "grants": [],
169
- "identified": false,
170
- "now": 1,
171
- "expected": { "ruleId": null, "effect": "allow", "satisfied": true }
172
- },
173
- {
174
- "name": "path glob ** matches any depth",
175
- "rules": [{ "id": "r1", "match": { "pathPattern": "/docs/**" }, "effect": "deny" }],
176
- "context": { "host": "acme.example.com", "path": "/docs/a/b/c", "ip": "", "country": "" },
177
- "grants": [],
178
- "identified": false,
179
- "now": 1,
180
- "expected": { "ruleId": "r1", "effect": "deny", "satisfied": true }
181
- },
182
- {
183
- "name": "path glob * matches one segment only, deeper path falls through",
184
- "rules": [
185
- { "id": "r1", "match": { "pathPattern": "/docs/*" }, "effect": "deny" },
186
- { "id": "r2", "match": {}, "effect": "allow" }
187
- ],
188
- "context": { "host": "acme.example.com", "path": "/docs/a/b", "ip": "", "country": "" },
189
- "grants": [],
190
- "identified": false,
191
- "now": 1,
192
- "expected": { "ruleId": "r2", "effect": "allow", "satisfied": true }
193
- },
194
- {
195
- "name": "country match denies",
196
- "rules": [{ "id": "r1", "match": { "country": "KP" }, "effect": "deny" }],
197
- "context": { "host": "acme.example.com", "path": "/", "ip": "", "country": "KP" },
198
- "grants": [],
199
- "identified": false,
200
- "now": 1,
201
- "expected": { "ruleId": "r1", "effect": "deny", "satisfied": true }
202
- },
203
- {
204
- "name": "country mismatch falls through to public allow",
205
- "rules": [{ "id": "r1", "match": { "country": "KP" }, "effect": "deny" }],
206
- "context": { "host": "acme.example.com", "path": "/", "ip": "", "country": "US" },
207
- "grants": [],
208
- "identified": false,
209
- "now": 1,
210
- "expected": { "ruleId": null, "effect": "allow", "satisfied": true }
211
- },
212
- {
213
- "name": "countryNotIn lets an explicitly allowed country fall through",
214
- "rules": [{ "id": "r1", "match": { "countryNotIn": ["US"] }, "effect": "deny" }],
215
- "context": { "host": "acme.example.com", "path": "/", "ip": "", "country": "US" },
216
- "grants": [],
217
- "identified": false,
218
- "now": 1,
219
- "expected": { "ruleId": null, "effect": "allow", "satisfied": true }
220
- },
221
- {
222
- "name": "countryNotIn denies a provider-special country",
223
- "rules": [{ "id": "r1", "match": { "countryNotIn": ["US"] }, "effect": "deny" }],
224
- "context": { "host": "acme.example.com", "path": "/", "ip": "", "country": "XX" },
225
- "grants": [],
226
- "identified": false,
227
- "now": 1,
228
- "expected": { "ruleId": "r1", "effect": "deny", "satisfied": true }
229
- },
230
- {
231
- "name": "countryNotIn denies a missing country",
232
- "rules": [{ "id": "r1", "match": { "countryNotIn": ["US"] }, "effect": "deny" }],
233
- "context": { "host": "acme.example.com", "path": "/", "ip": "", "country": "" },
234
- "grants": [],
235
- "identified": false,
236
- "now": 1,
237
- "expected": { "ruleId": "r1", "effect": "deny", "satisfied": true }
238
- },
239
- {
240
- "name": "ip cidr match denies",
241
- "rules": [{ "id": "r1", "match": { "ipCidrs": ["10.0.0.0/8"] }, "effect": "deny" }],
242
- "context": { "host": "acme.example.com", "path": "/", "ip": "10.1.2.3", "country": "" },
243
- "grants": [],
244
- "identified": false,
245
- "now": 1,
246
- "expected": { "ruleId": "r1", "effect": "deny", "satisfied": true }
247
- },
248
- {
249
- "name": "ip cidr mismatch falls through to public allow",
250
- "rules": [{ "id": "r1", "match": { "ipCidrs": ["10.0.0.0/8"] }, "effect": "deny" }],
251
- "context": { "host": "acme.example.com", "path": "/", "ip": "192.168.1.1", "country": "" },
252
- "grants": [],
253
- "identified": false,
254
- "now": 1,
255
- "expected": { "ruleId": null, "effect": "allow", "satisfied": true }
256
- },
257
- {
258
- "name": "agent-conditioned rule never fires when unsimulated (simulate.ts scope gap, negative-only)",
259
- "rules": [
260
- { "id": "r1", "match": { "agent": "Googlebot" }, "effect": "deny" },
261
- { "id": "r2", "match": {}, "effect": "allow" }
262
- ],
263
- "context": { "host": "acme.example.com", "path": "/", "ip": "", "country": "" },
264
- "grants": [],
265
- "identified": false,
266
- "now": 1,
267
- "expected": { "ruleId": "r2", "effect": "allow", "satisfied": true }
268
- },
269
- {
270
- "name": "grant glob intersection: email domain wildcard satisfies",
271
- "rules": [
272
- {
273
- "id": "r1",
274
- "match": {},
275
- "effect": "allow",
276
- "auth": { "requiredGrants": ["email:*@acme.com"] }
277
- }
278
- ],
279
- "context": { "host": "acme.example.com", "path": "/", "ip": "", "country": "" },
280
- "grants": ["email:carol@acme.com"],
281
- "identified": true,
282
- "now": 1,
283
- "expected": { "ruleId": "r1", "effect": "allow", "satisfied": true }
284
- },
285
- {
286
- "name": "grant glob intersection: email outside the domain wildcard does not satisfy",
287
- "rules": [
288
- {
289
- "id": "r1",
290
- "match": {},
291
- "effect": "allow",
292
- "auth": { "requiredGrants": ["email:*@acme.com"] }
293
- },
294
- { "id": "r2", "match": {}, "effect": "deny" }
295
- ],
296
- "context": { "host": "acme.example.com", "path": "/", "ip": "", "country": "" },
297
- "grants": ["email:carol@evil.com"],
298
- "identified": true,
299
- "now": 1,
300
- "expected": { "ruleId": "r2", "effect": "deny", "satisfied": true }
301
- },
302
- {
303
- "name": "anonymous rule with challenge effect collapses to deny (no credential leg can ever satisfy it)",
304
- "rules": [{ "id": "r1", "match": {}, "effect": "challenge" }],
305
- "context": { "host": "acme.example.com", "path": "/", "ip": "", "country": "" },
306
- "grants": [],
307
- "identified": false,
308
- "now": 1,
309
- "expected": { "ruleId": "r1", "effect": "deny", "satisfied": true }
310
- },
311
- {
312
- "name": "anonymous allow rule passes regardless of any carried grants",
313
- "rules": [{ "id": "r1", "match": {}, "effect": "allow" }],
314
- "context": { "host": "acme.example.com", "path": "/", "ip": "", "country": "" },
315
- "grants": ["email:carol@acme.com"],
316
- "identified": true,
317
- "now": 1,
318
- "expected": { "ruleId": "r1", "effect": "allow", "satisfied": true }
319
- },
320
- {
321
- "name": "no rules at all: public allow",
322
- "rules": [],
323
- "context": { "host": "acme.example.com", "path": "/", "ip": "", "country": "" },
324
- "grants": [],
325
- "identified": false,
326
- "now": 1,
327
- "expected": { "ruleId": null, "effect": "allow", "satisfied": true }
328
- },
329
- {
330
- "name": "no rule matches this host/path: public allow",
331
- "rules": [{ "id": "r1", "match": { "pathPattern": "/private/**" }, "effect": "deny" }],
332
- "context": { "host": "acme.example.com", "path": "/public/x", "ip": "", "country": "" },
333
- "grants": [],
334
- "identified": false,
335
- "now": 1,
336
- "expected": { "ruleId": null, "effect": "allow", "satisfied": true }
337
- },
338
- {
339
- "name": "an irrelevant carried grant (same as a revoked/tombstoned id absent from requiredGrants) is a normal non-intersecting case",
340
- "rules": [
341
- {
342
- "id": "r1",
343
- "match": {},
344
- "effect": "challenge",
345
- "auth": { "requiredGrants": ["team:t1:member"] }
346
- }
347
- ],
348
- "context": { "host": "acme.example.com", "path": "/", "ip": "", "country": "" },
349
- "grants": ["email:zoe@acme.com"],
350
- "identified": true,
351
- "now": 1,
352
- "expected": { "ruleId": "r1", "effect": "deny", "satisfied": false }
353
- },
354
- {
355
- "name": "a later invited reviewer falls through earlier identity allows and passes their own",
356
- "rules": [
357
- {
358
- "id": "cast-reviewer-a",
359
- "match": {},
360
- "effect": "allow",
361
- "managedBy": "cast_reviewer",
362
- "auth": { "requiredGrants": ["email:reviewer.a@example.com"] }
363
- },
364
- {
365
- "id": "cast-reviewer-b",
366
- "match": {},
367
- "effect": "allow",
368
- "managedBy": "cast_reviewer",
369
- "auth": { "requiredGrants": ["email:reviewer.b@example.com"] }
370
- },
371
- {
372
- "id": "cast-reviewers-audience",
373
- "match": {},
374
- "effect": "challenge",
375
- "managedBy": "cast_reviewer",
376
- "auth": {
377
- "requiredGrants": ["email:reviewer.a@example.com", "email:reviewer.b@example.com"]
378
- }
379
- }
380
- ],
381
- "context": { "host": "acme.example.com", "path": "/", "ip": "", "country": "" },
382
- "grants": ["email:reviewer.b@example.com"],
383
- "identified": true,
384
- "now": 1,
385
- "expected": { "ruleId": "cast-reviewer-b", "effect": "allow", "satisfied": true }
386
- },
387
- {
388
- "name": "a non-reviewer falls through identity allows and is denied by the terminal audience",
389
- "rules": [
390
- {
391
- "id": "cast-reviewer-a",
392
- "match": {},
393
- "effect": "allow",
394
- "managedBy": "cast_reviewer",
395
- "auth": { "requiredGrants": ["email:reviewer.a@example.com"] }
396
- },
397
- {
398
- "id": "cast-reviewer-b",
399
- "match": {},
400
- "effect": "allow",
401
- "managedBy": "cast_reviewer",
402
- "auth": { "requiredGrants": ["email:reviewer.b@example.com"] }
403
- },
404
- {
405
- "id": "cast-reviewers-audience",
406
- "match": {},
407
- "effect": "challenge",
408
- "managedBy": "cast_reviewer",
409
- "auth": {
410
- "requiredGrants": ["email:reviewer.a@example.com", "email:reviewer.b@example.com"]
411
- }
412
- }
413
- ],
414
- "context": { "host": "acme.example.com", "path": "/", "ip": "", "country": "" },
415
- "grants": ["email:outsider@example.com"],
416
- "identified": true,
417
- "now": 1,
418
- "expected": { "ruleId": "cast-reviewers-audience", "effect": "deny", "satisfied": false }
419
- }
420
- ]
421
- }
@@ -1,53 +0,0 @@
1
- export declare const FINGERPRINT_IMMUTABLE_CACHE_CONTROL = "public, max-age=31536000, immutable";
2
- export declare const FINGERPRINT_HASH_LENGTH = 8;
3
- export type FingerprintCandidateFile = {
4
- /** Canonical manifest path (no leading slash). */
5
- path: string;
6
- /** Full lowercase-hex sha256 of the file's bytes. */
7
- sha256?: string | undefined;
8
- /** UTF-8 text for html/css files that may need reference rewriting. */
9
- text?: string | undefined;
10
- };
11
- export type FingerprintSkipReason = "css_cycle" | "alias_collision" | "user_cache_control" | "budget";
12
- export type FingerprintPlan = {
13
- /**
14
- * Alias manifest entries to add, sorted by sourcePath; content is identical
15
- * to sourcePath's. This is also the "what got fingerprinted" relation —
16
- * one array, `path` = the hashed alias, `sourcePath` = the original.
17
- */
18
- aliases: Array<{
19
- path: string;
20
- sourcePath: string;
21
- }>;
22
- /** html/css files whose published content changes (both paths, one blob). */
23
- rewrites: Array<{
24
- path: string;
25
- text: string;
26
- sha256: string;
27
- }>;
28
- /** Eligible-looking files the pass left on the default lane, with reasons. */
29
- skipped: Array<{
30
- path: string;
31
- reason: FingerprintSkipReason;
32
- }>;
33
- };
34
- export declare function planAssetFingerprints(input: {
35
- files: readonly FingerprintCandidateFile[];
36
- /** sha256 as lowercase hex over UTF-8 bytes of `text`. */
37
- hashHex: (text: string) => string;
38
- /**
39
- * True when a user `_headers` Cache-Control rule already covers this URL
40
- * path ("/"-prefixed). Files whose original OR probe-alias path is covered
41
- * are never fingerprinted — user rules always win.
42
- */
43
- pathCoveredByUserCacheControl?: ((urlPath: string) => boolean) | undefined;
44
- /** Extra per-path exclusion (e.g. header-rule budget trimming). */
45
- excludePath?: ((path: string) => boolean) | undefined;
46
- }): FingerprintPlan;
47
- /**
48
- * Merges the generated immutable pins into user `_headers` content. The user
49
- * content is preserved byte-for-byte; generated exact-path rules are appended
50
- * (per-path Cache-Control conflicts are impossible — files covered by a user
51
- * Cache-Control rule are never fingerprinted).
52
- */
53
- export declare function mergeFingerprintHeaders(userHeaders: string | undefined, aliasPaths: readonly string[]): string;