@soulcraft/sdk 1.0.0 → 1.2.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 (112) hide show
  1. package/dist/client/index.d.ts +3 -0
  2. package/dist/client/index.d.ts.map +1 -1
  3. package/dist/client/index.js +2 -0
  4. package/dist/client/index.js.map +1 -1
  5. package/dist/index.d.ts +7 -6
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +1 -0
  8. package/dist/index.js.map +1 -1
  9. package/dist/modules/auth/service-token.d.ts +62 -0
  10. package/dist/modules/auth/service-token.d.ts.map +1 -0
  11. package/dist/modules/auth/service-token.js +99 -0
  12. package/dist/modules/auth/service-token.js.map +1 -0
  13. package/dist/modules/billing/firestore-provider.d.ts +60 -0
  14. package/dist/modules/billing/firestore-provider.d.ts.map +1 -0
  15. package/dist/modules/billing/firestore-provider.js +314 -0
  16. package/dist/modules/billing/firestore-provider.js.map +1 -0
  17. package/dist/modules/billing/index.d.ts +58 -0
  18. package/dist/modules/billing/index.d.ts.map +1 -0
  19. package/dist/modules/billing/index.js +164 -0
  20. package/dist/modules/billing/index.js.map +1 -0
  21. package/dist/modules/billing/local-provider.d.ts +38 -0
  22. package/dist/modules/billing/local-provider.d.ts.map +1 -0
  23. package/dist/modules/billing/local-provider.js +242 -0
  24. package/dist/modules/billing/local-provider.js.map +1 -0
  25. package/dist/modules/billing/portal-provider.d.ts +70 -0
  26. package/dist/modules/billing/portal-provider.d.ts.map +1 -0
  27. package/dist/modules/billing/portal-provider.js +204 -0
  28. package/dist/modules/billing/portal-provider.js.map +1 -0
  29. package/dist/modules/billing/types.d.ts +323 -3
  30. package/dist/modules/billing/types.d.ts.map +1 -1
  31. package/dist/modules/billing/types.js +22 -2
  32. package/dist/modules/billing/types.js.map +1 -1
  33. package/dist/modules/billing/usage-buffer.d.ts +72 -0
  34. package/dist/modules/billing/usage-buffer.d.ts.map +1 -0
  35. package/dist/modules/billing/usage-buffer.js +141 -0
  36. package/dist/modules/billing/usage-buffer.js.map +1 -0
  37. package/dist/modules/formats/types.d.ts +65 -3
  38. package/dist/modules/formats/types.d.ts.map +1 -1
  39. package/dist/modules/formats/types.js +40 -3
  40. package/dist/modules/formats/types.js.map +1 -1
  41. package/dist/modules/formats/wdoc.d.ts +263 -0
  42. package/dist/modules/formats/wdoc.d.ts.map +1 -0
  43. package/dist/modules/formats/wdoc.js +21 -0
  44. package/dist/modules/formats/wdoc.js.map +1 -0
  45. package/dist/modules/formats/wquiz.d.ts +122 -0
  46. package/dist/modules/formats/wquiz.d.ts.map +1 -0
  47. package/dist/modules/formats/wquiz.js +23 -0
  48. package/dist/modules/formats/wquiz.js.map +1 -0
  49. package/dist/modules/formats/wslide.d.ts +130 -0
  50. package/dist/modules/formats/wslide.d.ts.map +1 -0
  51. package/dist/modules/formats/wslide.js +23 -0
  52. package/dist/modules/formats/wslide.js.map +1 -0
  53. package/dist/modules/formats/wviz.d.ts +114 -0
  54. package/dist/modules/formats/wviz.d.ts.map +1 -0
  55. package/dist/modules/formats/wviz.js +21 -0
  56. package/dist/modules/formats/wviz.js.map +1 -0
  57. package/dist/modules/hall/browser.d.ts +88 -0
  58. package/dist/modules/hall/browser.d.ts.map +1 -0
  59. package/dist/modules/hall/browser.js +265 -0
  60. package/dist/modules/hall/browser.js.map +1 -0
  61. package/dist/modules/hall/protocol.d.ts +39 -0
  62. package/dist/modules/hall/protocol.d.ts.map +1 -0
  63. package/dist/modules/hall/protocol.js +52 -0
  64. package/dist/modules/hall/protocol.js.map +1 -0
  65. package/dist/modules/hall/server.d.ts +172 -0
  66. package/dist/modules/hall/server.d.ts.map +1 -0
  67. package/dist/modules/hall/server.js +457 -0
  68. package/dist/modules/hall/server.js.map +1 -0
  69. package/dist/modules/hall/types.d.ts +502 -31
  70. package/dist/modules/hall/types.d.ts.map +1 -1
  71. package/dist/modules/hall/types.js +13 -8
  72. package/dist/modules/hall/types.js.map +1 -1
  73. package/dist/modules/kits/index.d.ts +41 -0
  74. package/dist/modules/kits/index.d.ts.map +1 -0
  75. package/dist/modules/kits/index.js +85 -0
  76. package/dist/modules/kits/index.js.map +1 -0
  77. package/dist/modules/kits/types.d.ts +107 -3
  78. package/dist/modules/kits/types.d.ts.map +1 -1
  79. package/dist/modules/kits/types.js +15 -2
  80. package/dist/modules/kits/types.js.map +1 -1
  81. package/dist/modules/license/index.d.ts +53 -0
  82. package/dist/modules/license/index.d.ts.map +1 -0
  83. package/dist/modules/license/index.js +233 -0
  84. package/dist/modules/license/index.js.map +1 -0
  85. package/dist/modules/license/types.d.ts +222 -3
  86. package/dist/modules/license/types.d.ts.map +1 -1
  87. package/dist/modules/license/types.js +21 -2
  88. package/dist/modules/license/types.js.map +1 -1
  89. package/dist/modules/notifications/index.d.ts +40 -0
  90. package/dist/modules/notifications/index.d.ts.map +1 -0
  91. package/dist/modules/notifications/index.js +280 -0
  92. package/dist/modules/notifications/index.js.map +1 -0
  93. package/dist/modules/notifications/types.d.ts +152 -3
  94. package/dist/modules/notifications/types.d.ts.map +1 -1
  95. package/dist/modules/notifications/types.js +21 -2
  96. package/dist/modules/notifications/types.js.map +1 -1
  97. package/dist/server/create-sdk.d.ts +4 -0
  98. package/dist/server/create-sdk.d.ts.map +1 -1
  99. package/dist/server/create-sdk.js +19 -26
  100. package/dist/server/create-sdk.js.map +1 -1
  101. package/dist/server/hall-handlers.d.ts +90 -151
  102. package/dist/server/hall-handlers.d.ts.map +1 -1
  103. package/dist/server/hall-handlers.js +84 -204
  104. package/dist/server/hall-handlers.js.map +1 -1
  105. package/dist/server/index.d.ts +10 -2
  106. package/dist/server/index.d.ts.map +1 -1
  107. package/dist/server/index.js +9 -2
  108. package/dist/server/index.js.map +1 -1
  109. package/dist/types.d.ts +35 -25
  110. package/dist/types.d.ts.map +1 -1
  111. package/docs/USAGE.md +224 -1
  112. package/package.json +13 -5
