@spacefast/common 0.0.26 → 0.2.1

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 (302) hide show
  1. package/dist/agents/connect-targets.d.ts +6 -146
  2. package/dist/agents/connect-targets.js +63 -295
  3. package/dist/agents/private-key-oauth.d.ts +31 -1
  4. package/dist/agents/private-key-oauth.js +124 -33
  5. package/dist/agents/registry/core.d.ts +292 -0
  6. package/dist/agents/registry/core.js +1388 -0
  7. package/dist/agents/registry/deeplink-probes.d.ts +23 -0
  8. package/dist/agents/registry/deeplink-probes.js +18 -0
  9. package/dist/agents/registry/node.d.ts +56 -0
  10. package/dist/agents/registry/node.js +339 -0
  11. package/dist/brand-assets-build.js +1 -2
  12. package/dist/brand-assets.js +4 -7
  13. package/dist/brand.d.ts +17 -0
  14. package/dist/brand.js +24 -4
  15. package/dist/config/domains.d.ts +55 -28
  16. package/dist/config/domains.js +85 -41
  17. package/dist/config/index.js +1 -2
  18. package/dist/contracts/abuse.js +9 -24
  19. package/dist/contracts/access-profiles.d.ts +86 -0
  20. package/dist/contracts/access-profiles.js +89 -0
  21. package/dist/contracts/access.d.ts +21 -27
  22. package/dist/contracts/access.js +33 -64
  23. package/dist/contracts/activity.d.ts +18 -1
  24. package/dist/contracts/activity.js +70 -26
  25. package/dist/contracts/analytics.js +8 -10
  26. package/dist/contracts/api-keys.d.ts +77 -52
  27. package/dist/contracts/api-keys.js +44 -24
  28. package/dist/contracts/application-journal.d.ts +216 -0
  29. package/dist/contracts/application-journal.js +167 -0
  30. package/dist/contracts/auth.d.ts +90 -17
  31. package/dist/contracts/auth.js +86 -17
  32. package/dist/contracts/beta.d.ts +9 -4
  33. package/dist/contracts/beta.js +20 -16
  34. package/dist/contracts/billing.js +7 -11
  35. package/dist/contracts/bootstrap.d.ts +791 -0
  36. package/dist/contracts/bootstrap.js +51 -0
  37. package/dist/contracts/builds.d.ts +186 -7
  38. package/dist/contracts/builds.js +75 -21
  39. package/dist/contracts/channels.d.ts +43 -0
  40. package/dist/contracts/channels.js +25 -9
  41. package/dist/contracts/cli.d.ts +7 -0
  42. package/dist/contracts/cli.js +6 -0
  43. package/dist/contracts/collab-public.d.ts +1 -1
  44. package/dist/contracts/collab-public.js +5 -8
  45. package/dist/contracts/comments.d.ts +45 -35
  46. package/dist/contracts/comments.js +107 -77
  47. package/dist/contracts/commerce.d.ts +165 -0
  48. package/dist/contracts/commerce.js +146 -0
  49. package/dist/contracts/common.d.ts +3 -3
  50. package/dist/contracts/common.js +18 -29
  51. package/dist/contracts/content-contract-verification.d.ts +521 -0
  52. package/dist/contracts/content-contract-verification.js +320 -0
  53. package/dist/contracts/content-platform-fixture.d.ts +1278 -0
  54. package/dist/contracts/content-platform-fixture.js +44 -0
  55. package/dist/contracts/content-program.d.ts +994 -0
  56. package/dist/contracts/content-program.js +658 -0
  57. package/dist/contracts/content-sync.d.ts +290 -0
  58. package/dist/contracts/content-sync.js +167 -0
  59. package/dist/contracts/content.d.ts +432 -0
  60. package/dist/contracts/content.js +303 -0
  61. package/dist/contracts/continuation.d.ts +17 -1
  62. package/dist/contracts/continuation.js +23 -23
  63. package/dist/contracts/countries.js +3 -4
  64. package/dist/contracts/crons.d.ts +17 -0
  65. package/dist/contracts/crons.js +33 -15
  66. package/dist/contracts/dashboard-prefs.d.ts +56 -0
  67. package/dist/contracts/dashboard-prefs.js +51 -0
  68. package/dist/contracts/device-auth.d.ts +234 -37
  69. package/dist/contracts/device-auth.js +267 -53
  70. package/dist/contracts/docs.d.ts +6 -10
  71. package/dist/contracts/docs.js +5 -13
  72. package/dist/contracts/domains.d.ts +499 -102
  73. package/dist/contracts/domains.js +169 -58
  74. package/dist/contracts/email-preferences.d.ts +3 -3
  75. package/dist/contracts/email-preferences.js +6 -7
  76. package/dist/contracts/enums.d.ts +26 -26
  77. package/dist/contracts/enums.js +61 -54
  78. package/dist/contracts/error-code-meta.d.ts +269 -7
  79. package/dist/contracts/error-code-meta.js +80 -5
  80. package/dist/contracts/error-codes.d.ts +5 -5
  81. package/dist/contracts/error-codes.js +78 -16
  82. package/dist/contracts/events.d.ts +100 -20
  83. package/dist/contracts/events.js +107 -20
  84. package/dist/contracts/execution.d.ts +47 -66
  85. package/dist/contracts/execution.js +51 -64
  86. package/dist/contracts/feature-lifecycle.d.ts +70 -14
  87. package/dist/contracts/feature-lifecycle.js +86 -15
  88. package/dist/contracts/features.d.ts +100 -37
  89. package/dist/contracts/features.js +21 -27
  90. package/dist/contracts/fixtures/content-platform-v1.json +1108 -0
  91. package/dist/contracts/frame-session.d.ts +192 -0
  92. package/dist/contracts/frame-session.js +164 -0
  93. package/dist/contracts/functions.d.ts +218 -211
  94. package/dist/contracts/functions.js +273 -260
  95. package/dist/contracts/grant-copy.d.ts +43 -0
  96. package/dist/contracts/grant-copy.js +44 -0
  97. package/dist/contracts/grants.d.ts +64 -56
  98. package/dist/contracts/grants.js +124 -23
  99. package/dist/contracts/ids.d.ts +4 -1
  100. package/dist/contracts/ids.js +4 -1
  101. package/dist/contracts/internal.d.ts +5 -4
  102. package/dist/contracts/internal.js +12 -3
  103. package/dist/contracts/mcp.d.ts +17 -0
  104. package/dist/contracts/mcp.js +23 -0
  105. package/dist/contracts/me.d.ts +6 -1
  106. package/dist/contracts/me.js +12 -6
  107. package/dist/contracts/notifications.d.ts +27 -29
  108. package/dist/contracts/notifications.js +9 -4
  109. package/dist/contracts/oauth-resources.d.ts +112 -10
  110. package/dist/contracts/oauth-resources.js +116 -11
  111. package/dist/contracts/oauth-scope-actions.d.ts +90 -0
  112. package/dist/contracts/oauth-scope-actions.js +126 -0
  113. package/dist/contracts/operations.d.ts +27 -4
  114. package/dist/contracts/operations.js +11 -5
  115. package/dist/contracts/pages.d.ts +29 -5
  116. package/dist/contracts/pages.js +22 -5
  117. package/dist/contracts/partner-notifications.d.ts +3 -0
  118. package/dist/contracts/partner-notifications.js +65 -0
  119. package/dist/contracts/{platform.d.ts → partner.d.ts} +29 -42
  120. package/dist/contracts/{platform.js → partner.js} +27 -40
  121. package/dist/contracts/plan-policy.d.ts +1 -1
  122. package/dist/contracts/principal-assertion.d.ts +43 -0
  123. package/dist/contracts/principal-assertion.js +67 -0
  124. package/dist/contracts/principals.d.ts +73 -0
  125. package/dist/contracts/principals.js +59 -0
  126. package/dist/contracts/privacy.d.ts +11 -0
  127. package/dist/contracts/privacy.js +17 -0
  128. package/dist/contracts/problem-document.js +3 -4
  129. package/dist/contracts/publish-archive.d.ts +116 -18
  130. package/dist/contracts/publish-archive.js +6 -3
  131. package/dist/contracts/push-new.d.ts +4 -4
  132. package/dist/contracts/quotas.js +3 -3
  133. package/dist/contracts/realtime.d.ts +52 -0
  134. package/dist/contracts/realtime.js +54 -0
  135. package/dist/contracts/repository-connections.d.ts +1 -1
  136. package/dist/contracts/repository-connections.js +6 -2
  137. package/dist/contracts/resources.d.ts +105 -14
  138. package/dist/contracts/resources.js +145 -21
  139. package/dist/contracts/route-inventory.d.ts +358 -0
  140. package/dist/contracts/route-inventory.js +141 -0
  141. package/dist/contracts/runtime-api.d.ts +112 -35
  142. package/dist/contracts/runtime-api.js +86 -66
  143. package/dist/contracts/runtime-app.d.ts +11 -21
  144. package/dist/contracts/runtime-app.js +39 -24
  145. package/dist/contracts/runtime-components.d.ts +143 -0
  146. package/dist/contracts/runtime-components.js +199 -0
  147. package/dist/contracts/runtime-db.d.ts +45 -19
  148. package/dist/contracts/runtime-db.js +85 -20
  149. package/dist/contracts/runtime-purge.js +3 -5
  150. package/dist/contracts/runtime-services.d.ts +43 -75
  151. package/dist/contracts/runtime-services.js +29 -49
  152. package/dist/contracts/runtime-storage.d.ts +14 -14
  153. package/dist/contracts/runtime-storage.js +28 -13
  154. package/dist/contracts/sf-config-v1.d.ts +14 -18
  155. package/dist/contracts/slugs.js +13 -4
  156. package/dist/contracts/space-config.d.ts +235 -28
  157. package/dist/contracts/space-config.js +246 -91
  158. package/dist/contracts/spaces.d.ts +360 -255
  159. package/dist/contracts/spaces.js +190 -122
  160. package/dist/contracts/superadmin-activity.d.ts +3 -43
  161. package/dist/contracts/superadmin-activity.js +6 -30
  162. package/dist/contracts/superadmin-emails.d.ts +1 -0
  163. package/dist/contracts/superadmin-emails.js +17 -1
  164. package/dist/contracts/superadmin-runtime.d.ts +199 -0
  165. package/dist/contracts/superadmin-runtime.js +141 -0
  166. package/dist/contracts/superadmin-search.d.ts +22 -2
  167. package/dist/contracts/superadmin-search.js +14 -6
  168. package/dist/contracts/superadmin-spaces.d.ts +435 -186
  169. package/dist/contracts/superadmin-spaces.js +131 -25
  170. package/dist/contracts/superadmin-teams.d.ts +3 -0
  171. package/dist/contracts/superadmin-teams.js +1 -2
  172. package/dist/contracts/superadmin-tenants.d.ts +627 -6
  173. package/dist/contracts/superadmin-tenants.js +32 -7
  174. package/dist/contracts/superadmin.d.ts +98 -16
  175. package/dist/contracts/superadmin.js +63 -10
  176. package/dist/contracts/tags.d.ts +85 -58
  177. package/dist/contracts/tags.js +44 -34
  178. package/dist/contracts/teams.d.ts +72 -9
  179. package/dist/contracts/teams.js +84 -25
  180. package/dist/contracts/tenants.d.ts +135 -0
  181. package/dist/contracts/tenants.js +120 -0
  182. package/dist/contracts/test-triggers.d.ts +70 -0
  183. package/dist/contracts/test-triggers.js +116 -0
  184. package/dist/contracts/theme-json.js +3 -8
  185. package/dist/contracts/transfers.d.ts +1 -0
  186. package/dist/contracts/transfers.js +1 -0
  187. package/dist/contracts/usage.d.ts +209 -0
  188. package/dist/contracts/usage.js +124 -12
  189. package/dist/contracts/variables.d.ts +2 -2
  190. package/dist/contracts/variables.js +9 -13
  191. package/dist/contracts/webhooks.d.ts +13 -5
  192. package/dist/contracts/webhooks.js +3 -1
  193. package/dist/contracts/zero.d.ts +57 -64
  194. package/dist/contracts/zero.js +68 -66
  195. package/dist/dashboard-paths/index.d.ts +24 -21
  196. package/dist/dashboard-paths/index.js +35 -47
  197. package/dist/dashboard-paths/route-reservations.generated.d.ts +2 -0
  198. package/dist/dashboard-paths/route-reservations.generated.js +36 -0
  199. package/dist/docs/agent-arrival.d.ts +92 -0
  200. package/dist/docs/agent-arrival.js +227 -0
  201. package/dist/docs/agent-output-policy.d.ts +6 -0
  202. package/dist/docs/agent-output-policy.js +22 -0
  203. package/dist/docs/agent-prose.d.ts +11 -17
  204. package/dist/docs/agent-prose.js +62 -37
  205. package/dist/docs/agent-setup.d.ts +72 -41
  206. package/dist/docs/agent-setup.js +336 -436
  207. package/dist/docs/catalog.d.ts +147 -89
  208. package/dist/docs/catalog.js +157 -42
  209. package/dist/docs/error-docs.d.ts +2098 -1
  210. package/dist/docs/error-docs.js +281 -16
  211. package/dist/docs/index-build.d.ts +0 -1
  212. package/dist/docs/index-build.js +2 -3
  213. package/dist/docs/page-context-prompt.d.ts +77 -0
  214. package/dist/docs/page-context-prompt.js +131 -0
  215. package/dist/docs/reference-urls.d.ts +46 -0
  216. package/dist/docs/reference-urls.js +79 -0
  217. package/dist/docs/search.d.ts +6 -8
  218. package/dist/docs/search.js +10 -13
  219. package/dist/docs/skill-distribution.d.ts +4 -1
  220. package/dist/docs/skill-distribution.js +10 -5
  221. package/dist/docs/skills.d.ts +117 -117
  222. package/dist/docs/skills.js +120 -72
  223. package/dist/docs/start-prompts.d.ts +45 -0
  224. package/dist/docs/start-prompts.js +62 -0
  225. package/dist/domain-exploration.js +9 -13
  226. package/dist/og-template.d.ts +56 -0
  227. package/dist/og-template.js +56 -0
  228. package/dist/slug-policy/index.js +5 -11
  229. package/dist/utils/browser-credential.d.ts +13 -6
  230. package/dist/utils/browser-credential.js +14 -7
  231. package/dist/utils/build-settings.d.ts +16 -0
  232. package/dist/utils/build-settings.js +63 -17
  233. package/dist/utils/canonical-json.d.ts +3 -5
  234. package/dist/utils/canonical-json.js +3 -5
  235. package/dist/utils/cast-transport.d.ts +5 -17
  236. package/dist/utils/cast-transport.js +6 -19
  237. package/dist/utils/claim-token.js +1 -2
  238. package/dist/utils/comment-avatars.js +4 -6
  239. package/dist/utils/concurrency.js +2 -3
  240. package/dist/utils/content-type.d.ts +7 -6
  241. package/dist/utils/content-type.js +73 -51
  242. package/dist/utils/credential-policy.d.ts +50 -6
  243. package/dist/utils/credential-policy.js +123 -57
  244. package/dist/utils/egress-policy.fixtures.json +1 -1
  245. package/dist/utils/generate-space-name.d.ts +3 -8
  246. package/dist/utils/generate-space-name.js +3 -8
  247. package/dist/utils/grants.d.ts +0 -1
  248. package/dist/utils/grants.js +4 -7
  249. package/dist/utils/gravatar.d.ts +2 -4
  250. package/dist/utils/gravatar.js +6 -12
  251. package/dist/utils/id-hints.js +14 -23
  252. package/dist/utils/idempotency.d.ts +3 -3
  253. package/dist/utils/idempotency.js +6 -7
  254. package/dist/utils/local-space-state.d.ts +15 -15
  255. package/dist/utils/local-space-state.js +34 -23
  256. package/dist/utils/oauth-signed-query.d.ts +3 -5
  257. package/dist/utils/oauth-signed-query.js +6 -9
  258. package/dist/utils/one-shot-replay.d.ts +3 -5
  259. package/dist/utils/one-shot-replay.js +3 -5
  260. package/dist/utils/page-colors.d.ts +4 -10
  261. package/dist/utils/page-colors.js +11 -35
  262. package/dist/utils/page-fonts.js +6 -11
  263. package/dist/utils/page-preview.d.ts +0 -1
  264. package/dist/utils/page-preview.js +0 -1
  265. package/dist/utils/pages.d.ts +22 -11
  266. package/dist/utils/pages.js +70 -30
  267. package/dist/utils/privacy-regions.d.ts +19 -0
  268. package/dist/utils/privacy-regions.js +91 -0
  269. package/dist/utils/publish-form-data.d.ts +4 -5
  270. package/dist/utils/publish-form-data.js +2 -3
  271. package/dist/utils/publish-policy.d.ts +10 -23
  272. package/dist/utils/publish-policy.js +63 -116
  273. package/dist/utils/query-client.d.ts +2 -0
  274. package/dist/utils/query-client.js +10 -1
  275. package/dist/utils/runtime-paths.d.ts +4 -4
  276. package/dist/utils/runtime-paths.js +6 -8
  277. package/dist/utils/runtime-upload.d.ts +4 -0
  278. package/dist/utils/runtime-upload.js +5 -0
  279. package/dist/utils/secure-local-file.d.ts +3 -3
  280. package/dist/utils/secure-local-file.js +18 -24
  281. package/dist/utils/space-config.d.ts +11 -14
  282. package/dist/utils/space-config.js +10 -16
  283. package/dist/utils/static-runtime-policy.d.ts +5 -8
  284. package/dist/utils/static-runtime-policy.generated.d.ts +16 -0
  285. package/dist/utils/static-runtime-policy.generated.js +70 -0
  286. package/dist/utils/static-runtime-policy.js +17 -84
  287. package/dist/utils/storage-policy.js +1 -2
  288. package/dist/utils/upload-session.js +8 -14
  289. package/dist/utils/version-path.js +11 -19
  290. package/dist/utils/wpcom-auth-redirects.d.ts +5 -14
  291. package/dist/utils/wpcom-auth-redirects.js +1 -4
  292. package/dist/vocabulary.d.ts +7 -7
  293. package/dist/vocabulary.js +30 -16
  294. package/package.json +14 -2
  295. package/dist/agents/client-registry.d.ts +0 -22
  296. package/dist/agents/client-registry.js +0 -41
  297. package/dist/docs/agent-handoff-document.d.ts +0 -15
  298. package/dist/docs/agent-handoff-document.js +0 -180
  299. package/dist/docs/agent-solutions.d.ts +0 -110
  300. package/dist/docs/agent-solutions.js +0 -183
  301. package/dist/utils/query-keys.d.ts +0 -84
  302. package/dist/utils/query-keys.js +0 -108
