@soulcraft/sdk 1.0.0

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 (149) hide show
  1. package/dist/client/index.d.ts +62 -0
  2. package/dist/client/index.d.ts.map +1 -0
  3. package/dist/client/index.js +60 -0
  4. package/dist/client/index.js.map +1 -0
  5. package/dist/index.d.ts +33 -0
  6. package/dist/index.d.ts.map +1 -0
  7. package/dist/index.js +17 -0
  8. package/dist/index.js.map +1 -0
  9. package/dist/modules/ai/index.d.ts +55 -0
  10. package/dist/modules/ai/index.d.ts.map +1 -0
  11. package/dist/modules/ai/index.js +263 -0
  12. package/dist/modules/ai/index.js.map +1 -0
  13. package/dist/modules/ai/types.d.ts +216 -0
  14. package/dist/modules/ai/types.d.ts.map +1 -0
  15. package/dist/modules/ai/types.js +30 -0
  16. package/dist/modules/ai/types.js.map +1 -0
  17. package/dist/modules/auth/backchannel.d.ts +85 -0
  18. package/dist/modules/auth/backchannel.d.ts.map +1 -0
  19. package/dist/modules/auth/backchannel.js +168 -0
  20. package/dist/modules/auth/backchannel.js.map +1 -0
  21. package/dist/modules/auth/config.d.ts +122 -0
  22. package/dist/modules/auth/config.d.ts.map +1 -0
  23. package/dist/modules/auth/config.js +158 -0
  24. package/dist/modules/auth/config.js.map +1 -0
  25. package/dist/modules/auth/middleware.d.ts +146 -0
  26. package/dist/modules/auth/middleware.d.ts.map +1 -0
  27. package/dist/modules/auth/middleware.js +204 -0
  28. package/dist/modules/auth/middleware.js.map +1 -0
  29. package/dist/modules/auth/types.d.ts +162 -0
  30. package/dist/modules/auth/types.d.ts.map +1 -0
  31. package/dist/modules/auth/types.js +14 -0
  32. package/dist/modules/auth/types.js.map +1 -0
  33. package/dist/modules/billing/types.d.ts +7 -0
  34. package/dist/modules/billing/types.d.ts.map +1 -0
  35. package/dist/modules/billing/types.js +7 -0
  36. package/dist/modules/billing/types.js.map +1 -0
  37. package/dist/modules/brainy/auth.d.ts +104 -0
  38. package/dist/modules/brainy/auth.d.ts.map +1 -0
  39. package/dist/modules/brainy/auth.js +144 -0
  40. package/dist/modules/brainy/auth.js.map +1 -0
  41. package/dist/modules/brainy/errors.d.ts +118 -0
  42. package/dist/modules/brainy/errors.d.ts.map +1 -0
  43. package/dist/modules/brainy/errors.js +142 -0
  44. package/dist/modules/brainy/errors.js.map +1 -0
  45. package/dist/modules/brainy/events.d.ts +63 -0
  46. package/dist/modules/brainy/events.d.ts.map +1 -0
  47. package/dist/modules/brainy/events.js +14 -0
  48. package/dist/modules/brainy/events.js.map +1 -0
  49. package/dist/modules/brainy/proxy.d.ts +48 -0
  50. package/dist/modules/brainy/proxy.d.ts.map +1 -0
  51. package/dist/modules/brainy/proxy.js +95 -0
  52. package/dist/modules/brainy/proxy.js.map +1 -0
  53. package/dist/modules/brainy/types.d.ts +83 -0
  54. package/dist/modules/brainy/types.d.ts.map +1 -0
  55. package/dist/modules/brainy/types.js +21 -0
  56. package/dist/modules/brainy/types.js.map +1 -0
  57. package/dist/modules/events/index.d.ts +41 -0
  58. package/dist/modules/events/index.d.ts.map +1 -0
  59. package/dist/modules/events/index.js +53 -0
  60. package/dist/modules/events/index.js.map +1 -0
  61. package/dist/modules/events/types.d.ts +129 -0
  62. package/dist/modules/events/types.d.ts.map +1 -0
  63. package/dist/modules/events/types.js +32 -0
  64. package/dist/modules/events/types.js.map +1 -0
  65. package/dist/modules/formats/types.d.ts +7 -0
  66. package/dist/modules/formats/types.d.ts.map +1 -0
  67. package/dist/modules/formats/types.js +7 -0
  68. package/dist/modules/formats/types.js.map +1 -0
  69. package/dist/modules/hall/types.d.ts +56 -0
  70. package/dist/modules/hall/types.d.ts.map +1 -0
  71. package/dist/modules/hall/types.js +16 -0
  72. package/dist/modules/hall/types.js.map +1 -0
  73. package/dist/modules/kits/types.d.ts +7 -0
  74. package/dist/modules/kits/types.d.ts.map +1 -0
  75. package/dist/modules/kits/types.js +7 -0
  76. package/dist/modules/kits/types.js.map +1 -0
  77. package/dist/modules/license/types.d.ts +7 -0
  78. package/dist/modules/license/types.d.ts.map +1 -0
  79. package/dist/modules/license/types.js +7 -0
  80. package/dist/modules/license/types.js.map +1 -0
  81. package/dist/modules/notifications/types.d.ts +7 -0
  82. package/dist/modules/notifications/types.d.ts.map +1 -0
  83. package/dist/modules/notifications/types.js +7 -0
  84. package/dist/modules/notifications/types.js.map +1 -0
  85. package/dist/modules/skills/index.d.ts +60 -0
  86. package/dist/modules/skills/index.d.ts.map +1 -0
  87. package/dist/modules/skills/index.js +253 -0
  88. package/dist/modules/skills/index.js.map +1 -0
  89. package/dist/modules/skills/types.d.ts +127 -0
  90. package/dist/modules/skills/types.d.ts.map +1 -0
  91. package/dist/modules/skills/types.js +23 -0
  92. package/dist/modules/skills/types.js.map +1 -0
  93. package/dist/modules/versions/types.d.ts +31 -0
  94. package/dist/modules/versions/types.d.ts.map +1 -0
  95. package/dist/modules/versions/types.js +9 -0
  96. package/dist/modules/versions/types.js.map +1 -0
  97. package/dist/modules/vfs/types.d.ts +26 -0
  98. package/dist/modules/vfs/types.d.ts.map +1 -0
  99. package/dist/modules/vfs/types.js +11 -0
  100. package/dist/modules/vfs/types.js.map +1 -0
  101. package/dist/server/create-sdk.d.ts +70 -0
  102. package/dist/server/create-sdk.d.ts.map +1 -0
  103. package/dist/server/create-sdk.js +125 -0
  104. package/dist/server/create-sdk.js.map +1 -0
  105. package/dist/server/hall-handlers.d.ts +195 -0
  106. package/dist/server/hall-handlers.d.ts.map +1 -0
  107. package/dist/server/hall-handlers.js +239 -0
  108. package/dist/server/hall-handlers.js.map +1 -0
  109. package/dist/server/handlers.d.ts +216 -0
  110. package/dist/server/handlers.d.ts.map +1 -0
  111. package/dist/server/handlers.js +214 -0
  112. package/dist/server/handlers.js.map +1 -0
  113. package/dist/server/index.d.ts +52 -0
  114. package/dist/server/index.d.ts.map +1 -0
  115. package/dist/server/index.js +50 -0
  116. package/dist/server/index.js.map +1 -0
  117. package/dist/server/instance-pool.d.ts +299 -0
  118. package/dist/server/instance-pool.d.ts.map +1 -0
  119. package/dist/server/instance-pool.js +359 -0
  120. package/dist/server/instance-pool.js.map +1 -0
  121. package/dist/transports/http.d.ts +86 -0
  122. package/dist/transports/http.d.ts.map +1 -0
  123. package/dist/transports/http.js +134 -0
  124. package/dist/transports/http.js.map +1 -0
  125. package/dist/transports/local.d.ts +76 -0
  126. package/dist/transports/local.d.ts.map +1 -0
  127. package/dist/transports/local.js +101 -0
  128. package/dist/transports/local.js.map +1 -0
  129. package/dist/transports/sse.d.ts +99 -0
  130. package/dist/transports/sse.d.ts.map +1 -0
  131. package/dist/transports/sse.js +192 -0
  132. package/dist/transports/sse.js.map +1 -0
  133. package/dist/transports/transport.d.ts +68 -0
  134. package/dist/transports/transport.d.ts.map +1 -0
  135. package/dist/transports/transport.js +14 -0
  136. package/dist/transports/transport.js.map +1 -0
  137. package/dist/transports/ws.d.ts +135 -0
  138. package/dist/transports/ws.d.ts.map +1 -0
  139. package/dist/transports/ws.js +331 -0
  140. package/dist/transports/ws.js.map +1 -0
  141. package/dist/types.d.ts +152 -0
  142. package/dist/types.d.ts.map +1 -0
  143. package/dist/types.js +8 -0
  144. package/dist/types.js.map +1 -0
  145. package/docs/ADR-001-sdk-design.md +282 -0
  146. package/docs/IMPLEMENTATION-PLAN.md +708 -0
  147. package/docs/USAGE.md +646 -0
  148. package/docs/kit-sdk-guide.md +474 -0
  149. package/package.json +61 -0