@@ -0,0 +1,85 @@
1
+ /**
2
+ * @module kits
3
+ * @description Factory for sdk.kits.* — the Soulcraft kit registry module.
4
+ *
5
+ * Provides read-only access to kit configurations from the `@soulcraft/kits`
6
+ * package. The package is an optional peer dependency loaded lazily via
7
+ * `createRequire` so that the SDK compiles and runs without it installed;
8
+ * calls gracefully return `null` / empty array when it is absent.
9
+ *
10
+ * The factory accepts an optional `bundledRegistry` override (used in tests)
11
+ * to inject a mock registry without needing the real package.
12
+ *
13
+ * @example
14
+ * ```typescript
15
+ * import { createKitsModule } from '@soulcraft/sdk/server'
16
+ *
17
+ * const kits = createKitsModule()
18
+ * const kit = await kits.load('wicks-and-whiskers')
19
+ * console.log(kit?.name) // "Wicks & Whiskers"
20
+ * ```
21
+ */
22
+ import { createRequire } from 'node:module';
23
+ // createRequire enables CJS-style require() inside an ESM module — the only
24
+ // reliable way to conditionally load optional peer dependencies in Node/Bun ESM.
25
+ const _require = createRequire(import.meta.url);
26
+ // Module-level cache — loaded once per process, not per SDK instance.
27
+ let _registryCache = undefined;
28
+ /**
29
+ * Load the kit registry from the installed `@soulcraft/kits` package.
30
+ * Returns `null` when the package is not installed, allowing callers to
31
+ * degrade gracefully rather than throwing.
32
+ */
33
+ function _getBundledRegistry() {
34
+ if (_registryCache !== undefined)
35
+ return _registryCache;
36
+ try {
37
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
38
+ const kits = _require('@soulcraft/kits');
39
+ _registryCache = kits.kitRegistry ?? null;
40
+ }
41
+ catch {
42
+ _registryCache = null;
43
+ }
44
+ return _registryCache;
45
+ }
46
+ // ─────────────────────────────────────────────────────────────────────────────
47
+ // Factory
48
+ // ─────────────────────────────────────────────────────────────────────────────
49
+ /**
50
+ * Create the `sdk.kits.*` module.
51
+ *
52
+ * @param options - Optional overrides, primarily for testing.
53
+ * @returns A `KitsModule` backed by the `@soulcraft/kits` registry.
54
+ *
55
+ * @example
56
+ * ```typescript
57
+ * // In production:
58
+ * const kits = createKitsModule()
59
+ *
60
+ * // In tests — inject a mock registry to avoid the peer dep:
61
+ * const kits = createKitsModule({
62
+ * bundledRegistry: { 'test-kit': { id: 'test-kit', name: 'Test Kit', ... } }
63
+ * })
64
+ * ```
65
+ */
66
+ export function createKitsModule(options = {}) {
67
+ const getRegistry = options.bundledRegistry !== undefined
68
+ ? () => options.bundledRegistry ?? null
69
+ : _getBundledRegistry;
70
+ return {
71
+ async load(kitId) {
72
+ const registry = getRegistry();
73
+ if (!registry)
74
+ return null;
75
+ return registry[kitId] ?? null;
76
+ },
77
+ async list() {
78
+ const registry = getRegistry();
79
+ if (!registry)
80
+ return [];
81
+ return Object.values(registry);
82
+ },
83
+ };
84
+ }
85
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/modules/kits/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAG3C,4EAA4E;AAC5E,iFAAiF;AACjF,MAAM,QAAQ,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;AAE/C,sEAAsE;AACtE,IAAI,cAAc,GAA0D,SAAS,CAAA;AAErF;;;;GAIG;AACH,SAAS,mBAAmB;IAC1B,IAAI,cAAc,KAAK,SAAS;QAAE,OAAO,cAAc,CAAA;IACvD,IAAI,CAAC;QACH,8DAA8D;QAC9D,MAAM,IAAI,GAAG,QAAQ,CAAC,iBAAiB,CAAQ,CAAA;QAC/C,cAAc,GAAI,IAAI,CAAC,WAAkD,IAAI,IAAI,CAAA;IACnF,CAAC;IAAC,MAAM,CAAC;QACP,cAAc,GAAG,IAAI,CAAA;IACvB,CAAC;IACD,OAAO,cAAc,CAAA;AACvB,CAAC;AAED,gFAAgF;AAChF,UAAU;AACV,gFAAgF;AAEhF;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,gBAAgB,CAAC,UAAmC,EAAE;IACpE,MAAM,WAAW,GAAG,OAAO,CAAC,eAAe,KAAK,SAAS;QACvD,CAAC,CAAC,GAA8C,EAAE,CAAC,OAAO,CAAC,eAAe,IAAI,IAAI;QAClF,CAAC,CAAC,mBAAmB,CAAA;IAEvB,OAAO;QACL,KAAK,CAAC,IAAI,CAAC,KAAa;YACtB,MAAM,QAAQ,GAAG,WAAW,EAAE,CAAA;YAC9B,IAAI,CAAC,QAAQ;gBAAE,OAAO,IAAI,CAAA;YAC1B,OAAO,QAAQ,CAAC,KAAK,CAAC,IAAI,IAAI,CAAA;QAChC,CAAC;QAED,KAAK,CAAC,IAAI;YACR,MAAM,QAAQ,GAAG,WAAW,EAAE,CAAA;YAC9B,IAAI,CAAC,QAAQ;gBAAE,OAAO,EAAE,CAAA;YACxB,OAAO,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAA;QAChC,CAAC;KACF,CAAA;AACH,CAAC"}
@@ -1,7 +1,111 @@
1
1
  /**
2
2
  * @module kits/types
3
- * @description Type definitions for sdk.kits.*
4
- * Implementation: Phase 4 per ADR-001.
3
+ * @description Type definitions for sdk.kits.* — the kit loader and registry module.
4
+ *
5
+ * Kits (`@soulcraft/kits`) are pure configuration packages: `kit.json` manifests
6
+ * and `SKILL.md` prompt files that describe a domain, persona, glossary, and
7
+ * workflow. They contain no TypeScript logic, no server code, and no SDK imports.
8
+ *
9
+ * The `KitsModule` provides read-only access to the kit registry: loading a single
10
+ * kit by ID, listing all available kits, and accessing the raw skill registry.
11
+ *
12
+ * Kit initialization (populating a workspace's Brainy and VFS from a kit's
13
+ * `starterFiles`) is a product-level concern and lives in each product's
14
+ * bootstrap code, not in the SDK.
15
+ *
16
+ * @see `@soulcraft/kit-schema` for the full kit manifest schema with product-specific fields.
17
+ * @see `sdk.skills.*` for loading SKILL.md prompt files.
5
18
  */
