@soulcraft/sdk 1.6.2 → 2.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.
- package/dist/client/create-client-sdk.d.ts +16 -2
- package/dist/client/create-client-sdk.d.ts.map +1 -1
- package/dist/client/create-client-sdk.js +2 -7
- package/dist/client/create-client-sdk.js.map +1 -1
- package/dist/client/index.d.ts +48 -37
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +61 -42
- package/dist/client/index.js.map +1 -1
- package/dist/client/namespace-proxy.d.ts +108 -0
- package/dist/client/namespace-proxy.d.ts.map +1 -0
- package/dist/client/namespace-proxy.js +151 -0
- package/dist/client/namespace-proxy.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/modules/app-context/index.d.ts +214 -0
- package/dist/modules/app-context/index.d.ts.map +1 -0
- package/dist/modules/app-context/index.js +569 -0
- package/dist/modules/app-context/index.js.map +1 -0
- package/dist/modules/auth/products.d.ts +208 -0
- package/dist/modules/auth/products.d.ts.map +1 -0
- package/dist/modules/auth/products.js +165 -0
- package/dist/modules/auth/products.js.map +1 -0
- package/dist/namespaces.d.ts +2942 -0
- package/dist/namespaces.d.ts.map +1 -0
- package/dist/namespaces.js +37 -0
- package/dist/namespaces.js.map +1 -0
- package/dist/rpc.d.ts +156 -0
- package/dist/rpc.d.ts.map +1 -0
- package/dist/rpc.js +26 -0
- package/dist/rpc.js.map +1 -0
- package/dist/server/create-sdk.d.ts.map +1 -1
- package/dist/server/create-sdk.js +3 -13
- package/dist/server/create-sdk.js.map +1 -1
- package/dist/server/handlers/annotations.d.ts +52 -0
- package/dist/server/handlers/annotations.d.ts.map +1 -0
- package/dist/server/handlers/annotations.js +204 -0
- package/dist/server/handlers/annotations.js.map +1 -0
- package/dist/server/handlers/auth.d.ts +53 -0
- package/dist/server/handlers/auth.d.ts.map +1 -0
- package/dist/server/handlers/auth.js +66 -0
- package/dist/server/handlers/auth.js.map +1 -0
- package/dist/server/handlers/certification.d.ts +32 -0
- package/dist/server/handlers/certification.d.ts.map +1 -0
- package/dist/server/handlers/certification.js +253 -0
- package/dist/server/handlers/certification.js.map +1 -0
- package/dist/server/handlers/chat/conversations.d.ts +91 -0
- package/dist/server/handlers/chat/conversations.d.ts.map +1 -0
- package/dist/server/handlers/chat/conversations.js +314 -0
- package/dist/server/handlers/chat/conversations.js.map +1 -0
- package/dist/server/handlers/chat/delegator.d.ts +144 -0
- package/dist/server/handlers/chat/delegator.d.ts.map +1 -0
- package/dist/server/handlers/chat/delegator.js +431 -0
- package/dist/server/handlers/chat/delegator.js.map +1 -0
- package/dist/server/handlers/chat/engine.d.ts +81 -0
- package/dist/server/handlers/chat/engine.d.ts.map +1 -0
- package/dist/server/handlers/chat/engine.js +442 -0
- package/dist/server/handlers/chat/engine.js.map +1 -0
- package/dist/server/handlers/chat/executor.d.ts +65 -0
- package/dist/server/handlers/chat/executor.d.ts.map +1 -0
- package/dist/server/handlers/chat/executor.js +375 -0
- package/dist/server/handlers/chat/executor.js.map +1 -0
- package/dist/server/handlers/chat/index.d.ts +62 -0
- package/dist/server/handlers/chat/index.d.ts.map +1 -0
- package/dist/server/handlers/chat/index.js +182 -0
- package/dist/server/handlers/chat/index.js.map +1 -0
- package/dist/server/handlers/chat/memory.d.ts +91 -0
- package/dist/server/handlers/chat/memory.d.ts.map +1 -0
- package/dist/server/handlers/chat/memory.js +293 -0
- package/dist/server/handlers/chat/memory.js.map +1 -0
- package/dist/server/handlers/chat/models.d.ts +180 -0
- package/dist/server/handlers/chat/models.d.ts.map +1 -0
- package/dist/server/handlers/chat/models.js +304 -0
- package/dist/server/handlers/chat/models.js.map +1 -0
- package/dist/server/handlers/chat/planner.d.ts +116 -0
- package/dist/server/handlers/chat/planner.d.ts.map +1 -0
- package/dist/server/handlers/chat/planner.js +344 -0
- package/dist/server/handlers/chat/planner.js.map +1 -0
- package/dist/server/handlers/chat/types.d.ts +500 -0
- package/dist/server/handlers/chat/types.d.ts.map +1 -0
- package/dist/server/handlers/chat/types.js +11 -0
- package/dist/server/handlers/chat/types.js.map +1 -0
- package/dist/server/handlers/collections.d.ts +67 -0
- package/dist/server/handlers/collections.d.ts.map +1 -0
- package/dist/server/handlers/collections.js +484 -0
- package/dist/server/handlers/collections.js.map +1 -0
- package/dist/server/handlers/commerce.d.ts +106 -0
- package/dist/server/handlers/commerce.d.ts.map +1 -0
- package/dist/server/handlers/commerce.js +62 -0
- package/dist/server/handlers/commerce.js.map +1 -0
- package/dist/server/handlers/config.d.ts +112 -0
- package/dist/server/handlers/config.d.ts.map +1 -0
- package/dist/server/handlers/config.js +122 -0
- package/dist/server/handlers/config.js.map +1 -0
- package/dist/server/handlers/export.d.ts +72 -0
- package/dist/server/handlers/export.d.ts.map +1 -0
- package/dist/server/handlers/export.js +175 -0
- package/dist/server/handlers/export.js.map +1 -0
- package/dist/server/handlers/formats.d.ts +77 -0
- package/dist/server/handlers/formats.d.ts.map +1 -0
- package/dist/server/handlers/formats.js +65 -0
- package/dist/server/handlers/formats.js.map +1 -0
- package/dist/server/handlers/graph.d.ts +31 -0
- package/dist/server/handlers/graph.d.ts.map +1 -0
- package/dist/server/handlers/graph.js +490 -0
- package/dist/server/handlers/graph.js.map +1 -0
- package/dist/server/handlers/import.d.ts +96 -0
- package/dist/server/handlers/import.d.ts.map +1 -0
- package/dist/server/handlers/import.js +108 -0
- package/dist/server/handlers/import.js.map +1 -0
- package/dist/server/handlers/index.d.ts +68 -0
- package/dist/server/handlers/index.d.ts.map +1 -0
- package/dist/server/handlers/index.js +71 -0
- package/dist/server/handlers/index.js.map +1 -0
- package/dist/server/handlers/media.d.ts +76 -0
- package/dist/server/handlers/media.d.ts.map +1 -0
- package/dist/server/handlers/media.js +53 -0
- package/dist/server/handlers/media.js.map +1 -0
- package/dist/server/handlers/project.d.ts +45 -0
- package/dist/server/handlers/project.d.ts.map +1 -0
- package/dist/server/handlers/project.js +181 -0
- package/dist/server/handlers/project.js.map +1 -0
- package/dist/server/handlers/publish.d.ts +102 -0
- package/dist/server/handlers/publish.d.ts.map +1 -0
- package/dist/server/handlers/publish.js +130 -0
- package/dist/server/handlers/publish.js.map +1 -0
- package/dist/server/handlers/pulse.d.ts +39 -0
- package/dist/server/handlers/pulse.d.ts.map +1 -0
- package/dist/server/handlers/pulse.js +78 -0
- package/dist/server/handlers/pulse.js.map +1 -0
- package/dist/server/handlers/realtime.d.ts +55 -0
- package/dist/server/handlers/realtime.d.ts.map +1 -0
- package/dist/server/handlers/realtime.js +49 -0
- package/dist/server/handlers/realtime.js.map +1 -0
- package/dist/server/handlers/search.d.ts +21 -0
- package/dist/server/handlers/search.d.ts.map +1 -0
- package/dist/server/handlers/search.js +237 -0
- package/dist/server/handlers/search.js.map +1 -0
- package/dist/server/handlers/session.d.ts +47 -0
- package/dist/server/handlers/session.d.ts.map +1 -0
- package/dist/server/handlers/session.js +286 -0
- package/dist/server/handlers/session.js.map +1 -0
- package/dist/server/handlers/settings.d.ts +97 -0
- package/dist/server/handlers/settings.d.ts.map +1 -0
- package/dist/server/handlers/settings.js +131 -0
- package/dist/server/handlers/settings.js.map +1 -0
- package/dist/server/handlers/workspace.d.ts +78 -0
- package/dist/server/handlers/workspace.d.ts.map +1 -0
- package/dist/server/handlers/workspace.js +270 -0
- package/dist/server/handlers/workspace.js.map +1 -0
- package/dist/server/hono-router.d.ts +66 -0
- package/dist/server/hono-router.d.ts.map +1 -0
- package/dist/server/hono-router.js +203 -0
- package/dist/server/hono-router.js.map +1 -0
- package/dist/server/index.d.ts +29 -19
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +33 -19
- package/dist/server/index.js.map +1 -1
- package/dist/server/namespace-router.d.ts +204 -0
- package/dist/server/namespace-router.d.ts.map +1 -0
- package/dist/server/namespace-router.js +262 -0
- package/dist/server/namespace-router.js.map +1 -0
- package/dist/transports/http-namespace.d.ts +210 -0
- package/dist/transports/http-namespace.d.ts.map +1 -0
- package/dist/transports/http-namespace.js +514 -0
- package/dist/transports/http-namespace.js.map +1 -0
- package/dist/transports/workshop.d.ts +173 -0
- package/dist/transports/workshop.d.ts.map +1 -0
- package/dist/transports/workshop.js +307 -0
- package/dist/transports/workshop.js.map +1 -0
- package/dist/types.d.ts +65 -67
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +7 -3
- package/dist/types.js.map +1 -1
- package/docs/ADR-004-product-registry.md +108 -0
- package/package.json +1 -1
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module server/handlers/settings
|
|
3
|
+
* @description Settings namespace handler — BYOK API key management, AI usage
|
|
4
|
+
* stats, and workspace storage usage.
|
|
5
|
+
*
|
|
6
|
+
* Absorbs Workshop `routes/settings.ts`. The handler delegates to injected
|
|
7
|
+
* service interfaces for API key storage, billing, and storage tracking, so
|
|
8
|
+
* products can plug in their own implementations.
|
|
9
|
+
*
|
|
10
|
+
* Methods:
|
|
11
|
+
* - `saveApiKey` — Save a BYOK API key (encrypted at rest)
|
|
12
|
+
* - `getApiKey` — Get redacted API key info
|
|
13
|
+
* - `deleteApiKey` — Delete a saved API key
|
|
14
|
+
* - `getUsageStats` — Get AI usage statistics for the billing period
|
|
15
|
+
* - `getStorageUsage` — Get storage consumption breakdown
|
|
16
|
+
*/
|
|
17
|
+
import type { NamespaceProvider } from '../namespace-router.js';
|
|
18
|
+
/**
|
|
19
|
+
* API key storage interface.
|
|
20
|
+
*
|
|
21
|
+
* Products implement this to manage BYOK API key persistence. Workshop uses
|
|
22
|
+
* encrypted filesystem storage; Venue might use a secrets manager.
|
|
23
|
+
*/
|
|
24
|
+
export interface ApiKeyService {
|
|
25
|
+
/** Save an API key (encrypted at rest). */
|
|
26
|
+
saveKey(userId: string, provider: string, apiKey: string): Promise<{
|
|
27
|
+
success: boolean;
|
|
28
|
+
error?: string;
|
|
29
|
+
}>;
|
|
30
|
+
/**
|
|
31
|
+
* Get an API key for the given user and provider.
|
|
32
|
+
*
|
|
33
|
+
* @returns The key info, including whether it's a personal key or environment fallback.
|
|
34
|
+
*/
|
|
35
|
+
getKey(userId: string, workspaceId: string, provider: string): Promise<{
|
|
36
|
+
success: boolean;
|
|
37
|
+
apiKey?: string;
|
|
38
|
+
source?: 'workspace' | 'global' | 'environment' | 'none';
|
|
39
|
+
}>;
|
|
40
|
+
/** Delete an API key. */
|
|
41
|
+
deleteKey(userId: string, provider: string): Promise<{
|
|
42
|
+
success: boolean;
|
|
43
|
+
error?: string;
|
|
44
|
+
}>;
|
|
45
|
+
/** Validate an API key format before saving. */
|
|
46
|
+
isValidKey(apiKey: string): boolean;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Billing service subset needed by the settings handler.
|
|
50
|
+
*/
|
|
51
|
+
export interface SettingsBillingService {
|
|
52
|
+
/** Get AI usage status for the billing period. */
|
|
53
|
+
getUsageStatus(billingId: string, hasPersonalKey: boolean): Promise<Record<string, unknown>>;
|
|
54
|
+
/** Get the user's subscription for plan-based storage limits. */
|
|
55
|
+
getSubscription(billingId: string): Promise<{
|
|
56
|
+
plan?: string;
|
|
57
|
+
} | null>;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Storage tracking service for instant storage usage queries.
|
|
61
|
+
*/
|
|
62
|
+
export interface StorageTracker {
|
|
63
|
+
/** Get cached storage usage in bytes. */
|
|
64
|
+
getUsage(storageId: string, workspaceId: string): Promise<number>;
|
|
65
|
+
/** Whether the tracker has initialized for this user+workspace. */
|
|
66
|
+
isInitialized(storageId: string, workspaceId: string): boolean;
|
|
67
|
+
/** Force a one-time initialization (first load). */
|
|
68
|
+
forceInit(storageId: string, workspaceId: string): Promise<number>;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Storage limit resolver — maps plan ID to maximum bytes allowed.
|
|
72
|
+
*/
|
|
73
|
+
export interface StorageLimitResolver {
|
|
74
|
+
/** Get the storage limit in bytes for the given plan. */
|
|
75
|
+
getLimit(planId: string): Promise<number>;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Options for {@link createSettingsHandler}.
|
|
79
|
+
*/
|
|
80
|
+
export interface SettingsHandlerOptions {
|
|
81
|
+
/** API key storage service. */
|
|
82
|
+
apiKeyService: ApiKeyService;
|
|
83
|
+
/** Billing service for usage and subscription queries. */
|
|
84
|
+
billing: SettingsBillingService;
|
|
85
|
+
/** Storage tracking service for instant usage queries. */
|
|
86
|
+
storageTracker: StorageTracker;
|
|
87
|
+
/** Storage limit resolver for plan-based limits. */
|
|
88
|
+
storageLimitResolver: StorageLimitResolver;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Creates the `settings` namespace handler.
|
|
92
|
+
*
|
|
93
|
+
* @param options - Settings handler dependencies.
|
|
94
|
+
* @returns A {@link NamespaceProvider} implementing {@link SettingsNamespace}.
|
|
95
|
+
*/
|
|
96
|
+
export declare function createSettingsHandler(options: SettingsHandlerOptions): NamespaceProvider;
|
|
97
|
+
//# sourceMappingURL=settings.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"settings.d.ts","sourceRoot":"","sources":["../../../src/server/handlers/settings.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAkB,MAAM,wBAAwB,CAAA;AAO/E;;;;;GAKG;AACH,MAAM,WAAW,aAAa;IAC5B,2CAA2C;IAC3C,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IAExG;;;;OAIG;IACH,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;QACrE,OAAO,EAAE,OAAO,CAAA;QAChB,MAAM,CAAC,EAAE,MAAM,CAAA;QACf,MAAM,CAAC,EAAE,WAAW,GAAG,QAAQ,GAAG,aAAa,GAAG,MAAM,CAAA;KACzD,CAAC,CAAA;IAEF,yBAAyB;IACzB,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IAE1F,gDAAgD;IAChD,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAA;CACpC;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,kDAAkD;IAClD,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,cAAc,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;IAC5F,iEAAiE;IACjE,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC,CAAA;CACtE;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,yCAAyC;IACzC,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;IACjE,mEAAmE;IACnE,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAA;IAC9D,oDAAoD;IACpD,SAAS,CAAC,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;CACnE;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,yDAAyD;IACzD,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;CAC1C;AAMD;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,+BAA+B;IAC/B,aAAa,EAAE,aAAa,CAAA;IAC5B,0DAA0D;IAC1D,OAAO,EAAE,sBAAsB,CAAA;IAC/B,0DAA0D;IAC1D,cAAc,EAAE,cAAc,CAAA;IAC9B,oDAAoD;IACpD,oBAAoB,EAAE,oBAAoB,CAAA;CAC3C;AAMD;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,sBAAsB,GAAG,iBAAiB,CA6IxF"}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module server/handlers/settings
|
|
3
|
+
* @description Settings namespace handler — BYOK API key management, AI usage
|
|
4
|
+
* stats, and workspace storage usage.
|
|
5
|
+
*
|
|
6
|
+
* Absorbs Workshop `routes/settings.ts`. The handler delegates to injected
|
|
7
|
+
* service interfaces for API key storage, billing, and storage tracking, so
|
|
8
|
+
* products can plug in their own implementations.
|
|
9
|
+
*
|
|
10
|
+
* Methods:
|
|
11
|
+
* - `saveApiKey` — Save a BYOK API key (encrypted at rest)
|
|
12
|
+
* - `getApiKey` — Get redacted API key info
|
|
13
|
+
* - `deleteApiKey` — Delete a saved API key
|
|
14
|
+
* - `getUsageStats` — Get AI usage statistics for the billing period
|
|
15
|
+
* - `getStorageUsage` — Get storage consumption breakdown
|
|
16
|
+
*/
|
|
17
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
18
|
+
// Handler factory
|
|
19
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
20
|
+
/**
|
|
21
|
+
* Creates the `settings` namespace handler.
|
|
22
|
+
*
|
|
23
|
+
* @param options - Settings handler dependencies.
|
|
24
|
+
* @returns A {@link NamespaceProvider} implementing {@link SettingsNamespace}.
|
|
25
|
+
*/
|
|
26
|
+
export function createSettingsHandler(options) {
|
|
27
|
+
const { apiKeyService, billing, storageTracker, storageLimitResolver } = options;
|
|
28
|
+
return {
|
|
29
|
+
/**
|
|
30
|
+
* Save a BYOK API key, encrypted at rest.
|
|
31
|
+
*
|
|
32
|
+
* @param keyOptions - Provider name and raw key string.
|
|
33
|
+
* @param ctx - Handler context with authenticated user.
|
|
34
|
+
*/
|
|
35
|
+
async saveApiKey(keyOptions, ctx) {
|
|
36
|
+
const { provider, key } = keyOptions;
|
|
37
|
+
if (!apiKeyService.isValidKey(key)) {
|
|
38
|
+
throw new Error('Invalid API key format');
|
|
39
|
+
}
|
|
40
|
+
const result = await apiKeyService.saveKey(ctx.user.emailHash, provider, key);
|
|
41
|
+
if (!result.success) {
|
|
42
|
+
throw new Error(result.error || 'Failed to save API key');
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
/**
|
|
46
|
+
* Get redacted API key information.
|
|
47
|
+
*
|
|
48
|
+
* @param provider - AI provider name (e.g. `'anthropic'`).
|
|
49
|
+
* @param ctx - Handler context with authenticated user.
|
|
50
|
+
* @returns Redacted key info or `null` if no key is saved.
|
|
51
|
+
*/
|
|
52
|
+
async getApiKey(provider, ctx) {
|
|
53
|
+
const result = await apiKeyService.getKey(ctx.user.emailHash, ctx.workspaceId, provider);
|
|
54
|
+
// Only consider personal keys (workspace or global), not environment fallbacks
|
|
55
|
+
const isPersonalKey = result.source === 'workspace' || result.source === 'global';
|
|
56
|
+
if (!result.success || !result.apiKey || !isPersonalKey) {
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
return {
|
|
60
|
+
provider,
|
|
61
|
+
lastFour: result.apiKey.slice(-4),
|
|
62
|
+
createdAt: new Date().toISOString(), // Key service doesn't track creation date
|
|
63
|
+
};
|
|
64
|
+
},
|
|
65
|
+
/**
|
|
66
|
+
* Delete a saved API key.
|
|
67
|
+
*
|
|
68
|
+
* @param provider - AI provider whose key to delete.
|
|
69
|
+
* @param ctx - Handler context with authenticated user.
|
|
70
|
+
*/
|
|
71
|
+
async deleteApiKey(provider, ctx) {
|
|
72
|
+
const result = await apiKeyService.deleteKey(ctx.user.emailHash, provider);
|
|
73
|
+
if (!result.success) {
|
|
74
|
+
throw new Error(result.error || 'Failed to delete API key');
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
/**
|
|
78
|
+
* Get AI usage statistics for the current billing period.
|
|
79
|
+
*
|
|
80
|
+
* @param ctx - Handler context with authenticated user.
|
|
81
|
+
* @returns Message count, token totals, and period identifier.
|
|
82
|
+
*/
|
|
83
|
+
async getUsageStats(ctx) {
|
|
84
|
+
const billingId = ctx.user.email;
|
|
85
|
+
// Check if user has a personal key
|
|
86
|
+
const keyResult = await apiKeyService.getKey(ctx.user.emailHash, ctx.workspaceId, 'anthropic');
|
|
87
|
+
const hasPersonalKey = keyResult.success && keyResult.source === 'global';
|
|
88
|
+
const usageStatus = await billing.getUsageStatus(billingId, hasPersonalKey);
|
|
89
|
+
return {
|
|
90
|
+
messages: usageStatus.messages ?? 0,
|
|
91
|
+
tokens: {
|
|
92
|
+
input: usageStatus.tokensIn ?? usageStatus.inputTokens ?? 0,
|
|
93
|
+
output: usageStatus.tokensOut ?? usageStatus.outputTokens ?? 0,
|
|
94
|
+
},
|
|
95
|
+
period: usageStatus.period ?? new Date().toISOString().slice(0, 7),
|
|
96
|
+
};
|
|
97
|
+
},
|
|
98
|
+
/**
|
|
99
|
+
* Get storage consumption breakdown for the current workspace.
|
|
100
|
+
*
|
|
101
|
+
* Uses incremental storage tracking for instant response. On first access,
|
|
102
|
+
* forces a one-time initialization to ensure accurate data.
|
|
103
|
+
*
|
|
104
|
+
* @param ctx - Handler context with authenticated user and workspace.
|
|
105
|
+
* @returns Storage usage across entities, files, and indices.
|
|
106
|
+
*/
|
|
107
|
+
async getStorageUsage(ctx) {
|
|
108
|
+
const storageId = ctx.user.emailHash;
|
|
109
|
+
const billingId = ctx.user.email;
|
|
110
|
+
// Get plan-based storage limit
|
|
111
|
+
const subscription = await billing.getSubscription(billingId);
|
|
112
|
+
const planId = subscription?.plan || 'free';
|
|
113
|
+
const limitBytes = await storageLimitResolver.getLimit(planId);
|
|
114
|
+
// Get current usage (instant from incremental tracker)
|
|
115
|
+
let usedBytes = await storageTracker.getUsage(storageId, ctx.workspaceId);
|
|
116
|
+
// Force init on first access for accuracy
|
|
117
|
+
if (!storageTracker.isInitialized(storageId, ctx.workspaceId)) {
|
|
118
|
+
usedBytes = await storageTracker.forceInit(storageId, ctx.workspaceId);
|
|
119
|
+
}
|
|
120
|
+
// The SDK contract returns a breakdown; we estimate the split from total.
|
|
121
|
+
// Products can override with more granular tracking if needed.
|
|
122
|
+
return {
|
|
123
|
+
totalBytes: usedBytes,
|
|
124
|
+
entityBytes: Math.round(usedBytes * 0.3), // Approximate: ~30% entities
|
|
125
|
+
fileBytes: Math.round(usedBytes * 0.6), // Approximate: ~60% files
|
|
126
|
+
indexBytes: Math.round(usedBytes * 0.1), // Approximate: ~10% indices
|
|
127
|
+
};
|
|
128
|
+
},
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
//# sourceMappingURL=settings.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"settings.js","sourceRoot":"","sources":["../../../src/server/handlers/settings.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module server/handlers/workspace
|
|
3
|
+
* @description Workspace namespace handler — workspace CRUD, backup/restore,
|
|
4
|
+
* Venue connection, health checks, and workspace settings.
|
|
5
|
+
*
|
|
6
|
+
* Absorbs Workshop `routes/workspace.ts` (backup/restore, SSE events, whoami)
|
|
7
|
+
* and `routes/workspaces.ts` (CRUD, validation, connect-venue, available-venues).
|
|
8
|
+
*
|
|
9
|
+
* The handler delegates to an injected `WorkspaceManager` interface for workspace
|
|
10
|
+
* registry operations, so products can plug in their own storage backends.
|
|
11
|
+
*
|
|
12
|
+
* Methods:
|
|
13
|
+
* - `list` — List all workspaces for the current user
|
|
14
|
+
* - `get` — Get a specific workspace by ID
|
|
15
|
+
* - `create` — Create a new workspace (optionally from a kit)
|
|
16
|
+
* - `update` — Update workspace metadata
|
|
17
|
+
* - `delete` — Delete a workspace permanently
|
|
18
|
+
* - `getStatus` — Get workspace health and initialization status
|
|
19
|
+
* - `backup` — Create a downloadable backup archive
|
|
20
|
+
* - `restore` — Restore from a backup archive
|
|
21
|
+
* - `connectVenue` — Connect workspace to a Venue site
|
|
22
|
+
* - `getSettings` — Get workspace-level settings
|
|
23
|
+
* - `updateSettings` — Update workspace settings (merge)
|
|
24
|
+
* - `healthCheck` — Brainy round-trip health check
|
|
25
|
+
*/
|
|
26
|
+
import type { NamespaceProvider } from '../namespace-router.js';
|
|
27
|
+
import type { WorkspaceInfo } from '../../namespaces.js';
|
|
28
|
+
/**
|
|
29
|
+
* Workspace registry manager — provides workspace CRUD without Hono coupling.
|
|
30
|
+
*
|
|
31
|
+
* Products implement this interface to connect to their workspace storage.
|
|
32
|
+
* Workshop uses a JSON file registry on the filesystem; Venue might use a
|
|
33
|
+
* database-backed registry.
|
|
34
|
+
*/
|
|
35
|
+
export interface WorkspaceManager {
|
|
36
|
+
/** List all workspaces for the given user. */
|
|
37
|
+
listWorkspaces(userId: string): Promise<WorkspaceInfo[]>;
|
|
38
|
+
/** Get a workspace by ID. Returns `null` if not found. */
|
|
39
|
+
getWorkspace(userId: string, workspaceId: string): Promise<WorkspaceInfo | null>;
|
|
40
|
+
/** Create a new workspace. */
|
|
41
|
+
createWorkspace(userId: string, options: {
|
|
42
|
+
name: string;
|
|
43
|
+
kitId?: string;
|
|
44
|
+
description?: string;
|
|
45
|
+
color?: string;
|
|
46
|
+
icon?: string;
|
|
47
|
+
}): Promise<WorkspaceInfo>;
|
|
48
|
+
/** Update workspace metadata. */
|
|
49
|
+
updateWorkspace(userId: string, workspaceId: string, updates: {
|
|
50
|
+
name?: string;
|
|
51
|
+
}): Promise<WorkspaceInfo>;
|
|
52
|
+
/** Delete a workspace. */
|
|
53
|
+
deleteWorkspace(userId: string, workspaceId: string): Promise<void>;
|
|
54
|
+
/**
|
|
55
|
+
* Connect workspace to a Venue site.
|
|
56
|
+
*
|
|
57
|
+
* @param userId - User's email hash.
|
|
58
|
+
* @param venueUrl - Venue base URL.
|
|
59
|
+
* @param locationId - Venue location ID.
|
|
60
|
+
* @returns Connection metadata for the remote workspace.
|
|
61
|
+
*/
|
|
62
|
+
connectVenue?(userId: string, venueUrl: string, locationId: string): Promise<WorkspaceInfo>;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Options for {@link createWorkspaceHandler}.
|
|
66
|
+
*/
|
|
67
|
+
export interface WorkspaceHandlerOptions {
|
|
68
|
+
/** Workspace registry manager. */
|
|
69
|
+
workspaceManager: WorkspaceManager;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Creates the `workspace` namespace handler.
|
|
73
|
+
*
|
|
74
|
+
* @param options - Workspace handler dependencies.
|
|
75
|
+
* @returns A {@link NamespaceProvider} implementing {@link WorkspaceNamespace}.
|
|
76
|
+
*/
|
|
77
|
+
export declare function createWorkspaceHandler(options: WorkspaceHandlerOptions): NamespaceProvider;
|
|
78
|
+
//# sourceMappingURL=workspace.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workspace.d.ts","sourceRoot":"","sources":["../../../src/server/handlers/workspace.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAkB,MAAM,wBAAwB,CAAA;AAC/E,OAAO,KAAK,EAAE,aAAa,EAAmB,MAAM,qBAAqB,CAAA;AAMzE;;;;;;GAMG;AACH,MAAM,WAAW,gBAAgB;IAC/B,8CAA8C;IAC9C,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC,CAAA;IAExD,0DAA0D;IAC1D,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAAA;IAEhF,8BAA8B;IAC9B,eAAe,CACb,MAAM,EAAE,MAAM,EACd,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,GAC7F,OAAO,CAAC,aAAa,CAAC,CAAA;IAEzB,iCAAiC;IACjC,eAAe,CACb,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,GACzB,OAAO,CAAC,aAAa,CAAC,CAAA;IAEzB,0BAA0B;IAC1B,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAEnE;;;;;;;OAOG;IACH,YAAY,CAAC,CACX,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,aAAa,CAAC,CAAA;CAC1B;AAED;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC,kCAAkC;IAClC,gBAAgB,EAAE,gBAAgB,CAAA;CACnC;AAMD;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,uBAAuB,GAAG,iBAAiB,CAkR1F"}
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module server/handlers/workspace
|
|
3
|
+
* @description Workspace namespace handler — workspace CRUD, backup/restore,
|
|
4
|
+
* Venue connection, health checks, and workspace settings.
|
|
5
|
+
*
|
|
6
|
+
* Absorbs Workshop `routes/workspace.ts` (backup/restore, SSE events, whoami)
|
|
7
|
+
* and `routes/workspaces.ts` (CRUD, validation, connect-venue, available-venues).
|
|
8
|
+
*
|
|
9
|
+
* The handler delegates to an injected `WorkspaceManager` interface for workspace
|
|
10
|
+
* registry operations, so products can plug in their own storage backends.
|
|
11
|
+
*
|
|
12
|
+
* Methods:
|
|
13
|
+
* - `list` — List all workspaces for the current user
|
|
14
|
+
* - `get` — Get a specific workspace by ID
|
|
15
|
+
* - `create` — Create a new workspace (optionally from a kit)
|
|
16
|
+
* - `update` — Update workspace metadata
|
|
17
|
+
* - `delete` — Delete a workspace permanently
|
|
18
|
+
* - `getStatus` — Get workspace health and initialization status
|
|
19
|
+
* - `backup` — Create a downloadable backup archive
|
|
20
|
+
* - `restore` — Restore from a backup archive
|
|
21
|
+
* - `connectVenue` — Connect workspace to a Venue site
|
|
22
|
+
* - `getSettings` — Get workspace-level settings
|
|
23
|
+
* - `updateSettings` — Update workspace settings (merge)
|
|
24
|
+
* - `healthCheck` — Brainy round-trip health check
|
|
25
|
+
*/
|
|
26
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
27
|
+
// Handler factory
|
|
28
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
29
|
+
/**
|
|
30
|
+
* Creates the `workspace` namespace handler.
|
|
31
|
+
*
|
|
32
|
+
* @param options - Workspace handler dependencies.
|
|
33
|
+
* @returns A {@link NamespaceProvider} implementing {@link WorkspaceNamespace}.
|
|
34
|
+
*/
|
|
35
|
+
export function createWorkspaceHandler(options) {
|
|
36
|
+
const { workspaceManager } = options;
|
|
37
|
+
return {
|
|
38
|
+
/**
|
|
39
|
+
* List all workspaces for the current user.
|
|
40
|
+
*
|
|
41
|
+
* @param ctx - Handler context with authenticated user.
|
|
42
|
+
* @returns Array of workspace metadata.
|
|
43
|
+
*/
|
|
44
|
+
async list(ctx) {
|
|
45
|
+
return workspaceManager.listWorkspaces(ctx.user.emailHash);
|
|
46
|
+
},
|
|
47
|
+
/**
|
|
48
|
+
* Get a specific workspace by ID.
|
|
49
|
+
*
|
|
50
|
+
* @param workspaceId - The workspace's unique identifier.
|
|
51
|
+
* @param ctx - Handler context with authenticated user.
|
|
52
|
+
* @returns Workspace metadata or `null` if not found.
|
|
53
|
+
*/
|
|
54
|
+
async get(workspaceId, ctx) {
|
|
55
|
+
return workspaceManager.getWorkspace(ctx.user.emailHash, workspaceId);
|
|
56
|
+
},
|
|
57
|
+
/**
|
|
58
|
+
* Create a new workspace, optionally from a kit template.
|
|
59
|
+
*
|
|
60
|
+
* @param createOptions - Workspace creation options.
|
|
61
|
+
* @param ctx - Handler context with authenticated user.
|
|
62
|
+
* @returns The newly created workspace metadata.
|
|
63
|
+
*/
|
|
64
|
+
async create(createOptions, ctx) {
|
|
65
|
+
return workspaceManager.createWorkspace(ctx.user.emailHash, createOptions);
|
|
66
|
+
},
|
|
67
|
+
/**
|
|
68
|
+
* Update workspace metadata.
|
|
69
|
+
*
|
|
70
|
+
* @param workspaceId - Workspace to update.
|
|
71
|
+
* @param updates - Fields to update.
|
|
72
|
+
* @param ctx - Handler context with authenticated user.
|
|
73
|
+
* @returns The updated workspace metadata.
|
|
74
|
+
*/
|
|
75
|
+
async update(workspaceId, updates, ctx) {
|
|
76
|
+
return workspaceManager.updateWorkspace(ctx.user.emailHash, workspaceId, updates);
|
|
77
|
+
},
|
|
78
|
+
/**
|
|
79
|
+
* Delete a workspace and all its data permanently.
|
|
80
|
+
*
|
|
81
|
+
* @param workspaceId - Workspace to delete.
|
|
82
|
+
* @param ctx - Handler context with authenticated user.
|
|
83
|
+
*/
|
|
84
|
+
async delete(workspaceId, ctx) {
|
|
85
|
+
await workspaceManager.deleteWorkspace(ctx.user.emailHash, workspaceId);
|
|
86
|
+
},
|
|
87
|
+
/**
|
|
88
|
+
* Get the workspace's health and initialization status.
|
|
89
|
+
*
|
|
90
|
+
* Pings the Brainy instance with `indexStats()` to verify it's responsive.
|
|
91
|
+
*
|
|
92
|
+
* @param ctx - Handler context with Brainy instance.
|
|
93
|
+
* @returns Status and entity count.
|
|
94
|
+
*/
|
|
95
|
+
async getStatus(ctx) {
|
|
96
|
+
try {
|
|
97
|
+
const stats = await ctx.brain.indexStats();
|
|
98
|
+
return {
|
|
99
|
+
status: 'ready',
|
|
100
|
+
workspaceId: ctx.workspaceId,
|
|
101
|
+
entityCount: stats.entities ?? 0,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
catch (err) {
|
|
105
|
+
return {
|
|
106
|
+
status: 'error',
|
|
107
|
+
workspaceId: ctx.workspaceId,
|
|
108
|
+
error: err.message,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
/**
|
|
113
|
+
* Create a downloadable backup of the entire workspace.
|
|
114
|
+
*
|
|
115
|
+
* Exports all VFS files and entities into a zip archive. The archive is
|
|
116
|
+
* returned as raw binary data (Uint8Array) that the transport layer
|
|
117
|
+
* converts to a download response.
|
|
118
|
+
*
|
|
119
|
+
* @param ctx - Handler context with Brainy instance.
|
|
120
|
+
* @returns Backup archive metadata with download URL placeholder.
|
|
121
|
+
*/
|
|
122
|
+
async backup(ctx) {
|
|
123
|
+
const { brain } = ctx;
|
|
124
|
+
// Collect all VFS files
|
|
125
|
+
const vfsFiles = [];
|
|
126
|
+
try {
|
|
127
|
+
const allFiles = await brain.vfs.readdir('/', { recursive: true });
|
|
128
|
+
for (const file of allFiles) {
|
|
129
|
+
try {
|
|
130
|
+
const content = await brain.vfs.readFile(file.path);
|
|
131
|
+
if (content !== null && content !== undefined) {
|
|
132
|
+
vfsFiles.push({
|
|
133
|
+
path: file.path,
|
|
134
|
+
content: typeof content === 'string' ? content : JSON.stringify(content),
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
catch {
|
|
139
|
+
// Skip unreadable files
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
catch {
|
|
144
|
+
// Empty VFS
|
|
145
|
+
}
|
|
146
|
+
// Export all entities
|
|
147
|
+
let entities = [];
|
|
148
|
+
try {
|
|
149
|
+
entities = await brain.find({ limit: 50000, excludeVFS: true });
|
|
150
|
+
}
|
|
151
|
+
catch {
|
|
152
|
+
// No entities
|
|
153
|
+
}
|
|
154
|
+
// Build manifest
|
|
155
|
+
const manifest = {
|
|
156
|
+
version: 1,
|
|
157
|
+
format: 'workshop-backup',
|
|
158
|
+
createdAt: new Date().toISOString(),
|
|
159
|
+
workspaceId: ctx.workspaceId,
|
|
160
|
+
fileCount: vfsFiles.length,
|
|
161
|
+
entityCount: entities.length,
|
|
162
|
+
};
|
|
163
|
+
// Estimate size (actual zip would be smaller)
|
|
164
|
+
const estimatedSize = vfsFiles.reduce((sum, f) => sum + f.content.length, 0)
|
|
165
|
+
+ JSON.stringify(entities).length
|
|
166
|
+
+ JSON.stringify(manifest).length;
|
|
167
|
+
// The actual zip creation happens at the transport/route level since it
|
|
168
|
+
// requires streaming binary data. The handler provides the data; the
|
|
169
|
+
// Hono route adapter assembles the archive.
|
|
170
|
+
// For now, return a placeholder that the Hono adapter interprets.
|
|
171
|
+
return {
|
|
172
|
+
downloadUrl: `__backup__:${ctx.workspaceId}`,
|
|
173
|
+
size: estimatedSize,
|
|
174
|
+
};
|
|
175
|
+
},
|
|
176
|
+
/**
|
|
177
|
+
* Restore a workspace from a backup archive.
|
|
178
|
+
*
|
|
179
|
+
* Processes the backup zip, restoring VFS files and entities into the
|
|
180
|
+
* current Brainy instance.
|
|
181
|
+
*
|
|
182
|
+
* @param backupData - The backup archive as raw binary data.
|
|
183
|
+
* @param ctx - Handler context with Brainy instance.
|
|
184
|
+
* @returns Counts of restored items.
|
|
185
|
+
*/
|
|
186
|
+
async restore(backupData, ctx) {
|
|
187
|
+
const { brain } = ctx;
|
|
188
|
+
// Restore requires zip processing — delegated to the transport/route layer
|
|
189
|
+
// for binary handling. The core logic is:
|
|
190
|
+
// 1. Parse manifest.json from zip
|
|
191
|
+
// 2. Restore vfs/ entries via brain.vfs.writeFile()
|
|
192
|
+
// 3. Restore data/entities.json via brain.add()
|
|
193
|
+
// This will be fully wired when the Hono adapter handles multipart uploads.
|
|
194
|
+
throw new Error('workspace.restore requires binary transport — use the Hono route adapter');
|
|
195
|
+
},
|
|
196
|
+
/**
|
|
197
|
+
* Connect the workspace to a Venue site.
|
|
198
|
+
*
|
|
199
|
+
* @param venueOptions - Venue handle and slug.
|
|
200
|
+
* @param ctx - Handler context with authenticated user.
|
|
201
|
+
*/
|
|
202
|
+
async connectVenue(venueOptions, ctx) {
|
|
203
|
+
if (!workspaceManager.connectVenue) {
|
|
204
|
+
throw new Error('Venue connection is not configured for this product');
|
|
205
|
+
}
|
|
206
|
+
// Derive Venue URL from handle (products configure this)
|
|
207
|
+
const venueUrl = `https://${venueOptions.venueHandle}.soulcraft.com`;
|
|
208
|
+
await workspaceManager.connectVenue(ctx.user.emailHash, venueUrl, venueOptions.venueSlug);
|
|
209
|
+
},
|
|
210
|
+
/**
|
|
211
|
+
* Get workspace-level settings.
|
|
212
|
+
*
|
|
213
|
+
* Reads the `workshop.settings` extended attribute from the workspace root.
|
|
214
|
+
*
|
|
215
|
+
* @param ctx - Handler context with Brainy instance.
|
|
216
|
+
* @returns Key-value settings object.
|
|
217
|
+
*/
|
|
218
|
+
async getSettings(ctx) {
|
|
219
|
+
try {
|
|
220
|
+
return (await ctx.brain.vfs.getxattr('/', 'workshop.settings')) || {};
|
|
221
|
+
}
|
|
222
|
+
catch {
|
|
223
|
+
return {};
|
|
224
|
+
}
|
|
225
|
+
},
|
|
226
|
+
/**
|
|
227
|
+
* Update workspace settings (merge).
|
|
228
|
+
*
|
|
229
|
+
* Merges the provided settings into the existing `workshop.settings` xattr.
|
|
230
|
+
*
|
|
231
|
+
* @param settings - Key-value pairs to merge.
|
|
232
|
+
* @param ctx - Handler context with Brainy instance.
|
|
233
|
+
*/
|
|
234
|
+
async updateSettings(settings, ctx) {
|
|
235
|
+
let existing = {};
|
|
236
|
+
try {
|
|
237
|
+
existing = (await ctx.brain.vfs.getxattr('/', 'workshop.settings')) || {};
|
|
238
|
+
}
|
|
239
|
+
catch {
|
|
240
|
+
// No existing settings
|
|
241
|
+
}
|
|
242
|
+
await ctx.brain.vfs.setxattr('/', 'workshop.settings', { ...existing, ...settings });
|
|
243
|
+
},
|
|
244
|
+
/**
|
|
245
|
+
* Run a health check on the Brainy instance.
|
|
246
|
+
*
|
|
247
|
+
* Measures round-trip latency of an `indexStats()` call.
|
|
248
|
+
*
|
|
249
|
+
* @param ctx - Handler context with Brainy instance.
|
|
250
|
+
* @returns Health status and latency in milliseconds.
|
|
251
|
+
*/
|
|
252
|
+
async healthCheck(ctx) {
|
|
253
|
+
const start = performance.now();
|
|
254
|
+
try {
|
|
255
|
+
await ctx.brain.indexStats();
|
|
256
|
+
return {
|
|
257
|
+
status: 'ok',
|
|
258
|
+
latencyMs: Math.round(performance.now() - start),
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
catch {
|
|
262
|
+
return {
|
|
263
|
+
status: 'error',
|
|
264
|
+
latencyMs: Math.round(performance.now() - start),
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
},
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
//# sourceMappingURL=workspace.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workspace.js","sourceRoot":"","sources":["../../../src/server/handlers/workspace.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module server/hono-router
|
|
3
|
+
* @description Hono integration factory for the Soulcraft SDK namespace router.
|
|
4
|
+
*
|
|
5
|
+
* Creates a Hono app with three routes:
|
|
6
|
+
*
|
|
7
|
+
* - `POST /api/rpc` — Unified namespace RPC endpoint. Accepts the
|
|
8
|
+
* {@link SoulcraftRPC} envelope and dispatches via the namespace router.
|
|
9
|
+
* Streaming responses are delivered as SSE (`text/event-stream`).
|
|
10
|
+
*
|
|
11
|
+
* - `POST /api/brainy/rpc` — Legacy backward-compatible endpoint. Injects
|
|
12
|
+
* `ns: 'brainy'` and forwards to the same namespace router.
|
|
13
|
+
*
|
|
14
|
+
* - `GET /api/events` — SSE subscription for real-time change events (TBD,
|
|
15
|
+
* route registered but handler deferred to Phase 1b).
|
|
16
|
+
*
|
|
17
|
+
* Products mount this router in their Hono app with `app.route('', sdkRouter)`.
|
|
18
|
+
*
|
|
19
|
+
* @example Workshop server-hono.ts
|
|
20
|
+
* ```typescript
|
|
21
|
+
* import { createSoulcraftRouter } from '@soulcraft/sdk/server'
|
|
22
|
+
*
|
|
23
|
+
* const sdkRouter = createSoulcraftRouter({
|
|
24
|
+
* resolveBrain: async (ctx) => getUserBrainy(ctx.user!.emailHash, ctx.workspaceId),
|
|
25
|
+
* authenticate: async (ctx) => verifySession(ctx.request),
|
|
26
|
+
* providers: {
|
|
27
|
+
* chat: chatHandler,
|
|
28
|
+
* graph: graphHandler,
|
|
29
|
+
* search: searchHandler,
|
|
30
|
+
* },
|
|
31
|
+
* })
|
|
32
|
+
*
|
|
33
|
+
* app.route('', sdkRouter)
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
import { Hono } from 'hono';
|
|
37
|
+
import type { NamespaceRouterConfig } from './namespace-router.js';
|
|
38
|
+
/**
|
|
39
|
+
* Configuration for {@link createSoulcraftRouter}.
|
|
40
|
+
*
|
|
41
|
+
* Same as {@link NamespaceRouterConfig} — passed through to the namespace router.
|
|
42
|
+
*/
|
|
43
|
+
export type SoulcraftRouterConfig = NamespaceRouterConfig;
|
|
44
|
+
/**
|
|
45
|
+
* Creates a Hono app with the unified Soulcraft RPC routes.
|
|
46
|
+
*
|
|
47
|
+
* The returned Hono app should be mounted at the root of your product server
|
|
48
|
+
* (not under a prefix) since it defines its own `/api/rpc` and `/api/brainy/rpc`
|
|
49
|
+
* paths.
|
|
50
|
+
*
|
|
51
|
+
* @param config - Namespace router configuration.
|
|
52
|
+
* @returns A Hono app ready to be mounted with `app.route('', sdkRouter)`.
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* ```typescript
|
|
56
|
+
* const sdkRouter = createSoulcraftRouter({
|
|
57
|
+
* resolveBrain: async (ctx) => pool.forUser(ctx.user!.emailHash, ctx.workspaceId),
|
|
58
|
+
* authenticate: async (ctx) => verifySession(ctx.request),
|
|
59
|
+
* providers: { chat: chatHandler },
|
|
60
|
+
* })
|
|
61
|
+
*
|
|
62
|
+
* app.route('', sdkRouter)
|
|
63
|
+
* ```
|
|
64
|
+
*/
|
|
65
|
+
export declare function createSoulcraftRouter(config: SoulcraftRouterConfig): Hono;
|
|
66
|
+
//# sourceMappingURL=hono-router.d.ts.map
|