@@ -0,0 +1,162 @@
1
+ /**
2
+ * @module modules/auth/types
3
+ * @description Shared role definitions, session types, and OIDC configuration
4
+ * interfaces for the Soulcraft platform.
5
+ *
6
+ * These types are product-agnostic and drive access control across Workshop,
7
+ * Venue, Academy, and Portal. Platform-level roles control what products a user
8
+ * can access; product-level roles control what they can do within each product.
9
+ *
10
+ * This module absorbs and replaces `@soulcraft/auth/types`, which is deprecated
11
+ * in favour of importing directly from `@soulcraft/sdk`.
12
+ */
13
+ /**
14
+ * Top-level roles in the Soulcraft platform.
15
+ *
16
+ * - `creator` — Workshop user: creates workspaces, kits, and publishes to Venue
17
+ * - `viewer` — Read-only consumer of published Workshop content
18
+ * - `customer` — Venue customer: books sessions, manages loyalty account
19
+ * - `staff` — Venue staff: check in guests, run POS, log sessions
20
+ * - `manager` — Venue manager: all staff capabilities + analytics, scheduling
21
+ * - `owner` — Full platform owner: all capabilities + billing, kit selection, RBAC
22
+ * - `learner` — Academy learner: enrolled in courses, tracks progress
23
+ * - `instructor` — Academy instructor: creates courses, manages live sessions
24
+ */
25
+ export type PlatformRole = 'creator' | 'viewer' | 'customer' | 'staff' | 'manager' | 'owner' | 'learner' | 'instructor';
26
+ /**
27
+ * Auth providers supported across the Soulcraft platform.
28
+ *
29
+ * - `google` — Google OAuth (Workshop, Venue)
30
+ * - `github` — GitHub OAuth (Workshop only — developer-facing)
31
+ * - `apple` — Apple OAuth (Venue only — consumer-facing)
32
+ * - `passkey` — WebAuthn passkey (all products, primary auth method)
33
+ * - `magic-link` — Email magic link (Workshop + Venue customer login)
34
+ */
35
+ export type SoulcraftAuthProvider = 'google' | 'github' | 'apple' | 'passkey' | 'magic-link';
36
+ /**
37
+ * A Soulcraft organization ties together users across products.
38
+ *
39
+ * - Venue: one org per business location or franchise
40
+ * - Workshop: one org per team or enterprise account
41
+ * - Academy: one org per institution or cohort
42
+ */
43
+ export interface SoulcraftOrganization {
44
+ /** Unique org ID (better-auth organization ID). */
45
+ id: string;
46
+ /** Human-readable name, e.g. "Wicks & Whiskers Charlotte". */
47
+ name: string;
48
+ /** URL-safe slug, e.g. "wicks-charlotte". */
49
+ slug: string;
50
+ /** Which product this org belongs to. */
51
+ product: 'workshop' | 'venue' | 'academy' | 'portal';
52
+ /**
53
+ * Product-specific metadata.
54
+ * - Venue orgs: `{ locationId, kitId, subdomain }`
55
+ * - Workshop orgs: `{ plan, workspaceCount }`
56
+ * - Academy orgs: `{ cohortId, courseIds }`
57
+ */
58
+ metadata: Record<string, unknown>;
59
+ }
60
+ /**
61
+ * Additional fields stored on a Soulcraft user record beyond better-auth defaults.
62
+ *
63
+ * Registered via `betterAuth({ user: { additionalFields: SOULCRAFT_USER_FIELDS } })`.
64
+ */
65
+ export interface SoulcraftUserFields {
66
+ /**
67
+ * The user's primary platform role.
68
+ * Controls cross-product access at the IdP level.
69
+ */
70
+ platformRole: PlatformRole;
71
+ /**
72
+ * SHA-256 hex digest of the user's canonical email address.
73
+ *
74
+ * Computed once at account creation and never changes, even if the user updates
75
+ * their email or switches OAuth providers. Used by Workshop to deterministically
76
+ * locate the user's Brainy data directory without exposing the email in paths.
77
+ *
78
+ * Path pattern: `{brainyDataPath}/{emailHash.slice(0,8)}/{workspaceId}/`
79
+ *
80
+ * @see computeEmailHash in modules/auth/config.ts
81
+ */
82
+ emailHash: string;
83
+ }
84
+ /**
85
+ * The Soulcraft user object available after session resolution.
86
+ *
87
+ * Combines better-auth's standard session user with Soulcraft platform fields.
88
+ */
89
+ export interface SoulcraftSessionUser {
90
+ /** better-auth user ID (UUID). */
91
+ id: string;
92
+ /** User's email address. */
93
+ email: string;
94
+ /** Display name. */
95
+ name: string;
96
+ /** Avatar URL (from OAuth provider or profile). */
97
+ image?: string | null;
98
+ /** Platform role — controls coarse cross-product access. */
99
+ platformRole: PlatformRole;
100
+ /** SHA-256 hex digest of email for Brainy path isolation. */
101
+ emailHash: string;
102
+ }
103
+ /**
104
+ * A resolved Soulcraft session, returned by auth middleware.
105
+ */
106
+ export interface SoulcraftSession {
107
+ /** The authenticated user. */
108
+ user: SoulcraftSessionUser;
109
+ /** The better-auth session ID. */
110
+ sessionId: string;
111
+ /** Session expiry timestamp (Unix milliseconds). */
112
+ expiresAt: number;
113
+ }
114
+ /**
115
+ * Configuration for a product registering as an OIDC client of the central IdP.
116
+ *
117
+ * Used when `SOULCRAFT_IDP_URL` is set. Without it, each product runs
118
+ * better-auth standalone with its own SQLite auth database.
119
+ */
120
+ export interface OIDCClientConfig {
121
+ /** The central IdP base URL. @example "https://auth.soulcraft.com" */
122
+ idpUrl: string;
123
+ /** This product's OIDC client ID as registered with the central IdP. */
124
+ clientId: string;
125
+ /** This product's OIDC client secret. */
126
+ clientSecret: string;
127
+ /**
128
+ * This product's redirect URI for OIDC callbacks.
129
+ *
130
+ * Optional — better-auth's genericOAuth plugin derives it automatically from
131
+ * `BETTER_AUTH_URL` as `${BETTER_AUTH_URL}/api/auth/oauth2/callback/:providerId`.
132
+ */
133
+ redirectUri?: string;
134
+ }
135
+ /**
136
+ * The SSO mode this product instance is operating in.
137
+ *
138
+ * - `standalone` — better-auth handles auth locally (dev or before central IdP)
139
+ * - `oidc-client` — better-auth delegates to auth.soulcraft.com
140
+ */
141
+ export type AuthMode = 'standalone' | 'oidc-client';
142
+ /**
143
+ * @description The sdk.auth namespace on SoulcraftSDK.
144
+ *
145
+ * Provides session resolution and capability token utilities. The full
146
+ * better-auth instance and middleware factories are exported from
147
+ * `@soulcraft/sdk/server` and are not part of the runtime namespace.
148
+ */
149
+ export interface AuthModule {
150
+ /**
151
+ * Verify a capability token and return its claims, or null if invalid/expired.
152
+ * @param token - The token string (two dot-separated base64url parts).
153
+ * @param secret - The HMAC secret used to sign the token.
154
+ */
155
+ verifyToken(token: string, secret: string): Promise<import('../brainy/auth.js').CapabilityTokenClaims | null>;
156
+ /**
157
+ * Create a capability token for a user.
158
+ * @param options - Token options (email, scope, TTL, secret).
159
+ */
160
+ createToken(options: import('../brainy/auth.js').CreateCapabilityTokenOptions): Promise<string>;
161
+ }
162
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/modules/auth/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAMH;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,YAAY,GACpB,SAAS,GACT,QAAQ,GACR,UAAU,GACV,OAAO,GACP,SAAS,GACT,OAAO,GACP,SAAS,GACT,YAAY,CAAA;AAEhB;;;;;;;;GAQG;AACH,MAAM,MAAM,qBAAqB,GAAG,QAAQ,GAAG,QAAQ,GAAG,OAAO,GAAG,SAAS,GAAG,YAAY,CAAA;AAM5F;;;;;;GAMG;AACH,MAAM,WAAW,qBAAqB;IACpC,mDAAmD;IACnD,EAAE,EAAE,MAAM,CAAA;IACV,8DAA8D;IAC9D,IAAI,EAAE,MAAM,CAAA;IACZ,6CAA6C;IAC7C,IAAI,EAAE,MAAM,CAAA;IACZ,yCAAyC;IACzC,OAAO,EAAE,UAAU,GAAG,OAAO,GAAG,SAAS,GAAG,QAAQ,CAAA;IACpD;;;;;OAKG;IACH,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAClC;AAMD;;;;GAIG;AACH,MAAM,WAAW,mBAAmB;IAClC;;;OAGG;IACH,YAAY,EAAE,YAAY,CAAA;IAC1B;;;;;;;;;;OAUG;IACH,SAAS,EAAE,MAAM,CAAA;CAClB;AAED;;;;GAIG;AACH,MAAM,WAAW,oBAAoB;IACnC,kCAAkC;IAClC,EAAE,EAAE,MAAM,CAAA;IACV,4BAA4B;IAC5B,KAAK,EAAE,MAAM,CAAA;IACb,oBAAoB;IACpB,IAAI,EAAE,MAAM,CAAA;IACZ,mDAAmD;IACnD,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB,4DAA4D;IAC5D,YAAY,EAAE,YAAY,CAAA;IAC1B,6DAA6D;IAC7D,SAAS,EAAE,MAAM,CAAA;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,8BAA8B;IAC9B,IAAI,EAAE,oBAAoB,CAAA;IAC1B,kCAAkC;IAClC,SAAS,EAAE,MAAM,CAAA;IACjB,oDAAoD;IACpD,SAAS,EAAE,MAAM,CAAA;CAClB;AAMD;;;;;GAKG;AACH,MAAM,WAAW,gBAAgB;IAC/B,sEAAsE;IACtE,MAAM,EAAE,MAAM,CAAA;IACd,wEAAwE;IACxE,QAAQ,EAAE,MAAM,CAAA;IAChB,yCAAyC;IACzC,YAAY,EAAE,MAAM,CAAA;IACpB;;;;;OAKG;IACH,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AAED;;;;;GAKG;AACH,MAAM,MAAM,QAAQ,GAAG,YAAY,GAAG,aAAa,CAAA;AAMnD;;;;;;GAMG;AACH,MAAM,WAAW,UAAU;IACzB;;;;OAIG;IACH,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,mBAAmB,EAAE,qBAAqB,GAAG,IAAI,CAAC,CAAA;IAE7G;;;OAGG;IACH,WAAW,CAAC,OAAO,EAAE,OAAO,mBAAmB,EAAE,4BAA4B,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;CAChG"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * @module modules/auth/types
3
+ * @description Shared role definitions, session types, and OIDC configuration
4
+ * interfaces for the Soulcraft platform.
5
+ *
6
+ * These types are product-agnostic and drive access control across Workshop,
7
+ * Venue, Academy, and Portal. Platform-level roles control what products a user
8
+ * can access; product-level roles control what they can do within each product.
9
+ *
10
+ * This module absorbs and replaces `@soulcraft/auth/types`, which is deprecated
11
+ * in favour of importing directly from `@soulcraft/sdk`.
12
+ */
13
+ export {};
14
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/modules/auth/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @module billing/types
3
+ * @description Type definitions for sdk.billing.*
4
+ * Implementation: Phase 5 per ADR-001.
5
+ */
6
+ export type {};
7
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/modules/billing/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,YAAY,EAAE,CAAA"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @module billing/types
3
+ * @description Type definitions for sdk.billing.*
4
+ * Implementation: Phase 5 per ADR-001.
5
+ */
6
+ export {};
7
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/modules/billing/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
@@ -0,0 +1,104 @@
1
+ /**
2
+ * @module modules/brainy/auth
3
+ * @description HMAC-SHA256 capability token utilities for cross-product Brainy RPC access.
4
+ *
5
+ * Products that need to call another product's Brainy endpoint (e.g. Workshop reading
6
+ * Venue's inventory brain) authenticate with a short-lived capability token rather than
7
+ * a user session. Tokens encode the caller's email, an optional scope (e.g. a tenant
8
+ * slug), and an expiry timestamp. The receiving server verifies the token using a shared
9
+ * `VENUE_RPC_SECRET` (or equivalent product-pair secret).
10
+ *
11
+ * ## Token format
12
+ * ```
13
+ * <base64url(JSON payload)>.<base64url(HMAC-SHA256 signature)>
14
+ * ```
15
+ * where payload is `JSON.stringify({ email, scope?, exp })`.
16
+ *
17
+ * Intended for server-to-server use only — never include capability tokens in browser
18
+ * bundles or client-side code.
19
+ *
20
+ * @example
21
+ * ```typescript
22
+ * // Workshop backend — generate a token before a cross-product RPC call:
23
+ * const token = await createCapabilityToken({
24
+ * email: user.email,
25
+ * scope: 'wicks-and-whiskers',
26
+ * secret: process.env.VENUE_RPC_SECRET!,
27
+ * })
28
+ *
29
+ * // Venue — verify in the Brainy RPC handler:
30
+ * const claims = await verifyCapabilityToken(token, process.env.VENUE_RPC_SECRET!)
31
+ * if (!claims) return new Response('Unauthorized', { status: 401 })
32
+ * ```
33
+ */
34
+ /**
35
+ * Options for {@link createCapabilityToken}.
36
+ */
37
+ export interface CreateCapabilityTokenOptions {
38
+ /** The authenticated caller's email address. */
39
+ email: string;
40
+ /**
41
+ * Optional scope string — typically a tenant slug or location ID — that
42
+ * restricts the token to a specific resource. The receiving server validates
43
+ * this against the requested resource.
44
+ */
45
+ scope?: string;
46
+ /** The shared HMAC-SHA256 secret. Should be at least 32 characters. */
47
+ secret: string;
48
+ /**
49
+ * Token lifetime in milliseconds.
50
+ *
51
+ * @default 3_600_000 (1 hour)
52
+ */
53
+ ttlMs?: number;
54
+ }
55
+ /**
56
+ * The decoded, verified claims from a capability token.
57
+ */
58
+ export interface CapabilityTokenClaims {
59
+ /** The caller's email address. */
60
+ email: string;
61
+ /** Optional scope embedded in the token. */
62
+ scope?: string;
63
+ /** Expiry timestamp in milliseconds since epoch. */
64
+ exp: number;
65
+ }
66
+ /**
67
+ * Creates a short-lived HMAC-SHA256 capability token for authenticating a
68
+ * cross-product Brainy RPC call.
69
+ *
70
+ * @param options - Token creation options.
71
+ * @returns A signed capability token string in `<payload>.<signature>` format.
72
+ *
73
+ * @example
74
+ * ```typescript
75
+ * const token = await createCapabilityToken({
76
+ * email: 'admin@workshop.soulcraft.com',
77
+ * scope: 'wicks-and-whiskers',
78
+ * secret: process.env.VENUE_RPC_SECRET!,
79
+ * })
80
+ * // Attach as: Authorization: Bearer <token>
81
+ * ```
82
+ */
83
+ export declare function createCapabilityToken(options: CreateCapabilityTokenOptions): Promise<string>;
84
+ /**
85
+ * Verifies a capability token and returns its claims.
86
+ *
87
+ * Returns `null` (rather than throwing) for any invalid or expired token so
88
+ * callers can handle auth failures uniformly without try/catch.
89
+ *
90
+ * Uses constant-time comparison for the HMAC signature to prevent timing attacks.
91
+ *
92
+ * @param token - The token string returned by {@link createCapabilityToken}.
93
+ * @param secret - The shared HMAC secret used when the token was created.
94
+ * @returns The decoded claims, or `null` if the token is invalid or expired.
95
+ *
96
+ * @example
97
+ * ```typescript
98
+ * const claims = await verifyCapabilityToken(authHeader.slice(7), secret)
99
+ * if (!claims) return new Response('Unauthorized', { status: 401 })
100
+ * console.log(`Request from: ${claims.email}, scope: ${claims.scope}`)
101
+ * ```
102
+ */
103
+ export declare function verifyCapabilityToken(token: string, secret: string): Promise<CapabilityTokenClaims | null>;
104
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../../src/modules/brainy/auth.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAMH;;GAEG;AACH,MAAM,WAAW,4BAA4B;IAC3C,gDAAgD;IAChD,KAAK,EAAE,MAAM,CAAA;IACb;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,uEAAuE;IACvE,MAAM,EAAE,MAAM,CAAA;IACd;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,kCAAkC;IAClC,KAAK,EAAE,MAAM,CAAA;IACb,4CAA4C;IAC5C,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,oDAAoD;IACpD,GAAG,EAAE,MAAM,CAAA;CACZ;AAMD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,4BAA4B,GACpC,OAAO,CAAC,MAAM,CAAC,CAWjB;AAMD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,qBAAqB,CACzC,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,qBAAqB,GAAG,IAAI,CAAC,CAmCvC"}
@@ -0,0 +1,144 @@
1
+ /**
2
+ * @module modules/brainy/auth
3
+ * @description HMAC-SHA256 capability token utilities for cross-product Brainy RPC access.
4
+ *
5
+ * Products that need to call another product's Brainy endpoint (e.g. Workshop reading
6
+ * Venue's inventory brain) authenticate with a short-lived capability token rather than
7
+ * a user session. Tokens encode the caller's email, an optional scope (e.g. a tenant
8
+ * slug), and an expiry timestamp. The receiving server verifies the token using a shared
9
+ * `VENUE_RPC_SECRET` (or equivalent product-pair secret).
10
+ *
11
+ * ## Token format
12
+ * ```
13
+ * <base64url(JSON payload)>.<base64url(HMAC-SHA256 signature)>
14
+ * ```
15
+ * where payload is `JSON.stringify({ email, scope?, exp })`.
16
+ *
17
+ * Intended for server-to-server use only — never include capability tokens in browser
18
+ * bundles or client-side code.
19
+ *
20
+ * @example
21
+ * ```typescript
22
+ * // Workshop backend — generate a token before a cross-product RPC call:
23
+ * const token = await createCapabilityToken({
24
+ * email: user.email,
25
+ * scope: 'wicks-and-whiskers',
26
+ * secret: process.env.VENUE_RPC_SECRET!,
27
+ * })
28
+ *
29
+ * // Venue — verify in the Brainy RPC handler:
30
+ * const claims = await verifyCapabilityToken(token, process.env.VENUE_RPC_SECRET!)
31
+ * if (!claims) return new Response('Unauthorized', { status: 401 })
32
+ * ```
33
+ */
34
+ // ─────────────────────────────────────────────────────────────────────────────
35
+ // Token creation
36
+ // ─────────────────────────────────────────────────────────────────────────────
37
+ /**
38
+ * Creates a short-lived HMAC-SHA256 capability token for authenticating a
39
+ * cross-product Brainy RPC call.
40
+ *
41
+ * @param options - Token creation options.
42
+ * @returns A signed capability token string in `<payload>.<signature>` format.
43
+ *
44
+ * @example
45
+ * ```typescript
46
+ * const token = await createCapabilityToken({
47
+ * email: 'admin@workshop.soulcraft.com',
48
+ * scope: 'wicks-and-whiskers',
49
+ * secret: process.env.VENUE_RPC_SECRET!,
50
+ * })
51
+ * // Attach as: Authorization: Bearer <token>
52
+ * ```
53
+ */
54
+ export async function createCapabilityToken(options) {
55
+ const { email, scope, secret, ttlMs = 3_600_000 } = options;
56
+ const payload = { email, exp: Date.now() + ttlMs };
57
+ if (scope !== undefined)
58
+ payload['scope'] = scope;
59
+ const payloadB64 = Buffer.from(JSON.stringify(payload)).toString('base64url');
60
+ const key = await _importHmacKey(secret);
61
+ const sigBytes = await crypto.subtle.sign('HMAC', key, new TextEncoder().encode(payloadB64));
62
+ const sigB64 = Buffer.from(sigBytes).toString('base64url');
63
+ return `${payloadB64}.${sigB64}`;
64
+ }
65
+ // ─────────────────────────────────────────────────────────────────────────────
66
+ // Token verification
67
+ // ─────────────────────────────────────────────────────────────────────────────
68
+ /**
69
+ * Verifies a capability token and returns its claims.
70
+ *
71
+ * Returns `null` (rather than throwing) for any invalid or expired token so
72
+ * callers can handle auth failures uniformly without try/catch.
73
+ *
74
+ * Uses constant-time comparison for the HMAC signature to prevent timing attacks.
75
+ *
76
+ * @param token - The token string returned by {@link createCapabilityToken}.
77
+ * @param secret - The shared HMAC secret used when the token was created.
78
+ * @returns The decoded claims, or `null` if the token is invalid or expired.
79
+ *
80
+ * @example
81
+ * ```typescript
82
+ * const claims = await verifyCapabilityToken(authHeader.slice(7), secret)
83
+ * if (!claims) return new Response('Unauthorized', { status: 401 })
84
+ * console.log(`Request from: ${claims.email}, scope: ${claims.scope}`)
85
+ * ```
86
+ */
87
+ export async function verifyCapabilityToken(token, secret) {
88
+ const parts = token.split('.');
89
+ if (parts.length !== 2)
90
+ return null;
91
+ const [payloadB64, sigB64] = parts;
92
+ try {
93
+ const key = await _importHmacKey(secret);
94
+ const expected = await crypto.subtle.sign('HMAC', key, new TextEncoder().encode(payloadB64));
95
+ const actual = Buffer.from(sigB64, 'base64url');
96
+ if (!_timingSafeEqual(new Uint8Array(expected), actual))
97
+ return null;
98
+ const payload = JSON.parse(Buffer.from(payloadB64, 'base64url').toString('utf-8'));
99
+ if (typeof payload['exp'] !== 'number' || payload['exp'] < Date.now())
100
+ return null;
101
+ if (typeof payload['email'] !== 'string')
102
+ return null;
103
+ const claims = {
104
+ email: payload['email'],
105
+ exp: payload['exp'],
106
+ };
107
+ if (typeof payload['scope'] === 'string') {
108
+ claims.scope = payload['scope'];
109
+ }
110
+ return claims;
111
+ }
112
+ catch {
113
+ return null;
114
+ }
115
+ }
116
+ // ─────────────────────────────────────────────────────────────────────────────
117
+ // Internal helpers
118
+ // ─────────────────────────────────────────────────────────────────────────────
119
+ /**
120
+ * Imports a raw HMAC-SHA256 CryptoKey from a UTF-8 secret string.
121
+ *
122
+ * @param secret - The raw secret bytes expressed as a string.
123
+ * @returns A CryptoKey for HMAC sign/verify operations.
124
+ */
125
+ async function _importHmacKey(secret) {
126
+ return crypto.subtle.importKey('raw', new TextEncoder().encode(secret), { name: 'HMAC', hash: 'SHA-256' }, false, ['sign', 'verify']);
127
+ }
128
+ /**
129
+ * Constant-time byte comparison to prevent timing attacks during signature verification.
130
+ *
131
+ * @param a - First byte array.
132
+ * @param b - Second byte array.
133
+ * @returns `true` if the arrays have identical length and content.
134
+ */
135
+ function _timingSafeEqual(a, b) {
136
+ if (a.length !== b.length)
137
+ return false;
138
+ let diff = 0;
139
+ for (let i = 0; i < a.length; i++) {
140
+ diff |= (a[i] ?? 0) ^ (b[i] ?? 0);
141
+ }
142
+ return diff === 0;
143
+ }
144
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../../src/modules/brainy/auth.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,118 @@
1
+ /**
2
+ * @module modules/brainy/errors
3
+ * @description Typed error classes for @soulcraft/sdk Brainy operations.
4
+ *
5
+ * All errors thrown by SDK transports and handlers extend `SDKError` so callers
6
+ * can distinguish Soulcraft-specific failures from generic `Error`s with a single
7
+ * `instanceof` check. Machine-readable `code` fields allow programmatic handling.
8
+ *
9
+ * @example
10
+ * ```typescript
11
+ * try {
12
+ * await sdk.brainy.find({ query: 'inventory items' })
13
+ * } catch (err) {
14
+ * if (err instanceof SDKTimeoutError) {
15
+ * showToast('Connection slow — please retry')
16
+ * } else if (err instanceof SDKError) {
17
+ * console.error('SDK error:', err.code, err.message)
18
+ * } else {
19
+ * throw err // unexpected
20
+ * }
21
+ * }
22
+ * ```
23
+ */
24
+ /**
25
+ * Base class for all @soulcraft/sdk errors.
26
+ *
27
+ * Carries a machine-readable `code` for programmatic error handling.
28
+ * All SDK errors extend this class so callers can use a single `instanceof SDKError` check.
29
+ */
30
+ export declare class SDKError extends Error {
31
+ /** Machine-readable error code (e.g. `'DISCONNECTED'`, `'TIMEOUT'`). */
32
+ readonly code: string;
33
+ /**
34
+ * @param code - Machine-readable identifier.
35
+ * @param message - Human-readable description.
36
+ */
37
+ constructor(code: string, message: string);
38
+ }
39
+ /**
40
+ * Thrown when an RPC call is attempted while the transport is not connected.
41
+ *
42
+ * Occurs for the HTTP transport when the server is unreachable, or for the
43
+ * WebSocket transport when the connection is in a disconnected or closed state.
44
+ */
45
+ export declare class SDKDisconnectedError extends SDKError {
46
+ constructor();
47
+ }
48
+ /**
49
+ * Thrown when an RPC call exceeds the configured response timeout.
50
+ *
51
+ * The call is cancelled on the client side; the server may still process it.
52
+ *
53
+ * @example
54
+ * ```typescript
55
+ * if (err instanceof SDKTimeoutError) {
56
+ * console.error(`Timed out waiting for: ${err.method}`)
57
+ * }
58
+ * ```
59
+ */
60
+ export declare class SDKTimeoutError extends SDKError {
61
+ /** The Brainy method name that timed out (e.g. `'find'`, `'vfs.readdir'`). */
62
+ readonly method: string;
63
+ /**
64
+ * @param method - Dot-separated Brainy method name that timed out.
65
+ */
66
+ constructor(method: string);
67
+ }
68
+ /**
69
+ * Thrown when the server rejects an RPC call due to authentication failure.
70
+ *
71
+ * For WebSocket transport: server sends close code 4001 (unauthorized).
72
+ * For HTTP transport: server responds with HTTP 401.
73
+ */
74
+ export declare class SDKAuthError extends SDKError {
75
+ /**
76
+ * @param detail - Optional detail appended to the error message.
77
+ */
78
+ constructor(detail?: string);
79
+ }
80
+ /**
81
+ * Thrown when the server rejects an RPC call due to insufficient permissions.
82
+ *
83
+ * For WebSocket transport: server sends close code 4003 (forbidden).
84
+ * For HTTP transport: server responds with HTTP 403.
85
+ */
86
+ export declare class SDKForbiddenError extends SDKError {
87
+ /**
88
+ * @param detail - Optional detail appended to the error message.
89
+ */
90
+ constructor(detail?: string);
91
+ }
92
+ /**
93
+ * Thrown when a remote RPC call fails on the server side.
94
+ *
95
+ * Wraps the server's error code and message for client-side inspection.
96
+ */
97
+ export declare class SDKRpcError extends SDKError {
98
+ /** The server-side error code returned in the RPC error response. */
99
+ readonly serverCode: string;
100
+ /**
101
+ * @param serverCode - The error code returned by the server.
102
+ * @param serverMessage - The human-readable message returned by the server.
103
+ */
104
+ constructor(serverCode: string, serverMessage: string);
105
+ }
106
+ /**
107
+ * Thrown when a method path cannot be resolved on the target Brainy instance.
108
+ *
109
+ * Occurs in the local transport when the dot-separated method string resolves
110
+ * to a non-existent or non-callable property.
111
+ */
112
+ export declare class SDKMethodNotFoundError extends SDKError {
113
+ /**
114
+ * @param method - The dot-separated method path that could not be resolved.
115
+ */
116
+ constructor(method: string);
117
+ }
118
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../src/modules/brainy/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH;;;;;GAKG;AACH,qBAAa,QAAS,SAAQ,KAAK;IACjC,wEAAwE;IACxE,SAAgB,IAAI,EAAE,MAAM,CAAA;IAE5B;;;OAGG;gBACS,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;CAK1C;AAED;;;;;GAKG;AACH,qBAAa,oBAAqB,SAAQ,QAAQ;;CAKjD;AAED;;;;;;;;;;;GAWG;AACH,qBAAa,eAAgB,SAAQ,QAAQ;IAC3C,8EAA8E;IAC9E,SAAgB,MAAM,EAAE,MAAM,CAAA;IAE9B;;OAEG;gBACS,MAAM,EAAE,MAAM;CAK3B;AAED;;;;;GAKG;AACH,qBAAa,YAAa,SAAQ,QAAQ;IACxC;;OAEG;gBACS,MAAM,CAAC,EAAE,MAAM;CAI5B;AAED;;;;;GAKG;AACH,qBAAa,iBAAkB,SAAQ,QAAQ;IAC7C;;OAEG;gBACS,MAAM,CAAC,EAAE,MAAM;CAI5B;AAED;;;;GAIG;AACH,qBAAa,WAAY,SAAQ,QAAQ;IACvC,qEAAqE;IACrE,SAAgB,UAAU,EAAE,MAAM,CAAA;IAElC;;;OAGG;gBACS,UAAU,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM;CAKtD;AAED;;;;;GAKG;AACH,qBAAa,sBAAuB,SAAQ,QAAQ;IAClD;;OAEG;gBACS,MAAM,EAAE,MAAM;CAI3B"}