6
- export type {};
19
+ /**
20
+ * Base fields shared by every Soulcraft kit manifest.
21
+ *
22
+ * This is a structural subset of `BaseKitManifest` from `@soulcraft/kit-schema`.
23
+ * The SDK uses this minimal type to avoid a hard dependency on the schema package.
24
+ * Product-specific fields (venue config, workshop config, etc.) are accessible
25
+ * via type assertion against the full `@soulcraft/kit-schema` types if needed.
26
+ */
27
+ export interface SoulcraftKitConfig {
28
+ /** Unique kit identifier, used as the registry key (e.g. `'wicks-and-whiskers'`). */
29
+ id: string;
30
+ /** Display name of the kit. */
31
+ name: string;
32
+ /** One-sentence description of what this kit is for. */
33
+ description: string;
34
+ /** Semantic version string (e.g. `'1.0.0'`). */
35
+ version: string;
36
+ /** Kit type discriminant. */
37
+ type: 'venue' | 'content' | 'app' | 'academy' | 'soulcraft';
38
+ /** Shared cross-product configuration. */
39
+ shared?: {
40
+ /** AI persona system prompt. */
41
+ aiPersona?: string;
42
+ /** Suggestion chips for AI chat interfaces. */
43
+ suggestions?: Array<{
44
+ label: string;
45
+ prompt: string;
46
+ }>;
47
+ };
48
+ /** Additional product-specific fields are permitted. */
49
+ [key: string]: unknown;
50
+ }
51
+ /**
52
+ * Options passed to `createKitsModule()` to override the bundled registry.
53
+ * Primarily useful in tests.
54
+ */
55
+ export interface CreateKitsModuleOptions {
56
+ /**
57
+ * Override the kit registry loaded from `@soulcraft/kits`.
58
+ * When provided, the module uses this registry directly instead of requiring
59
+ * the package. Set to `null` to simulate the package being absent.
60
+ */
61
+ bundledRegistry?: Record<string, SoulcraftKitConfig> | null;
62
+ }
63
+ /**
64
+ * The `sdk.kits.*` namespace — read-only access to the Soulcraft kit registry.
65
+ *
66
+ * Backed by the `@soulcraft/kits` package (a peer dependency). If the package
67
+ * is not installed, `load()` returns `null` and `list()` returns an empty array.
68
+ *
69
+ * @example
70
+ * ```typescript
71
+ * const kit = await sdk.kits.load('wicks-and-whiskers')
72
+ * if (kit) {
73
+ * const response = await sdk.ai.complete({
74
+ * messages: [{ role: 'user', content: 'What candles are low in stock?' }],
75
+ * systemPrompt: kit.shared?.aiPersona,
76
+ * })
77
+ * }
78
+ * ```
79
+ */
80
+ export interface KitsModule {
81
+ /**
82
+ * Load a single kit configuration by ID.
83
+ *
84
+ * Returns `null` if the kit is not found or `@soulcraft/kits` is not installed.
85
+ *
86
+ * @param kitId - The kit identifier (e.g. `'wicks-and-whiskers'`).
87
+ * @returns The kit configuration, or `null` if not found.
88
+ *
89
+ * @example
90
+ * ```typescript
91
+ * const kit = await sdk.kits.load('wicks-and-whiskers')
92
+ * console.log(kit?.name) // → "Wicks & Whiskers"
93
+ * ```
94
+ */
95
+ load(kitId: string): Promise<SoulcraftKitConfig | null>;
96
+ /**
97
+ * List all available kits from the registry.
98
+ *
99
+ * Returns an empty array if `@soulcraft/kits` is not installed.
100
+ *
101
+ * @returns All kit configurations as an array.
102
+ *
103
+ * @example
104
+ * ```typescript
105
+ * const kits = await sdk.kits.list()
106
+ * console.log(kits.map(k => k.name))
107
+ * ```
108
+ */
109
+ list(): Promise<SoulcraftKitConfig[]>;
110
+ }
7
111
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/modules/kits/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,YAAY,EAAE,CAAA"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/modules/kits/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAMH;;;;;;;GAOG;AACH,MAAM,WAAW,kBAAkB;IACjC,qFAAqF;IACrF,EAAE,EAAE,MAAM,CAAA;IACV,+BAA+B;IAC/B,IAAI,EAAE,MAAM,CAAA;IACZ,wDAAwD;IACxD,WAAW,EAAE,MAAM,CAAA;IACnB,gDAAgD;IAChD,OAAO,EAAE,MAAM,CAAA;IACf,6BAA6B;IAC7B,IAAI,EAAE,OAAO,GAAG,SAAS,GAAG,KAAK,GAAG,SAAS,GAAG,WAAW,CAAA;IAC3D,0CAA0C;IAC1C,MAAM,CAAC,EAAE;QACP,gCAAgC;QAChC,SAAS,CAAC,EAAE,MAAM,CAAA;QAClB,+CAA+C;QAC/C,WAAW,CAAC,EAAE,KAAK,CAAC;YAAE,KAAK,EAAE,MAAM,CAAC;YAAC,MAAM,EAAE,MAAM,CAAA;SAAE,CAAC,CAAA;KACvD,CAAA;IACD,wDAAwD;IACxD,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CACvB;AAMD;;;GAGG;AACH,MAAM,WAAW,uBAAuB;IACtC;;;;OAIG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,GAAG,IAAI,CAAA;CAC5D;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,WAAW,UAAU;IACzB;;;;;;;;;;;;;OAaG;IACH,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CAAA;IAEvD;;;;;;;;;;;;OAYG;IACH,IAAI,IAAI,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAAA;CACtC"}
@@ -1,7 +1,20 @@
1
1
  /**
2
2
  * @module kits/types
3
- * @description Type definitions for sdk.kits.*
4
- * Implementation: Phase 4 per ADR-001.
3
+ * @description Type definitions for sdk.kits.* — the kit loader and registry module.
4
+ *
5
+ * Kits (`@soulcraft/kits`) are pure configuration packages: `kit.json` manifests
6
+ * and `SKILL.md` prompt files that describe a domain, persona, glossary, and
7
+ * workflow. They contain no TypeScript logic, no server code, and no SDK imports.
8
+ *
9
+ * The `KitsModule` provides read-only access to the kit registry: loading a single
10
+ * kit by ID, listing all available kits, and accessing the raw skill registry.
11
+ *
12
+ * Kit initialization (populating a workspace's Brainy and VFS from a kit's
13
+ * `starterFiles`) is a product-level concern and lives in each product's
14
+ * bootstrap code, not in the SDK.
15
+ *
16
+ * @see `@soulcraft/kit-schema` for the full kit manifest schema with product-specific fields.
17
+ * @see `sdk.skills.*` for loading SKILL.md prompt files.
5
18
  */
