@aigne/afs-sqlite 1.11.0-beta.1 → 1.11.0-beta.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. package/README.md +3 -3
  2. package/dist/_virtual/_@oxc-project_runtime@0.108.0/helpers/decorate.cjs +11 -0
  3. package/dist/_virtual/_@oxc-project_runtime@0.108.0/helpers/decorate.mjs +10 -0
  4. package/dist/_virtual/rolldown_runtime.mjs +7 -0
  5. package/dist/actions/built-in.cjs +1262 -15
  6. package/dist/actions/built-in.d.cts.map +1 -1
  7. package/dist/actions/built-in.d.mts.map +1 -1
  8. package/dist/actions/built-in.mjs +1262 -15
  9. package/dist/actions/built-in.mjs.map +1 -1
  10. package/dist/actions/operators.cjs +156 -0
  11. package/dist/actions/operators.mjs +157 -0
  12. package/dist/actions/operators.mjs.map +1 -0
  13. package/dist/actions/registry.cjs +35 -3
  14. package/dist/actions/registry.d.cts +36 -17
  15. package/dist/actions/registry.d.cts.map +1 -1
  16. package/dist/actions/registry.d.mts +36 -17
  17. package/dist/actions/registry.d.mts.map +1 -1
  18. package/dist/actions/registry.mjs +35 -3
  19. package/dist/actions/registry.mjs.map +1 -1
  20. package/dist/actions/types.cjs +33 -0
  21. package/dist/actions/types.d.cts +46 -5
  22. package/dist/actions/types.d.cts.map +1 -1
  23. package/dist/actions/types.d.mts +46 -5
  24. package/dist/actions/types.d.mts.map +1 -1
  25. package/dist/actions/types.mjs +32 -0
  26. package/dist/actions/types.mjs.map +1 -0
  27. package/dist/config.cjs +1 -1
  28. package/dist/config.d.cts +9 -36
  29. package/dist/config.d.cts.map +1 -1
  30. package/dist/config.d.mts +9 -36
  31. package/dist/config.d.mts.map +1 -1
  32. package/dist/config.mjs +1 -1
  33. package/dist/config.mjs.map +1 -1
  34. package/dist/index.cjs +4 -3
  35. package/dist/index.d.cts +4 -3
  36. package/dist/index.d.mts +4 -3
  37. package/dist/index.mjs +3 -2
  38. package/dist/node/builder.cjs +74 -91
  39. package/dist/node/builder.d.cts +11 -15
  40. package/dist/node/builder.d.cts.map +1 -1
  41. package/dist/node/builder.d.mts +11 -15
  42. package/dist/node/builder.d.mts.map +1 -1
  43. package/dist/node/builder.mjs +72 -89
  44. package/dist/node/builder.mjs.map +1 -1
  45. package/dist/operations/crud.cjs +24 -68
  46. package/dist/operations/crud.d.cts +23 -38
  47. package/dist/operations/crud.d.cts.map +1 -1
  48. package/dist/operations/crud.d.mts +23 -38
  49. package/dist/operations/crud.d.mts.map +1 -1
  50. package/dist/operations/crud.mjs +25 -69
  51. package/dist/operations/crud.mjs.map +1 -1
  52. package/dist/operations/query-builder.cjs +2 -2
  53. package/dist/operations/query-builder.d.cts.map +1 -1
  54. package/dist/operations/query-builder.d.mts.map +1 -1
  55. package/dist/operations/query-builder.mjs +2 -2
  56. package/dist/operations/query-builder.mjs.map +1 -1
  57. package/dist/operations/search.cjs +5 -11
  58. package/dist/operations/search.d.cts +19 -23
  59. package/dist/operations/search.d.cts.map +1 -1
  60. package/dist/operations/search.d.mts +19 -23
  61. package/dist/operations/search.d.mts.map +1 -1
  62. package/dist/operations/search.mjs +5 -11
  63. package/dist/operations/search.mjs.map +1 -1
  64. package/dist/router/path-router.cjs +7 -15
  65. package/dist/router/path-router.d.cts +4 -7
  66. package/dist/router/path-router.d.cts.map +1 -1
  67. package/dist/router/path-router.d.mts +4 -7
  68. package/dist/router/path-router.d.mts.map +1 -1
  69. package/dist/router/path-router.mjs +7 -15
  70. package/dist/router/path-router.mjs.map +1 -1
  71. package/dist/router/types.d.cts.map +1 -1
  72. package/dist/router/types.d.mts.map +1 -1
  73. package/dist/schema/introspector.d.cts +19 -19
  74. package/dist/schema/introspector.d.cts.map +1 -1
  75. package/dist/schema/introspector.d.mts +19 -19
  76. package/dist/schema/introspector.d.mts.map +1 -1
  77. package/dist/schema/service.cjs +86 -0
  78. package/dist/schema/service.d.cts +52 -0
  79. package/dist/schema/service.d.cts.map +1 -0
  80. package/dist/schema/service.d.mts +52 -0
  81. package/dist/schema/service.d.mts.map +1 -0
  82. package/dist/schema/service.mjs +87 -0
  83. package/dist/schema/service.mjs.map +1 -0
  84. package/dist/schema/types.d.cts.map +1 -1
  85. package/dist/schema/types.d.mts.map +1 -1
  86. package/dist/sqlite-afs.cjs +693 -121
  87. package/dist/sqlite-afs.d.cts +279 -101
  88. package/dist/sqlite-afs.d.cts.map +1 -1
  89. package/dist/sqlite-afs.d.mts +279 -101
  90. package/dist/sqlite-afs.d.mts.map +1 -1
  91. package/dist/sqlite-afs.mjs +696 -123
  92. package/dist/sqlite-afs.mjs.map +1 -1
  93. package/package.json +5 -4
@@ -4,31 +4,44 @@ const require_config = require('./config.cjs');
4
4
  const require_builder = require('./node/builder.cjs');
5
5
  const require_crud = require('./operations/crud.cjs');
6
6
  const require_search = require('./operations/search.cjs');
7
- const require_path_router = require('./router/path-router.cjs');
8
- const require_introspector = require('./schema/introspector.cjs');
7
+ const require_service = require('./schema/service.cjs');
8
+ const require_decorate = require('./_virtual/_@oxc-project_runtime@0.108.0/helpers/decorate.cjs');
9
9
  let _aigne_sqlite = require("@aigne/sqlite");
10
+ let _aigne_afs = require("@aigne/afs");
11
+ let zod = require("zod");
12
+ let _aigne_afs_provider = require("@aigne/afs/provider");
10
13
 