@@ -1,17 +1,12 @@
1
1
  import { z } from "zod";
2
2
  import { grantConstraintsPatchSchema, grantConstraintsSchema, grantResourceSetSchema, grantTargetSelectorSchema, } from "./grants.js";
3
- // ---------------------------------------------------------------------------
4
- // Canonical sharing model
5
- // ---------------------------------------------------------------------------
6
3
  export const SPACE_ACCESS_PRESETS = ["private", "team", "public"];
7
4
  export const ACCESS_HANDOFF_MEDIA_TYPE = "application/vnd.spacefast.access-handoff+json";
8
5
  export const spaceAccessPresetSchema = z.enum(SPACE_ACCESS_PRESETS);
9
6
  /**
10
7
  * The sharing vocabulary. Capabilities are the ground truth; a role is a named
11
- * set of them, ordered from least to most. This is the only role enum and the
12
- * only role⇄capability mapping in the product every surface (dashboard, CLI,
13
- * API, comments) names access with these four words and derives capabilities
14
- * here rather than keeping its own preset list.
8
+ * set of them, ordered from least to most. This is the product's only role enum
9
+ * and role⇄capability mapping: every surface derives its capabilities here.
15
10
  */
16
11
  export const ACCESS_ROLES = ["viewer", "commenter", "editor", "manager"];