6
19
  export {};
7
20
  //# sourceMappingURL=types.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/modules/kits/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/modules/kits/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * @module license
3
+ * @description Factory for sdk.license.* — license validation, AI credit management,
4
+ * and BYOK API key support.
5
+ *
6
+ * Validates the product license against the Portal license server. Initialization
7
+ * is lazy: the first call to `validate()` performs an online check against
8
+ * `portal.soulcraft.com` and starts the background heartbeat.
9
+ *
10
+ * License state is read from the `SOULCRAFT_LICENSE_KEY` environment variable
11
+ * or a `.soulcraft.json` file in the working directory. On free-tier deployments
12
+ * (no key configured), `validate()` returns `{ valid: false, tier: 'free' }` and
13
+ * all AI credit limits apply.
14
+ *
15
+ * **AI credit metering** delegates to the `sdk.billing.*` module for storage and
16
+ * period management. The license module provides the gate check and credit recording
17
+ * interface; billing handles persistence.
18
+ *
19
+ * **BYOK users** always bypass credit metering — they provide their own Anthropic key
20
+ * and are not subject to monthly limits.
21
+ *
22
+ * @example Server startup
23
+ * ```typescript
24
+ * // Force immediate license check and start heartbeat:
25
+ * sdk.license.startHeartbeat()
26
+ * const result = await sdk.license.validate(true)
27
+ * if (!result.valid) console.warn('[SDK] No active license — running in free tier')
28
+ * ```
29
+ */
30
+ import type { LicenseModule } from './types.js';
31
+ import type { BillingModule } from '../billing/types.js';
32
+ /** Options for `createLicenseModule()`. */
33
+ export interface CreateLicenseModuleOptions {
34
+ /**
35
+ * The billing module instance, used for AI credit metering.
36
+ * When not provided, credit checks assume unlimited (no billing gate).
37
+ */
38
+ billing?: BillingModule;
39
+ /**
40
+ * Register a user's BYOK Anthropic API key.
41
+ * The license module uses this to short-circuit credit checks for BYOK users.
42
+ */
43
+ byokKeys?: Map<string, string>;
44
+ }
45
+ /**
46
+ * Create the `sdk.license.*` module.
47
+ *
48
+ * @param options - Optional billing module and BYOK key overrides.
49
+ * @returns A fully configured `LicenseModule`.
50
+ */
51
+ export declare function createLicenseModule(options?: CreateLicenseModuleOptions): LicenseModule;
52
+ export type { LicenseResult, LicensePlanTier, LicenseFeatures, AICreditCheckResult, AIUsageRecord, AIProviderConfig, LicenseModule, } from './types.js';
53
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/modules/license/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAGH,OAAO,KAAK,EACV,aAAa,EAMd,MAAM,YAAY,CAAA;AACnB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAqDxD,2CAA2C;AAC3C,MAAM,WAAW,0BAA0B;IACzC;;;OAGG;IACH,OAAO,CAAC,EAAE,aAAa,CAAA;IACvB;;;OAGG;IACH,QAAQ,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAC/B;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,GAAE,0BAA+B,GAAG,aAAa,CAqK3F;AAGD,YAAY,EACV,aAAa,EACb,eAAe,EACf,eAAe,EACf,mBAAmB,EACnB,aAAa,EACb,gBAAgB,EAChB,aAAa,GACd,MAAM,YAAY,CAAA"}
@@ -0,0 +1,233 @@
1
+ /**
2
+ * @module license
3
+ * @description Factory for sdk.license.* — license validation, AI credit management,
4
+ * and BYOK API key support.
5
+ *
6
+ * Validates the product license against the Portal license server. Initialization
7
+ * is lazy: the first call to `validate()` performs an online check against
8
+ * `portal.soulcraft.com` and starts the background heartbeat.
9
+ *
10
+ * License state is read from the `SOULCRAFT_LICENSE_KEY` environment variable
11
+ * or a `.soulcraft.json` file in the working directory. On free-tier deployments
12
+ * (no key configured), `validate()` returns `{ valid: false, tier: 'free' }` and
13
+ * all AI credit limits apply.
14
+ *
15
+ * **AI credit metering** delegates to the `sdk.billing.*` module for storage and
16
+ * period management. The license module provides the gate check and credit recording
17
+ * interface; billing handles persistence.
18
+ *
19
+ * **BYOK users** always bypass credit metering — they provide their own Anthropic key
20
+ * and are not subject to monthly limits.
21
+ *
22
+ * @example Server startup
23
+ * ```typescript
24
+ * // Force immediate license check and start heartbeat:
25
+ * sdk.license.startHeartbeat()
26
+ * const result = await sdk.license.validate(true)
27
+ * if (!result.valid) console.warn('[SDK] No active license — running in free tier')
28
+ * ```
29
+ */
30
+ // ─────────────────────────────────────────────────────────────────────────────
31
+ // Portal license API
32
+ // ─────────────────────────────────────────────────────────────────────────────
33
+ /** Default heartbeat interval: 4 hours. */
34
+ const DEFAULT_CHECK_INTERVAL_MS = 4 * 60 * 60 * 1000;
35
+ /** Portal license validation endpoint. */
36
+ const PORTAL_LICENSE_URL = 'https://portal.soulcraft.com/api/license/validate';
37
+ /**
38
+ * Validate the license key against Portal.
39
+ * Reads `SOULCRAFT_LICENSE_KEY` from the environment.
40
+ * Returns a free-tier result when no key is configured.
41
+ */
42
+ async function _validateWithPortal() {
43
+ const key = process.env['SOULCRAFT_LICENSE_KEY'];
44
+ if (!key) {
45
+ return { valid: false, tier: 'free', reason: 'No license key configured (SOULCRAFT_LICENSE_KEY)' };
46
+ }
47
+ try {
48
+ const response = await fetch(PORTAL_LICENSE_URL, {
49
+ method: 'POST',
50
+ headers: { 'Content-Type': 'application/json' },
51
+ body: JSON.stringify({ key }),
52
+ signal: AbortSignal.timeout(10_000),
53
+ });
54
+ if (!response.ok) {
55
+ return { valid: false, tier: 'free', reason: `Portal responded ${response.status}` };
56
+ }
57
+ return (await response.json());
58
+ }
59
+ catch {
60
+ // Network failure — degrade gracefully. The cached result (if any) remains valid.
61
+ return { valid: false, tier: 'free', reason: 'License check failed (network error)' };
62
+ }
63
+ }
64
+ // ─────────────────────────────────────────────────────────────────────────────
65
+ // BYOK key storage (in-process, keyed by userId)
66
+ // ─────────────────────────────────────────────────────────────────────────────
67
+ // BYOK keys are stored in memory only — they are never written to disk by the
68
+ // SDK. Products are responsible for persisting them (e.g. encrypted in Firestore
69
+ // or a user settings document). The license module reads them via getAIProvider()
70
+ // which is overridable per-user via the byokStore.
71
+ const _byokStore = new Map();
72
+ /**
73
+ * Create the `sdk.license.*` module.
74
+ *
75
+ * @param options - Optional billing module and BYOK key overrides.
76
+ * @returns A fully configured `LicenseModule`.
77
+ */
78
+ export function createLicenseModule(options = {}) {
79
+ const billing = options.billing;
80
+ const byokStore = options.byokKeys ?? _byokStore;
81
+ // Cached validation result — refreshed by heartbeat or explicit forceRefresh.
82
+ let _cachedResult;
83
+ // Whether the heartbeat interval is running.
84
+ let _heartbeatTimer;
85
+ // Pending init promise — deduplicates concurrent first-call races.
86
+ let _initPromise;
87
+ // ── Internal helpers ──────────────────────────────────────────────────────
88
+ async function _init() {
89
+ if (_initPromise)
90
+ return _initPromise;
91
+ _initPromise = (async () => {
92
+ const result = await _validateWithPortal();
93
+ _cachedResult = result;
94
+ // Start background heartbeat after first successful init.
95
+ if (!_heartbeatTimer) {
96
+ _startHeartbeat(DEFAULT_CHECK_INTERVAL_MS);
97
+ }
98
+ return result;
99
+ })();
100
+ return _initPromise;
101
+ }
102
+ async function _refreshHeartbeat() {
103
+ try {
104
+ const result = await _validateWithPortal();
105
+ _cachedResult = result;
106
+ }
107
+ catch {
108
+ // Heartbeat failures are non-fatal — the cached result remains valid.
109
+ }
110
+ }
111
+ function _startHeartbeat(intervalMs) {
112
+ if (_heartbeatTimer)
113
+ clearInterval(_heartbeatTimer);
114
+ _heartbeatTimer = setInterval(() => {
115
+ void _refreshHeartbeat();
116
+ }, intervalMs);
117
+ // Allow the process to exit normally even if the heartbeat is running.
118
+ if (_heartbeatTimer.unref)
119
+ _heartbeatTimer.unref();
120
+ }
121
+ function _tierToFeatures(tier) {
122
+ switch (tier) {
123
+ case 'enterprise':
124
+ case 'internal':
125
+ return { cortex: true, ai: { monthlyCredits: null } };
126
+ case 'pro':
127
+ return { cortex: true, ai: { monthlyCredits: 1000 } };
128
+ case 'free':
129
+ default:
130
+ return { cortex: false, ai: { monthlyCredits: 100 } };
131
+ }
132
+ }
133
+ // ── Public API ────────────────────────────────────────────────────────────
134
+ return {
135
+ async validate(forceRefresh = false) {
136
+ if (forceRefresh || !_cachedResult) {
137
+ _initPromise = undefined; // Allow re-init on force refresh.
138
+ return _init();
139
+ }
140
+ return _cachedResult;
141
+ },
142
+ async isActive() {
143
+ const result = await _init();
144
+ return result.valid;
145
+ },
146
+ async plan() {
147
+ const result = await _init();
148
+ if (!result.valid)
149
+ return 'free';
150
+ return result.tier;
151
+ },
152
+ async features() {
153
+ const tier = await this.plan();
154
+ return _tierToFeatures(tier);
155
+ },
156
+ async checkAICredits(userId) {
157
+ // BYOK users bypass all credit metering.
158
+ if (byokStore.has(userId)) {
159
+ return { ok: true, remaining: null, isByok: true };
160
+ }
161
+ // If no billing module, assume unlimited (dev/free tier).
162
+ if (!billing) {
163
+ const active = await this.isActive();
164
+ if (!active) {
165
+ return { ok: false, remaining: null, isByok: false, reason: 'license_inactive' };
166
+ }
167
+ return { ok: true, remaining: null, isByok: false };
168
+ }
169
+ const check = await billing.checkLimit(userId, false);
170
+ if (!check.ok) {
171
+ return { ok: false, remaining: check.remaining, isByok: false, reason: 'limit_reached' };
172
+ }
173
+ return { ok: true, remaining: check.remaining, isByok: false };
174
+ },
175
+ consumeAICredit(userId, usage) {
176
+ // BYOK users are not metered.
177
+ if (byokStore.has(userId))
178
+ return;
179
+ if (!billing)
180
+ return;
181
+ // Fire-and-forget — billing buffers and flushes asynchronously.
182
+ void billing.recordUsage(userId, usage.inputTokens, usage.outputTokens, usage.model);
183
+ },
184
+ async validateBYOK(apiKey) {
185
+ // Validate by attempting a minimal Anthropic API call (count_tokens endpoint
186
+ // is cheaper than a full completion).
187
+ try {
188
+ const response = await fetch('https://api.anthropic.com/v1/messages/count_tokens', {
189
+ method: 'POST',
190
+ headers: {
191
+ 'x-api-key': apiKey,
192
+ 'anthropic-version': '2023-06-01',
193
+ 'content-type': 'application/json',
194
+ },
195
+ body: JSON.stringify({
196
+ model: 'claude-haiku-4-5-20251001',
197
+ messages: [{ role: 'user', content: 'hi' }],
198
+ }),
199
+ });
200
+ // 200 = valid key, 401 = invalid key, other = network/service error
201
+ return response.status === 200;
202
+ }
203
+ catch {
204
+ return false;
205
+ }
206
+ },
207
+ async getAIProvider(userId) {
208
+ const byokKey = byokStore.get(userId);
209
+ if (byokKey) {
210
+ return { apiKey: byokKey, source: 'byok' };
211
+ }
212
+ const platformKey = process.env['ANTHROPIC_API_KEY'];
213
+ if (!platformKey) {
214
+ throw new Error('No Anthropic API key available. Set ANTHROPIC_API_KEY in the environment ' +
215
+ 'or provide a BYOK key for this user via sdk.license.');
216
+ }
217
+ return { apiKey: platformKey, source: 'platform' };
218
+ },
219
+ startHeartbeat(intervalMs) {
220
+ const interval = intervalMs ?? DEFAULT_CHECK_INTERVAL_MS;
221
+ _startHeartbeat(interval);
222
+ // Force an immediate online check on explicit startHeartbeat() call.
223
+ void _refreshHeartbeat();
224
+ },
225
+ stopHeartbeat() {
226
+ if (_heartbeatTimer) {
227
+ clearInterval(_heartbeatTimer);
228
+ _heartbeatTimer = undefined;
229
+ }
230
+ },
231
+ };
232
+ }
233
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/modules/license/index.ts"],"names":[],"mappings":"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"}