11
14
  //#region src/sqlite-afs.ts
12
15
  /**
13
16
  * SQLite AFS Module
14
17
  *
15
18
  * Exposes SQLite databases as AFS nodes with full CRUD support,
16
- * schema introspection, FTS5 search, and virtual paths (@attr, @meta, @actions).
19
+ * schema introspection, FTS5 search, and virtual paths (.meta, .actions).
17
20
  */
18
- var SQLiteAFS = class SQLiteAFS {
21
+ var SQLiteAFS = class SQLiteAFS extends _aigne_afs_provider.AFSBaseProvider {
19
22
  name;
20
23
  description;
21
24
  accessMode;
22
25
  db;
23
- schemas = /* @__PURE__ */ new Map();
24
- router;
26
+ schemaService;
25
27
  crud;
26
28
  ftsSearch;
27
29
  actions;
28
30
  ftsConfig;
29
31
  initialized = false;
30
32
  constructor(options) {
33
+ super();
31
34
  this.options = options;
35
+ if (options.localPath && !options.url) options.url = `file:${options.localPath}`;
36
+ if (options.url.startsWith("file:")) {
37
+ const { existsSync, mkdirSync, writeFileSync } = require("node:fs");
38
+ const { dirname } = require("node:path");
39
+ const dbPath = options.url.slice(5);
40
+ if (!existsSync(dbPath)) {
41
+ mkdirSync(dirname(dbPath), { recursive: true });
42
+ writeFileSync(dbPath, "");
43
+ }
44
+ }
32
45
  this.name = options.name ?? "sqlite-afs";
33
46
  this.description = options.description ?? `SQLite database: ${options.url}`;
34
47
  this.accessMode = options.accessMode ?? "readwrite";
@@ -42,20 +55,24 @@ var SQLiteAFS = class SQLiteAFS {
42
55
  static schema() {
43
56
  return require_config.sqliteAFSConfigSchema;
44
57
  }
45
- /**
46
- * Loads a module instance from configuration
47
- */
48
- static async load({ parsed }) {
49
- return new SQLiteAFS(require_config.sqliteAFSConfigSchema.parse(parsed));
58
+ static manifest() {
59
+ return {
60
+ name: "sqlite",
61
+ description: "SQLite database tables as directories, rows as nodes.\n- Browse tables and rows, full-text search (FTS5), schema introspection\n- Exec actions: `insert`, `update`, `delete` at table/row level, custom SQL\n- Path structure: `/{table}/{primary-key}`",
62
+ uriTemplate: "sqlite://{localPath+}",
63
+ category: "database",
64
+ schema: zod.z.object({ localPath: zod.z.string() }),
65
+ tags: ["sqlite", "database"]
66
+ };
50
67
  }
51
68
  /**
52
- * Called when the module is mounted to AFS
69
+ * Loads a module instance from configuration
53
70
  */
54
- async onMount(_afs) {
55
- await this.initialize();
71
+ static async load({ config } = {}) {
72
+ return new SQLiteAFS(require_config.sqliteAFSConfigSchema.parse(config));
56
73
  }
57
74
  /**
58
- * Initializes the database connection and introspects schema
75
+ * Initializes the database connection and schema service
59
76
  */
60
77
  async initialize() {
61
78
  if (this.initialized) return;
@@ -64,158 +81,672 @@ var SQLiteAFS = class SQLiteAFS {
64
81
  wal: this.options.wal ?? true
65
82
  });
66
83
  const db = this.db;
67
- this.schemas = await new require_introspector.SchemaIntrospector().introspect(db, {
84
+ this.schemaService = new require_service.SchemaService(db, {
68
85
  tables: this.options.tables,
69
86
  excludeTables: this.options.excludeTables
70
87
  });
71
- this.router = require_path_router.createPathRouter();
72
- this.crud = new require_crud.CRUDOperations(db, this.schemas, "");
73
- this.ftsSearch = new require_search.FTSSearch(db, this.schemas, this.ftsConfig, "");
88
+ this.crud = new require_crud.CRUDOperations(db, this.schemaService, "");
89
+ this.ftsSearch = new require_search.FTSSearch(db, this.schemaService, this.ftsConfig, "");
74
90
  this.initialized = true;
75
91
  }
76
92
  /**
77
- * Ensures the module is initialized
93
+ * Ensures the module is initialized.
94
+ * This is called automatically by handlers, but can also be called
95
+ * manually to trigger initialization (e.g., in tests).
78
96
  */
79
97
  async ensureInitialized() {
80
98
  if (!this.initialized) await this.initialize();
81
99
  }
82
100
  /**
83
- * Lists entries at a path
84
- */
85
- async list(path, options) {
86
- await this.ensureInitialized();
87
- const match = require_path_router.matchPath(this.router, path);
88
- if (!match) return { data: [] };
89
- switch (match.action) {
90
- case "listTables": return this.crud.listTables();
91
- case "listTable":
92
- if (!match.params.table) return { data: [] };
93
- return this.crud.listTable(match.params.table, options);
94
- case "listAttributes":
95
- if (!match.params.table || !match.params.pk) return { data: [] };
96
- return this.crud.listAttributes(match.params.table, match.params.pk);
97
- case "listActions":
98
- if (!match.params.table || !match.params.pk) return { data: [] };
99
- return this.listActions(match.params.table, match.params.pk);
100
- default: return { data: [] };
101
- }
101
+ * List all tables
102
+ * Note: list() returns only children, never the path itself (per new semantics)
103
+ */
104
+ async listTablesHandler(_ctx) {
105
+ await this.ensureInitialized();
106
+ return { data: (await this.crud.listTables()).data };
107
+ }
108
+ /**
109
+ * List rows in a table
110
+ * Note: list() returns only children (rows), never the table itself (per new semantics)
111
+ */
112
+ async listTableHandler(ctx) {
113
+ await this.ensureInitialized();
114
+ if (!await this.schemaService.getSchema(ctx.params.table)) throw new _aigne_afs.AFSNotFoundError(`/${ctx.params.table}`);
115
+ return { data: (await this.crud.listTable(ctx.params.table, ctx.options)).data };
116
+ }
117
+ /**
118
+ * List a row - rows are leaf nodes with no children
119
+ * Note: list() returns only children, never the path itself (per new semantics)
120
+ */
121
+ async listRowHandler(ctx) {
122
+ await this.ensureInitialized();
123
+ if (!(await this.crud.readRow(ctx.params.table, ctx.params.pk)).data) throw new _aigne_afs.AFSNotFoundError(`/${ctx.params.table}/${ctx.params.pk}`);
124
+ return { data: [] };
125
+ }
126
+ /**
127
+ * List actions for a row
128
+ */
129
+ async listActionsHandler(ctx) {
130
+ await this.ensureInitialized();
131
+ const schema = await this.schemaService.getSchema(ctx.params.table);
132
+ if (!schema) throw new _aigne_afs.AFSNotFoundError(`/${ctx.params.table}`);
133
+ const actions = this.actions.listWithInfo({ rowLevel: true }, {
134
+ tableSchema: schema,
135
+ tableName: ctx.params.table,
136
+ schemaService: this.schemaService
137
+ });
138
+ return { data: require_builder.buildActionsListEntry(ctx.params.table, ctx.params.pk, actions, { basePath: "" }) };
139
+ }
140
+ /**
141
+ * List actions for a table (table-level actions)
142
+ */
143
+ async listTableActionsHandler(ctx) {
144
+ await this.ensureInitialized();
145
+ const schema = await this.schemaService.getSchema(ctx.params.table);
146
+ if (!schema) throw new _aigne_afs.AFSNotFoundError(`/${ctx.params.table}`);
147
+ const actions = this.actions.listWithInfo({ tableLevel: true }, {
148
+ tableSchema: schema,
149
+ tableName: ctx.params.table,
150
+ schemaService: this.schemaService
151
+ });
152
+ return { data: require_builder.buildTableActionsListEntry(ctx.params.table, actions, { basePath: "" }) };
153
+ }
154
+ /**
155
+ * List actions at root level (database-level actions)
156
+ */
157
+ async listRootActionsHandler(_ctx) {
158
+ await this.ensureInitialized();
159
+ return { data: require_builder.buildRootActionsListEntry(this.actions.listWithInfo({ rootLevel: true }, { schemaService: this.schemaService }), { basePath: "" }) };
160
+ }
161
+ /**
162
+ * Read root (database) entry
163
+ */
164
+ async readRootHandler(_ctx) {
165
+ await this.ensureInitialized();
166
+ return require_builder.buildRootEntry(await this.schemaService.getAllSchemas(), { basePath: "" });
167
+ }
168
+ /**
169
+ * Read root metadata (database-level schema information)
170
+ */
171
+ async readRootMetaHandler(_ctx) {
172
+ await this.ensureInitialized();
173
+ const schemas = await this.schemaService.getAllSchemas();
174
+ const tables = Array.from(schemas.entries()).sort((a, b) => a[0].localeCompare(b[0])).map(([name, schema]) => ({
175
+ name,
176
+ description: `Table with ${schema.columns.length} columns`,
177
+ columnCount: schema.columns.length,
178
+ primaryKey: schema.primaryKey
179
+ }));
180
+ return {
181
+ id: "root:.meta",
182
+ path: "/.meta",
183
+ content: {
184
+ type: "sqlite",
185
+ tableCount: schemas.size,
186
+ tables
187
+ },
188
+ meta: {
189
+ childrenCount: tables.length,
190
+ tables: tables.map((t) => t.name)
191
+ }
192
+ };
193
+ }
194
+ /**
195
+ * Read capabilities manifest
196
+ * Returns information about available actions at different levels
197
+ */
198
+ async readCapabilitiesHandler(_ctx) {
199
+ await this.ensureInitialized();
200
+ const actionCatalogs = [];
201
+ const rootActions = this.actions.listWithInfo({ rootLevel: true }, { schemaService: this.schemaService });
202
+ if (rootActions.length > 0) actionCatalogs.push({
203
+ kind: "sqlite:root",
204
+ description: "Database-level operations",
205
+ catalog: rootActions.map((a) => ({
206
+ name: a.name,
207
+ description: a.description,
208
+ inputSchema: a.inputSchema
209
+ })),
210
+ discovery: {
211
+ pathTemplate: "/.actions",
212
+ note: "Available at database root"
213
+ }
214
+ });
215
+ const tableActions = this.actions.listWithInfo({ tableLevel: true }, { schemaService: this.schemaService });
216
+ if (tableActions.length > 0) actionCatalogs.push({
217
+ kind: "sqlite:table",
218
+ description: "Table-level operations",
219
+ catalog: tableActions.map((a) => ({
220
+ name: a.name,
221
+ description: a.description,
222
+ inputSchema: a.inputSchema
223
+ })),
224
+ discovery: {
225
+ pathTemplate: "/:table/.actions",
226
+ note: "Replace :table with actual table name"
227
+ }
228
+ });
229
+ const rowActions = this.actions.listWithInfo({ rowLevel: true }, { schemaService: this.schemaService });
230
+ if (rowActions.length > 0) actionCatalogs.push({
231
+ kind: "sqlite:row",
232
+ description: "Row-level operations",
233
+ catalog: rowActions.map((a) => ({
234
+ name: a.name,
235
+ description: a.description,
236
+ inputSchema: a.inputSchema
237
+ })),
238
+ discovery: {
239
+ pathTemplate: "/:table/:pk/.actions",
240
+ note: "Replace :table with table name, :pk with primary key value"
241
+ }
242
+ });
243
+ return {
244
+ id: "/.meta/.capabilities",
245
+ path: "/.meta/.capabilities",
246
+ content: {
247
+ schemaVersion: 1,
248
+ provider: this.name,
249
+ version: "1.0.0",
250
+ description: this.description,
251
+ tools: [],
252
+ actions: actionCatalogs,
253
+ operations: this.getOperationsDeclaration()
254
+ },
255
+ meta: { kind: "afs:capabilities" }
256
+ };
257
+ }
258
+ /**
259
+ * Read table (directory) entry
260
+ */
261
+ async readTableHandler(ctx) {
262
+ await this.ensureInitialized();
263
+ const schema = await this.schemaService.getSchema(ctx.params.table);
264
+ if (!schema) throw new _aigne_afs.AFSNotFoundError(`/${ctx.params.table}`);
265
+ const rowCount = (await this.db.all(_aigne_sqlite.sql.raw(`SELECT COUNT(*) as count FROM "${ctx.params.table}"`)))[0]?.count ?? 0;
266
+ return require_builder.buildTableEntry(ctx.params.table, schema, {
267
+ basePath: "",
268
+ rowCount
269
+ });
270
+ }
271
+ /**
272
+ * Read table metadata (table-level schema information)
273
+ */
274
+ async readTableMetaHandler(ctx) {
275
+ await this.ensureInitialized();
276
+ const schema = await this.schemaService.getSchema(ctx.params.table);
277
+ if (!schema) throw new _aigne_afs.AFSNotFoundError(`/${ctx.params.table}`);
278
+ const rowCount = (await this.db.all(_aigne_sqlite.sql.raw(`SELECT COUNT(*) as count FROM "${ctx.params.table}"`)))[0]?.count ?? 0;
279
+ const columns = schema.columns.map((col) => ({
280
+ name: col.name,
281
+ type: col.type,
282
+ nullable: !col.notnull,
283
+ primaryKey: col.pk > 0,
284
+ defaultValue: col.dfltValue
285
+ }));
286
+ return {
287
+ id: `${ctx.params.table}:.meta`,
288
+ path: `/${ctx.params.table}/.meta`,
289
+ content: {
290
+ table: ctx.params.table,
291
+ columns,
292
+ primaryKey: schema.primaryKey,
293
+ foreignKeys: schema.foreignKeys.map((fk) => ({
294
+ column: fk.from,
295
+ referencesTable: fk.table,
296
+ referencesColumn: fk.to,
297
+ onUpdate: fk.onUpdate,
298
+ onDelete: fk.onDelete
299
+ })),
300
+ indexes: schema.indexes.map((idx) => ({
301
+ name: idx.name,
302
+ unique: idx.unique,
303
+ origin: idx.origin
304
+ })),
305
+ rowCount
306
+ },
307
+ meta: {
308
+ table: ctx.params.table,
309
+ description: `Table "${ctx.params.table}" with ${columns.length} columns`,
310
+ childrenCount: rowCount,
311
+ columnCount: columns.length,
312
+ columns: columns.map((c) => c.name),
313
+ primaryKey: schema.primaryKey
314
+ }
315
+ };
316
+ }
317
+ /**
318
+ * Read a row
319
+ */
320
+ async readRowHandler(ctx) {
321
+ await this.ensureInitialized();
322
+ return (await this.crud.readRow(ctx.params.table, ctx.params.pk)).data;
323
+ }
324
+ /**
325
+ * Get row metadata (@meta suffix - SQLite-specific)
326
+ */
327
+ async getMetaHandler(ctx) {
328
+ await this.ensureInitialized();
329
+ return (await this.crud.getMeta(ctx.params.table, ctx.params.pk)).data;
330
+ }
331
+ /**
332
+ * Get row metadata (.meta suffix - row-level schema information)
333
+ */
334
+ async getRowDotMetaHandler(ctx) {
335
+ await this.ensureInitialized();
336
+ const schema = await this.schemaService.getSchema(ctx.params.table);
337
+ if (!schema) throw new _aigne_afs.AFSNotFoundError(`/${ctx.params.table}`);
338
+ if (!(await this.crud.readRow(ctx.params.table, ctx.params.pk)).data) throw new _aigne_afs.AFSNotFoundError(`/${ctx.params.table}/${ctx.params.pk}`);
339
+ const pkColumn = schema.primaryKey[0] ?? "rowid";
340
+ return {
341
+ id: `${ctx.params.table}:${ctx.params.pk}:.meta`,
342
+ path: `/${ctx.params.table}/${ctx.params.pk}/.meta`,
343
+ content: {
344
+ table: ctx.params.table,
345
+ primaryKey: pkColumn,
346
+ primaryKeyValue: ctx.params.pk,
347
+ columns: schema.columns.map((col) => ({
348
+ name: col.name,
349
+ type: col.type,
350
+ nullable: !col.notnull,
351
+ primaryKey: col.pk > 0
352
+ })),
353
+ foreignKeys: schema.foreignKeys.map((fk) => ({
354
+ column: fk.from,
355
+ referencesTable: fk.table,
356
+ referencesColumn: fk.to
357
+ }))
358
+ },
359
+ meta: {
360
+ table: ctx.params.table,
361
+ primaryKeyValue: ctx.params.pk,
362
+ columns: schema.columns.map((col) => col.name)
363
+ }
364
+ };
365
+ }
366
+ /**
367
+ * Create a new row
368
+ */
369
+ async createRowHandler(ctx, content) {
370
+ await this.ensureInitialized();
371
+ return this.crud.createRow(ctx.params.table, content.content ?? content);
372
+ }
373
+ /**
374
+ * Update an existing row
375
+ */
376
+ async updateRowHandler(ctx, content) {
377
+ await this.ensureInitialized();
378
+ return this.crud.updateRow(ctx.params.table, ctx.params.pk, content.content ?? content);
379
+ }
380
+ /**
381
+ * Execute action via write (for triggering row-level actions)
382
+ */
383
+ async executeActionWriteHandler(ctx, content) {
384
+ await this.ensureInitialized();
385
+ return this.executeAction(ctx.params.table, ctx.params.pk, ctx.params.action, content.content ?? content);
386
+ }
387
+ /**
388
+ * Execute action via write (for triggering table-level actions)
389
+ */
390
+ async executeTableActionWriteHandler(ctx, content) {
391
+ await this.ensureInitialized();
392
+ return this.executeAction(ctx.params.table, void 0, ctx.params.action, content.content ?? content);
393
+ }
394
+ /**
395
+ * Execute action via write (for triggering root-level actions)
396
+ */
397
+ async executeRootActionWriteHandler(ctx, content) {
398
+ await this.ensureInitialized();
399
+ return this.executeRootAction(ctx.params.action, content.content ?? content);
400
+ }
401
+ /**
402
+ * Delete a table entry (not supported - always throws)
403
+ */
404
+ async deleteTableHandler(ctx) {
405
+ await this.ensureInitialized();
406
+ if (!await this.schemaService.hasTable(ctx.params.table)) throw new _aigne_afs.AFSNotFoundError(`/${ctx.params.table}`);
407
+ throw new Error(`Cannot delete table '${ctx.params.table}'. Use SQL directly to drop tables.`);
408
+ }
409
+ /**
410
+ * Delete a row
411
+ */
412
+ async deleteRowHandler(ctx) {
413
+ await this.ensureInitialized();
414
+ return this.crud.deleteRow(ctx.params.table, ctx.params.pk);
415
+ }
416
+ /**
417
+ * Search all tables
418
+ */
419
+ async searchAllHandler(_ctx, query, options) {
420
+ await this.ensureInitialized();
421
+ return this.ftsSearch.search(query, options);
422
+ }
423
+ /**
424
+ * Search a specific table
425
+ */
426
+ async searchTableHandler(ctx, query, options) {
427
+ await this.ensureInitialized();
428
+ return this.ftsSearch.searchTable(ctx.params.table, query, options);
429
+ }
430
+ /**
431
+ * Get stat for root (database level)
432
+ */
433
+ async statRootHandler(_ctx) {
434
+ await this.ensureInitialized();
435
+ const schemas = await this.schemaService.getAllSchemas();
436
+ const actions = this.actions.listWithInfo({ rootLevel: true }, { schemaService: this.schemaService });
437
+ return { data: {
438
+ id: "/",
439
+ path: "/",
440
+ meta: {
441
+ kind: "sqlite:database",
442
+ kinds: ["sqlite:database", "afs:node"],
443
+ tableCount: schemas.size,
444
+ childrenCount: schemas.size
445
+ },
446
+ actions: actions.length > 0 ? actions.map((a) => ({
447
+ name: a.name,
448
+ description: a.description
449
+ })) : void 0
450
+ } };
102
451
  }
103
452
  /**
104
- * Reads an entry at a path
105
- */
106
- async read(path, _options) {
107
- await this.ensureInitialized();
108
- const match = require_path_router.matchPath(this.router, path);
109
- if (!match) return {};
110
- switch (match.action) {
111
- case "readRow":
112
- if (!match.params.table || !match.params.pk) return {};
113
- return this.crud.readRow(match.params.table, match.params.pk);
114
- case "getSchema":
115
- if (!match.params.table) return {};
116
- return this.crud.getSchema(match.params.table);
117
- case "getAttribute":
118
- if (!match.params.table || !match.params.pk || !match.params.column) return {};
119
- return this.crud.getAttribute(match.params.table, match.params.pk, match.params.column);
120
- case "getMeta":
121
- if (!match.params.table || !match.params.pk) return {};
122
- return this.crud.getMeta(match.params.table, match.params.pk);
123
- default: return {};
453
+ * Get stat for a table
454
+ */
455
+ async statTableHandler(ctx) {
456
+ await this.ensureInitialized();
457
+ const schema = await this.schemaService.getSchema(ctx.params.table);
458
+ if (!schema) throw new _aigne_afs.AFSNotFoundError(`/${ctx.params.table}`);
459
+ const rowCount = (await this.db.all(_aigne_sqlite.sql.raw(`SELECT COUNT(*) as count FROM "${ctx.params.table}"`)))[0]?.count ?? 0;
460
+ const actions = this.actions.listWithInfo({ tableLevel: true }, {
461
+ tableSchema: schema,
462
+ tableName: ctx.params.table,
463
+ schemaService: this.schemaService
464
+ });
465
+ const columns = schema.columns.map((col) => ({
466
+ name: col.name,
467
+ type: col.type,
468
+ nullable: !col.notnull,
469
+ primaryKey: col.pk > 0
470
+ }));
471
+ return { data: {
472
+ id: ctx.params.table,
473
+ path: `/${ctx.params.table}`,
474
+ meta: {
475
+ kind: "sqlite:table",
476
+ kinds: ["sqlite:table", "afs:node"],
477
+ table: ctx.params.table,
478
+ columnCount: schema.columns.length,
479
+ columns,
480
+ primaryKey: schema.primaryKey[0],
481
+ childrenCount: rowCount
482
+ },
483
+ actions: actions.length > 0 ? actions.map((a) => ({
484
+ name: a.name,
485
+ description: a.description
486
+ })) : void 0
487
+ } };
488
+ }
489
+ /**
490
+ * Get stat for a row
491
+ */
492
+ async statRowHandler(ctx) {
493
+ await this.ensureInitialized();
494
+ const schema = await this.schemaService.getSchema(ctx.params.table);
495
+ if (!schema) throw new _aigne_afs.AFSNotFoundError(`/${ctx.params.table}`);
496
+ if (!(await this.crud.readRow(ctx.params.table, ctx.params.pk)).data) throw new _aigne_afs.AFSNotFoundError(`/${ctx.params.table}/${ctx.params.pk}`);
497
+ const actions = this.actions.listWithInfo({ rowLevel: true }, {
498
+ tableSchema: schema,
499
+ tableName: ctx.params.table,
500
+ schemaService: this.schemaService
501
+ });
502
+ const columns = schema.columns.map((col) => ({
503
+ name: col.name,
504
+ type: col.type,
505
+ nullable: !col.notnull,
506
+ primaryKey: col.pk > 0
507
+ }));
508
+ return { data: {
509
+ id: ctx.params.pk,
510
+ path: `/${ctx.params.table}/${ctx.params.pk}`,
511
+ meta: {
512
+ kind: "sqlite:row",
513
+ kinds: ["sqlite:row", "afs:node"],
514
+ table: ctx.params.table,
515
+ primaryKey: ctx.params.pk,
516
+ columnCount: schema.columns.length,
517
+ columns,
518
+ childrenCount: 0
519
+ },
520
+ actions: actions.length > 0 ? actions.map((a) => ({
521
+ name: a.name,
522
+ description: a.description
523
+ })) : void 0
524
+ } };
525
+ }
526
+ /**
527
+ * Explain root (database level)
528
+ */
529
+ async explainRootHandler(ctx) {
530
+ await this.ensureInitialized();
531
+ const format = ctx.options?.format || "markdown";
532
+ const schemas = await this.schemaService.getAllSchemas();
533
+ const tables = Array.from(schemas.values());
534
+ const lines = [];
535
+ if (format === "markdown") {
536
+ lines.push(`# ${this.name}`);
537
+ lines.push("");
538
+ lines.push(`**Type:** SQLite Database`);
539
+ lines.push(`**Tables:** ${tables.length}`);
540
+ lines.push("");
541
+ if (tables.length > 0) {
542
+ lines.push("## Tables");
543
+ lines.push("");
544
+ lines.push("| Table | Columns | Primary Key |");
545
+ lines.push("|-------|---------|-------------|");
546
+ for (const table of tables) {
547
+ const pk = table.primaryKey.join(", ") || "rowid";
548
+ lines.push(`| ${table.name} | ${table.columns.length} | ${pk} |`);
549
+ }
550
+ }
551
+ } else {
552
+ lines.push(`${this.name} (SQLite Database)`);
553
+ lines.push(`Tables: ${tables.length}`);
554
+ for (const table of tables) lines.push(` - ${table.name} (${table.columns.length} columns)`);
124
555
  }
556
+ return {
557
+ content: lines.join("\n"),
558
+ format
559
+ };
125
560
  }
126
561
  /**
127
- * Writes an entry at a path
128
- */
129
- async write(path, content, _options) {
130
- await this.ensureInitialized();
131
- if (this.accessMode === "readonly") throw new Error("Module is in readonly mode");
132
- const match = require_path_router.matchPath(this.router, path);
133
- if (!match) throw new Error(`Invalid path: ${path}`);
134
- switch (match.action) {
135
- case "createRow":
136
- if (!match.params.table) throw new Error("Table name required for create");
137
- return this.crud.createRow(match.params.table, content.content ?? content);
138
- case "readRow":
139
- if (!match.params.table || !match.params.pk) throw new Error("Table and primary key required for update");
140
- return this.crud.updateRow(match.params.table, match.params.pk, content.content ?? content);
141
- case "executeAction":
142
- if (!match.params.table || !match.params.action) throw new Error("Table and action name required");
143
- return this.executeAction(match.params.table, match.params.pk, match.params.action, content.content ?? content);
144
- default: throw new Error(`Write not supported for path: ${path}`);
562
+ * Explain a table
563
+ */
564
+ async explainTableHandler(ctx) {
565
+ await this.ensureInitialized();
566
+ const format = ctx.options?.format || "markdown";
567
+ const schema = await this.schemaService.getSchema(ctx.params.table);
568
+ if (!schema) throw new _aigne_afs.AFSNotFoundError(`/${ctx.params.table}`);
569
+ const rowCount = (await this.db.all(_aigne_sqlite.sql.raw(`SELECT COUNT(*) as count FROM "${ctx.params.table}"`)))[0]?.count ?? 0;
570
+ const lines = [];
571
+ if (format === "markdown") {
572
+ lines.push(`# ${ctx.params.table}`);
573
+ lines.push("");
574
+ lines.push(`**Type:** SQLite Table`);
575
+ lines.push(`**Rows:** ${rowCount}`);
576
+ lines.push(`**Primary Key:** ${schema.primaryKey.join(", ") || "rowid"}`);
577
+ lines.push("");
578
+ lines.push("## Columns");
579
+ lines.push("");
580
+ lines.push("| Column | Type | Nullable | Primary Key | Default |");
581
+ lines.push("|--------|------|----------|-------------|---------|");
582
+ for (const col of schema.columns) {
583
+ const nullable = col.notnull ? "NO" : "YES";
584
+ const pk = col.pk > 0 ? "YES" : "";
585
+ const dflt = col.dfltValue !== null && col.dfltValue !== void 0 ? String(col.dfltValue) : "";
586
+ lines.push(`| ${col.name} | ${col.type} | ${nullable} | ${pk} | ${dflt} |`);
587
+ }
588
+ if (schema.indexes.length > 0) {
589
+ lines.push("");
590
+ lines.push("## Indexes");
591
+ lines.push("");
592
+ for (const idx of schema.indexes) {
593
+ const uniqueStr = idx.unique ? " (UNIQUE)" : "";
594
+ lines.push(`- **${idx.name}**${uniqueStr}`);
595
+ }
596
+ }
597
+ if (schema.foreignKeys.length > 0) {
598
+ lines.push("");
599
+ lines.push("## Foreign Keys");
600
+ lines.push("");
601
+ for (const fk of schema.foreignKeys) lines.push(`- \`${fk.from}\` → \`${fk.table}\`(\`${fk.to}\`) ON DELETE ${fk.onDelete}`);
602
+ }
603
+ } else {
604
+ lines.push(`${ctx.params.table} (SQLite Table)`);
605
+ lines.push(`Rows: ${rowCount}`);
606
+ lines.push(`Primary Key: ${schema.primaryKey.join(", ") || "rowid"}`);
607
+ lines.push(`Columns: ${schema.columns.map((c) => `${c.name} (${c.type})`).join(", ")}`);
608
+ if (schema.indexes.length > 0) lines.push(`Indexes: ${schema.indexes.map((i) => i.name).join(", ")}`);
609
+ if (schema.foreignKeys.length > 0) lines.push(`Foreign Keys: ${schema.foreignKeys.map((fk) => `${fk.from} → ${fk.table}(${fk.to})`).join(", ")}`);
145
610
  }
611
+ return {
612
+ content: lines.join("\n"),
613
+ format
614
+ };
146
615
  }
147
616
  /**
148
- * Deletes an entry at a path
617
+ * Explain a row
149
618
  */
150
- async delete(path, _options) {
619
+ async explainRowHandler(ctx) {
151
620
  await this.ensureInitialized();
152
- if (this.accessMode === "readonly") throw new Error("Module is in readonly mode");
153
- const match = require_path_router.matchPath(this.router, path);
154
- if (!match || match.action !== "readRow") throw new Error(`Delete not supported for path: ${path}`);
155
- if (!match.params.table || !match.params.pk) throw new Error("Table and primary key required for delete");
156
- return this.crud.deleteRow(match.params.table, match.params.pk);
621
+ const format = ctx.options?.format || "markdown";
622
+ const schema = await this.schemaService.getSchema(ctx.params.table);
623
+ if (!schema) throw new _aigne_afs.AFSNotFoundError(`/${ctx.params.table}`);
624
+ const result = await this.crud.readRow(ctx.params.table, ctx.params.pk);
625
+ if (!result.data) throw new _aigne_afs.AFSNotFoundError(`/${ctx.params.table}/${ctx.params.pk}`);
626
+ const rowContent = result.data.content;
627
+ const pkColumn = schema.primaryKey[0] ?? "rowid";
628
+ const lines = [];
629
+ if (format === "markdown") {
630
+ lines.push(`# ${ctx.params.table}/${ctx.params.pk}`);
631
+ lines.push("");
632
+ lines.push(`**Table:** ${ctx.params.table}`);
633
+ lines.push(`**Primary Key:** ${pkColumn} = ${ctx.params.pk}`);
634
+ lines.push("");
635
+ if (rowContent) {
636
+ lines.push("## Values");
637
+ lines.push("");
638
+ lines.push("| Column | Value |");
639
+ lines.push("|--------|-------|");
640
+ for (const col of schema.columns) {
641
+ const val = rowContent[col.name];
642
+ const displayVal = val === null || val === void 0 ? "*null*" : truncateValue(String(val), 100);
643
+ lines.push(`| ${col.name} | ${displayVal} |`);
644
+ }
645
+ }
646
+ } else {
647
+ lines.push(`${ctx.params.table}/${ctx.params.pk} (SQLite Row)`);
648
+ lines.push(`Table: ${ctx.params.table}, ${pkColumn} = ${ctx.params.pk}`);
649
+ if (rowContent) for (const col of schema.columns) {
650
+ const val = rowContent[col.name];
651
+ lines.push(` ${col.name}: ${val === null || val === void 0 ? "null" : truncateValue(String(val), 100)}`);
652
+ }
653
+ }
654
+ return {
655
+ content: lines.join("\n"),
656
+ format
657
+ };
157
658
  }
158
659
  /**
159
- * Searches for entries matching a query
660
+ * Execute action via exec (row-level)
160
661
  */
161
- async search(path, query, options) {
662
+ async handleRowActionExec(ctx, args) {
162
663
  await this.ensureInitialized();
163
- const match = require_path_router.matchPath(this.router, path);
164
- if (match?.params.table) return this.ftsSearch.searchTable(match.params.table, query, options);
165
- return this.ftsSearch.search(query, options);
664
+ return this.executeActionRaw(ctx.params.table, ctx.params.pk, ctx.params.action, args);
166
665
  }
167
666
  /**
168
- * Executes a module operation
667
+ * Execute action via exec (table-level)
169
668
  */
170
- async exec(path, args, _options) {
669
+ async handleTableActionExec(ctx, args) {
171
670
  await this.ensureInitialized();
172
- const match = require_path_router.matchPath(this.router, path);
173
- if (match?.action === "executeAction" && match.params.table && match.params.action) return { data: (await this.executeAction(match.params.table, match.params.pk, match.params.action, args)).data };
174
- throw new Error(`Exec not supported for path: ${path}`);
671
+ return this.executeActionRaw(ctx.params.table, void 0, ctx.params.action, args);
175
672
  }
176
673
  /**
177
- * Lists available actions for a row
674
+ * Execute action via exec (root-level)
178
675
  */
179
- listActions(table, pk) {
180
- return { data: require_builder.buildActionsListEntry(table, pk, this.actions.listNames({ rowLevel: true }), { basePath: "" }) };
676
+ async handleRootActionExec(ctx, args) {
677
+ await this.ensureInitialized();
678
+ return this.executeRootActionRaw(ctx.params.action, args);
181
679
  }
182
680
  /**
183
- * Executes an action
681
+ * Executes an action and returns raw result (for exec handlers)
682
+ * Returns AFSExecResult structure: { success: boolean, data?: Record<string, unknown> }
184
683
  */
185
- async executeAction(table, pk, actionName, params) {
186
- if (!this.schemas.get(table)) throw new Error(`Table '${table}' not found`);
684
+ async executeActionRaw(table, pk, actionName, params) {
685
+ if (!await this.schemaService.getSchema(table)) throw new _aigne_afs.AFSNotFoundError(`/${table}`);
187
686
  let row;
188
687
  if (pk) row = (await this.crud.readRow(table, pk)).data?.content;
189
688
  const ctx = {
190
689
  db: this.db,
191
- schemas: this.schemas,
690
+ schemaService: this.schemaService,
192
691
  table,
193
692
  pk,
194
693
  row,
195
- module: {
196
- refreshSchema: () => this.refreshSchema(),
197
- exportTable: (t, f) => this.exportTable(t, f)
198
- }
694
+ module: { exportTable: (t, f) => this.exportTable(t, f) }
199
695
  };
200
696
  const result = await this.actions.execute(actionName, ctx, params);
201
697
  if (!result.success) throw new Error(result.message ?? "Action failed");
698
+ if (Array.isArray(result.data)) return {
699
+ success: true,
700
+ data: { data: result.data }
701
+ };
702
+ return {
703
+ success: true,
704
+ data: result.data
705
+ };
706
+ }
707
+ /**
708
+ * Executes a root-level action and returns raw result (for exec handlers)
709
+ * Returns AFSExecResult structure: { success: boolean, data?: Record<string, unknown> }
710
+ */
711
+ async executeRootActionRaw(actionName, params) {
712
+ const ctx = {
713
+ db: this.db,
714
+ schemaService: this.schemaService,
715
+ table: "",
716
+ module: { exportTable: (t, f) => this.exportTable(t, f) }
717
+ };
718
+ const result = await this.actions.execute(actionName, ctx, params);
719
+ if (!result.success) throw new Error(result.message ?? "Action failed");
720
+ if (Array.isArray(result.data)) return {
721
+ success: true,
722
+ data: { data: result.data }
723
+ };
724
+ return {
725
+ success: true,
726
+ data: result.data
727
+ };
728
+ }
729
+ /**
730
+ * Executes an action (for write handlers - wraps in AFSEntry)
731
+ */
732
+ async executeAction(table, pk, actionName, params) {
733
+ const result = await this.executeActionRaw(table, pk, actionName, params);
202
734
  return { data: {
203
- id: `${table}:${pk ?? ""}:@actions:${actionName}`,
204
- path: pk ? `/${table}/${pk}/@actions/${actionName}` : `/${table}/@actions/${actionName}`,
205
- content: result.data
735
+ id: `${table}:${pk ?? ""}:.actions:${actionName}`,
736
+ path: pk ? `/${table}/${pk}/.actions/${actionName}` : `/${table}/.actions/${actionName}`,
737
+ content: result
206
738
  } };
207
739
  }
208
740
  /**
209
- * Refreshes the schema cache
741
+ * Executes a root-level action (for write handlers - wraps in AFSEntry)
210
742
  */
211
- async refreshSchema() {
212
- const db = this.db;
213
- this.schemas = await new require_introspector.SchemaIntrospector().introspect(db, {
214
- tables: this.options.tables,
215
- excludeTables: this.options.excludeTables
216
- });
217
- this.crud.setSchemas(this.schemas);
218
- this.ftsSearch.setSchemas(this.schemas);
743
+ async executeRootAction(actionName, params) {
744
+ const result = await this.executeRootActionRaw(actionName, params);
745
+ return { data: {
746
+ id: `:.actions:${actionName}`,
747
+ path: `/.actions/${actionName}`,
748
+ content: result
749
+ } };
219
750
  }
220
751
  /**
221
752
  * Exports table data in specified format
@@ -223,8 +754,8 @@ var SQLiteAFS = class SQLiteAFS {
223
754
  async exportTable(table, format) {
224
755
  const listResult = await this.crud.listTable(table, { limit: 1e4 });
225
756
  if (format === "csv") {
226
- const schema = this.schemas.get(table);
227
- if (!schema) throw new Error(`Table '${table}' not found`);
757
+ const schema = await this.schemaService.getSchema(table);
758
+ if (!schema) throw new _aigne_afs.AFSNotFoundError(`/${table}`);
228
759
  return `${schema.columns.map((c) => c.name).join(",")}\n${listResult.data.map((entry) => {
229
760
  const content = entry.content;
230
761
  return schema.columns.map((c) => {
@@ -248,9 +779,11 @@ var SQLiteAFS = class SQLiteAFS {
248
779
  }
249
780
  /**
250
781
  * Gets table schemas (for external access)
782
+ * Note: This queries the database on-demand
251
783
  */
252
- getSchemas() {
253
- return this.schemas;
784
+ async getSchemas() {
785
+ await this.ensureInitialized();
786
+ return this.schemaService.getAllSchemas();
254
787
  }
255
788
  /**
256
789
  * Gets the database instance (for advanced operations)
@@ -259,6 +792,45 @@ var SQLiteAFS = class SQLiteAFS {
259
792
  return this.db;
260
793
  }
261
794
  };
795
+ require_decorate.__decorate([(0, _aigne_afs_provider.List)("/")], SQLiteAFS.prototype, "listTablesHandler", null);
796
+ require_decorate.__decorate([(0, _aigne_afs_provider.List)("/:table")], SQLiteAFS.prototype, "listTableHandler", null);
797
+ require_decorate.__decorate([(0, _aigne_afs_provider.List)("/:table/:pk")], SQLiteAFS.prototype, "listRowHandler", null);
798
+ require_decorate.__decorate([(0, _aigne_afs_provider.Actions)("/:table/:pk")], SQLiteAFS.prototype, "listActionsHandler", null);
799
+ require_decorate.__decorate([(0, _aigne_afs_provider.Actions)("/:table")], SQLiteAFS.prototype, "listTableActionsHandler", null);
800
+ require_decorate.__decorate([(0, _aigne_afs_provider.Actions)("/")], SQLiteAFS.prototype, "listRootActionsHandler", null);
801
+ require_decorate.__decorate([(0, _aigne_afs_provider.Read)("/")], SQLiteAFS.prototype, "readRootHandler", null);
802
+ require_decorate.__decorate([(0, _aigne_afs_provider.Meta)("/")], SQLiteAFS.prototype, "readRootMetaHandler", null);
803
+ require_decorate.__decorate([(0, _aigne_afs_provider.Read)("/.meta/.capabilities")], SQLiteAFS.prototype, "readCapabilitiesHandler", null);
804
+ require_decorate.__decorate([(0, _aigne_afs_provider.Read)("/:table")], SQLiteAFS.prototype, "readTableHandler", null);
805
+ require_decorate.__decorate([(0, _aigne_afs_provider.Meta)("/:table")], SQLiteAFS.prototype, "readTableMetaHandler", null);
806
+ require_decorate.__decorate([(0, _aigne_afs_provider.Read)("/:table/:pk")], SQLiteAFS.prototype, "readRowHandler", null);
807
+ require_decorate.__decorate([(0, _aigne_afs_provider.Read)("/:table/:pk/@meta")], SQLiteAFS.prototype, "getMetaHandler", null);
808
+ require_decorate.__decorate([(0, _aigne_afs_provider.Meta)("/:table/:pk")], SQLiteAFS.prototype, "getRowDotMetaHandler", null);
809
+ require_decorate.__decorate([(0, _aigne_afs_provider.Write)("/:table/new")], SQLiteAFS.prototype, "createRowHandler", null);
810
+ require_decorate.__decorate([(0, _aigne_afs_provider.Write)("/:table/:pk")], SQLiteAFS.prototype, "updateRowHandler", null);
811
+ require_decorate.__decorate([(0, _aigne_afs_provider.Write)("/:table/:pk/.actions/:action")], SQLiteAFS.prototype, "executeActionWriteHandler", null);
812
+ require_decorate.__decorate([(0, _aigne_afs_provider.Write)("/:table/.actions/:action")], SQLiteAFS.prototype, "executeTableActionWriteHandler", null);
813
+ require_decorate.__decorate([(0, _aigne_afs_provider.Write)("/.actions/:action")], SQLiteAFS.prototype, "executeRootActionWriteHandler", null);
814
+ require_decorate.__decorate([(0, _aigne_afs_provider.Delete)("/:table")], SQLiteAFS.prototype, "deleteTableHandler", null);
815
+ require_decorate.__decorate([(0, _aigne_afs_provider.Delete)("/:table/:pk")], SQLiteAFS.prototype, "deleteRowHandler", null);
816
+ require_decorate.__decorate([(0, _aigne_afs_provider.Search)("/")], SQLiteAFS.prototype, "searchAllHandler", null);
817
+ require_decorate.__decorate([(0, _aigne_afs_provider.Search)("/:table")], SQLiteAFS.prototype, "searchTableHandler", null);
818
+ require_decorate.__decorate([(0, _aigne_afs_provider.Stat)("/")], SQLiteAFS.prototype, "statRootHandler", null);
819
+ require_decorate.__decorate([(0, _aigne_afs_provider.Stat)("/:table")], SQLiteAFS.prototype, "statTableHandler", null);
820
+ require_decorate.__decorate([(0, _aigne_afs_provider.Stat)("/:table/:pk")], SQLiteAFS.prototype, "statRowHandler", null);
821
+ require_decorate.__decorate([(0, _aigne_afs_provider.Explain)("/")], SQLiteAFS.prototype, "explainRootHandler", null);
822
+ require_decorate.__decorate([(0, _aigne_afs_provider.Explain)("/:table")], SQLiteAFS.prototype, "explainTableHandler", null);
823
+ require_decorate.__decorate([(0, _aigne_afs_provider.Explain)("/:table/:pk")], SQLiteAFS.prototype, "explainRowHandler", null);
824
+ require_decorate.__decorate([_aigne_afs_provider.Actions.Exec("/:table/:pk")], SQLiteAFS.prototype, "handleRowActionExec", null);
825
+ require_decorate.__decorate([_aigne_afs_provider.Actions.Exec("/:table")], SQLiteAFS.prototype, "handleTableActionExec", null);
826
+ require_decorate.__decorate([_aigne_afs_provider.Actions.Exec("/")], SQLiteAFS.prototype, "handleRootActionExec", null);
827
+ /**
828
+ * Truncate a string value for display purposes.
829
+ */
830
+ function truncateValue(value, maxLength) {
831
+ if (value.length <= maxLength) return value;
832
+ return `${value.slice(0, maxLength)}...`;
833
+ }
262
834
 
263
835
  //#endregion
264
836
  exports.SQLiteAFS = SQLiteAFS;