@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.
- package/dist/client/index.d.ts +62 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +60 -0
- package/dist/client/index.js.map +1 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -0
- package/dist/modules/ai/index.d.ts +55 -0
- package/dist/modules/ai/index.d.ts.map +1 -0
- package/dist/modules/ai/index.js +263 -0
- package/dist/modules/ai/index.js.map +1 -0
- package/dist/modules/ai/types.d.ts +216 -0
- package/dist/modules/ai/types.d.ts.map +1 -0
- package/dist/modules/ai/types.js +30 -0
- package/dist/modules/ai/types.js.map +1 -0
- package/dist/modules/auth/backchannel.d.ts +85 -0
- package/dist/modules/auth/backchannel.d.ts.map +1 -0
- package/dist/modules/auth/backchannel.js +168 -0
- package/dist/modules/auth/backchannel.js.map +1 -0
- package/dist/modules/auth/config.d.ts +122 -0
- package/dist/modules/auth/config.d.ts.map +1 -0
- package/dist/modules/auth/config.js +158 -0
- package/dist/modules/auth/config.js.map +1 -0
- package/dist/modules/auth/middleware.d.ts +146 -0
- package/dist/modules/auth/middleware.d.ts.map +1 -0
- package/dist/modules/auth/middleware.js +204 -0
- package/dist/modules/auth/middleware.js.map +1 -0
- package/dist/modules/auth/types.d.ts +162 -0
- package/dist/modules/auth/types.d.ts.map +1 -0
- package/dist/modules/auth/types.js +14 -0
- package/dist/modules/auth/types.js.map +1 -0
- package/dist/modules/billing/types.d.ts +7 -0
- package/dist/modules/billing/types.d.ts.map +1 -0
- package/dist/modules/billing/types.js +7 -0
- package/dist/modules/billing/types.js.map +1 -0
- package/dist/modules/brainy/auth.d.ts +104 -0
- package/dist/modules/brainy/auth.d.ts.map +1 -0
- package/dist/modules/brainy/auth.js +144 -0
- package/dist/modules/brainy/auth.js.map +1 -0
- package/dist/modules/brainy/errors.d.ts +118 -0
- package/dist/modules/brainy/errors.d.ts.map +1 -0
- package/dist/modules/brainy/errors.js +142 -0
- package/dist/modules/brainy/errors.js.map +1 -0
- package/dist/modules/brainy/events.d.ts +63 -0
- package/dist/modules/brainy/events.d.ts.map +1 -0
- package/dist/modules/brainy/events.js +14 -0
- package/dist/modules/brainy/events.js.map +1 -0
- package/dist/modules/brainy/proxy.d.ts +48 -0
- package/dist/modules/brainy/proxy.d.ts.map +1 -0
- package/dist/modules/brainy/proxy.js +95 -0
- package/dist/modules/brainy/proxy.js.map +1 -0
- package/dist/modules/brainy/types.d.ts +83 -0
- package/dist/modules/brainy/types.d.ts.map +1 -0
- package/dist/modules/brainy/types.js +21 -0
- package/dist/modules/brainy/types.js.map +1 -0
- package/dist/modules/events/index.d.ts +41 -0
- package/dist/modules/events/index.d.ts.map +1 -0
- package/dist/modules/events/index.js +53 -0
- package/dist/modules/events/index.js.map +1 -0
- package/dist/modules/events/types.d.ts +129 -0
- package/dist/modules/events/types.d.ts.map +1 -0
- package/dist/modules/events/types.js +32 -0
- package/dist/modules/events/types.js.map +1 -0
- package/dist/modules/formats/types.d.ts +7 -0
- package/dist/modules/formats/types.d.ts.map +1 -0
- package/dist/modules/formats/types.js +7 -0
- package/dist/modules/formats/types.js.map +1 -0
- package/dist/modules/hall/types.d.ts +56 -0
- package/dist/modules/hall/types.d.ts.map +1 -0
- package/dist/modules/hall/types.js +16 -0
- package/dist/modules/hall/types.js.map +1 -0
- package/dist/modules/kits/types.d.ts +7 -0
- package/dist/modules/kits/types.d.ts.map +1 -0
- package/dist/modules/kits/types.js +7 -0
- package/dist/modules/kits/types.js.map +1 -0
- package/dist/modules/license/types.d.ts +7 -0
- package/dist/modules/license/types.d.ts.map +1 -0
- package/dist/modules/license/types.js +7 -0
- package/dist/modules/license/types.js.map +1 -0
- package/dist/modules/notifications/types.d.ts +7 -0
- package/dist/modules/notifications/types.d.ts.map +1 -0
- package/dist/modules/notifications/types.js +7 -0
- package/dist/modules/notifications/types.js.map +1 -0
- package/dist/modules/skills/index.d.ts +60 -0
- package/dist/modules/skills/index.d.ts.map +1 -0
- package/dist/modules/skills/index.js +253 -0
- package/dist/modules/skills/index.js.map +1 -0
- package/dist/modules/skills/types.d.ts +127 -0
- package/dist/modules/skills/types.d.ts.map +1 -0
- package/dist/modules/skills/types.js +23 -0
- package/dist/modules/skills/types.js.map +1 -0
- package/dist/modules/versions/types.d.ts +31 -0
- package/dist/modules/versions/types.d.ts.map +1 -0
- package/dist/modules/versions/types.js +9 -0
- package/dist/modules/versions/types.js.map +1 -0
- package/dist/modules/vfs/types.d.ts +26 -0
- package/dist/modules/vfs/types.d.ts.map +1 -0
- package/dist/modules/vfs/types.js +11 -0
- package/dist/modules/vfs/types.js.map +1 -0
- package/dist/server/create-sdk.d.ts +70 -0
- package/dist/server/create-sdk.d.ts.map +1 -0
- package/dist/server/create-sdk.js +125 -0
- package/dist/server/create-sdk.js.map +1 -0
- package/dist/server/hall-handlers.d.ts +195 -0
- package/dist/server/hall-handlers.d.ts.map +1 -0
- package/dist/server/hall-handlers.js +239 -0
- package/dist/server/hall-handlers.js.map +1 -0
- package/dist/server/handlers.d.ts +216 -0
- package/dist/server/handlers.d.ts.map +1 -0
- package/dist/server/handlers.js +214 -0
- package/dist/server/handlers.js.map +1 -0
- package/dist/server/index.d.ts +52 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +50 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/instance-pool.d.ts +299 -0
- package/dist/server/instance-pool.d.ts.map +1 -0
- package/dist/server/instance-pool.js +359 -0
- package/dist/server/instance-pool.js.map +1 -0
- package/dist/transports/http.d.ts +86 -0
- package/dist/transports/http.d.ts.map +1 -0
- package/dist/transports/http.js +134 -0
- package/dist/transports/http.js.map +1 -0
- package/dist/transports/local.d.ts +76 -0
- package/dist/transports/local.d.ts.map +1 -0
- package/dist/transports/local.js +101 -0
- package/dist/transports/local.js.map +1 -0
- package/dist/transports/sse.d.ts +99 -0
- package/dist/transports/sse.d.ts.map +1 -0
- package/dist/transports/sse.js +192 -0
- package/dist/transports/sse.js.map +1 -0
- package/dist/transports/transport.d.ts +68 -0
- package/dist/transports/transport.d.ts.map +1 -0
- package/dist/transports/transport.js +14 -0
- package/dist/transports/transport.js.map +1 -0
- package/dist/transports/ws.d.ts +135 -0
- package/dist/transports/ws.d.ts.map +1 -0
- package/dist/transports/ws.js +331 -0
- package/dist/transports/ws.js.map +1 -0
- package/dist/types.d.ts +152 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +8 -0
- package/dist/types.js.map +1 -0
- package/docs/ADR-001-sdk-design.md +282 -0
- package/docs/IMPLEMENTATION-PLAN.md +708 -0
- package/docs/USAGE.md +646 -0
- package/docs/kit-sdk-guide.md +474 -0
- package/package.json +61 -0
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module modules/ai/types
|
|
3
|
+
* @description Type definitions for `sdk.ai.*` — the Claude AI integration module.
|
|
4
|
+
*
|
|
5
|
+
* Wraps the Anthropic Claude API with Soulcraft-specific defaults:
|
|
6
|
+
* - Canonical model IDs for each tier (haiku for speed, sonnet for quality, opus for complex)
|
|
7
|
+
* - Structured tool call handling with full type safety
|
|
8
|
+
* - Streaming support via async iteration
|
|
9
|
+
*
|
|
10
|
+
* The AI module does not depend on any particular transport — it calls the
|
|
11
|
+
* Anthropic API directly from the server process and is not proxied through Brainy.
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Canonical Anthropic model IDs for each Soulcraft platform tier.
|
|
15
|
+
*
|
|
16
|
+
* Use these constants instead of hardcoding model strings to ensure consistency
|
|
17
|
+
* across products and easier future upgrades.
|
|
18
|
+
*/
|
|
19
|
+
export declare const AI_MODELS: {
|
|
20
|
+
/** Fast, affordable — routine lookups, data extraction, simple Q&A. */
|
|
21
|
+
readonly haiku: "claude-haiku-4-5-20251001";
|
|
22
|
+
/** Balanced — most kit operations, content generation, analysis. */
|
|
23
|
+
readonly sonnet: "claude-sonnet-4-6";
|
|
24
|
+
/** Most capable — complex reasoning, long-form synthesis, multi-step planning. */
|
|
25
|
+
readonly opus: "claude-opus-4-6";
|
|
26
|
+
};
|
|
27
|
+
/** A valid Soulcraft Claude model tier ID. */
|
|
28
|
+
export type AiModel = typeof AI_MODELS[keyof typeof AI_MODELS] | string;
|
|
29
|
+
/**
|
|
30
|
+
* A single message in a Claude conversation.
|
|
31
|
+
*/
|
|
32
|
+
export interface AiMessage {
|
|
33
|
+
/** The role of the message author. */
|
|
34
|
+
role: 'user' | 'assistant';
|
|
35
|
+
/**
|
|
36
|
+
* The message content.
|
|
37
|
+
*
|
|
38
|
+
* For simple text: a plain string.
|
|
39
|
+
* For tool results: an array of content blocks (see Anthropic API docs).
|
|
40
|
+
*/
|
|
41
|
+
content: string | AiContentBlock[];
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* A content block within a message — text, image, tool use, or tool result.
|
|
45
|
+
*/
|
|
46
|
+
export type AiContentBlock = {
|
|
47
|
+
type: 'text';
|
|
48
|
+
text: string;
|
|
49
|
+
} | {
|
|
50
|
+
type: 'image';
|
|
51
|
+
source: {
|
|
52
|
+
type: 'base64';
|
|
53
|
+
media_type: string;
|
|
54
|
+
data: string;
|
|
55
|
+
};
|
|
56
|
+
} | {
|
|
57
|
+
type: 'tool_use';
|
|
58
|
+
id: string;
|
|
59
|
+
name: string;
|
|
60
|
+
input: Record<string, unknown>;
|
|
61
|
+
} | {
|
|
62
|
+
type: 'tool_result';
|
|
63
|
+
tool_use_id: string;
|
|
64
|
+
content: string;
|
|
65
|
+
};
|
|
66
|
+
/**
|
|
67
|
+
* A tool that Claude can call during a completion.
|
|
68
|
+
*/
|
|
69
|
+
export interface AiTool {
|
|
70
|
+
/** Machine-readable tool name (snake_case). */
|
|
71
|
+
name: string;
|
|
72
|
+
/** Human-readable description used by Claude to decide when to call this tool. */
|
|
73
|
+
description: string;
|
|
74
|
+
/** JSON Schema for the tool's input parameters. */
|
|
75
|
+
inputSchema: {
|
|
76
|
+
type: 'object';
|
|
77
|
+
properties: Record<string, unknown>;
|
|
78
|
+
required?: string[];
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* A tool call emitted by Claude in a completion response.
|
|
83
|
+
*/
|
|
84
|
+
export interface AiToolCall {
|
|
85
|
+
/** Unique ID for this tool call (used when feeding results back). */
|
|
86
|
+
id: string;
|
|
87
|
+
/** The name of the tool to call. */
|
|
88
|
+
name: string;
|
|
89
|
+
/** The arguments Claude wants to pass to the tool. */
|
|
90
|
+
input: Record<string, unknown>;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Options for a single Claude completion request.
|
|
94
|
+
*/
|
|
95
|
+
export interface AiCompleteOptions {
|
|
96
|
+
/** The conversation history, alternating user/assistant messages. */
|
|
97
|
+
messages: AiMessage[];
|
|
98
|
+
/**
|
|
99
|
+
* System prompt injected before the conversation.
|
|
100
|
+
* Typically derived from `kit.shared.aiPersona` for kit applications.
|
|
101
|
+
*/
|
|
102
|
+
systemPrompt?: string;
|
|
103
|
+
/**
|
|
104
|
+
* The Claude model to use.
|
|
105
|
+
*
|
|
106
|
+
* @default AI_MODELS.sonnet
|
|
107
|
+
*/
|
|
108
|
+
model?: AiModel;
|
|
109
|
+
/**
|
|
110
|
+
* Tools available to Claude during this completion.
|
|
111
|
+
*
|
|
112
|
+
* When Claude calls a tool, the response will include `toolCalls` instead of
|
|
113
|
+
* (or in addition to) `text`. The caller is responsible for executing the
|
|
114
|
+
* tool and continuing the conversation.
|
|
115
|
+
*/
|
|
116
|
+
tools?: AiTool[];
|
|
117
|
+
/**
|
|
118
|
+
* Maximum tokens in the response.
|
|
119
|
+
*
|
|
120
|
+
* @default 8192
|
|
121
|
+
*/
|
|
122
|
+
maxTokens?: number;
|
|
123
|
+
/**
|
|
124
|
+
* Temperature for sampling (0–1). Lower = more deterministic.
|
|
125
|
+
*
|
|
126
|
+
* @default 1 (Anthropic default)
|
|
127
|
+
*/
|
|
128
|
+
temperature?: number;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* The result of a single Claude completion.
|
|
132
|
+
*
|
|
133
|
+
* `text` and `toolCalls` may both be present if Claude includes a text
|
|
134
|
+
* explanation alongside tool invocations.
|
|
135
|
+
*/
|
|
136
|
+
export interface AiCompleteResult {
|
|
137
|
+
/** The text portion of Claude's response, if any. */
|
|
138
|
+
text: string | null;
|
|
139
|
+
/** Tool calls Claude wants to make, if any. */
|
|
140
|
+
toolCalls: AiToolCall[] | null;
|
|
141
|
+
/** The reason Claude stopped generating. */
|
|
142
|
+
stopReason: 'end_turn' | 'tool_use' | 'max_tokens' | 'stop_sequence' | string;
|
|
143
|
+
/** Token usage for billing/metering. */
|
|
144
|
+
usage: {
|
|
145
|
+
inputTokens: number;
|
|
146
|
+
outputTokens: number;
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Options for a streaming Claude completion.
|
|
151
|
+
*
|
|
152
|
+
* Extends {@link AiCompleteOptions} — same fields apply.
|
|
153
|
+
*/
|
|
154
|
+
export type AiStreamOptions = AiCompleteOptions;
|
|
155
|
+
/**
|
|
156
|
+
* A single event emitted by a streaming Claude completion.
|
|
157
|
+
*/
|
|
158
|
+
export type AiStreamEvent = {
|
|
159
|
+
type: 'text';
|
|
160
|
+
text: string;
|
|
161
|
+
} | {
|
|
162
|
+
type: 'tool_use';
|
|
163
|
+
toolCall: AiToolCall;
|
|
164
|
+
} | {
|
|
165
|
+
type: 'done';
|
|
166
|
+
result: AiCompleteResult;
|
|
167
|
+
};
|
|
168
|
+
/**
|
|
169
|
+
* The `sdk.ai` namespace.
|
|
170
|
+
*
|
|
171
|
+
* Provides direct access to Claude for kit applications and product backends.
|
|
172
|
+
* Handles model selection, tool calls, and streaming without boilerplate.
|
|
173
|
+
*
|
|
174
|
+
* @example Basic completion
|
|
175
|
+
* ```typescript
|
|
176
|
+
* const response = await sdk.ai.complete({
|
|
177
|
+
* messages: [{ role: 'user', content: 'What candles are low in stock?' }],
|
|
178
|
+
* systemPrompt: kit.shared.aiPersona,
|
|
179
|
+
* model: 'claude-haiku-4-5-20251001',
|
|
180
|
+
* tools: [searchInventoryTool],
|
|
181
|
+
* })
|
|
182
|
+
*
|
|
183
|
+
* if (response.toolCalls) {
|
|
184
|
+
* for (const call of response.toolCalls) {
|
|
185
|
+
* // execute tool and continue conversation
|
|
186
|
+
* }
|
|
187
|
+
* }
|
|
188
|
+
* ```
|
|
189
|
+
*
|
|
190
|
+
* @example Streaming
|
|
191
|
+
* ```typescript
|
|
192
|
+
* for await (const event of sdk.ai.stream({ messages, systemPrompt })) {
|
|
193
|
+
* if (event.type === 'text') process.stdout.write(event.text)
|
|
194
|
+
* if (event.type === 'done') console.log('Tokens:', event.result.usage)
|
|
195
|
+
* }
|
|
196
|
+
* ```
|
|
197
|
+
*/
|
|
198
|
+
export interface AiModule {
|
|
199
|
+
/**
|
|
200
|
+
* Run a single Claude completion and return the full result.
|
|
201
|
+
*
|
|
202
|
+
* @param options - Completion options including messages, model, and tools.
|
|
203
|
+
* @returns The full completion result with text and/or tool calls.
|
|
204
|
+
* @throws {Error} If the Anthropic API returns an error.
|
|
205
|
+
*/
|
|
206
|
+
complete(options: AiCompleteOptions): Promise<AiCompleteResult>;
|
|
207
|
+
/**
|
|
208
|
+
* Run a streaming Claude completion, yielding events as they arrive.
|
|
209
|
+
*
|
|
210
|
+
* @param options - Completion options (same as {@link AiModule.complete}).
|
|
211
|
+
* @returns An async iterable of stream events ending with a `done` event.
|
|
212
|
+
* @throws {Error} If the Anthropic API returns an error.
|
|
213
|
+
*/
|
|
214
|
+
stream(options: AiStreamOptions): AsyncIterable<AiStreamEvent>;
|
|
215
|
+
}
|
|
216
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/modules/ai/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module modules/ai/types
|
|
3
|
+
* @description Type definitions for `sdk.ai.*` — the Claude AI integration module.
|
|
4
|
+
*
|
|
5
|
+
* Wraps the Anthropic Claude API with Soulcraft-specific defaults:
|
|
6
|
+
* - Canonical model IDs for each tier (haiku for speed, sonnet for quality, opus for complex)
|
|
7
|
+
* - Structured tool call handling with full type safety
|
|
8
|
+
* - Streaming support via async iteration
|
|
9
|
+
*
|
|
10
|
+
* The AI module does not depend on any particular transport — it calls the
|
|
11
|
+
* Anthropic API directly from the server process and is not proxied through Brainy.
|
|
12
|
+
*/
|
|
13
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
14
|
+
// Model tiers
|
|
15
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
16
|
+
/**
|
|
17
|
+
* Canonical Anthropic model IDs for each Soulcraft platform tier.
|
|
18
|
+
*
|
|
19
|
+
* Use these constants instead of hardcoding model strings to ensure consistency
|
|
20
|
+
* across products and easier future upgrades.
|
|
21
|
+
*/
|
|
22
|
+
export const AI_MODELS = {
|
|
23
|
+
/** Fast, affordable — routine lookups, data extraction, simple Q&A. */
|
|
24
|
+
haiku: 'claude-haiku-4-5-20251001',
|
|
25
|
+
/** Balanced — most kit operations, content generation, analysis. */
|
|
26
|
+
sonnet: 'claude-sonnet-4-6',
|
|
27
|
+
/** Most capable — complex reasoning, long-form synthesis, multi-step planning. */
|
|
28
|
+
opus: 'claude-opus-4-6',
|
|
29
|
+
};
|
|
30
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/modules/ai/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,gFAAgF;AAChF,cAAc;AACd,gFAAgF;AAEhF;;;;;GAKG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG;IACvB,uEAAuE;IACvE,KAAK,EAAE,2BAA2B;IAClC,oEAAoE;IACpE,MAAM,EAAE,mBAAmB;IAC3B,kFAAkF;IAClF,IAAI,EAAE,iBAAiB;CACf,CAAA"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module modules/auth/backchannel
|
|
3
|
+
* @description OIDC back-channel logout handler factory for Soulcraft product backends.
|
|
4
|
+
*
|
|
5
|
+
* Implements the OpenID Connect Back-Channel Logout 1.0 specification. When a user
|
|
6
|
+
* signs out of the central IdP (`auth.soulcraft.com`), the IdP POSTs a signed
|
|
7
|
+
* `logout_token` (HS256 JWT) to every registered product's back-channel logout
|
|
8
|
+
* endpoint. This handler verifies the token and deletes all active sessions for
|
|
9
|
+
* the identified user, ensuring immediate logout across all products.
|
|
10
|
+
*
|
|
11
|
+
* ## Protocol
|
|
12
|
+
*
|
|
13
|
+
* 1. IdP POSTs `application/x-www-form-urlencoded` body with `logout_token` field
|
|
14
|
+
* 2. Handler verifies HS256 JWT signature using the OIDC client secret
|
|
15
|
+
* 3. Handler validates standard claims: `iss`, `aud`, `events` (must contain
|
|
16
|
+
* `http://schemas.openid.net/event/backchannel-logout`)
|
|
17
|
+
* 4. Handler deletes all better-auth sessions for the `sub` (user ID) claim
|
|
18
|
+
* 5. Returns 200 on success, 400 for malformed tokens, 401 for bad signatures
|
|
19
|
+
*
|
|
20
|
+
* ## Mounting (Hono)
|
|
21
|
+
*
|
|
22
|
+
* ```typescript
|
|
23
|
+
* import { createBackchannelLogoutHandler } from '@soulcraft/sdk/server'
|
|
24
|
+
*
|
|
25
|
+
* app.post('/api/auth/backchannel-logout', createBackchannelLogoutHandler({
|
|
26
|
+
* auth,
|
|
27
|
+
* clientSecret: process.env.SOULCRAFT_OIDC_CLIENT_SECRET!,
|
|
28
|
+
* idpUrl: process.env.SOULCRAFT_IDP_URL!,
|
|
29
|
+
* clientId: process.env.SOULCRAFT_OIDC_CLIENT_ID!,
|
|
30
|
+
* }))
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
import type { Context } from 'hono';
|
|
34
|
+
/** Minimal better-auth API surface needed for session deletion. */
|
|
35
|
+
export interface BackchannelAuthLike {
|
|
36
|
+
api: {
|
|
37
|
+
revokeUserSessions(opts: {
|
|
38
|
+
body: {
|
|
39
|
+
userId: string;
|
|
40
|
+
};
|
|
41
|
+
headers?: Headers;
|
|
42
|
+
}): Promise<unknown>;
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* @description Configuration for createBackchannelLogoutHandler().
|
|
47
|
+
*/
|
|
48
|
+
export interface BackchannelLogoutConfig {
|
|
49
|
+
/** The product's better-auth instance (used to delete sessions). */
|
|
50
|
+
auth: BackchannelAuthLike;
|
|
51
|
+
/** This product's OIDC client secret — used to verify the logout_token signature. */
|
|
52
|
+
clientSecret: string;
|
|
53
|
+
/** The central IdP base URL — used to validate the `iss` claim. */
|
|
54
|
+
idpUrl: string;
|
|
55
|
+
/** This product's OIDC client ID — used to validate the `aud` claim. */
|
|
56
|
+
clientId: string;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* @description Creates a Hono route handler for the OIDC back-channel logout endpoint.
|
|
60
|
+
*
|
|
61
|
+
* Mount at `POST /api/auth/backchannel-logout`. The handler:
|
|
62
|
+
* 1. Parses the `logout_token` from the form-encoded body
|
|
63
|
+
* 2. Verifies the HS256 JWT signature using the OIDC client secret
|
|
64
|
+
* 3. Validates `iss` (must match idpUrl), `aud` (must match clientId),
|
|
65
|
+
* and `events` (must contain the back-channel logout event URI)
|
|
66
|
+
* 4. Calls `auth.api.revokeUserSessions({ body: { userId: sub } })` to
|
|
67
|
+
* immediately invalidate all sessions for the identified user
|
|
68
|
+
* 5. Returns 200 on success, 400 for malformed/missing token, 401 for
|
|
69
|
+
* invalid signature or failed claims validation
|
|
70
|
+
*
|
|
71
|
+
* @param config - Auth instance, client secret, IdP URL, and client ID.
|
|
72
|
+
* @returns A Hono-compatible request handler function.
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* ```typescript
|
|
76
|
+
* app.post('/api/auth/backchannel-logout', createBackchannelLogoutHandler({
|
|
77
|
+
* auth,
|
|
78
|
+
* clientSecret: process.env.SOULCRAFT_OIDC_CLIENT_SECRET!,
|
|
79
|
+
* idpUrl: process.env.SOULCRAFT_IDP_URL!,
|
|
80
|
+
* clientId: process.env.SOULCRAFT_OIDC_CLIENT_ID!,
|
|
81
|
+
* }))
|
|
82
|
+
* ```
|
|
83
|
+
*/
|
|
84
|
+
export declare function createBackchannelLogoutHandler(config: BackchannelLogoutConfig): (c: Context) => Promise<Response>;
|
|
85
|
+
//# sourceMappingURL=backchannel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"backchannel.d.ts","sourceRoot":"","sources":["../../../src/modules/auth/backchannel.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAA;AAMnC,mEAAmE;AACnE,MAAM,WAAW,mBAAmB;IAClC,GAAG,EAAE;QACH,kBAAkB,CAAC,IAAI,EAAE;YAAE,IAAI,EAAE;gBAAE,MAAM,EAAE,MAAM,CAAA;aAAE,CAAC;YAAC,OAAO,CAAC,EAAE,OAAO,CAAA;SAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;KAC5F,CAAA;CACF;AAED;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC,oEAAoE;IACpE,IAAI,EAAE,mBAAmB,CAAA;IACzB,qFAAqF;IACrF,YAAY,EAAE,MAAM,CAAA;IACpB,mEAAmE;IACnE,MAAM,EAAE,MAAM,CAAA;IACd,wEAAwE;IACxE,QAAQ,EAAE,MAAM,CAAA;CACjB;AA0ED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,8BAA8B,CAC5C,MAAM,EAAE,uBAAuB,GAC9B,CAAC,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAgEnC"}
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module modules/auth/backchannel
|
|
3
|
+
* @description OIDC back-channel logout handler factory for Soulcraft product backends.
|
|
4
|
+
*
|
|
5
|
+
* Implements the OpenID Connect Back-Channel Logout 1.0 specification. When a user
|
|
6
|
+
* signs out of the central IdP (`auth.soulcraft.com`), the IdP POSTs a signed
|
|
7
|
+
* `logout_token` (HS256 JWT) to every registered product's back-channel logout
|
|
8
|
+
* endpoint. This handler verifies the token and deletes all active sessions for
|
|
9
|
+
* the identified user, ensuring immediate logout across all products.
|
|
10
|
+
*
|
|
11
|
+
* ## Protocol
|
|
12
|
+
*
|
|
13
|
+
* 1. IdP POSTs `application/x-www-form-urlencoded` body with `logout_token` field
|
|
14
|
+
* 2. Handler verifies HS256 JWT signature using the OIDC client secret
|
|
15
|
+
* 3. Handler validates standard claims: `iss`, `aud`, `events` (must contain
|
|
16
|
+
* `http://schemas.openid.net/event/backchannel-logout`)
|
|
17
|
+
* 4. Handler deletes all better-auth sessions for the `sub` (user ID) claim
|
|
18
|
+
* 5. Returns 200 on success, 400 for malformed tokens, 401 for bad signatures
|
|
19
|
+
*
|
|
20
|
+
* ## Mounting (Hono)
|
|
21
|
+
*
|
|
22
|
+
* ```typescript
|
|
23
|
+
* import { createBackchannelLogoutHandler } from '@soulcraft/sdk/server'
|
|
24
|
+
*
|
|
25
|
+
* app.post('/api/auth/backchannel-logout', createBackchannelLogoutHandler({
|
|
26
|
+
* auth,
|
|
27
|
+
* clientSecret: process.env.SOULCRAFT_OIDC_CLIENT_SECRET!,
|
|
28
|
+
* idpUrl: process.env.SOULCRAFT_IDP_URL!,
|
|
29
|
+
* clientId: process.env.SOULCRAFT_OIDC_CLIENT_ID!,
|
|
30
|
+
* }))
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
// The OIDC back-channel logout events claim URI.
|
|
34
|
+
const BACKCHANNEL_LOGOUT_EVENT = 'http://schemas.openid.net/event/backchannel-logout';
|
|
35
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
36
|
+
// JWT verification helpers (Web Crypto API — no external deps)
|
|
37
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
38
|
+
/**
|
|
39
|
+
* Verify an HS256 JWT using the Web Crypto API.
|
|
40
|
+
*
|
|
41
|
+
* @param token - Raw JWT string (`header.payload.signature`).
|
|
42
|
+
* @param secret - HMAC secret for signature verification.
|
|
43
|
+
* @returns The decoded payload if the signature is valid, or null.
|
|
44
|
+
*/
|
|
45
|
+
async function verifyHS256JWT(token, secret) {
|
|
46
|
+
const parts = token.split('.');
|
|
47
|
+
if (parts.length !== 3)
|
|
48
|
+
return null;
|
|
49
|
+
const [headerB64, payloadB64, sigB64] = parts;
|
|
50
|
+
// Import the HMAC key
|
|
51
|
+
let key;
|
|
52
|
+
try {
|
|
53
|
+
key = await crypto.subtle.importKey('raw', new TextEncoder().encode(secret), { name: 'HMAC', hash: 'SHA-256' }, false, ['verify']);
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
// Verify signature over `header.payload`
|
|
59
|
+
const signingInput = `${headerB64}.${payloadB64}`;
|
|
60
|
+
let sigBytes;
|
|
61
|
+
try {
|
|
62
|
+
sigBytes = Uint8Array.from(atob(sigB64.replace(/-/g, '+').replace(/_/g, '/')), (c) => c.charCodeAt(0));
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
const valid = await crypto.subtle.verify('HMAC', key, sigBytes.buffer, new TextEncoder().encode(signingInput));
|
|
68
|
+
if (!valid)
|
|
69
|
+
return null;
|
|
70
|
+
// Decode payload
|
|
71
|
+
try {
|
|
72
|
+
const padded = payloadB64.replace(/-/g, '+').replace(/_/g, '/') +
|
|
73
|
+
'=='.slice(0, (4 - (payloadB64.length % 4)) % 4);
|
|
74
|
+
return JSON.parse(atob(padded));
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
81
|
+
// createBackchannelLogoutHandler
|
|
82
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
83
|
+
/**
|
|
84
|
+
* @description Creates a Hono route handler for the OIDC back-channel logout endpoint.
|
|
85
|
+
*
|
|
86
|
+
* Mount at `POST /api/auth/backchannel-logout`. The handler:
|
|
87
|
+
* 1. Parses the `logout_token` from the form-encoded body
|
|
88
|
+
* 2. Verifies the HS256 JWT signature using the OIDC client secret
|
|
89
|
+
* 3. Validates `iss` (must match idpUrl), `aud` (must match clientId),
|
|
90
|
+
* and `events` (must contain the back-channel logout event URI)
|
|
91
|
+
* 4. Calls `auth.api.revokeUserSessions({ body: { userId: sub } })` to
|
|
92
|
+
* immediately invalidate all sessions for the identified user
|
|
93
|
+
* 5. Returns 200 on success, 400 for malformed/missing token, 401 for
|
|
94
|
+
* invalid signature or failed claims validation
|
|
95
|
+
*
|
|
96
|
+
* @param config - Auth instance, client secret, IdP URL, and client ID.
|
|
97
|
+
* @returns A Hono-compatible request handler function.
|
|
98
|
+
*
|
|
99
|
+
* @example
|
|
100
|
+
* ```typescript
|
|
101
|
+
* app.post('/api/auth/backchannel-logout', createBackchannelLogoutHandler({
|
|
102
|
+
* auth,
|
|
103
|
+
* clientSecret: process.env.SOULCRAFT_OIDC_CLIENT_SECRET!,
|
|
104
|
+
* idpUrl: process.env.SOULCRAFT_IDP_URL!,
|
|
105
|
+
* clientId: process.env.SOULCRAFT_OIDC_CLIENT_ID!,
|
|
106
|
+
* }))
|
|
107
|
+
* ```
|
|
108
|
+
*/
|
|
109
|
+
export function createBackchannelLogoutHandler(config) {
|
|
110
|
+
const idpOrigin = config.idpUrl.replace(/\/$/, '');
|
|
111
|
+
return async function backchannelLogoutHandler(c) {
|
|
112
|
+
// Parse the logout_token from the form-encoded body
|
|
113
|
+
let logoutToken = null;
|
|
114
|
+
try {
|
|
115
|
+
const contentType = c.req.header('content-type') ?? '';
|
|
116
|
+
if (contentType.includes('application/x-www-form-urlencoded')) {
|
|
117
|
+
const body = await c.req.parseBody();
|
|
118
|
+
logoutToken = body['logout_token'] ?? null;
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
// Also accept JSON body for easier testing
|
|
122
|
+
const body = await c.req.json();
|
|
123
|
+
logoutToken = body['logout_token'] ?? null;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
return c.json({ error: 'Failed to parse request body' }, 400);
|
|
128
|
+
}
|
|
129
|
+
if (!logoutToken || typeof logoutToken !== 'string') {
|
|
130
|
+
return c.json({ error: 'Missing logout_token' }, 400);
|
|
131
|
+
}
|
|
132
|
+
// Verify the JWT
|
|
133
|
+
const payload = await verifyHS256JWT(logoutToken, config.clientSecret);
|
|
134
|
+
if (!payload) {
|
|
135
|
+
return c.json({ error: 'Invalid logout_token signature' }, 401);
|
|
136
|
+
}
|
|
137
|
+
// Validate issuer
|
|
138
|
+
if (payload['iss'] !== idpOrigin) {
|
|
139
|
+
return c.json({ error: 'Invalid issuer' }, 401);
|
|
140
|
+
}
|
|
141
|
+
// Validate audience — may be a string or array of strings
|
|
142
|
+
const aud = payload['aud'];
|
|
143
|
+
const audList = Array.isArray(aud) ? aud : [String(aud ?? '')];
|
|
144
|
+
if (!audList.includes(config.clientId)) {
|
|
145
|
+
return c.json({ error: 'Invalid audience' }, 401);
|
|
146
|
+
}
|
|
147
|
+
// Validate events claim
|
|
148
|
+
const events = payload['events'];
|
|
149
|
+
if (!events || !(BACKCHANNEL_LOGOUT_EVENT in events)) {
|
|
150
|
+
return c.json({ error: 'Missing backchannel logout event' }, 400);
|
|
151
|
+
}
|
|
152
|
+
// Extract the subject user ID
|
|
153
|
+
const sub = payload['sub'];
|
|
154
|
+
if (!sub || typeof sub !== 'string') {
|
|
155
|
+
return c.json({ error: 'Missing sub claim' }, 400);
|
|
156
|
+
}
|
|
157
|
+
// Revoke all sessions for this user
|
|
158
|
+
try {
|
|
159
|
+
await config.auth.api.revokeUserSessions({ body: { userId: sub } });
|
|
160
|
+
}
|
|
161
|
+
catch (err) {
|
|
162
|
+
console.error(`[SDK/backchannel] Failed to revoke sessions for user ${sub}:`, err);
|
|
163
|
+
return c.json({ error: 'Failed to revoke sessions' }, 500);
|
|
164
|
+
}
|
|
165
|
+
return c.json({ ok: true }, 200);
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
//# sourceMappingURL=backchannel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"backchannel.js","sourceRoot":"","sources":["../../../src/modules/auth/backchannel.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module modules/auth/config
|
|
3
|
+
* @description Shared constants, utilities, and environment helpers for Soulcraft
|
|
4
|
+
* platform authentication.
|
|
5
|
+
*
|
|
6
|
+
* Provides ONLY well-typed shared values — no `betterAuth()` wrappers. Each product
|
|
7
|
+
* (Workshop, Venue, Academy) assembles its own fully-typed `betterAuth()` configuration
|
|
8
|
+
* using these constants and utilities, keeping TypeScript inference intact end-to-end.
|
|
9
|
+
*
|
|
10
|
+
* ## Why no config factory functions?
|
|
11
|
+
*
|
|
12
|
+
* A factory returning a broad object type loses compile-time safety when passed to
|
|
13
|
+
* `betterAuth()`. The correct boundary is:
|
|
14
|
+
* - **This module** → exports typed field definitions, session config, and pure utilities
|
|
15
|
+
* - **Each product** → imports those exports and constructs its own `betterAuth()` call
|
|
16
|
+
*
|
|
17
|
+
* This absorbs and replaces `@soulcraft/auth/config`, which is deprecated.
|
|
18
|
+
*
|
|
19
|
+
* @example Workshop auth setup
|
|
20
|
+
* ```typescript
|
|
21
|
+
* import { betterAuth } from 'better-auth'
|
|
22
|
+
* import {
|
|
23
|
+
* SOULCRAFT_USER_FIELDS,
|
|
24
|
+
* SOULCRAFT_SESSION_CONFIG,
|
|
25
|
+
* computeEmailHash,
|
|
26
|
+
* } from '@soulcraft/sdk/server'
|
|
27
|
+
*
|
|
28
|
+
* export const auth = betterAuth({
|
|
29
|
+
* database: new Database('./auth.db'),
|
|
30
|
+
* secret: process.env.BETTER_AUTH_SECRET!,
|
|
31
|
+
* session: SOULCRAFT_SESSION_CONFIG,
|
|
32
|
+
* user: { additionalFields: SOULCRAFT_USER_FIELDS },
|
|
33
|
+
* databaseHooks: {
|
|
34
|
+
* user: { create: { before: async (user) => ({
|
|
35
|
+
* data: { ...user, emailHash: computeEmailHash(user.email), platformRole: 'creator' }
|
|
36
|
+
* })}}
|
|
37
|
+
* },
|
|
38
|
+
* })
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
import type { AuthMode, OIDCClientConfig } from './types.js';
|
|
42
|
+
/**
|
|
43
|
+
* Additional fields to register on the better-auth `user` table.
|
|
44
|
+
*
|
|
45
|
+
* Pass to `betterAuth({ user: { additionalFields: SOULCRAFT_USER_FIELDS } })`.
|
|
46
|
+
*
|
|
47
|
+
* `emailHash` must be populated at user-creation time via a
|
|
48
|
+
* `databaseHooks.user.create.before` hook. `platformRole` defaults to `'creator'`
|
|
49
|
+
* for Workshop; products override this in their own hook.
|
|
50
|
+
*/
|
|
51
|
+
export declare const SOULCRAFT_USER_FIELDS: {
|
|
52
|
+
readonly platformRole: {
|
|
53
|
+
readonly type: "string";
|
|
54
|
+
readonly required: false;
|
|
55
|
+
readonly defaultValue: "creator";
|
|
56
|
+
};
|
|
57
|
+
readonly emailHash: {
|
|
58
|
+
readonly type: "string";
|
|
59
|
+
readonly required: false;
|
|
60
|
+
readonly defaultValue: "";
|
|
61
|
+
};
|
|
62
|
+
};
|
|
63
|
+
/**
|
|
64
|
+
* Session lifetime configuration shared across all Soulcraft products.
|
|
65
|
+
*
|
|
66
|
+
* Pass to `betterAuth({ session: SOULCRAFT_SESSION_CONFIG })`.
|
|
67
|
+
*
|
|
68
|
+
* - Sessions are valid for 30 days from issuance
|
|
69
|
+
* - Silently refreshed after 24 hours of activity, resetting the 30-day window
|
|
70
|
+
*/
|
|
71
|
+
export declare const SOULCRAFT_SESSION_CONFIG: {
|
|
72
|
+
readonly expiresIn: number;
|
|
73
|
+
readonly updateAge: number;
|
|
74
|
+
};
|
|
75
|
+
/**
|
|
76
|
+
* Compute the SHA-256 hex digest of a canonical email address.
|
|
77
|
+
*
|
|
78
|
+
* The email is lower-cased and trimmed before hashing to ensure the same
|
|
79
|
+
* input always yields the same digest regardless of capitalisation or whitespace.
|
|
80
|
+
*
|
|
81
|
+
* Stored as `emailHash` on the user record. Used by Workshop to deterministically
|
|
82
|
+
* locate the user's Brainy data directory without exposing the raw email in paths.
|
|
83
|
+
*
|
|
84
|
+
* @param email - Raw email address (any case, may have leading/trailing whitespace).
|
|
85
|
+
* @returns 64-character lowercase hex SHA-256 digest.
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* computeEmailHash('Alice@Example.COM') === computeEmailHash('alice@example.com') // true
|
|
89
|
+
* computeEmailHash('alice@example.com')
|
|
90
|
+
* // → 'b4c9a289522dd28a04617a41d7b14cf18d43d06febe513d9e27b5da67c17e52e'
|
|
91
|
+
*/
|
|
92
|
+
export declare function computeEmailHash(email: string): string;
|
|
93
|
+
/**
|
|
94
|
+
* Determine the authentication mode from environment variables.
|
|
95
|
+
*
|
|
96
|
+
* - `'standalone'` — each product runs its own better-auth instance with a local
|
|
97
|
+
* SQLite database. No cross-product SSO. Default before `auth.soulcraft.com` is live.
|
|
98
|
+
* - `'oidc-client'` — set `SOULCRAFT_IDP_URL` to activate. The product's better-auth
|
|
99
|
+
* instance delegates all authentication to the central IdP.
|
|
100
|
+
*
|
|
101
|
+
* @returns The current auth mode derived from `SOULCRAFT_IDP_URL`.
|
|
102
|
+
*/
|
|
103
|
+
export declare function getAuthMode(): AuthMode;
|
|
104
|
+
/**
|
|
105
|
+
* Read OIDC client configuration from environment variables.
|
|
106
|
+
*
|
|
107
|
+
* Returns `null` in standalone mode (when `SOULCRAFT_IDP_URL` is unset).
|
|
108
|
+
* Throws with a descriptive message if the URL is set but required variables
|
|
109
|
+
* are missing — prevents silent misconfiguration.
|
|
110
|
+
*
|
|
111
|
+
* | Variable | Required | Description |
|
|
112
|
+
* |------------------------------|----------|-----------------------------------------|
|
|
113
|
+
* | `SOULCRAFT_IDP_URL` | Yes | Central IdP base URL |
|
|
114
|
+
* | `SOULCRAFT_OIDC_CLIENT_ID` | Yes | This product's registered client ID |
|
|
115
|
+
* | `SOULCRAFT_OIDC_CLIENT_SECRET` | Yes | This product's registered client secret |
|
|
116
|
+
* | `SOULCRAFT_OIDC_REDIRECT_URI` | No | Deprecated — auto-derived from BETTER_AUTH_URL |
|
|
117
|
+
*
|
|
118
|
+
* @returns OIDC client config or null in standalone mode.
|
|
119
|
+
* @throws {Error} If `SOULCRAFT_IDP_URL` is set but client ID or secret are missing.
|
|
120
|
+
*/
|
|
121
|
+
export declare function getOIDCClientConfig(): OIDCClientConfig | null;
|
|
122
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../src/modules/auth/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AAGH,OAAO,KAAK,EAAE,QAAQ,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAM5D;;;;;;;;GAQG;AACH,eAAO,MAAM,qBAAqB;;;;;;;;;;;CAWxB,CAAA;AAMV;;;;;;;GAOG;AACH,eAAO,MAAM,wBAAwB;;;CAG3B,CAAA;AAMV;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAItD;AAMD;;;;;;;;;GASG;AACH,wBAAgB,WAAW,IAAI,QAAQ,CAEtC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,mBAAmB,IAAI,gBAAgB,GAAG,IAAI,CAuB7D"}
|