@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,406 @@
1
+ import { z } from "zod";
2
+ // Spec plan vocabulary (internal-docs/platform.md "Plans And Limits").
3
+ // `enterprise` and `internal` are named plans without self-serve pricing.
4
+ export const PLAN_CODES = ["free", "personal", "work", "enterprise", "internal"];
5
+ export const planCodeSchema = z.enum(PLAN_CODES).describe("Plan code.");
6
+ export const DEFAULT_PLAN_CODE = "free";
7
+ export const FEATURE_KEYS = [
8
+ "plans.paid.available",
9
+ "anonymous.publishing",
10
+ "beta.enrollment_gate",
11
+ "domains.search",
12
+ "domains.registration",
13
+ "domains.dns_management",
14
+ "domains.proxy_bindings",
15
+ "annotations.preview_loader",
16
+ "annotations.comments",
17
+ "annotations.anonymous_reviewers",
18
+ "annotations.cli",
19
+ "annotations.notices",
20
+ "annotations.spacefast_token",
21
+ "annotations.published_comments",
22
+ "sites.dedicated_runtime",
23
+ "shelf",
24
+ "tags",
25
+ "zero",
26
+ ];
27
+ export const featureKeySchema = z.enum(FEATURE_KEYS).describe("Feature flag key.");
28
+ // Feature override states (env `SPACEFAST_FLAG_*` and the feature_overrides
29
+ // table). `kill_switch` short-circuits every other resolution layer.
30
+ export const FEATURE_OVERRIDE_STATES = ["enabled", "disabled", "kill_switch"];
31
+ export const featureOverrideStateSchema = z.enum(FEATURE_OVERRIDE_STATES);
32
+ export const planLimitValueSchema = z
33
+ .union([z.number().int().nonnegative(), z.literal("unlimited")])
34
+ .describe('Plan limit value; "unlimited" when the plan does not bound this axis.');
35
+ // Named plan limit table (internal-docs/platform.md "Plans And Limits",
36
+ // Free/Personal/Work columns verbatim). Keys mirror `PlanPolicyResponse.limits`
37
+ // so plan policy is a projection of this data, never a re-derivation.
38
+ export const planLimitsSchema = z
39
+ .object({
40
+ storageBytes: planLimitValueSchema,
41
+ teamMembers: planLimitValueSchema,
42
+ subTeams: planLimitValueSchema,
43
+ externalDomainGroups: planLimitValueSchema,
44
+ publicImmutableVersionWindowDays: planLimitValueSchema,
45
+ // Version retention (charter arbitration A3, internal plan data — never on
46
+ // the PlanPolicyResponse wire shape): `versionRetentionDays` is the included
47
+ // full-retention window; after it versions stay stored but gated until
48
+ // `versionGatedKeepDays` from readyAt, then retention-delete with notice.
49
+ // Live and channel-referenced versions are never retention-deleted.
50
+ versionRetentionDays: planLimitValueSchema,
51
+ versionGatedKeepDays: planLimitValueSchema,
52
+ // Per-space daily bandwidth cap feeding the egress kill-switch sweep
53
+ // (internal-docs/platform.md "Abuse Posture"; internal plan data — never on
54
+ // the PlanPolicyResponse wire shape). WORST_CASE_QUOTAS
55
+ // .maxEgressBytesPerSpacePerDay stays the absolute platform ceiling.
56
+ egressBytesPerDay: planLimitValueSchema,
57
+ maxFileBytes: planLimitValueSchema,
58
+ // Files per version. Plan policy may LOWER the 100k contract ceiling
59
+ // (Free 20,000), never raise it; the validator clamps at the ceiling.
60
+ maxVersionFiles: planLimitValueSchema,
61
+ routingRules: planLimitValueSchema,
62
+ auditLogRetentionHours: planLimitValueSchema,
63
+ buildAccessLogRetentionHours: planLimitValueSchema,
64
+ // One pooled limit on purpose: pricing never separates user pushes from CI builds.
65
+ buildsDeploysMonthly: planLimitValueSchema,
66
+ // Queryable analytics history window. Storage retains rollups for everyone
67
+ // (env-bounded); this only clamps how far back the analytics API serves.
68
+ analyticsRetentionDays: planLimitValueSchema,
69
+ })
70
+ .describe("Named plan limit table.");
71
+ // Resolved team entitlements: plan limits after add-on grants plus the
72
+ // capability dials that are not number|"unlimited" limits. Served by
73
+ // `GET /v1/teams/{teamId}/entitlements`.
74
+ export const teamEntitlementsSchema = z
75
+ .object({
76
+ planCode: planCodeSchema,
77
+ limits: planLimitsSchema,
78
+ headersBasicAuth: z
79
+ .boolean()
80
+ .describe("Whether `_headers` Basic-Auth rules compile on this plan."),
81
+ externalProxy: z.boolean().describe("Whether external proxy upstreams compile on this plan."),
82
+ runtimePhpWorkers: z.number().int().describe("PHP workers per serving site."),
83
+ analyticsHourlyGranularity: z
84
+ .boolean()
85
+ .describe("Whether analytics series resolve to hourly buckets (daily otherwise)."),
86
+ versionDiagnosticsIncluded: z
87
+ .boolean()
88
+ .describe("Whether version diagnostics are included with the plan."),
89
+ })
90
+ .describe("Resolved entitlements for a team: plan limits after add-on grants.");
91
+ // Wire projection of TeamEntitlements for GET /v1/teams/{teamId}/entitlements.
92
+ // `versionRetentionDays`/`versionGatedKeepDays` (charter A3) and
93
+ // `egressBytesPerDay` (abuse posture) are internal plan data — never on a wire
94
+ // shape, mirroring PlanPolicyResponse's deliberate exclusion.
95
+ export const teamEntitlementsResponseSchema = teamEntitlementsSchema
96
+ .extend({
97
+ limits: planLimitsSchema.omit({
98
+ versionRetentionDays: true,
99
+ versionGatedKeepDays: true,
100
+ egressBytesPerDay: true,
101
+ }),
102
+ })
103
+ .describe("Resolved entitlements for a team: plan limits after add-on grants.");
104
+ const GB = 1024 * 1024 * 1024;
105
+ const MB = 1024 * 1024;
106
+ const MONTH_HOURS = 30 * 24;
107
+ const UNLIMITED_LIMITS = {
108
+ storageBytes: "unlimited",
109
+ teamMembers: "unlimited",
110
+ subTeams: "unlimited",
111
+ externalDomainGroups: "unlimited",
112
+ publicImmutableVersionWindowDays: "unlimited",
113
+ versionRetentionDays: "unlimited",
114
+ versionGatedKeepDays: "unlimited",
115
+ egressBytesPerDay: "unlimited",
116
+ maxFileBytes: "unlimited",
117
+ maxVersionFiles: "unlimited",
118
+ routingRules: "unlimited",
119
+ auditLogRetentionHours: "unlimited",
120
+ buildAccessLogRetentionHours: "unlimited",
121
+ buildsDeploysMonthly: "unlimited",
122
+ analyticsRetentionDays: "unlimited",
123
+ };
124
+ export const PLAN_DEFINITIONS = {
125
+ free: {
126
+ code: "free",
127
+ name: "Free",
128
+ monthlyPriceUsd: 0,
129
+ limits: {
130
+ storageBytes: 5 * GB,
131
+ teamMembers: 3,
132
+ subTeams: 0,
133
+ externalDomainGroups: 1,
134
+ publicImmutableVersionWindowDays: 7,
135
+ versionRetentionDays: 30, // included full-retention window (charter A3)
136
+ versionGatedKeepDays: 183, // kept gated ~6 months from readyAt, then deleted
137
+ egressBytesPerDay: 100 * GB, // = worst-case ceiling; tunable per plan
138
+ maxFileBytes: 50 * MB,
139
+ maxVersionFiles: 20_000,
140
+ routingRules: 10,
141
+ auditLogRetentionHours: 48,
142
+ buildAccessLogRetentionHours: 48,
143
+ buildsDeploysMonthly: 100,
144
+ analyticsRetentionDays: 30,
145
+ },
146
+ headersBasicAuth: false,
147
+ externalProxy: false,
148
+ runtimePhpWorkers: 2,
149
+ analyticsHourlyGranularity: false,
150
+ },
151
+ personal: {
152
+ code: "personal",
153
+ name: "Personal",
154
+ monthlyPriceUsd: 5,
155
+ limits: {
156
+ ...UNLIMITED_LIMITS,
157
+ storageBytes: 20 * GB,
158
+ teamMembers: 5,
159
+ subTeams: 0,
160
+ externalDomainGroups: 10,
161
+ maxFileBytes: 1 * GB,
162
+ routingRules: 1000,
163
+ auditLogRetentionHours: MONTH_HOURS,
164
+ buildAccessLogRetentionHours: MONTH_HOURS,
165
+ buildsDeploysMonthly: 1000,
166
+ analyticsRetentionDays: 365,
167
+ },
168
+ headersBasicAuth: true,
169
+ externalProxy: true,
170
+ runtimePhpWorkers: 4,
171
+ analyticsHourlyGranularity: true,
172
+ },
173
+ work: {
174
+ code: "work",
175
+ name: "Work",
176
+ monthlyPriceUsd: 15,
177
+ limits: {
178
+ ...UNLIMITED_LIMITS,
179
+ storageBytes: 50 * GB,
180
+ // 15 seats included; the $1/seat add-on rides EntitlementGrant
181
+ // ({ limit: "teamMembers", add: n }) — grants are no-ops on
182
+ // "unlimited" limits, so this must stay numeric.
183
+ teamMembers: 15,
184
+ subTeams: 0,
185
+ },
186
+ headersBasicAuth: true,
187
+ externalProxy: true,
188
+ runtimePhpWorkers: 4,
189
+ analyticsHourlyGranularity: true,
190
+ },
191
+ // Footnote-only publicly ("custom — talk to us"); manual grant, never self-serve.
192
+ enterprise: {
193
+ code: "enterprise",
194
+ name: "Enterprise",
195
+ monthlyPriceUsd: null,
196
+ limits: { ...UNLIMITED_LIMITS },
197
+ headersBasicAuth: true,
198
+ externalProxy: true,
199
+ runtimePhpWorkers: 4,
200
+ analyticsHourlyGranularity: true,
201
+ },
202
+ internal: {
203
+ code: "internal",
204
+ name: "Internal",
205
+ monthlyPriceUsd: null,
206
+ limits: { ...UNLIMITED_LIMITS },
207
+ headersBasicAuth: true,
208
+ externalProxy: true,
209
+ runtimePhpWorkers: 4,
210
+ analyticsHourlyGranularity: true,
211
+ },
212
+ };
213
+ export const FEATURE_DEFINITIONS = {
214
+ "plans.paid.available": {
215
+ key: "plans.paid.available",
216
+ name: "Paid plans available",
217
+ description: "Controls whether paid plan upgrade and management surfaces are available.",
218
+ defaultEnabled: false,
219
+ enabledForA8c: true,
220
+ planDefaults: {},
221
+ },
222
+ "anonymous.publishing": {
223
+ key: "anonymous.publishing",
224
+ name: "Anonymous publishing",
225
+ description: "Allows unauthenticated space creation and publishing.",
226
+ defaultEnabled: true,
227
+ enabledForA8c: true,
228
+ planDefaults: {},
229
+ },
230
+ // Flipped in prod via env (`SPACEFAST_FLAG_BETA_ENROLLMENT_GATE`), so launch
231
+ // day is an env flip, not a deploy — exact precedent of anonymous.publishing.
232
+ "beta.enrollment_gate": {
233
+ key: "beta.enrollment_gate",
234
+ name: "Beta enrollment gate",
235
+ description: "Gates the whole API behind private-beta enrollment; non-enrolled credentials get 403 not_enrolled.",
236
+ defaultEnabled: false,
237
+ enabledForA8c: true,
238
+ planDefaults: {},
239
+ },
240
+ "domains.search": {
241
+ key: "domains.search",
242
+ name: "Domain search",
243
+ description: "Allows domain availability search and suggestion surfaces.",
244
+ defaultEnabled: false,
245
+ enabledInDevelopment: true,
246
+ enabledForA8c: true,
247
+ planDefaults: {},
248
+ },
249
+ "domains.registration": {
250
+ key: "domains.registration",
251
+ name: "Domain registration",
252
+ description: "Allows domain registration, purchase, and transfer-in surfaces.",
253
+ defaultEnabled: false,
254
+ enabledInDevelopment: true,
255
+ enabledForA8c: true,
256
+ planDefaults: {},
257
+ },
258
+ "domains.dns_management": {
259
+ key: "domains.dns_management",
260
+ name: "DNS management",
261
+ description: "Allows customer DNS zone, nameserver, and record-management surfaces.",
262
+ defaultEnabled: false,
263
+ enabledInDevelopment: true,
264
+ enabledForA8c: true,
265
+ planDefaults: {},
266
+ },
267
+ "domains.proxy_bindings": {
268
+ key: "domains.proxy_bindings",
269
+ name: "Domain proxy bindings",
270
+ description: "Allow a team to proxy custom-domain traffic to an external HTTP upstream.",
271
+ defaultEnabled: false,
272
+ enabledForA8c: true,
273
+ planDefaults: {
274
+ internal: true,
275
+ },
276
+ },
277
+ "annotations.preview_loader": {
278
+ key: "annotations.preview_loader",
279
+ name: "Annotations preview loader",
280
+ description: "Allows immutable version URLs to receive a no-secret preview overlay configuration.",
281
+ defaultEnabled: false,
282
+ enabledInDevelopment: true,
283
+ enabledForA8c: true,
284
+ planDefaults: {},
285
+ },
286
+ "annotations.comments": {
287
+ key: "annotations.comments",
288
+ name: "Annotation comments",
289
+ description: "Enables Cast-backed comments on eligible immutable version URLs.",
290
+ defaultEnabled: false,
291
+ enabledInDevelopment: true,
292
+ enabledForA8c: true,
293
+ planDefaults: {},
294
+ },
295
+ "annotations.anonymous_reviewers": {
296
+ key: "annotations.anonymous_reviewers",
297
+ name: "Anonymous annotation reviewers",
298
+ description: "Allows anyone-with-link annotation identities when space policy allows it.",
299
+ defaultEnabled: false,
300
+ enabledForA8c: true,
301
+ planDefaults: {},
302
+ },
303
+ "annotations.cli": {
304
+ key: "annotations.cli",
305
+ name: "Annotation CLI access",
306
+ description: "Enables scriptable annotation read/export/reply/resolve operations.",
307
+ defaultEnabled: false,
308
+ enabledInDevelopment: true,
309
+ enabledForA8c: true,
310
+ planDefaults: {},
311
+ },
312
+ "annotations.notices": {
313
+ key: "annotations.notices",
314
+ name: "Realtime notices",
315
+ description: "Reserved kill-switch for future realtime preview notices.",
316
+ defaultEnabled: false,
317
+ enabledForA8c: true,
318
+ planDefaults: {},
319
+ },
320
+ "annotations.spacefast_token": {
321
+ key: "annotations.spacefast_token",
322
+ name: "Spacefast-native annotation tokens",
323
+ description: "Mints collaboration tokens as Spacefast EdDSA access tokens (dedicated Cast kid) instead of the legacy HS256 path; the Spacefast-native auth cutover.",
324
+ defaultEnabled: false,
325
+ enabledInDevelopment: true,
326
+ enabledForA8c: true,
327
+ planDefaults: {},
328
+ },
329
+ "annotations.published_comments": {
330
+ key: "annotations.published_comments",
331
+ name: "Published host annotation comments",
332
+ description: "Allows the annotation overlay to mount comments on a space's live/published host, not just immutable preview URLs.",
333
+ defaultEnabled: false,
334
+ // ON in local dev so the Spacefast-native published path is exercised end-to-end
335
+ // alongside annotations.comments + annotations.spacefast_token (which already
336
+ // default on in dev). Production stays gated behind the per-space toggle.
337
+ enabledInDevelopment: true,
338
+ enabledForA8c: true,
339
+ planDefaults: {},
340
+ },
341
+ "sites.dedicated_runtime": {
342
+ key: "sites.dedicated_runtime",
343
+ name: "Dedicated runtime sites",
344
+ description: "Allows teams to create dedicated WP.Cloud sites and place team spaces on them.",
345
+ defaultEnabled: false,
346
+ enabledInDevelopment: true,
347
+ enabledForA8c: true,
348
+ planDefaults: {},
349
+ },
350
+ shelf: {
351
+ key: "shelf",
352
+ name: "Shelf",
353
+ description: "Exposes the per-user artifact shelf: dashboard curation and public /shelf/{handle} pages.",
354
+ defaultEnabled: false,
355
+ enabledInDevelopment: true,
356
+ enabledForA8c: true,
357
+ planDefaults: {},
358
+ },
359
+ tags: {
360
+ key: "tags",
361
+ name: "Spacefast Tag Manager",
362
+ description: "Enables Spacefast Tag Manager command surfaces, SDK configuration, and governed tag workflows.",
363
+ defaultEnabled: false,
364
+ enabledInDevelopment: true,
365
+ enabledForA8c: true,
366
+ planDefaults: {},
367
+ },
368
+ zero: {
369
+ key: "zero",
370
+ name: "Spacefast Zero",
371
+ description: "Enables Spacefast Zero command surfaces and hosted Zero app workflows.",
372
+ defaultEnabled: false,
373
+ enabledForA8c: true,
374
+ planDefaults: {},
375
+ },
376
+ };
377
+ export const featureStateSourceSchema = z
378
+ .enum(["kill_switch", "env", "override", "default"])
379
+ .describe("Layer that decided the flag: kill_switch (emergency off), env (SPACEFAST_FLAG_* variable), " +
380
+ "override (feature_overrides row), default (plan/code default).");
381
+ export const FeatureStateSchema = z.object({
382
+ key: featureKeySchema,
383
+ enabled: z.boolean().describe("Whether the feature is enabled for the requesting actor."),
384
+ source: featureStateSourceSchema,
385
+ });
386
+ export const FeatureStateResponseSchema = z.object({
387
+ planCode: planCodeSchema.describe("Plan the flags were evaluated against."),
388
+ features: z
389
+ .record(featureKeySchema, FeatureStateSchema)
390
+ .describe("Evaluated state for every known feature flag."),
391
+ });
392
+ export function normalizePlanCode(planCode) {
393
+ if (!planCode) {
394
+ return DEFAULT_PLAN_CODE;
395
+ }
396
+ const normalized = planCode.trim().toLowerCase();
397
+ return planCodeSchema.safeParse(normalized).data ?? DEFAULT_PLAN_CODE;
398
+ }
399
+ export function featureDefaultForPlan(key, planCode) {
400
+ const definition = FEATURE_DEFINITIONS[key];
401
+ return definition.planDefaults[normalizePlanCode(planCode)] ?? definition.defaultEnabled;
402
+ }
403
+ /** Numeric value of a plan limit; `null` means unlimited. */
404
+ export function planLimitNumber(value) {
405
+ return value === "unlimited" ? null : value;
406
+ }