17
12
  export const accessRoleSchema = z.enum(ACCESS_ROLES);
@@ -25,9 +20,8 @@ export function accessRoleCapabilities(role) {
25
20
  return [...ACCESS_ROLE_CAPABILITIES[role]];
26
21
  }
27
22
  /**
28
- * The role a capability set amounts to, named by the strongest capability it
29
- * carries. A Grant assembled capability-by-capability need not match a role
30
- * exactly; this reports the role it reaches, never more.
23
+ * The role a capability set amounts to: the strongest role it reaches, never
24
+ * more. A Grant assembled capability-by-capability need not match one exactly.
31
25
  */
32
26
  export function accessRoleForCapabilities(capabilities) {
33
27
  if (capabilities.includes("access.manage"))
@@ -39,9 +33,8 @@ export function accessRoleForCapabilities(capabilities) {
39
33
  return "viewer";
40
34
  }
41
35
  /**
42
- * Roles a credential-backed audience can carry. A Link or a password is a
43
- * secret anyone can forward, so it never publishes and never manages access —
44
- * the same boundary `grantSchema` enforces on the capabilities themselves.
36
+ * Roles a forwardable secret (a Link, a password) can carry. It never publishes
37
+ * and never manages access; `grantSchema` enforces that on capabilities too.
45
38
  */
46
39
  export const VISITOR_ACCESS_ROLES = [
47
40
  "viewer",
@@ -137,16 +130,12 @@ export const authorityReferenceSchema = z
137
130
  .string()
138
131
  .regex(/^(member|person|link|password|machine|claim-preview|external):[A-Za-z0-9_.-]+$/);
139
132
  // WHO a session is, orthogonal to WHAT it may do. A session has exactly one
140
- // principal and any number of authorities; neither implies the other. A member
141
- // who arrives by share link is still that member, and a link authority alone
142
- // never makes someone anonymous.
133
+ // principal and any number of authorities; neither implies the other.
143
134
  export const accountPrincipalSchema = z.string().regex(/^account:[A-Za-z0-9_-]+$/);
144
- // The three kinds of somebody. `account:` is a Spacefast user. `person:` is
145
- // someone this Space invited by email and who accepted a real, named identity
146
- // with no platform account behind it. `external:` is a subject an identity
147
- // connection vouched for. Anything else a share Link, a password, a machine
148
- // key, a claim preview — authenticates no one: those sessions stay anonymous
149
- // and carry the credential purely as an authority.
135
+ // `person:` is someone this Space invited by email and who accepted, a named
136
+ // identity with no platform account behind it. `external:` is a subject an
137
+ // identity connection vouched for. Every other authority class (Link, password,
138
+ // machine, claim preview) authenticates no one and leaves the session anonymous.
150
139
  export const identifiedPrincipalSchema = z
151
140
  .string()
152
141
  .regex(/^(?:account|person|external):[A-Za-z0-9_.-]+$/);
@@ -161,9 +150,8 @@ export function accountPrincipalUserId(principal) {
161
150
  return principal.slice("account:".length);
162
151
  }
163
152
  /**
164
- * The identity an authority reference names on its own, if any. Credential
165
- * classes name nobody. This is the ONE place a class maps to an identity: at
166
- * the exchange that just authenticated it, never downstream.
153
+ * The identity an authority reference names on its own, if any. The ONE place a
154
+ * class maps to an identity: at the exchange that authenticated it, never after.
167
155
  */
168
156
  export function principalForAuthority(reference) {
169
157
  return reference.startsWith("person:") || reference.startsWith("external:")
@@ -238,16 +226,14 @@ export const accessShareLinkSchema = z.object({
238
226
  export const accessShareLinkWithUrlSchema = accessShareLinkSchema.extend({
239
227
  url: z.string().url(),
240
228
  });
241
- // Reads re-derive the durable branded URL from the sealed token. Links minted
242
- // before branded URLs existed report null until the backfill mints theirs,
243
- // rather than pretending to hold a URL that would not open.
229
+ // Reads re-derive the branded URL from the sealed token. Links minted before
230
+ // branded URLs existed report null until the backfill mints theirs.
244
231
  export const accessShareLinkReadSchema = accessShareLinkSchema.extend({
245
232
  url: z.string().url().nullable(),
246
233
  });
247
- // The publish receipt exposes one durable access capability in both of its
248
- // useful transports: a browser entry URL and the raw token integrations send
249
- // in X-SF-Authorization. It is access to published bytes, never proof of
250
- // ownership; claim credentials stay a separate receipt field.
234
+ // One durable access capability in both transports: a browser entry URL and the
235
+ // raw token integrations send in X-SF-Authorization. It is access to published
236
+ // bytes, never proof of ownership; claim credentials are a separate receipt field.
251
237
  export const publishedAccessSchema = z.object({
252
238
  url: z.string().url(),
253
239
  token: z.string().min(16).max(512),
@@ -292,8 +278,6 @@ export const linkCapabilitiesSchema = z
292
278
  export const personGrantWriteSchema = z.object({
293
279
  scope: accessScopePathSchema,
294
280
  role: accessRoleSchema,
295
- // A Person can be invited to the live site, to one immutable Version, to a
296
- // branch, or to every Version — the same selector Links and Grants take.
297
281
  target: grantTargetSelectorSchema.default({ kind: "live" }),
298
282
  });
299
283
  export const spacePersonInviteWriteSchema = z.object({
@@ -307,8 +291,6 @@ export const accessShareLinkCreateSchema = z.object({
307
291
  name: z.string().trim().min(1).max(200),
308
292
  landingPath: accessScopePathSchema.default("/"),
309
293
  resources: grantResourceSetSchema,
310
- // Anonymous commenting is a product default: a Link that names no
311
- // capabilities admits reading the page and leaving a comment.
312
294
  capabilities: linkCapabilitiesSchema.default(["page.view", "comments.read", "comments.write"]),
313
295
  constraints: grantConstraintsSchema.default({}),
314
296
  target: grantTargetSelectorSchema.default({ kind: "live" }),
@@ -353,27 +335,21 @@ export const teamSpaceAccessDefaultSchema = z.object({
353
335
  export const teamSpaceAccessDefaultWriteSchema = z.object({
354
336
  newSpaceGrantPreset: spaceAccessPresetSchema,
355
337
  });
356
- // ---------------------------------------------------------------------------
357
- // Unified visitor and collaboration tokens
358
- // ---------------------------------------------------------------------------
359
338
  export const ACCESS_TOKEN_KID = "spacefast-runtime-v1";
360
339
  export const ACCESS_TOKEN_ALG = "EdDSA";
361
340
  /**
362
- * The claim-schema version every platform token carries in `v`. One signer,
363
- * one claim contract: a verifier that understands v1 refuses a token minted
364
- * under a later shape instead of reading unknown claims optimistically.
341
+ * The claim-schema version every platform token carries in `v`. A verifier that
342
+ * understands v1 refuses a token minted under a later shape.
365
343
  */
366
344
  export const PLATFORM_TOKEN_CLAIM_VERSION = 1;
367
345
  export const BLOB_GATE_DOWNLOAD_TTL_SECONDS = 10 * 60;
368
346
  export const BLOB_GATE_SCAN_TTL_SECONDS = 60 * 60;
369
347
  export const BLOB_GATE_UPLOAD_TTL_SECONDS = 60 * 60;
370
348
  export const RUNTIME_JWKS_WELL_KNOWN_FILENAME = "spacefast-runtime-jwks.json";
371
- // Public identity attached only when a token consumer needs to render the
372
- // person behind an authority. Collaboration tickets carry this audience-bound
373
- // claim so Cast can paint an avatar without ever seeing an address: the
374
- // minting side normalizes a provider avatar or derives one from the email,
375
- // then drops the email. Raw email and provider-private profile metadata never
376
- // belong here.
349
+ // Public identity, attached only when a consumer must render the person behind
350
+ // an authority. The minting side normalizes a provider avatar or derives one
351
+ // from the email, then drops the email. Raw email and provider-private profile
352
+ // metadata never belong here.
377
353
  export const accessTokenPublicProfileSchema = z
378
354
  .object({
379
355
  name: z.string().min(1).max(120).optional(),
@@ -386,32 +362,25 @@ export const accessTokenPublicProfileSchema = z
386
362
  .strict();
387
363
  export const accessTokenPayloadSchema = z.object({
388
364
  // Typed purpose from the one platform signer. The runtime REQUIRES exactly
389
- // this value before consuming the jti: a system-view token (or any other
390
- // purpose signed by the same key) can never redeem into a visitor session,
391
- // and a handoff can never pass a system-view check.
365
+ // this value before consuming the jti, so no other purpose signed by the same
366
+ // key can redeem into a visitor session.
392
367
  purpose: z.literal("handoff"),
393
- // Claim-schema version stamped by the one signer.
394
368
  v: z.literal(PLATFORM_TOKEN_CLAIM_VERSION),
395
369
  sub: authorityReferenceSchema,
396
- // Who this handoff authenticated, when it authenticated anybody. The account
397
- // lane names the signed-in user; the invite and identity-connection lanes
398
- // name the Person or external subject they just proved. Link, password,
399
- // machine, and claim-preview lanes never set it, and its absence means the
400
- // runtime session is anonymous. Identity comes from here alone — never
401
- // inferred from the authority classes below.
370
+ // Who this handoff authenticated, when it authenticated anybody. Its absence
371
+ // means the runtime session is anonymous. Identity comes from here alone,
372
+ // never inferred from the authority classes below.
402
373
  principal: identifiedPrincipalSchema.optional(),
403
374
  authorities: z.array(authorityReferenceSchema).min(1).max(16),
404
375
  exp: z.number().int().nonnegative(),
405
376
  nbf: z.number().int().nonnegative(),
406
377
  iat: z.number().int().nonnegative(),
407
378
  iss: z.string().min(1),
408
- // The Space this handoff belongs to, and the token's identity: a Space keeps
409
- // its id across claim, rename, and every custom domain it later answers on,
410
- // so the audience is stable where a serving host is not.
379
+ // The Space this handoff belongs to. A Space keeps its id across claim,
380
+ // rename, and custom domains, so the audience is stable where a host is not.
411
381
  aud: z.string().min(1),
412
- // The lowercased serving host the handoff was minted for. Host binding did
413
- // not go away when `aud` stopped carrying it — it lives here, and the runtime
414
- // rejects a token presented on any other host.
382
+ // The lowercased serving host the handoff was minted for. The runtime rejects
383
+ // a token presented on any other host.
415
384
  host: z.string().min(1),
416
385
  spaceId: z.string().min(1),
417
386
  // Shared opaque identity for the runtime session and its access-origin
@@ -1,5 +1,5 @@
1
1
  import { z } from "zod";
2
- export declare const ACTIVITY_EVENT_CODES: readonly ["space.created", "space.claimed", "feedback.lead_claim_pending", "space.transferred", "space.expired", "space.disabled", "space.enabled", "space.deleted", "space.config_updated", "space.slug_updated", "site.provision_requested", "site.placement_hold_set", "site.placement_hold_cleared", "site.burst_toggled", "space.access_logout_all", "space.access_transfer_scrub", "space.share_link_created", "space.share_link_revoked", "space.access_request_created", "space.access_request_resolved", "space.grant_created", "space.grant_updated", "space.grant_revoked", "team.access_defaults_updated", "version.created", "version.ready", "version.warning", "version.failed", "version.expired", "version.canceled", "version.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", "domain.attached", "domain.activated", "domain.blocked", "domain.detached", "transfer.requested", "transfer.confirmed", "transfer.completed", "transfer.canceled", "transfer.expired", "transfer.failed", "cron.failed", "variable.updated", "variable.deleted", "api_key.created", "api_key.updated", "api_key.revoked", "agent_handoff.created", "agent_handoff.redeemed", "agent_handoff.revoked", "webhook.created", "webhook.updated", "webhook.secret_rotated", "webhook.disabled", "webhook.deleted", "team.updated", "team.slug_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", "comment.token_minted", "comment.created", "comment.reply_created", "comment.archived", "comment.unarchived", "abuse_report.created", "abuse_report.updated", "claim.blocked_takedown", "claim.authority_rotated", "user.created", "user.signed_in", "user.deleted", "user.impersonation_started", "user.impersonation_stopped", "user.two_factor_enabled", "user.two_factor_disabled"];
2
+ export declare const ACTIVITY_EVENT_CODES: readonly ["space.created", "space.claimed", "feedback.lead_claim_pending", "space.transferred", "space.expired", "space.disabled", "space.enabled", "space.deleted", "space.config_updated", "space.slug_updated", "site.provision_requested", "site.burst_toggled", "space.access_logout_all", "space.access_transfer_scrub", "space.share_link_created", "space.share_link_revoked", "space.access_request_created", "space.access_request_resolved", "space.grant_created", "space.grant_updated", "space.grant_revoked", "team.access_defaults_updated", "version.created", "version.ready", "version.warning", "version.failed", "version.expired", "version.canceled", "version.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", "domain.attached", "domain.activated", "domain.blocked", "domain.detached", "transfer.requested", "transfer.confirmed", "transfer.completed", "transfer.canceled", "transfer.expired", "transfer.failed", "cron.failed", "variable.updated", "variable.deleted", "api_key.created", "api_key.updated", "api_key.revoked", "agent_handoff.created", "agent_handoff.redeemed", "agent_handoff.revoked", "webhook.created", "webhook.updated", "webhook.secret_rotated", "webhook.disabled", "webhook.deleted", "team.updated", "team.slug_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", "principal.plan_reset", "principal.space_quota_exceeded", "principal.suspended", "principal.unsuspended", "principal.closed", "usage.threshold_crossed", "usage.period_finalized", "usage.corrected", "principal.notification.claim", "principal.notification.space_expiry", "principal.notification.access_invitation", "principal.notification.access_request", "principal.notification.access_verification", "principal.notification.publish_receipt", "principal.notification.comment", "comment.token_minted", "comment.created", "comment.reply_created", "comment.archived", "comment.unarchived", "abuse_report.created", "abuse_report.updated", "claim.blocked_takedown", "claim.authority_rotated", "user.created", "user.signed_in", "user.deleted", "user.impersonation_started", "user.impersonation_stopped", "user.two_factor_enabled", "user.two_factor_disabled", "user.password_set", "user.password_changed", "user.provider_linked", "user.provider_unlinked", "user.email_added", "user.email_removed", "user.primary_email_changed", "user.superadmin_granted", "user.superadmin_revoked", "user.privacy_updated", "user.deletion_requested", "user.deletion_completed"];
3
3
  export type ActivityEventCode = (typeof ACTIVITY_EVENT_CODES)[number];
4
4
  export declare function isActivityEventCode(value: string): value is ActivityEventCode;
5
5
  export declare function isValidActivityEventFilter(filter: string): boolean;
@@ -10,6 +10,9 @@ export declare const activityActorSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
10
10
  }, z.core.$strip>, z.ZodObject<{
11
11
  type: z.ZodLiteral<"api_key">;
12
12
  id: z.ZodString;
13
+ }, z.core.$strip>, z.ZodObject<{
14
+ type: z.ZodLiteral<"partner_token">;
15
+ id: z.ZodString;
13
16
  }, z.core.$strip>, z.ZodObject<{
14
17
  type: z.ZodLiteral<"oauth_client">;
15
18
  id: z.ZodString;
@@ -32,6 +35,10 @@ export declare const activityEventSchema: z.ZodObject<{
32
35
  id: z.ZodString;
33
36
  sequence: z.ZodNumber;
34
37
  tenantId: z.ZodString;
38
+ mode: z.ZodEnum<{
39
+ live: "live";
40
+ test: "test";
41
+ }>;
35
42
  principal: z.ZodNullable<z.ZodObject<{
36
43
  tenantId: z.ZodString;
37
44
  principalType: z.ZodEnum<{
@@ -47,6 +54,9 @@ export declare const activityEventSchema: z.ZodObject<{
47
54
  }, z.core.$strip>, z.ZodObject<{
48
55
  type: z.ZodLiteral<"api_key">;
49
56
  id: z.ZodString;
57
+ }, z.core.$strip>, z.ZodObject<{
58
+ type: z.ZodLiteral<"partner_token">;
59
+ id: z.ZodString;
50
60
  }, z.core.$strip>, z.ZodObject<{
51
61
  type: z.ZodLiteral<"oauth_client">;
52
62
  id: z.ZodString;
@@ -80,6 +90,10 @@ export declare const activityListResponseSchema: z.ZodObject<{
80
90
  id: z.ZodString;
81
91
  sequence: z.ZodNumber;
82
92
  tenantId: z.ZodString;
93
+ mode: z.ZodEnum<{
94
+ live: "live";
95
+ test: "test";
96
+ }>;
83
97
  principal: z.ZodNullable<z.ZodObject<{
84
98
  tenantId: z.ZodString;
85
99
  principalType: z.ZodEnum<{
@@ -95,6 +109,9 @@ export declare const activityListResponseSchema: z.ZodObject<{
95
109
  }, z.core.$strip>, z.ZodObject<{
96
110
  type: z.ZodLiteral<"api_key">;
97
111
  id: z.ZodString;
112
+ }, z.core.$strip>, z.ZodObject<{
113
+ type: z.ZodLiteral<"partner_token">;
114
+ id: z.ZodString;
98
115
  }, z.core.$strip>, z.ZodObject<{
99
116
  type: z.ZodLiteral<"oauth_client">;
100
117
  id: z.ZodString;
@@ -1,10 +1,10 @@
1
1
  import { z } from "zod";
2
2
  import { AnyObjectSchema, CursorPaginationSchema, cursorListQuerySchema } from "./common.js";
3
- // The single event taxonomy (the platform spec "Event taxonomy").
4
- // Every emitted activity event and every webhook `events` filter selects on
5
- // these codes.
6
- // `appendActivityEvent` is typed against this list, so emitting a code that is
7
- // not in the table is a typecheck (CI) failure.
3
+ import { tenantMode } from "./enums.js";
4
+ import { PRINCIPAL_NOTIFICATION_EVENT_CODES } from "./partner-notifications.js";
5
+ // The single event taxonomy (the platform spec "Event taxonomy"). Every emitted
6
+ // event and every webhook `events` filter selects on these codes, and
7
+ // `appendActivityEvent` is typed against the list, so an off-list code fails CI.
8
8
  export const ACTIVITY_EVENT_CODES = [
9
9
  // space
10
10
  "space.created",
@@ -19,8 +19,6 @@ export const ACTIVITY_EVENT_CODES = [
19
19
  "space.slug_updated",
20
20
  // site
21
21
  "site.provision_requested",
22
- "site.placement_hold_set",
23
- "site.placement_hold_cleared",
24
22
  "site.burst_toggled",
25
23
  // access
26
24
  "space.access_logout_all",
@@ -94,38 +92,59 @@ export const ACTIVITY_EVENT_CODES = [
94
92
  "webhook.secret_rotated",
95
93
  "webhook.disabled",
96
94
  "webhook.deleted",
97
- // team (builds_deploys_quota_exceeded is a shipped additive extension: the
98
- // pooled monthly builds+deploys meter is SOFT — it tracks, never blocks)
95
+ // team (the pooled monthly builds+deploys meter is SOFT: it tracks, never blocks)
99
96
  "team.updated",
100
97
  "team.slug_updated",
101
98
  "team.member_added",
102
99
  "team.member_removed",
103
100
  "team.member_role_updated",
104
101
  "team.builds_deploys_quota_exceeded",
105
- // tenant (tenant.deleted is a shipped additive extension)
102
+ // tenant
106
103
  "tenant.past_due",
107
104
  "tenant.suspended",
108
105
  "tenant.reactivated",
109
106
  "tenant.deleted",
107
+ // principal (partner commerce lifecycle; §4/§5). `plan_reset` fires when a
108
+ // plan an external principal is assigned to drops out of the tenant's
109
+ // system-space plan catalog and the assignment falls back to the default.
110
+ "principal.plan_reset",
111
+ // Fires when an external principal creates a space that trips its plan's
112
+ // space-count quota under the `warn` enforcement policy — the create is
113
+ // allowed through and this records the overage instead of blocking.
114
+ "principal.space_quota_exceeded",
115
+ // Lifecycle transitions (§4). `suspended` darkens the principal's spaces
116
+ // (402 suspended page) and blocks its mutations; `unsuspended` restores both;
117
+ // `closed` is terminal. Each carries the acting actor so a Spacefast-applied
118
+ // status is distinguishable from a partner-applied one.
119
+ "principal.suspended",
120
+ "principal.unsuspended",
121
+ "principal.closed",
122
+ // partner usage ledger
123
+ "usage.threshold_crossed",
124
+ "usage.period_finalized",
125
+ "usage.corrected",
126
+ // principal notifications (partner API §7): the customer-facing notifications
127
+ // a partner white-labels. Spacefast delegates them — instead of emailing the
128
+ // partner's own end customer, it emits the event here for the partner to
129
+ // deliver. Defined in partner-notifications.ts (the subscribe-side catalog)
130
+ // and folded in so each is a first-class taxonomy code with a grammar row and
131
+ // a valid webhook filter.
132
+ ...PRINCIPAL_NOTIFICATION_EVENT_CODES,
110
133
  // comments
111
134
  "comment.token_minted",
112
135
  "comment.created",
113
136
  "comment.reply_created",
114
137
  "comment.archived",
115
138
  "comment.unarchived",
116
- // abuse (additive extension: operator-tunable abuse-control telemetry)
139
+ // abuse
117
140
  "abuse_report.created",
118
141
  "abuse_report.updated",
119
- // claim (additive extension: a claim attempt against a taken-down space is
120
- // flagged, never silently 404ed — the platform spec "Abuse Posture")
142
+ // claim (an attempt against a taken-down space is flagged, never silently 404ed)
121
143
  "claim.blocked_takedown",
122
144
  "claim.authority_rotated",
123
- // user (additive extension: account lifecycle plus the 2FA and
124
- // admin-impersonation effects that must surface through ActivityEvent
125
- // the platform spec Better Auth usage). `user.created` fires once on
126
- // signup; `user.signed_in` fires per non-impersonation session creation;
127
- // `user.deleted` fires on account deletion and retains the analyticsId in
128
- // its details so right-to-erasure can be completed in every provider.
145
+ // user. `user.signed_in` fires per non-impersonation session creation.
146
+ // `user.deleted` retains the analyticsId in its details so right-to-erasure
147
+ // can be completed in every provider.
129
148
  "user.created",
130
149
  "user.signed_in",
131
150
  "user.deleted",
@@ -133,20 +152,43 @@ export const ACTIVITY_EVENT_CODES = [
133
152
  "user.impersonation_stopped",
134
153
  "user.two_factor_enabled",
135
154
  "user.two_factor_disabled",
155
+ // Security notifications (auth/security-events.ts): every auth mutation that
156
+ // changes how the account can be entered lands here AND mails the owner
157
+ // through the same pipeline. Ids only in details, never addresses or names.
158
+ "user.password_set",
159
+ "user.password_changed",
160
+ "user.provider_linked",
161
+ "user.provider_unlinked",
162
+ "user.email_added",
163
+ "user.email_removed",
164
+ "user.primary_email_changed",
165
+ "user.superadmin_granted",
166
+ "user.superadmin_revoked",
167
+ "user.privacy_updated",
168
+ "user.deletion_requested",
169
+ "user.deletion_completed",
136
170
  ];
137
171
  const ACTIVITY_EVENT_CODE_SET = new Set(ACTIVITY_EVENT_CODES);
138
- const ACTIVITY_EVENT_RESOURCES = new Set(ACTIVITY_EVENT_CODES.map((code) => code.split(".", 1)[0]));
172
+ // Every dot-delimited prefix a code carries, at each segment boundary — the set
173
+ // a prefix wildcard may name. `version.ready` contributes `version`;
174
+ // `principal.notification.claim` contributes both `principal` and
175
+ // `principal.notification`, so a partner can subscribe to the whole
176
+ // `principal.notification.*` class in one filter.
177
+ const ACTIVITY_EVENT_PREFIXES = new Set(ACTIVITY_EVENT_CODES.flatMap((code) => {
178
+ const parts = code.split(".");
179
+ return parts.slice(0, -1).map((_, index) => parts.slice(0, index + 1).join("."));
180
+ }));
139
181
  export function isActivityEventCode(value) {
140
182
  return ACTIVITY_EVENT_CODE_SET.has(value);
141
183
  }
142
- // Webhook `events` filters accept exact codes, prefix wildcards ("version.*"),
143
- // and the catch-all ["*"].
184
+ // Webhook `events` filters accept exact codes, prefix wildcards ("version.*",
185
+ // "principal.notification.*"), and the catch-all ["*"].
144
186
  export function isValidActivityEventFilter(filter) {
145
187
  if (filter === "*") {
146
188
  return true;
147
189
  }
148
190
  if (filter.endsWith(".*")) {
149
- return ACTIVITY_EVENT_RESOURCES.has(filter.slice(0, -2));
191
+ return ACTIVITY_EVENT_PREFIXES.has(filter.slice(0, -2));
150
192
  }
151
193
  return ACTIVITY_EVENT_CODE_SET.has(filter);
152
194
  }
@@ -158,6 +200,7 @@ export function matchesActivityEventFilters(filters, code) {
158
200
  export const activityActorSchema = z.discriminatedUnion("type", [
159
201
  z.object({ type: z.literal("user"), id: z.string().min(1) }),
160
202
  z.object({ type: z.literal("api_key"), id: z.string().min(1) }),
203
+ z.object({ type: z.literal("partner_token"), id: z.string().min(1) }),
161
204
  z.object({ type: z.literal("oauth_client"), id: z.string().min(1) }),
162
205
  z.object({ type: z.literal("anonymous_claim"), id: z.string().min(1) }),
163
206
  z.object({ type: z.literal("system"), id: z.string().min(1) }),
@@ -171,6 +214,7 @@ export const activityEventSchema = z.object({
171
214
  id: z.string(),
172
215
  sequence: z.number().int().nonnegative(),
173
216
  tenantId: z.string(),
217
+ mode: tenantMode.describe("`test` when the event's tenant is a linked test tenant, `live` otherwise."),
174
218
  principal: activityPrincipalSchema.nullable(),
175
219
  spaceId: z.string().nullable(),
176
220
  actor: activityActorSchema,
@@ -183,9 +227,9 @@ export const activityQuerySchema = cursorListQuerySchema.extend({
183
227
  principalType: z
184
228
  .enum(["team", "external"])
185
229
  .optional()
186
- .describe("Filter to events owned by a team or an external customer principal."),
187
- principalId: z.string().min(1).optional().describe("Filter to a single principal id."),
188
- spaceId: z.string().min(1).optional().describe("Filter to events for one space."),
230
+ .describe("Filter by owning principal type."),
231
+ principalId: z.string().min(1).optional().describe("Filter to one principal."),
232
+ spaceId: z.string().min(1).optional().describe("Filter to one space."),
189
233
  code: z
190
234
  .string()
191
235
  .min(1)
@@ -4,11 +4,10 @@ export const DOMAIN_SSH_ANALYTICS_EVENTS = [
4
4
  "domain_ssh_session_ended",
5
5
  "domain_ssh_lookup_requested",
6
6
  ];
7
- // Direct product analytics events. These cover request/funnel moments that the
8
- // activity taxonomy (contracts/activity.ts) intentionally does NOT record
9
- // queue requests, anonymous publish receipts, gating decisions. Everything
10
- // that IS an activity event reaches the analytics providers through the
11
- // activity fan-out instead, so a business moment is never captured twice.
7
+ // Direct product analytics events: request/funnel moments the activity taxonomy
8
+ // (contracts/activity.ts) deliberately does NOT record. Everything that IS an
9
+ // activity event reaches the providers through the activity fan-out, so a
10
+ // business moment is never captured twice.
12
11
  export const ANALYTICS_EVENTS = [
13
12
  "version_intent_created",
14
13
  "version_finalize_queued",
@@ -57,11 +56,10 @@ export const domainSshAnalyticsEventSchema = z.object({
57
56
  .optional(),
58
57
  units: z.coerce.number().int().min(1).max(DOMAIN_SSH_ANALYTICS_MAX_UNITS).optional(),
59
58
  });
60
- // Tracks (Automattic analytics) naming rules, shared by the browser pixel
61
- // client and the control-plane REST client: event names are
62
- // `stattic_<noun>_<verb>` snake_case tokens and property names are lowercase
63
- // snake_case (calypso-analytics validation rules). Internal names use dots
64
- // (`space.created`, `cli.command`) and camelCase details, so both normalize.
59
+ // Tracks (Automattic analytics) naming rules, shared by the browser pixel client
60
+ // and the control-plane REST client: event names are `stattic_<noun>_<verb>` and
61
+ // property names lowercase snake_case (calypso-analytics validation). Internal
62
+ // names use dots and camelCase, so both normalize.
65
63
  export const TRACKS_EVENT_PREFIX = "stattic";
66
64
  export function tracksEventName(name) {
67
65
  const normalized = name