@tangle-network/agent-app 0.30.0 → 0.32.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/IntakeInterview-WHVKMNQW.js +8 -0
- package/dist/IntakeInterview-WHVKMNQW.js.map +1 -0
- package/dist/VaultPane-2BRLHKEB.js +7 -0
- package/dist/VaultPane-2BRLHKEB.js.map +1 -0
- package/dist/VaultPane-B8ipCqkB.d.ts +118 -0
- package/dist/chunk-4K7BZYO7.js +124 -0
- package/dist/chunk-4K7BZYO7.js.map +1 -0
- package/dist/chunk-5I72FRZY.js +212 -0
- package/dist/chunk-5I72FRZY.js.map +1 -0
- package/dist/{chunk-WOVCWPFF.js → chunk-FJUOBNIY.js} +1 -1
- package/dist/chunk-ND3XEGBE.js +119 -0
- package/dist/chunk-ND3XEGBE.js.map +1 -0
- package/dist/chunk-SMVD76VC.js +584 -0
- package/dist/chunk-SMVD76VC.js.map +1 -0
- package/dist/chunk-USYXHDKE.js +30 -0
- package/dist/chunk-USYXHDKE.js.map +1 -0
- package/dist/design-canvas-react/index.js +1 -1
- package/dist/design-canvas-react/lazy.js +1 -1
- package/dist/intakes/api.d.ts +59 -0
- package/dist/intakes/api.js +63 -0
- package/dist/intakes/api.js.map +1 -0
- package/dist/intakes/drizzle.d.ts +385 -0
- package/dist/intakes/drizzle.js +61 -0
- package/dist/intakes/drizzle.js.map +1 -0
- package/dist/intakes/index.d.ts +42 -0
- package/dist/intakes/index.js +31 -0
- package/dist/intakes/index.js.map +1 -0
- package/dist/intakes-react/index.d.ts +48 -0
- package/dist/intakes-react/index.js +8 -0
- package/dist/intakes-react/index.js.map +1 -0
- package/dist/intakes-react/lazy.d.ts +8 -0
- package/dist/intakes-react/lazy.js +9 -0
- package/dist/intakes-react/lazy.js.map +1 -0
- package/dist/model-Cuj7d-xT.d.ts +116 -0
- package/dist/vault/index.d.ts +22 -0
- package/dist/vault/index.js +9 -0
- package/dist/vault/index.js.map +1 -0
- package/dist/vault/lazy.d.ts +7 -0
- package/dist/vault/lazy.js +9 -0
- package/dist/vault/lazy.js.map +1 -0
- package/package.json +36 -1
- /package/dist/{chunk-WOVCWPFF.js.map → chunk-FJUOBNIY.js.map} +0 -0
|
@@ -0,0 +1,385 @@
|
|
|
1
|
+
import * as drizzle_orm_sqlite_core from 'drizzle-orm/sqlite-core';
|
|
2
|
+
import { AnySQLiteTable, AnySQLiteColumn, BaseSQLiteDatabase } from 'drizzle-orm/sqlite-core';
|
|
3
|
+
import { I as IntakeAnswerValue, b as IntakeGraph } from '../model-Cuj7d-xT.js';
|
|
4
|
+
import { IntakePayload } from './index.js';
|
|
5
|
+
|
|
6
|
+
/** A product table referenced by FK — only the `id` column is touched. */
|
|
7
|
+
type IntakeParentTable = AnySQLiteTable & {
|
|
8
|
+
id: AnySQLiteColumn;
|
|
9
|
+
};
|
|
10
|
+
interface CreateIntakeTablesOptions {
|
|
11
|
+
/** The product's user table — user-intake rows reference `userTable.id`. */
|
|
12
|
+
userTable: IntakeParentTable;
|
|
13
|
+
/**
|
|
14
|
+
* The product's workspace table — project-intake rows reference
|
|
15
|
+
* `workspaceTable.id`. OPTIONAL: omit it for a single-user / non-workspace
|
|
16
|
+
* app that wants per-user onboarding only. When omitted, no `projectIntake`
|
|
17
|
+
* table is created.
|
|
18
|
+
*/
|
|
19
|
+
workspaceTable?: IntakeParentTable;
|
|
20
|
+
}
|
|
21
|
+
declare function createUserIntakeTable(userTable: IntakeParentTable): drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
|
|
22
|
+
name: "user_intake";
|
|
23
|
+
schema: undefined;
|
|
24
|
+
columns: {
|
|
25
|
+
id: drizzle_orm_sqlite_core.SQLiteColumn<{
|
|
26
|
+
name: "id";
|
|
27
|
+
tableName: "user_intake";
|
|
28
|
+
dataType: "string";
|
|
29
|
+
columnType: "SQLiteText";
|
|
30
|
+
data: string;
|
|
31
|
+
driverParam: string;
|
|
32
|
+
notNull: true;
|
|
33
|
+
hasDefault: true;
|
|
34
|
+
isPrimaryKey: true;
|
|
35
|
+
isAutoincrement: false;
|
|
36
|
+
hasRuntimeDefault: false;
|
|
37
|
+
enumValues: [string, ...string[]];
|
|
38
|
+
baseColumn: never;
|
|
39
|
+
identity: undefined;
|
|
40
|
+
generated: undefined;
|
|
41
|
+
}, {}, {
|
|
42
|
+
length: number | undefined;
|
|
43
|
+
}>;
|
|
44
|
+
userId: drizzle_orm_sqlite_core.SQLiteColumn<{
|
|
45
|
+
name: "user_id";
|
|
46
|
+
tableName: "user_intake";
|
|
47
|
+
dataType: "string";
|
|
48
|
+
columnType: "SQLiteText";
|
|
49
|
+
data: string;
|
|
50
|
+
driverParam: string;
|
|
51
|
+
notNull: true;
|
|
52
|
+
hasDefault: false;
|
|
53
|
+
isPrimaryKey: false;
|
|
54
|
+
isAutoincrement: false;
|
|
55
|
+
hasRuntimeDefault: false;
|
|
56
|
+
enumValues: [string, ...string[]];
|
|
57
|
+
baseColumn: never;
|
|
58
|
+
identity: undefined;
|
|
59
|
+
generated: undefined;
|
|
60
|
+
}, {}, {
|
|
61
|
+
length: number | undefined;
|
|
62
|
+
}>;
|
|
63
|
+
graphId: drizzle_orm_sqlite_core.SQLiteColumn<{
|
|
64
|
+
name: "graph_id";
|
|
65
|
+
tableName: "user_intake";
|
|
66
|
+
dataType: "string";
|
|
67
|
+
columnType: "SQLiteText";
|
|
68
|
+
data: string;
|
|
69
|
+
driverParam: string;
|
|
70
|
+
notNull: true;
|
|
71
|
+
hasDefault: false;
|
|
72
|
+
isPrimaryKey: false;
|
|
73
|
+
isAutoincrement: false;
|
|
74
|
+
hasRuntimeDefault: false;
|
|
75
|
+
enumValues: [string, ...string[]];
|
|
76
|
+
baseColumn: never;
|
|
77
|
+
identity: undefined;
|
|
78
|
+
generated: undefined;
|
|
79
|
+
}, {}, {
|
|
80
|
+
length: number | undefined;
|
|
81
|
+
}>;
|
|
82
|
+
payload: drizzle_orm_sqlite_core.SQLiteColumn<{
|
|
83
|
+
name: "payload";
|
|
84
|
+
tableName: "user_intake";
|
|
85
|
+
dataType: "json";
|
|
86
|
+
columnType: "SQLiteTextJson";
|
|
87
|
+
data: unknown;
|
|
88
|
+
driverParam: string;
|
|
89
|
+
notNull: true;
|
|
90
|
+
hasDefault: false;
|
|
91
|
+
isPrimaryKey: false;
|
|
92
|
+
isAutoincrement: false;
|
|
93
|
+
hasRuntimeDefault: false;
|
|
94
|
+
enumValues: undefined;
|
|
95
|
+
baseColumn: never;
|
|
96
|
+
identity: undefined;
|
|
97
|
+
generated: undefined;
|
|
98
|
+
}, {}, {}>;
|
|
99
|
+
completedAt: drizzle_orm_sqlite_core.SQLiteColumn<{
|
|
100
|
+
name: "completed_at";
|
|
101
|
+
tableName: "user_intake";
|
|
102
|
+
dataType: "date";
|
|
103
|
+
columnType: "SQLiteTimestamp";
|
|
104
|
+
data: Date;
|
|
105
|
+
driverParam: number;
|
|
106
|
+
notNull: false;
|
|
107
|
+
hasDefault: false;
|
|
108
|
+
isPrimaryKey: false;
|
|
109
|
+
isAutoincrement: false;
|
|
110
|
+
hasRuntimeDefault: false;
|
|
111
|
+
enumValues: undefined;
|
|
112
|
+
baseColumn: never;
|
|
113
|
+
identity: undefined;
|
|
114
|
+
generated: undefined;
|
|
115
|
+
}, {}, {}>;
|
|
116
|
+
createdAt: drizzle_orm_sqlite_core.SQLiteColumn<{
|
|
117
|
+
name: "created_at";
|
|
118
|
+
tableName: "user_intake";
|
|
119
|
+
dataType: "date";
|
|
120
|
+
columnType: "SQLiteTimestamp";
|
|
121
|
+
data: Date;
|
|
122
|
+
driverParam: number;
|
|
123
|
+
notNull: true;
|
|
124
|
+
hasDefault: true;
|
|
125
|
+
isPrimaryKey: false;
|
|
126
|
+
isAutoincrement: false;
|
|
127
|
+
hasRuntimeDefault: false;
|
|
128
|
+
enumValues: undefined;
|
|
129
|
+
baseColumn: never;
|
|
130
|
+
identity: undefined;
|
|
131
|
+
generated: undefined;
|
|
132
|
+
}, {}, {}>;
|
|
133
|
+
updatedAt: drizzle_orm_sqlite_core.SQLiteColumn<{
|
|
134
|
+
name: "updated_at";
|
|
135
|
+
tableName: "user_intake";
|
|
136
|
+
dataType: "date";
|
|
137
|
+
columnType: "SQLiteTimestamp";
|
|
138
|
+
data: Date;
|
|
139
|
+
driverParam: number;
|
|
140
|
+
notNull: true;
|
|
141
|
+
hasDefault: true;
|
|
142
|
+
isPrimaryKey: false;
|
|
143
|
+
isAutoincrement: false;
|
|
144
|
+
hasRuntimeDefault: false;
|
|
145
|
+
enumValues: undefined;
|
|
146
|
+
baseColumn: never;
|
|
147
|
+
identity: undefined;
|
|
148
|
+
generated: undefined;
|
|
149
|
+
}, {}, {}>;
|
|
150
|
+
};
|
|
151
|
+
dialect: "sqlite";
|
|
152
|
+
}>;
|
|
153
|
+
declare function createProjectIntakeTable(workspaceTable: IntakeParentTable): drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
|
|
154
|
+
name: "project_intake";
|
|
155
|
+
schema: undefined;
|
|
156
|
+
columns: {
|
|
157
|
+
id: drizzle_orm_sqlite_core.SQLiteColumn<{
|
|
158
|
+
name: "id";
|
|
159
|
+
tableName: "project_intake";
|
|
160
|
+
dataType: "string";
|
|
161
|
+
columnType: "SQLiteText";
|
|
162
|
+
data: string;
|
|
163
|
+
driverParam: string;
|
|
164
|
+
notNull: true;
|
|
165
|
+
hasDefault: true;
|
|
166
|
+
isPrimaryKey: true;
|
|
167
|
+
isAutoincrement: false;
|
|
168
|
+
hasRuntimeDefault: false;
|
|
169
|
+
enumValues: [string, ...string[]];
|
|
170
|
+
baseColumn: never;
|
|
171
|
+
identity: undefined;
|
|
172
|
+
generated: undefined;
|
|
173
|
+
}, {}, {
|
|
174
|
+
length: number | undefined;
|
|
175
|
+
}>;
|
|
176
|
+
workspaceId: drizzle_orm_sqlite_core.SQLiteColumn<{
|
|
177
|
+
name: "workspace_id";
|
|
178
|
+
tableName: "project_intake";
|
|
179
|
+
dataType: "string";
|
|
180
|
+
columnType: "SQLiteText";
|
|
181
|
+
data: string;
|
|
182
|
+
driverParam: string;
|
|
183
|
+
notNull: true;
|
|
184
|
+
hasDefault: false;
|
|
185
|
+
isPrimaryKey: false;
|
|
186
|
+
isAutoincrement: false;
|
|
187
|
+
hasRuntimeDefault: false;
|
|
188
|
+
enumValues: [string, ...string[]];
|
|
189
|
+
baseColumn: never;
|
|
190
|
+
identity: undefined;
|
|
191
|
+
generated: undefined;
|
|
192
|
+
}, {}, {
|
|
193
|
+
length: number | undefined;
|
|
194
|
+
}>;
|
|
195
|
+
graphId: drizzle_orm_sqlite_core.SQLiteColumn<{
|
|
196
|
+
name: "graph_id";
|
|
197
|
+
tableName: "project_intake";
|
|
198
|
+
dataType: "string";
|
|
199
|
+
columnType: "SQLiteText";
|
|
200
|
+
data: string;
|
|
201
|
+
driverParam: string;
|
|
202
|
+
notNull: true;
|
|
203
|
+
hasDefault: false;
|
|
204
|
+
isPrimaryKey: false;
|
|
205
|
+
isAutoincrement: false;
|
|
206
|
+
hasRuntimeDefault: false;
|
|
207
|
+
enumValues: [string, ...string[]];
|
|
208
|
+
baseColumn: never;
|
|
209
|
+
identity: undefined;
|
|
210
|
+
generated: undefined;
|
|
211
|
+
}, {}, {
|
|
212
|
+
length: number | undefined;
|
|
213
|
+
}>;
|
|
214
|
+
payload: drizzle_orm_sqlite_core.SQLiteColumn<{
|
|
215
|
+
name: "payload";
|
|
216
|
+
tableName: "project_intake";
|
|
217
|
+
dataType: "json";
|
|
218
|
+
columnType: "SQLiteTextJson";
|
|
219
|
+
data: unknown;
|
|
220
|
+
driverParam: string;
|
|
221
|
+
notNull: true;
|
|
222
|
+
hasDefault: false;
|
|
223
|
+
isPrimaryKey: false;
|
|
224
|
+
isAutoincrement: false;
|
|
225
|
+
hasRuntimeDefault: false;
|
|
226
|
+
enumValues: undefined;
|
|
227
|
+
baseColumn: never;
|
|
228
|
+
identity: undefined;
|
|
229
|
+
generated: undefined;
|
|
230
|
+
}, {}, {}>;
|
|
231
|
+
completedAt: drizzle_orm_sqlite_core.SQLiteColumn<{
|
|
232
|
+
name: "completed_at";
|
|
233
|
+
tableName: "project_intake";
|
|
234
|
+
dataType: "date";
|
|
235
|
+
columnType: "SQLiteTimestamp";
|
|
236
|
+
data: Date;
|
|
237
|
+
driverParam: number;
|
|
238
|
+
notNull: false;
|
|
239
|
+
hasDefault: false;
|
|
240
|
+
isPrimaryKey: false;
|
|
241
|
+
isAutoincrement: false;
|
|
242
|
+
hasRuntimeDefault: false;
|
|
243
|
+
enumValues: undefined;
|
|
244
|
+
baseColumn: never;
|
|
245
|
+
identity: undefined;
|
|
246
|
+
generated: undefined;
|
|
247
|
+
}, {}, {}>;
|
|
248
|
+
createdAt: drizzle_orm_sqlite_core.SQLiteColumn<{
|
|
249
|
+
name: "created_at";
|
|
250
|
+
tableName: "project_intake";
|
|
251
|
+
dataType: "date";
|
|
252
|
+
columnType: "SQLiteTimestamp";
|
|
253
|
+
data: Date;
|
|
254
|
+
driverParam: number;
|
|
255
|
+
notNull: true;
|
|
256
|
+
hasDefault: true;
|
|
257
|
+
isPrimaryKey: false;
|
|
258
|
+
isAutoincrement: false;
|
|
259
|
+
hasRuntimeDefault: false;
|
|
260
|
+
enumValues: undefined;
|
|
261
|
+
baseColumn: never;
|
|
262
|
+
identity: undefined;
|
|
263
|
+
generated: undefined;
|
|
264
|
+
}, {}, {}>;
|
|
265
|
+
updatedAt: drizzle_orm_sqlite_core.SQLiteColumn<{
|
|
266
|
+
name: "updated_at";
|
|
267
|
+
tableName: "project_intake";
|
|
268
|
+
dataType: "date";
|
|
269
|
+
columnType: "SQLiteTimestamp";
|
|
270
|
+
data: Date;
|
|
271
|
+
driverParam: number;
|
|
272
|
+
notNull: true;
|
|
273
|
+
hasDefault: true;
|
|
274
|
+
isPrimaryKey: false;
|
|
275
|
+
isAutoincrement: false;
|
|
276
|
+
hasRuntimeDefault: false;
|
|
277
|
+
enumValues: undefined;
|
|
278
|
+
baseColumn: never;
|
|
279
|
+
identity: undefined;
|
|
280
|
+
generated: undefined;
|
|
281
|
+
}, {}, {}>;
|
|
282
|
+
};
|
|
283
|
+
dialect: "sqlite";
|
|
284
|
+
}>;
|
|
285
|
+
/**
|
|
286
|
+
* Build the intake tables wired to the product's tables. Always returns
|
|
287
|
+
* `userIntake`; returns `projectIntake` only when `workspaceTable` is passed.
|
|
288
|
+
* The return type carries `projectIntake?` so a consumer that passes no
|
|
289
|
+
* workspace table cannot reference a table that does not exist.
|
|
290
|
+
*/
|
|
291
|
+
declare function createIntakeTables<O extends CreateIntakeTablesOptions>(opts: O): IntakeTables<O>;
|
|
292
|
+
type UserIntakeTable = ReturnType<typeof createUserIntakeTable>;
|
|
293
|
+
type ProjectIntakeTable = ReturnType<typeof createProjectIntakeTable>;
|
|
294
|
+
/**
|
|
295
|
+
* The tables returned for a given options shape: `projectIntake` is present in
|
|
296
|
+
* the type exactly when `workspaceTable` was provided.
|
|
297
|
+
*/
|
|
298
|
+
type IntakeTables<O extends CreateIntakeTablesOptions> = O extends {
|
|
299
|
+
workspaceTable: IntakeParentTable;
|
|
300
|
+
} ? {
|
|
301
|
+
userIntake: UserIntakeTable;
|
|
302
|
+
projectIntake: ProjectIntakeTable;
|
|
303
|
+
} : {
|
|
304
|
+
userIntake: UserIntakeTable;
|
|
305
|
+
projectIntake?: ProjectIntakeTable;
|
|
306
|
+
};
|
|
307
|
+
/** The union table shape, for code that handles either scope generically. */
|
|
308
|
+
type AnyIntakeTables = {
|
|
309
|
+
userIntake: UserIntakeTable;
|
|
310
|
+
projectIntake?: ProjectIntakeTable;
|
|
311
|
+
};
|
|
312
|
+
type UserIntakeRow = UserIntakeTable['$inferSelect'];
|
|
313
|
+
type ProjectIntakeRow = ProjectIntakeTable['$inferSelect'];
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* Drizzle-backed store over the tables from `createIntakeTables`. One store
|
|
317
|
+
* builder per scope: `createUserIntakeStore` (keyed on userId) and
|
|
318
|
+
* `createProjectIntakeStore` (keyed on workspaceId). Each returns the same
|
|
319
|
+
* three-method surface — `get` / `save` / `complete` — so the api handlers and
|
|
320
|
+
* the UI talk to one shape regardless of scope.
|
|
321
|
+
*
|
|
322
|
+
* Works against any SQLite drizzle driver (better-sqlite3, D1, libsql): the
|
|
323
|
+
* builders are awaited, never `.run()`/`.all()`, so sync and async drivers
|
|
324
|
+
* behave identically.
|
|
325
|
+
*
|
|
326
|
+
* Validation is fail-loud and pure (from the `./intakes` leaf). `save` runs
|
|
327
|
+
* `validateAnswer` before writing, so an invalid answer can never enter the
|
|
328
|
+
* payload; `complete` runs `payloadComplete` and refuses to stamp an
|
|
329
|
+
* incomplete (or stale-graph) intake — it throws a typed `IntakeError` rather
|
|
330
|
+
* than silently writing a half-finished onboarding state.
|
|
331
|
+
*
|
|
332
|
+
* `getProjectIntakeStore` pins `workspaceId` in every WHERE clause; RBAC runs
|
|
333
|
+
* in the route before the store is built, but the scope key is enforced here
|
|
334
|
+
* too, so a leaked id can never read or write across the boundary.
|
|
335
|
+
*
|
|
336
|
+
* Imports `drizzle-orm`, so this is a subpath, never re-exported from root.
|
|
337
|
+
*/
|
|
338
|
+
|
|
339
|
+
/** Any SQLite drizzle database — `any` erases driver-specific generics so
|
|
340
|
+
* better-sqlite3, D1, and libsql handles all fit. */
|
|
341
|
+
type IntakeDatabase = BaseSQLiteDatabase<'sync' | 'async', any, any>;
|
|
342
|
+
/** A loaded intake: the payload plus whether it is complete against the graph. */
|
|
343
|
+
interface IntakeState {
|
|
344
|
+
payload: IntakePayload;
|
|
345
|
+
completed: boolean;
|
|
346
|
+
completedAt: Date | null;
|
|
347
|
+
}
|
|
348
|
+
type IntakeErrorCode = 'invalid-answer' | 'unknown-question' | 'incomplete' | 'stale-graph';
|
|
349
|
+
/** Thrown by store mutations on a refused write — callers map it to a 4xx. */
|
|
350
|
+
declare class IntakeError extends Error {
|
|
351
|
+
readonly code: IntakeErrorCode;
|
|
352
|
+
constructor(code: IntakeErrorCode, message: string);
|
|
353
|
+
}
|
|
354
|
+
/** The three-method store surface, identical for both scopes. */
|
|
355
|
+
interface IntakeStore {
|
|
356
|
+
/** Load the current intake, or seed an empty payload when none exists yet. */
|
|
357
|
+
get(): Promise<IntakeState>;
|
|
358
|
+
/** Validate and persist one answer; returns the updated state. */
|
|
359
|
+
save(questionId: string, value: IntakeAnswerValue): Promise<IntakeState>;
|
|
360
|
+
/** Stamp the intake complete; throws IntakeError when not yet completable. */
|
|
361
|
+
complete(): Promise<IntakeState>;
|
|
362
|
+
}
|
|
363
|
+
interface CreateUserIntakeStoreOptions {
|
|
364
|
+
db: IntakeDatabase;
|
|
365
|
+
/** The user-intake table from createIntakeTables. */
|
|
366
|
+
table: UserIntakeTable;
|
|
367
|
+
/** The intake definition this store collects answers against. */
|
|
368
|
+
graph: IntakeGraph;
|
|
369
|
+
/** The user whose onboarding this is. */
|
|
370
|
+
userId: string;
|
|
371
|
+
}
|
|
372
|
+
/** Build the per-user onboarding store, scoped to one userId. */
|
|
373
|
+
declare function createUserIntakeStore(opts: CreateUserIntakeStoreOptions): IntakeStore;
|
|
374
|
+
interface CreateProjectIntakeStoreOptions {
|
|
375
|
+
db: IntakeDatabase;
|
|
376
|
+
/** The project-intake table from createIntakeTables (workspace scope). */
|
|
377
|
+
table: ProjectIntakeTable;
|
|
378
|
+
graph: IntakeGraph;
|
|
379
|
+
/** The workspace this intake is attached to. */
|
|
380
|
+
workspaceId: string;
|
|
381
|
+
}
|
|
382
|
+
/** Build the per-project store, scoped to one workspaceId. */
|
|
383
|
+
declare function createProjectIntakeStore(opts: CreateProjectIntakeStoreOptions): IntakeStore;
|
|
384
|
+
|
|
385
|
+
export { type AnyIntakeTables, type CreateIntakeTablesOptions, type CreateProjectIntakeStoreOptions, type CreateUserIntakeStoreOptions, type IntakeDatabase, IntakeError, type IntakeErrorCode, type IntakeParentTable, type IntakeState, type IntakeStore, type IntakeTables, type ProjectIntakeRow, type ProjectIntakeTable, type UserIntakeRow, type UserIntakeTable, createIntakeTables, createProjectIntakeStore, createUserIntakeStore };
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import {
|
|
2
|
+
IntakeError,
|
|
3
|
+
createProjectIntakeStore,
|
|
4
|
+
createUserIntakeStore
|
|
5
|
+
} from "../chunk-4K7BZYO7.js";
|
|
6
|
+
import "../chunk-USYXHDKE.js";
|
|
7
|
+
import "../chunk-ND3XEGBE.js";
|
|
8
|
+
|
|
9
|
+
// src/intakes/drizzle/schema.ts
|
|
10
|
+
import { sql } from "drizzle-orm";
|
|
11
|
+
import { index, integer, sqliteTable, text, uniqueIndex } from "drizzle-orm/sqlite-core";
|
|
12
|
+
var hexId = () => text("id").primaryKey().default(sql`(lower(hex(randomblob(16))))`);
|
|
13
|
+
var createdAt = () => integer("created_at", { mode: "timestamp" }).notNull().default(sql`(unixepoch())`);
|
|
14
|
+
var updatedAt = () => integer("updated_at", { mode: "timestamp" }).notNull().default(sql`(unixepoch())`);
|
|
15
|
+
function createUserIntakeTable(userTable) {
|
|
16
|
+
return sqliteTable("user_intake", {
|
|
17
|
+
id: hexId(),
|
|
18
|
+
userId: text("user_id").notNull().references(() => userTable.id, { onDelete: "cascade" }),
|
|
19
|
+
/** The intake definition id the payload was collected against. */
|
|
20
|
+
graphId: text("graph_id").notNull(),
|
|
21
|
+
/** The IntakePayload JSON blob. */
|
|
22
|
+
payload: text("payload", { mode: "json" }).notNull(),
|
|
23
|
+
/** Set when the user finishes the onboarding interview; null while open. */
|
|
24
|
+
completedAt: integer("completed_at", { mode: "timestamp" }),
|
|
25
|
+
createdAt: createdAt(),
|
|
26
|
+
updatedAt: updatedAt()
|
|
27
|
+
}, (table) => [
|
|
28
|
+
uniqueIndex("uniq_user_intake_user").on(table.userId)
|
|
29
|
+
]);
|
|
30
|
+
}
|
|
31
|
+
function createProjectIntakeTable(workspaceTable) {
|
|
32
|
+
return sqliteTable("project_intake", {
|
|
33
|
+
id: hexId(),
|
|
34
|
+
workspaceId: text("workspace_id").notNull().references(() => workspaceTable.id, { onDelete: "cascade" }),
|
|
35
|
+
graphId: text("graph_id").notNull(),
|
|
36
|
+
payload: text("payload", { mode: "json" }).notNull(),
|
|
37
|
+
completedAt: integer("completed_at", { mode: "timestamp" }),
|
|
38
|
+
createdAt: createdAt(),
|
|
39
|
+
updatedAt: updatedAt()
|
|
40
|
+
}, (table) => [
|
|
41
|
+
uniqueIndex("uniq_project_intake_workspace").on(table.workspaceId),
|
|
42
|
+
index("idx_project_intake_graph").on(table.graphId)
|
|
43
|
+
]);
|
|
44
|
+
}
|
|
45
|
+
function createIntakeTables(opts) {
|
|
46
|
+
const userIntake = createUserIntakeTable(opts.userTable);
|
|
47
|
+
const result = {
|
|
48
|
+
userIntake
|
|
49
|
+
};
|
|
50
|
+
if (opts.workspaceTable) {
|
|
51
|
+
result.projectIntake = createProjectIntakeTable(opts.workspaceTable);
|
|
52
|
+
}
|
|
53
|
+
return result;
|
|
54
|
+
}
|
|
55
|
+
export {
|
|
56
|
+
IntakeError,
|
|
57
|
+
createIntakeTables,
|
|
58
|
+
createProjectIntakeStore,
|
|
59
|
+
createUserIntakeStore
|
|
60
|
+
};
|
|
61
|
+
//# sourceMappingURL=drizzle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/intakes/drizzle/schema.ts"],"sourcesContent":["/**\n * Drizzle schema factory for the intake tables. The product owns the user (and\n * optionally workspace) tables; this factory creates the intake tables and\n * wires their foreign keys into the passed-in tables so the whole graph lives\n * in one drizzle schema with real cascade semantics.\n *\n * Two tables, two scopes:\n * - `user_intake` — the one-time onboarding interview, keyed on `user.id`\n * (UNIQUE per user: one onboarding payload per user). ALWAYS created.\n * - `project_intake` — the structured intake attached to a workspace, keyed\n * on `workspace.id` (UNIQUE per workspace). Created ONLY when a\n * `workspaceTable` is passed.\n *\n * `workspaceTable` is OPTIONAL by design: a non-workspace app (a single-user\n * tool, tax-without-workspaces) adopts per-user onboarding alone with zero\n * teams and zero workspace concept. When omitted, `createIntakeTables` returns\n * `{ userIntake }` and no `projectIntake` — the FK to a workspace table that\n * does not exist is never created.\n *\n * Imports `drizzle-orm` at module top — that is WHY this lives behind the\n * `/intakes/drizzle` sub-subpath. The pure `./intakes` leaf imports none of\n * this, so a consumer that never touches the DB never pulls the optional peer.\n */\n\nimport { sql } from 'drizzle-orm'\nimport { index, integer, sqliteTable, text, uniqueIndex } from 'drizzle-orm/sqlite-core'\nimport type { AnySQLiteColumn, AnySQLiteTable } from 'drizzle-orm/sqlite-core'\n\n/** A product table referenced by FK — only the `id` column is touched. */\nexport type IntakeParentTable = AnySQLiteTable & { id: AnySQLiteColumn }\n\nexport interface CreateIntakeTablesOptions {\n /** The product's user table — user-intake rows reference `userTable.id`. */\n userTable: IntakeParentTable\n /**\n * The product's workspace table — project-intake rows reference\n * `workspaceTable.id`. OPTIONAL: omit it for a single-user / non-workspace\n * app that wants per-user onboarding only. When omitted, no `projectIntake`\n * table is created.\n */\n workspaceTable?: IntakeParentTable\n}\n\nconst hexId = () => text('id').primaryKey().default(sql`(lower(hex(randomblob(16))))`)\n\nconst createdAt = () => integer('created_at', { mode: 'timestamp' }).notNull().default(sql`(unixepoch())`)\n\nconst updatedAt = () => integer('updated_at', { mode: 'timestamp' }).notNull().default(sql`(unixepoch())`)\n\nfunction createUserIntakeTable(userTable: IntakeParentTable) {\n return sqliteTable('user_intake', {\n id: hexId(),\n userId: text('user_id').notNull().references(() => userTable.id, { onDelete: 'cascade' }),\n /** The intake definition id the payload was collected against. */\n graphId: text('graph_id').notNull(),\n /** The IntakePayload JSON blob. */\n payload: text('payload', { mode: 'json' }).notNull(),\n /** Set when the user finishes the onboarding interview; null while open. */\n completedAt: integer('completed_at', { mode: 'timestamp' }),\n createdAt: createdAt(),\n updatedAt: updatedAt(),\n }, (table) => [\n uniqueIndex('uniq_user_intake_user').on(table.userId),\n ])\n}\n\nfunction createProjectIntakeTable(workspaceTable: IntakeParentTable) {\n return sqliteTable('project_intake', {\n id: hexId(),\n workspaceId: text('workspace_id').notNull().references(() => workspaceTable.id, { onDelete: 'cascade' }),\n graphId: text('graph_id').notNull(),\n payload: text('payload', { mode: 'json' }).notNull(),\n completedAt: integer('completed_at', { mode: 'timestamp' }),\n createdAt: createdAt(),\n updatedAt: updatedAt(),\n }, (table) => [\n uniqueIndex('uniq_project_intake_workspace').on(table.workspaceId),\n index('idx_project_intake_graph').on(table.graphId),\n ])\n}\n\n/**\n * Build the intake tables wired to the product's tables. Always returns\n * `userIntake`; returns `projectIntake` only when `workspaceTable` is passed.\n * The return type carries `projectIntake?` so a consumer that passes no\n * workspace table cannot reference a table that does not exist.\n */\nexport function createIntakeTables<O extends CreateIntakeTablesOptions>(\n opts: O,\n): IntakeTables<O> {\n const userIntake = createUserIntakeTable(opts.userTable)\n const result: { userIntake: ReturnType<typeof createUserIntakeTable>; projectIntake?: ReturnType<typeof createProjectIntakeTable> } = {\n userIntake,\n }\n if (opts.workspaceTable) {\n result.projectIntake = createProjectIntakeTable(opts.workspaceTable)\n }\n return result as IntakeTables<O>\n}\n\nexport type UserIntakeTable = ReturnType<typeof createUserIntakeTable>\nexport type ProjectIntakeTable = ReturnType<typeof createProjectIntakeTable>\n\n/**\n * The tables returned for a given options shape: `projectIntake` is present in\n * the type exactly when `workspaceTable` was provided.\n */\nexport type IntakeTables<O extends CreateIntakeTablesOptions> =\n O extends { workspaceTable: IntakeParentTable }\n ? { userIntake: UserIntakeTable; projectIntake: ProjectIntakeTable }\n : { userIntake: UserIntakeTable; projectIntake?: ProjectIntakeTable }\n\n/** The union table shape, for code that handles either scope generically. */\nexport type AnyIntakeTables = { userIntake: UserIntakeTable; projectIntake?: ProjectIntakeTable }\n\nexport type UserIntakeRow = UserIntakeTable['$inferSelect']\nexport type ProjectIntakeRow = ProjectIntakeTable['$inferSelect']\n"],"mappings":";;;;;;;;;AAwBA,SAAS,WAAW;AACpB,SAAS,OAAO,SAAS,aAAa,MAAM,mBAAmB;AAkB/D,IAAM,QAAQ,MAAM,KAAK,IAAI,EAAE,WAAW,EAAE,QAAQ,iCAAiC;AAErF,IAAM,YAAY,MAAM,QAAQ,cAAc,EAAE,MAAM,YAAY,CAAC,EAAE,QAAQ,EAAE,QAAQ,kBAAkB;AAEzG,IAAM,YAAY,MAAM,QAAQ,cAAc,EAAE,MAAM,YAAY,CAAC,EAAE,QAAQ,EAAE,QAAQ,kBAAkB;AAEzG,SAAS,sBAAsB,WAA8B;AAC3D,SAAO,YAAY,eAAe;AAAA,IAChC,IAAI,MAAM;AAAA,IACV,QAAQ,KAAK,SAAS,EAAE,QAAQ,EAAE,WAAW,MAAM,UAAU,IAAI,EAAE,UAAU,UAAU,CAAC;AAAA;AAAA,IAExF,SAAS,KAAK,UAAU,EAAE,QAAQ;AAAA;AAAA,IAElC,SAAS,KAAK,WAAW,EAAE,MAAM,OAAO,CAAC,EAAE,QAAQ;AAAA;AAAA,IAEnD,aAAa,QAAQ,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAAA,IAC1D,WAAW,UAAU;AAAA,IACrB,WAAW,UAAU;AAAA,EACvB,GAAG,CAAC,UAAU;AAAA,IACZ,YAAY,uBAAuB,EAAE,GAAG,MAAM,MAAM;AAAA,EACtD,CAAC;AACH;AAEA,SAAS,yBAAyB,gBAAmC;AACnE,SAAO,YAAY,kBAAkB;AAAA,IACnC,IAAI,MAAM;AAAA,IACV,aAAa,KAAK,cAAc,EAAE,QAAQ,EAAE,WAAW,MAAM,eAAe,IAAI,EAAE,UAAU,UAAU,CAAC;AAAA,IACvG,SAAS,KAAK,UAAU,EAAE,QAAQ;AAAA,IAClC,SAAS,KAAK,WAAW,EAAE,MAAM,OAAO,CAAC,EAAE,QAAQ;AAAA,IACnD,aAAa,QAAQ,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAAA,IAC1D,WAAW,UAAU;AAAA,IACrB,WAAW,UAAU;AAAA,EACvB,GAAG,CAAC,UAAU;AAAA,IACZ,YAAY,+BAA+B,EAAE,GAAG,MAAM,WAAW;AAAA,IACjE,MAAM,0BAA0B,EAAE,GAAG,MAAM,OAAO;AAAA,EACpD,CAAC;AACH;AAQO,SAAS,mBACd,MACiB;AACjB,QAAM,aAAa,sBAAsB,KAAK,SAAS;AACvD,QAAM,SAAgI;AAAA,IACpI;AAAA,EACF;AACA,MAAI,KAAK,gBAAgB;AACvB,WAAO,gBAAgB,yBAAyB,KAAK,cAAc;AAAA,EACrE;AACA,SAAO;AACT;","names":[]}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { c as IntakeAnswers, b as IntakeGraph, I as IntakeAnswerValue } from '../model-Cuj7d-xT.js';
|
|
2
|
+
export { A as AnswerRejectionReason, d as AnswerValidationResult, e as IntakeAnswerType, f as IntakeOption, a as IntakeQuestion, g as getQuestion, h as hasAnswer, i as intakeProgress, j as isComplete, n as nextQuestion, r as reachableQuestions, v as validateAnswer } from '../model-Cuj7d-xT.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Pure completion-state helpers for an intake payload — the small algebra over
|
|
6
|
+
* the JSON blob the store persists. No I/O: the store reads/writes the row;
|
|
7
|
+
* these functions only build and judge the payload shape, so the same logic
|
|
8
|
+
* runs in the UI, the handlers, and the DB layer without divergence.
|
|
9
|
+
*
|
|
10
|
+
* A payload is `{ graphId, answers, completedAt? }`. It carries the answers
|
|
11
|
+
* and the id of the graph they were collected against, so a later graph
|
|
12
|
+
* revision can detect a stale payload (`graphId` mismatch) rather than
|
|
13
|
+
* silently mixing answers from two question sets.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/** The persisted JSON for one intake (the `payload` column). */
|
|
17
|
+
interface IntakePayload {
|
|
18
|
+
/** The graph id the answers were collected against — guards stale schemas. */
|
|
19
|
+
graphId: string;
|
|
20
|
+
answers: IntakeAnswers;
|
|
21
|
+
/** ISO-8601 instant the intake was completed, or undefined while in progress. */
|
|
22
|
+
completedAt?: string;
|
|
23
|
+
}
|
|
24
|
+
/** An empty payload for a fresh intake against `graph`. */
|
|
25
|
+
declare function emptyPayload(graph: IntakeGraph): IntakePayload;
|
|
26
|
+
/** A copy of `payload` with one answer set (does not mutate the input). */
|
|
27
|
+
declare function withAnswer(payload: IntakePayload, questionId: string, value: IntakeAnswerValue): IntakePayload;
|
|
28
|
+
/**
|
|
29
|
+
* True when the payload's answers complete the graph AND the payload was
|
|
30
|
+
* collected against THIS graph. A `graphId` mismatch is never "complete" —
|
|
31
|
+
* the answers belong to a different question set and must be re-collected.
|
|
32
|
+
*/
|
|
33
|
+
declare function payloadComplete(graph: IntakeGraph, payload: IntakePayload): boolean;
|
|
34
|
+
/** True when the payload was collected against a DIFFERENT graph revision. */
|
|
35
|
+
declare function payloadIsStale(graph: IntakeGraph, payload: IntakePayload): boolean;
|
|
36
|
+
/**
|
|
37
|
+
* Stamp the payload complete at `at` (default now). Returns a copy; pure. The
|
|
38
|
+
* caller has already checked `payloadComplete` — this only records the instant.
|
|
39
|
+
*/
|
|
40
|
+
declare function markComplete(payload: IntakePayload, at?: Date): IntakePayload;
|
|
41
|
+
|
|
42
|
+
export { IntakeAnswerValue, IntakeAnswers, IntakeGraph, type IntakePayload, emptyPayload, markComplete, payloadComplete, payloadIsStale, withAnswer };
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import {
|
|
2
|
+
emptyPayload,
|
|
3
|
+
markComplete,
|
|
4
|
+
payloadComplete,
|
|
5
|
+
payloadIsStale,
|
|
6
|
+
withAnswer
|
|
7
|
+
} from "../chunk-USYXHDKE.js";
|
|
8
|
+
import {
|
|
9
|
+
getQuestion,
|
|
10
|
+
hasAnswer,
|
|
11
|
+
intakeProgress,
|
|
12
|
+
isComplete,
|
|
13
|
+
nextQuestion,
|
|
14
|
+
reachableQuestions,
|
|
15
|
+
validateAnswer
|
|
16
|
+
} from "../chunk-ND3XEGBE.js";
|
|
17
|
+
export {
|
|
18
|
+
emptyPayload,
|
|
19
|
+
getQuestion,
|
|
20
|
+
hasAnswer,
|
|
21
|
+
intakeProgress,
|
|
22
|
+
isComplete,
|
|
23
|
+
markComplete,
|
|
24
|
+
nextQuestion,
|
|
25
|
+
payloadComplete,
|
|
26
|
+
payloadIsStale,
|
|
27
|
+
reachableQuestions,
|
|
28
|
+
validateAnswer,
|
|
29
|
+
withAnswer
|
|
30
|
+
};
|
|
31
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { I as IntakeAnswerValue, a as IntakeQuestion } from '../model-Cuj7d-xT.js';
|
|
2
|
+
import * as react from 'react';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Seams between the intakes React surface and the host app. Everything here is
|
|
6
|
+
* interface-only and callback-driven: the components never import an app's
|
|
7
|
+
* router, fetch client, or toast system. The host passes the loaded view in and
|
|
8
|
+
* supplies the async callbacks (which it backs with `./intakes/api` over fetch),
|
|
9
|
+
* so the same interview mounts in any app and for either scope (user / project).
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/** The state the interview renders — the shape `./intakes/api` returns. */
|
|
13
|
+
interface IntakeView {
|
|
14
|
+
title: string;
|
|
15
|
+
description?: string;
|
|
16
|
+
answers: Record<string, IntakeAnswerValue>;
|
|
17
|
+
/** The next question to ask, or null when the interview is done. */
|
|
18
|
+
nextQuestion: IntakeQuestion | null;
|
|
19
|
+
completed: boolean;
|
|
20
|
+
progress: {
|
|
21
|
+
answered: number;
|
|
22
|
+
total: number;
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
interface IntakeInterviewProps {
|
|
26
|
+
view: IntakeView;
|
|
27
|
+
/**
|
|
28
|
+
* Persist one answer; resolve with the next view (the server re-derives the
|
|
29
|
+
* next question + progress). The component re-renders from the returned view.
|
|
30
|
+
*/
|
|
31
|
+
onAnswer(input: {
|
|
32
|
+
questionId: string;
|
|
33
|
+
value: IntakeAnswerValue;
|
|
34
|
+
}): Promise<IntakeView>;
|
|
35
|
+
/** Finish the interview; resolve with the final view. */
|
|
36
|
+
onComplete(): Promise<IntakeView>;
|
|
37
|
+
/** Called once when the interview is done (completed view), for navigation. */
|
|
38
|
+
onDone?(): void;
|
|
39
|
+
/** Optional toast/notice hook; defaults to a no-op (host owns its UX). */
|
|
40
|
+
onNotice?(notice: {
|
|
41
|
+
kind: 'success' | 'error';
|
|
42
|
+
message: string;
|
|
43
|
+
}): void;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
declare function IntakeInterview({ view: initialView, onAnswer, onComplete, onDone, onNotice, }: IntakeInterviewProps): react.JSX.Element;
|
|
47
|
+
|
|
48
|
+
export { IntakeInterview, type IntakeInterviewProps, type IntakeView };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { IntakeInterview } from './index.js';
|
|
3
|
+
export { IntakeInterviewProps } from './index.js';
|
|
4
|
+
import '../model-Cuj7d-xT.js';
|
|
5
|
+
|
|
6
|
+
declare const IntakeInterviewLazy: react.LazyExoticComponent<typeof IntakeInterview>;
|
|
7
|
+
|
|
8
|
+
export { IntakeInterviewLazy };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
// src/intakes-react/lazy.tsx
|
|
2
|
+
import { lazy } from "react";
|
|
3
|
+
var IntakeInterviewLazy = lazy(
|
|
4
|
+
() => import("../IntakeInterview-WHVKMNQW.js").then((m) => ({ default: m.IntakeInterview }))
|
|
5
|
+
);
|
|
6
|
+
export {
|
|
7
|
+
IntakeInterviewLazy
|
|
8
|
+
};
|
|
9
|
+
//# sourceMappingURL=lazy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/intakes-react/lazy.tsx"],"sourcesContent":["/**\n * Code-split entry for the intakes React surface. Products that don't need the\n * interview UI on initial load import this `React.lazy` handle instead of the\n * component directly, so the interview chunk loads on first render. Mount inside\n * a `<Suspense>` boundary; the product provides the fallback.\n */\n\nimport { lazy } from 'react'\nimport type { IntakeInterviewProps } from './contracts'\n\nexport type { IntakeInterviewProps }\n\nexport const IntakeInterviewLazy = lazy(\n () => import('./components/IntakeInterview').then((m) => ({ default: m.IntakeInterview })),\n)\n"],"mappings":";AAOA,SAAS,YAAY;AAKd,IAAM,sBAAsB;AAAA,EACjC,MAAM,OAAO,gCAA8B,EAAE,KAAK,CAAC,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE;AAC3F;","names":[]}
|