@aigne/afs-sqlite 1.11.0-beta.6 → 1.11.0-beta.7

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 (40) hide show
  1. package/dist/actions/built-in.cjs +870 -16
  2. package/dist/actions/built-in.d.cts.map +1 -1
  3. package/dist/actions/built-in.d.mts.map +1 -1
  4. package/dist/actions/built-in.mjs +870 -16
  5. package/dist/actions/built-in.mjs.map +1 -1
  6. package/dist/actions/operators.cjs +156 -0
  7. package/dist/actions/operators.mjs +157 -0
  8. package/dist/actions/operators.mjs.map +1 -0
  9. package/dist/actions/types.cjs +33 -0
  10. package/dist/actions/types.d.cts +22 -0
  11. package/dist/actions/types.d.cts.map +1 -1
  12. package/dist/actions/types.d.mts +22 -0
  13. package/dist/actions/types.d.mts.map +1 -1
  14. package/dist/actions/types.mjs +32 -0
  15. package/dist/actions/types.mjs.map +1 -0
  16. package/dist/index.cjs +2 -0
  17. package/dist/index.d.cts +1 -1
  18. package/dist/index.d.mts +1 -1
  19. package/dist/index.mjs +1 -1
  20. package/dist/node/builder.cjs +11 -8
  21. package/dist/node/builder.d.cts.map +1 -1
  22. package/dist/node/builder.d.mts.map +1 -1
  23. package/dist/node/builder.mjs +11 -8
  24. package/dist/node/builder.mjs.map +1 -1
  25. package/dist/operations/query-builder.cjs +2 -2
  26. package/dist/operations/query-builder.d.cts.map +1 -1
  27. package/dist/operations/query-builder.d.mts.map +1 -1
  28. package/dist/operations/query-builder.mjs +2 -2
  29. package/dist/operations/query-builder.mjs.map +1 -1
  30. package/dist/operations/search.cjs +1 -1
  31. package/dist/operations/search.mjs +1 -1
  32. package/dist/operations/search.mjs.map +1 -1
  33. package/dist/sqlite-afs.cjs +247 -26
  34. package/dist/sqlite-afs.d.cts +29 -4
  35. package/dist/sqlite-afs.d.cts.map +1 -1
  36. package/dist/sqlite-afs.d.mts +29 -4
  37. package/dist/sqlite-afs.d.mts.map +1 -1
  38. package/dist/sqlite-afs.mjs +248 -27
  39. package/dist/sqlite-afs.mjs.map +1 -1
  40. package/package.json +4 -3
@@ -0,0 +1,33 @@
1
+
2
+ //#region src/actions/types.ts
3
+ /**
4
+ * Error codes for SQLite actions
5
+ *
6
+ * Simplified to 3 core codes. Specific error types are distinguished via message.
7
+ */
8
+ let SQLiteActionErrorCode = /* @__PURE__ */ function(SQLiteActionErrorCode) {
9
+ /** Input parameters invalid (schema, type, format errors) */
10
+ SQLiteActionErrorCode[SQLiteActionErrorCode["INVALID_INPUT"] = 1001] = "INVALID_INPUT";
11
+ /** Table, column, index, or row not found */
12
+ SQLiteActionErrorCode[SQLiteActionErrorCode["NOT_FOUND"] = 2001] = "NOT_FOUND";
13
+ /** Constraint violation (unique, foreign key, not null, etc.) */
14
+ SQLiteActionErrorCode[SQLiteActionErrorCode["CONSTRAINT_VIOLATION"] = 3001] = "CONSTRAINT_VIOLATION";
15
+ return SQLiteActionErrorCode;
16
+ }({});
17
+ /**
18
+ * Helper to create an error result
19
+ */
20
+ function errorResult(code, message, details) {
21
+ return {
22
+ success: false,
23
+ error: {
24
+ code,
25
+ message,
26
+ details
27
+ }
28
+ };
29
+ }
30
+
31
+ //#endregion
32
+ exports.SQLiteActionErrorCode = SQLiteActionErrorCode;
33
+ exports.errorResult = errorResult;
@@ -41,6 +41,27 @@ type InputSchemaGenerator = (ctx: SchemaGeneratorContext) => Record<string, unkn
41
41
  * Action handler function signature
42
42
  */
43
43
  type ActionHandler = (ctx: ActionContext, params: Record<string, unknown>) => Promise<ActionResult>;
44
+ /**
45
+ * Error codes for SQLite actions
46
+ *
47
+ * Simplified to 3 core codes. Specific error types are distinguished via message.
48
+ */
49
+ declare enum SQLiteActionErrorCode {
50
+ /** Input parameters invalid (schema, type, format errors) */
51
+ INVALID_INPUT = 1001,
52
+ /** Table, column, index, or row not found */
53
+ NOT_FOUND = 2001,
54
+ /** Constraint violation (unique, foreign key, not null, etc.) */
55
+ CONSTRAINT_VIOLATION = 3001
56
+ }
57
+ /**
58
+ * Error details for failed actions
59
+ */
60
+ interface ActionError {
61
+ code: SQLiteActionErrorCode;
62
+ message: string;
63
+ details?: Record<string, unknown>;
64
+ }
44
65
  /**
45
66
  * Result from an action execution
46
67
  */
@@ -48,6 +69,7 @@ interface ActionResult {
48
69
  success: boolean;
49
70
  data?: unknown;
50
71
  message?: string;
72
+ error?: ActionError;
51
73
  }
52
74
  /**
53
75
  * Action definition with metadata
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.cts","names":[],"sources":["../../src/actions/types.ts"],"mappings":";;;;;;;AAOA;UAAiB,aAAA;;EAEf,EAAA,EAAI,cAAA;EAEW;EAAf,aAAA,EAAe,aAAA;EAS+B;EAP9C,KAAA;EAOqD;EALrD,EAAA;EANI;EAQJ,GAAA,GAAM,MAAA;EANS;EAQf,MAAA;IACE,WAAA,CAAY,KAAA,UAAe,MAAA,WAAiB,OAAA;EAAA;AAAA;;;;UAO/B,sBAAA;EAP+B;EAS9C,WAAA,GAAc,WAAA;EATuC;EAWrD,SAAA;EAJqC;EAMrC,aAAA,EAAe,aAAA;AAAA;;;;KAML,oBAAA,IAAwB,GAAA,EAAK,sBAAA,KAA2B,MAAA;;;;KAKxD,aAAA,IACV,GAAA,EAAK,aAAA,EACL,MAAA,EAAQ,MAAA,sBACL,OAAA,CAAQ,YAAA;;;;UAKI,YAAA;EACf,OAAA;EACA,IAAA;EACA,OAAA;AAAA;AAXF;;;AAAA,UAiBiB,gBAAA;EAfP;EAiBR,IAAA;EAhBG;EAkBH,WAAA;EAlBU;EAoBV,SAAA;EAtBA;EAwBA,UAAA;EAvBA;EAyBA,QAAA;EAxBW;EA0BX,WAAA,GAAc,MAAA;EA1BS;EA4BvB,oBAAA,GAAuB,oBAAA;EAvBI;EAyB3B,OAAA,EAAS,aAAA;AAAA"}
1
+ {"version":3,"file":"types.d.cts","names":[],"sources":["../../src/actions/types.ts"],"mappings":";;;;;;;AAOA;UAAiB,aAAA;;EAEf,EAAA,EAAI,cAAA;EAEW;EAAf,aAAA,EAAe,aAAA;EAS+B;EAP9C,KAAA;EAOqD;EALrD,EAAA;EANI;EAQJ,GAAA,GAAM,MAAA;EANS;EAQf,MAAA;IACE,WAAA,CAAY,KAAA,UAAe,MAAA,WAAiB,OAAA;EAAA;AAAA;;;;UAO/B,sBAAA;EAP+B;EAS9C,WAAA,GAAc,WAAA;EATuC;EAWrD,SAAA;EAJqC;EAMrC,aAAA,EAAe,aAAA;AAAA;;;;KAML,oBAAA,IAAwB,GAAA,EAAK,sBAAA,KAA2B,MAAA;;;;KAKxD,aAAA,IACV,GAAA,EAAK,aAAA,EACL,MAAA,EAAQ,MAAA,sBACL,OAAA,CAAQ,YAAA;;;;;;aAOD,qBAAA;EAf8D;EAiBxE,aAAA;EAZU;EAcV,SAAA;;EAEA,oBAAA;AAAA;;;;UAMe,WAAA;EACf,IAAA,EAAM,qBAAA;EACN,OAAA;EACA,OAAA,GAAU,MAAA;AAAA;;;;UAMK,YAAA;EACf,OAAA;EACA,IAAA;EACA,OAAA;EACA,KAAA,GAAQ,WAAA;AAAA;AAbV;;;AAAA,UAiCiB,gBAAA;EAhCf;EAkCA,IAAA;EAjCA;EAmCA,WAAA;EAlCU;EAoCV,SAAA;EApCgB;EAsChB,UAAA;EAhC2B;EAkC3B,QAAA;EA9BmB;EAgCnB,WAAA,GAAc,MAAA;EAlCd;EAoCA,oBAAA,GAAuB,oBAAA;EAlCvB;EAoCA,OAAA,EAAS,aAAA;AAAA"}
@@ -41,6 +41,27 @@ type InputSchemaGenerator = (ctx: SchemaGeneratorContext) => Record<string, unkn
41
41
  * Action handler function signature
42
42
  */
43
43
  type ActionHandler = (ctx: ActionContext, params: Record<string, unknown>) => Promise<ActionResult>;
44
+ /**
45
+ * Error codes for SQLite actions
46
+ *
47
+ * Simplified to 3 core codes. Specific error types are distinguished via message.
48
+ */
49
+ declare enum SQLiteActionErrorCode {
50
+ /** Input parameters invalid (schema, type, format errors) */
51
+ INVALID_INPUT = 1001,
52
+ /** Table, column, index, or row not found */
53
+ NOT_FOUND = 2001,
54
+ /** Constraint violation (unique, foreign key, not null, etc.) */
55
+ CONSTRAINT_VIOLATION = 3001
56
+ }
57
+ /**
58
+ * Error details for failed actions
59
+ */
60
+ interface ActionError {
61
+ code: SQLiteActionErrorCode;
62
+ message: string;
63
+ details?: Record<string, unknown>;
64
+ }
44
65
  /**
45
66
  * Result from an action execution
46
67
  */
@@ -48,6 +69,7 @@ interface ActionResult {
48
69
  success: boolean;
49
70
  data?: unknown;
50
71
  message?: string;
72
+ error?: ActionError;
51
73
  }
52
74
  /**
53
75
  * Action definition with metadata
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.mts","names":[],"sources":["../../src/actions/types.ts"],"mappings":";;;;;;;AAOA;UAAiB,aAAA;;EAEf,EAAA,EAAI,cAAA;EAEW;EAAf,aAAA,EAAe,aAAA;EAS+B;EAP9C,KAAA;EAOqD;EALrD,EAAA;EANI;EAQJ,GAAA,GAAM,MAAA;EANS;EAQf,MAAA;IACE,WAAA,CAAY,KAAA,UAAe,MAAA,WAAiB,OAAA;EAAA;AAAA;;;;UAO/B,sBAAA;EAP+B;EAS9C,WAAA,GAAc,WAAA;EATuC;EAWrD,SAAA;EAJqC;EAMrC,aAAA,EAAe,aAAA;AAAA;;;;KAML,oBAAA,IAAwB,GAAA,EAAK,sBAAA,KAA2B,MAAA;;;;KAKxD,aAAA,IACV,GAAA,EAAK,aAAA,EACL,MAAA,EAAQ,MAAA,sBACL,OAAA,CAAQ,YAAA;;;;UAKI,YAAA;EACf,OAAA;EACA,IAAA;EACA,OAAA;AAAA;AAXF;;;AAAA,UAiBiB,gBAAA;EAfP;EAiBR,IAAA;EAhBG;EAkBH,WAAA;EAlBU;EAoBV,SAAA;EAtBA;EAwBA,UAAA;EAvBA;EAyBA,QAAA;EAxBW;EA0BX,WAAA,GAAc,MAAA;EA1BS;EA4BvB,oBAAA,GAAuB,oBAAA;EAvBI;EAyB3B,OAAA,EAAS,aAAA;AAAA"}
1
+ {"version":3,"file":"types.d.mts","names":[],"sources":["../../src/actions/types.ts"],"mappings":";;;;;;;AAOA;UAAiB,aAAA;;EAEf,EAAA,EAAI,cAAA;EAEW;EAAf,aAAA,EAAe,aAAA;EAS+B;EAP9C,KAAA;EAOqD;EALrD,EAAA;EANI;EAQJ,GAAA,GAAM,MAAA;EANS;EAQf,MAAA;IACE,WAAA,CAAY,KAAA,UAAe,MAAA,WAAiB,OAAA;EAAA;AAAA;;;;UAO/B,sBAAA;EAP+B;EAS9C,WAAA,GAAc,WAAA;EATuC;EAWrD,SAAA;EAJqC;EAMrC,aAAA,EAAe,aAAA;AAAA;;;;KAML,oBAAA,IAAwB,GAAA,EAAK,sBAAA,KAA2B,MAAA;;;;KAKxD,aAAA,IACV,GAAA,EAAK,aAAA,EACL,MAAA,EAAQ,MAAA,sBACL,OAAA,CAAQ,YAAA;;;;;;aAOD,qBAAA;EAf8D;EAiBxE,aAAA;EAZU;EAcV,SAAA;;EAEA,oBAAA;AAAA;;;;UAMe,WAAA;EACf,IAAA,EAAM,qBAAA;EACN,OAAA;EACA,OAAA,GAAU,MAAA;AAAA;;;;UAMK,YAAA;EACf,OAAA;EACA,IAAA;EACA,OAAA;EACA,KAAA,GAAQ,WAAA;AAAA;AAbV;;;AAAA,UAiCiB,gBAAA;EAhCf;EAkCA,IAAA;EAjCA;EAmCA,WAAA;EAlCU;EAoCV,SAAA;EApCgB;EAsChB,UAAA;EAhC2B;EAkC3B,QAAA;EA9BmB;EAgCnB,WAAA,GAAc,MAAA;EAlCd;EAoCA,oBAAA,GAAuB,oBAAA;EAlCvB;EAoCA,OAAA,EAAS,aAAA;AAAA"}
@@ -0,0 +1,32 @@
1
+ //#region src/actions/types.ts
2
+ /**
3
+ * Error codes for SQLite actions
4
+ *
5
+ * Simplified to 3 core codes. Specific error types are distinguished via message.
6
+ */
7
+ let SQLiteActionErrorCode = /* @__PURE__ */ function(SQLiteActionErrorCode) {
8
+ /** Input parameters invalid (schema, type, format errors) */
9
+ SQLiteActionErrorCode[SQLiteActionErrorCode["INVALID_INPUT"] = 1001] = "INVALID_INPUT";
10
+ /** Table, column, index, or row not found */
11
+ SQLiteActionErrorCode[SQLiteActionErrorCode["NOT_FOUND"] = 2001] = "NOT_FOUND";
12
+ /** Constraint violation (unique, foreign key, not null, etc.) */
13
+ SQLiteActionErrorCode[SQLiteActionErrorCode["CONSTRAINT_VIOLATION"] = 3001] = "CONSTRAINT_VIOLATION";
14
+ return SQLiteActionErrorCode;
15
+ }({});
16
+ /**
17
+ * Helper to create an error result
18
+ */
19
+ function errorResult(code, message, details) {
20
+ return {
21
+ success: false,
22
+ error: {
23
+ code,
24
+ message,
25
+ details
26
+ }
27
+ };
28
+ }
29
+
30
+ //#endregion
31
+ export { SQLiteActionErrorCode, errorResult };
32
+ //# sourceMappingURL=types.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.mjs","names":[],"sources":["../../src/actions/types.ts"],"sourcesContent":["import type { LibSQLDatabase } from \"drizzle-orm/libsql\";\nimport type { SchemaService } from \"../schema/service.js\";\nimport type { TableSchema } from \"../schema/types.js\";\n\n/**\n * Context provided to action handlers\n */\nexport interface ActionContext {\n /** Database instance */\n db: LibSQLDatabase;\n /** Schema service for querying table schemas on-demand */\n schemaService: SchemaService;\n /** Table this action is being executed on */\n table: string;\n /** Primary key of the row (if row-level action) */\n pk?: string;\n /** The row data (if available) */\n row?: Record<string, unknown>;\n /** Reference to the parent module for advanced operations */\n module: {\n exportTable(table: string, format: string): Promise<unknown>;\n };\n}\n\n/**\n * Context for generating dynamic input schemas\n */\nexport interface SchemaGeneratorContext {\n /** Table schema (for table/row-level actions) */\n tableSchema?: TableSchema;\n /** Table name */\n tableName?: string;\n /** Schema service for querying schemas */\n schemaService: SchemaService;\n}\n\n/**\n * Function that generates input schema dynamically based on context\n */\nexport type InputSchemaGenerator = (ctx: SchemaGeneratorContext) => Record<string, unknown>;\n\n/**\n * Action handler function signature\n */\nexport type ActionHandler = (\n ctx: ActionContext,\n params: Record<string, unknown>,\n) => Promise<ActionResult>;\n\n/**\n * Error codes for SQLite actions\n *\n * Simplified to 3 core codes. Specific error types are distinguished via message.\n */\nexport enum SQLiteActionErrorCode {\n /** Input parameters invalid (schema, type, format errors) */\n INVALID_INPUT = 1001,\n /** Table, column, index, or row not found */\n NOT_FOUND = 2001,\n /** Constraint violation (unique, foreign key, not null, etc.) */\n CONSTRAINT_VIOLATION = 3001,\n}\n\n/**\n * Error details for failed actions\n */\nexport interface ActionError {\n code: SQLiteActionErrorCode;\n message: string;\n details?: Record<string, unknown>;\n}\n\n/**\n * Result from an action execution\n */\nexport interface ActionResult {\n success: boolean;\n data?: unknown;\n message?: string;\n error?: ActionError;\n}\n\n/**\n * Helper to create an error result\n */\nexport function errorResult(\n code: SQLiteActionErrorCode,\n message: string,\n details?: Record<string, unknown>,\n): ActionResult {\n return {\n success: false,\n error: { code, message, details },\n };\n}\n\n/**\n * Action definition with metadata\n */\nexport interface ActionDefinition {\n /** Action name */\n name: string;\n /** Description of what the action does */\n description?: string;\n /** Whether this action is available at root level (database operations) */\n rootLevel?: boolean;\n /** Whether this action is available at table level (vs row level) */\n tableLevel?: boolean;\n /** Whether this action is available at row level */\n rowLevel?: boolean;\n /** Static input schema for the action parameters */\n inputSchema?: Record<string, unknown>;\n /** Dynamic input schema generator (takes precedence over static inputSchema) */\n inputSchemaGenerator?: InputSchemaGenerator;\n /** The handler function */\n handler: ActionHandler;\n}\n"],"mappings":";;;;;;AAsDA,IAAY,wEAAL;;AAEL;;AAEA;;AAEA;;;;;;AAyBF,SAAgB,YACd,MACA,SACA,SACc;AACd,QAAO;EACL,SAAS;EACT,OAAO;GAAE;GAAM;GAAS;GAAS;EAClC"}
package/dist/index.cjs CHANGED
@@ -1,3 +1,4 @@
1
+ Object.defineProperty(exports, '__esModule', { value: true });
1
2
  const require_built_in = require('./actions/built-in.cjs');
2
3
  const require_registry = require('./actions/registry.cjs');
3
4
  const require_config = require('./config.cjs');
@@ -30,6 +31,7 @@ exports.buildTableEntry = require_builder.buildTableEntry;
30
31
  exports.buildUpdate = require_query_builder.buildUpdate;
31
32
  exports.createFTSConfig = require_search.createFTSConfig;
32
33
  exports.createPathRouter = require_path_router.createPathRouter;
34
+ exports.default = require_sqlite_afs.SQLiteAFS;
33
35
  exports.getVirtualPathType = require_path_router.getVirtualPathType;
34
36
  exports.isVirtualPath = require_path_router.isVirtualPath;
35
37
  exports.matchPath = require_path_router.matchPath;
package/dist/index.d.cts CHANGED
@@ -12,4 +12,4 @@ import { RouteAction, RouteData, RouteMatch, RouteParams } from "./router/types.
12
12
  import { buildPath, createPathRouter, getVirtualPathType, isVirtualPath, matchPath } from "./router/path-router.cjs";
13
13
  import { SchemaIntrospector } from "./schema/introspector.cjs";
14
14
  import { SQLiteAFS } from "./sqlite-afs.cjs";
15
- export { type ActionContext, type ActionDefinition, type ActionHandler, type ActionResult, ActionsRegistry, type BuildEntryOptions, CRUDOperations, type ColumnInfo, type FTSConfig, FTSSearch, type FTSTableConfig, type ForeignKeyInfo, type IndexInfo, type PragmaForeignKeyRow, type PragmaIndexListRow, type PragmaTableInfoRow, type RouteAction, type RouteData, type RouteMatch, type RouteParams, SQLiteAFS, type SQLiteAFSConfig, type SQLiteAFSOptions, type SchemaGeneratorContext, SchemaIntrospector, SchemaService, type SchemaServiceOptions, type TableSchema, buildActionsListEntry, buildDelete, buildGetLastRowId, buildInsert, buildMetaEntry, buildPath, buildRowEntry, buildSearchEntry, buildSelectAll, buildSelectByPK, buildTableEntry, buildUpdate, createFTSConfig, createPathRouter, getVirtualPathType, isVirtualPath, matchPath, registerBuiltInActions, sqliteAFSConfigSchema };
15
+ export { type ActionContext, type ActionDefinition, type ActionHandler, type ActionResult, ActionsRegistry, type BuildEntryOptions, CRUDOperations, type ColumnInfo, type FTSConfig, FTSSearch, type FTSTableConfig, type ForeignKeyInfo, type IndexInfo, type PragmaForeignKeyRow, type PragmaIndexListRow, type PragmaTableInfoRow, type RouteAction, type RouteData, type RouteMatch, type RouteParams, SQLiteAFS, type SQLiteAFSConfig, type SQLiteAFSOptions, type SchemaGeneratorContext, SchemaIntrospector, SchemaService, type SchemaServiceOptions, type TableSchema, buildActionsListEntry, buildDelete, buildGetLastRowId, buildInsert, buildMetaEntry, buildPath, buildRowEntry, buildSearchEntry, buildSelectAll, buildSelectByPK, buildTableEntry, buildUpdate, createFTSConfig, createPathRouter, SQLiteAFS as default, getVirtualPathType, isVirtualPath, matchPath, registerBuiltInActions, sqliteAFSConfigSchema };
package/dist/index.d.mts CHANGED
@@ -12,4 +12,4 @@ import { RouteAction, RouteData, RouteMatch, RouteParams } from "./router/types.
12
12
  import { buildPath, createPathRouter, getVirtualPathType, isVirtualPath, matchPath } from "./router/path-router.mjs";
13
13
  import { SchemaIntrospector } from "./schema/introspector.mjs";
14
14
  import { SQLiteAFS } from "./sqlite-afs.mjs";
15
- export { type ActionContext, type ActionDefinition, type ActionHandler, type ActionResult, ActionsRegistry, type BuildEntryOptions, CRUDOperations, type ColumnInfo, type FTSConfig, FTSSearch, type FTSTableConfig, type ForeignKeyInfo, type IndexInfo, type PragmaForeignKeyRow, type PragmaIndexListRow, type PragmaTableInfoRow, type RouteAction, type RouteData, type RouteMatch, type RouteParams, SQLiteAFS, type SQLiteAFSConfig, type SQLiteAFSOptions, type SchemaGeneratorContext, SchemaIntrospector, SchemaService, type SchemaServiceOptions, type TableSchema, buildActionsListEntry, buildDelete, buildGetLastRowId, buildInsert, buildMetaEntry, buildPath, buildRowEntry, buildSearchEntry, buildSelectAll, buildSelectByPK, buildTableEntry, buildUpdate, createFTSConfig, createPathRouter, getVirtualPathType, isVirtualPath, matchPath, registerBuiltInActions, sqliteAFSConfigSchema };
15
+ export { type ActionContext, type ActionDefinition, type ActionHandler, type ActionResult, ActionsRegistry, type BuildEntryOptions, CRUDOperations, type ColumnInfo, type FTSConfig, FTSSearch, type FTSTableConfig, type ForeignKeyInfo, type IndexInfo, type PragmaForeignKeyRow, type PragmaIndexListRow, type PragmaTableInfoRow, type RouteAction, type RouteData, type RouteMatch, type RouteParams, SQLiteAFS, type SQLiteAFSConfig, type SQLiteAFSOptions, type SchemaGeneratorContext, SchemaIntrospector, SchemaService, type SchemaServiceOptions, type TableSchema, buildActionsListEntry, buildDelete, buildGetLastRowId, buildInsert, buildMetaEntry, buildPath, buildRowEntry, buildSearchEntry, buildSelectAll, buildSelectByPK, buildTableEntry, buildUpdate, createFTSConfig, createPathRouter, SQLiteAFS as default, getVirtualPathType, isVirtualPath, matchPath, registerBuiltInActions, sqliteAFSConfigSchema };
package/dist/index.mjs CHANGED
@@ -10,4 +10,4 @@ import { SchemaIntrospector } from "./schema/introspector.mjs";
10
10
  import { SchemaService } from "./schema/service.mjs";
11
11
  import { SQLiteAFS } from "./sqlite-afs.mjs";
12
12
 
13
- export { ActionsRegistry, CRUDOperations, FTSSearch, SQLiteAFS, SchemaIntrospector, SchemaService, buildActionsListEntry, buildDelete, buildGetLastRowId, buildInsert, buildMetaEntry, buildPath, buildRowEntry, buildSearchEntry, buildSelectAll, buildSelectByPK, buildTableEntry, buildUpdate, createFTSConfig, createPathRouter, getVirtualPathType, isVirtualPath, matchPath, registerBuiltInActions, sqliteAFSConfigSchema };
13
+ export { ActionsRegistry, CRUDOperations, FTSSearch, SQLiteAFS, SchemaIntrospector, SchemaService, buildActionsListEntry, buildDelete, buildGetLastRowId, buildInsert, buildMetaEntry, buildPath, buildRowEntry, buildSearchEntry, buildSelectAll, buildSelectByPK, buildTableEntry, buildUpdate, createFTSConfig, createPathRouter, SQLiteAFS as default, getVirtualPathType, isVirtualPath, matchPath, registerBuiltInActions, sqliteAFSConfigSchema };
@@ -11,7 +11,8 @@ function buildRowEntry(table, schema, row, options) {
11
11
  id: `${table}:${pk}`,
12
12
  path: `${basePath}/${table}/${pk}`,
13
13
  content: row,
14
- metadata: {
14
+ meta: {
15
+ kind: "sqlite:row",
15
16
  table,
16
17
  primaryKey: pkColumn,
17
18
  primaryKeyValue: pk
@@ -27,12 +28,13 @@ function buildTableEntry(table, schema, options) {
27
28
  return {
28
29
  id: table,
29
30
  path: `${options?.basePath ?? ""}/${table}`,
30
- metadata: {
31
+ meta: {
32
+ kind: "sqlite:table",
31
33
  description: `Table: ${table} (${schema.columns.length} columns)`,
32
34
  table,
33
35
  columnCount: schema.columns.length,
34
36
  primaryKey: schema.primaryKey,
35
- childrenCount: options?.rowCount
37
+ childrenCount: options?.rowCount || -1
36
38
  }
37
39
  };
38
40
  }
@@ -55,7 +57,7 @@ function buildMetaEntry(table, schema, pk, row, options) {
55
57
  foreignKeys: schema.foreignKeys.filter((fk) => Object.keys(row).includes(fk.from)),
56
58
  rowid: row.rowid
57
59
  },
58
- metadata: {
60
+ meta: {
59
61
  table,
60
62
  type: "meta"
61
63
  }
@@ -70,7 +72,7 @@ function buildActionsListEntry(table, pk, actions, options) {
70
72
  id: `${table}:${pk}:.actions:${action.name}`,
71
73
  path: `${basePath}/${table}/${pk}/.actions/${action.name}`,
72
74
  summary: action.name,
73
- metadata: {
75
+ meta: {
74
76
  kind: "afs:executable",
75
77
  kinds: ["afs:executable", "afs:node"],
76
78
  name: action.name,
@@ -88,7 +90,7 @@ function buildTableActionsListEntry(table, actions, options) {
88
90
  id: `${table}:.actions:${action.name}`,
89
91
  path: `${basePath}/${table}/.actions/${action.name}`,
90
92
  summary: action.name,
91
- metadata: {
93
+ meta: {
92
94
  kind: "afs:executable",
93
95
  kinds: ["afs:executable", "afs:node"],
94
96
  name: action.name,
@@ -106,7 +108,7 @@ function buildRootActionsListEntry(actions, options) {
106
108
  id: `:actions:${action.name}`,
107
109
  path: `${basePath}/.actions/${action.name}`,
108
110
  summary: action.name,
109
- metadata: {
111
+ meta: {
110
112
  kind: "afs:executable",
111
113
  kinds: ["afs:executable", "afs:node"],
112
114
  name: action.name,
@@ -131,7 +133,8 @@ function buildRootEntry(schemas, options) {
131
133
  return {
132
134
  id: "root",
133
135
  path: basePath === "" ? "/" : basePath,
134
- metadata: {
136
+ meta: {
137
+ kind: "sqlite:database",
135
138
  description: "SQLite database root",
136
139
  childrenCount: schemas.size,
137
140
  tableCount: schemas.size
@@ -1 +1 @@
1
- {"version":3,"file":"builder.d.cts","names":[],"sources":["../../src/node/builder.ts"],"mappings":";;;;;;AAMA;UAAiB,iBAAA;;EAEf,QAAA;AAAA;AAMF;;;AAAA,iBAAgB,aAAA,CACd,KAAA,UACA,MAAA,EAAQ,WAAA,EACR,GAAA,EAAK,MAAA,mBACL,OAAA,GAAU,iBAAA,GACT,QAAA;;;;iBAsBa,eAAA,CACd,KAAA,UACA,MAAA,EAAQ,WAAA,EACR,OAAA,GAAU,iBAAA;EAAsB,QAAA;AAAA,IAC/B,QAAA;;;;iBAmBa,cAAA,CACd,KAAA,UACA,MAAA,EAAQ,WAAA,EACR,EAAA,UACA,GAAA,EAAK,MAAA,mBACL,OAAA,GAAU,iBAAA,GACT,QAAA;;AA7BH;;UAiFiB,oBAAA;EACf,IAAA;EACA,WAAA;EACA,WAAA,GAAc,MAAA;AAAA;;;;iBAMA,qBAAA,CACd,KAAA,UACA,EAAA,UACA,OAAA,EAAS,oBAAA,IACT,OAAA,GAAU,iBAAA,GACT,QAAA;;;;iBAmEa,gBAAA,CACd,KAAA,UACA,MAAA,EAAQ,WAAA,EACR,GAAA,EAAK,MAAA,mBACL,OAAA,WACA,OAAA,GAAU,iBAAA,GACT,QAAA"}
1
+ {"version":3,"file":"builder.d.cts","names":[],"sources":["../../src/node/builder.ts"],"mappings":";;;;;;AAMA;UAAiB,iBAAA;;EAEf,QAAA;AAAA;AAMF;;;AAAA,iBAAgB,aAAA,CACd,KAAA,UACA,MAAA,EAAQ,WAAA,EACR,GAAA,EAAK,MAAA,mBACL,OAAA,GAAU,iBAAA,GACT,QAAA;;;;iBAuBa,eAAA,CACd,KAAA,UACA,MAAA,EAAQ,WAAA,EACR,OAAA,GAAU,iBAAA;EAAsB,QAAA;AAAA,IAC/B,QAAA;;;;iBAoBa,cAAA,CACd,KAAA,UACA,MAAA,EAAQ,WAAA,EACR,EAAA,UACA,GAAA,EAAK,MAAA,mBACL,OAAA,GAAU,iBAAA,GACT,QAAA;;AA9BH;;UAkFiB,oBAAA;EACf,IAAA;EACA,WAAA;EACA,WAAA,GAAc,MAAA;AAAA;;;;iBAMA,qBAAA,CACd,KAAA,UACA,EAAA,UACA,OAAA,EAAS,oBAAA,IACT,OAAA,GAAU,iBAAA,GACT,QAAA;;;;iBAmEa,gBAAA,CACd,KAAA,UACA,MAAA,EAAQ,WAAA,EACR,GAAA,EAAK,MAAA,mBACL,OAAA,WACA,OAAA,GAAU,iBAAA,GACT,QAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"builder.d.mts","names":[],"sources":["../../src/node/builder.ts"],"mappings":";;;;;;AAMA;UAAiB,iBAAA;;EAEf,QAAA;AAAA;AAMF;;;AAAA,iBAAgB,aAAA,CACd,KAAA,UACA,MAAA,EAAQ,WAAA,EACR,GAAA,EAAK,MAAA,mBACL,OAAA,GAAU,iBAAA,GACT,QAAA;;;;iBAsBa,eAAA,CACd,KAAA,UACA,MAAA,EAAQ,WAAA,EACR,OAAA,GAAU,iBAAA;EAAsB,QAAA;AAAA,IAC/B,QAAA;;;;iBAmBa,cAAA,CACd,KAAA,UACA,MAAA,EAAQ,WAAA,EACR,EAAA,UACA,GAAA,EAAK,MAAA,mBACL,OAAA,GAAU,iBAAA,GACT,QAAA;;AA7BH;;UAiFiB,oBAAA;EACf,IAAA;EACA,WAAA;EACA,WAAA,GAAc,MAAA;AAAA;;;;iBAMA,qBAAA,CACd,KAAA,UACA,EAAA,UACA,OAAA,EAAS,oBAAA,IACT,OAAA,GAAU,iBAAA,GACT,QAAA;;;;iBAmEa,gBAAA,CACd,KAAA,UACA,MAAA,EAAQ,WAAA,EACR,GAAA,EAAK,MAAA,mBACL,OAAA,WACA,OAAA,GAAU,iBAAA,GACT,QAAA"}
1
+ {"version":3,"file":"builder.d.mts","names":[],"sources":["../../src/node/builder.ts"],"mappings":";;;;;;AAMA;UAAiB,iBAAA;;EAEf,QAAA;AAAA;AAMF;;;AAAA,iBAAgB,aAAA,CACd,KAAA,UACA,MAAA,EAAQ,WAAA,EACR,GAAA,EAAK,MAAA,mBACL,OAAA,GAAU,iBAAA,GACT,QAAA;;;;iBAuBa,eAAA,CACd,KAAA,UACA,MAAA,EAAQ,WAAA,EACR,OAAA,GAAU,iBAAA;EAAsB,QAAA;AAAA,IAC/B,QAAA;;;;iBAoBa,cAAA,CACd,KAAA,UACA,MAAA,EAAQ,WAAA,EACR,EAAA,UACA,GAAA,EAAK,MAAA,mBACL,OAAA,GAAU,iBAAA,GACT,QAAA;;AA9BH;;UAkFiB,oBAAA;EACf,IAAA;EACA,WAAA;EACA,WAAA,GAAc,MAAA;AAAA;;;;iBAMA,qBAAA,CACd,KAAA,UACA,EAAA,UACA,OAAA,EAAS,oBAAA,IACT,OAAA,GAAU,iBAAA,GACT,QAAA;;;;iBAmEa,gBAAA,CACd,KAAA,UACA,MAAA,EAAQ,WAAA,EACR,GAAA,EAAK,MAAA,mBACL,OAAA,WACA,OAAA,GAAU,iBAAA,GACT,QAAA"}
@@ -10,7 +10,8 @@ function buildRowEntry(table, schema, row, options) {
10
10
  id: `${table}:${pk}`,
11
11
  path: `${basePath}/${table}/${pk}`,
12
12
  content: row,
13
- metadata: {
13
+ meta: {
14
+ kind: "sqlite:row",
14
15
  table,
15
16
  primaryKey: pkColumn,
16
17
  primaryKeyValue: pk
@@ -26,12 +27,13 @@ function buildTableEntry(table, schema, options) {
26
27
  return {
27
28
  id: table,
28
29
  path: `${options?.basePath ?? ""}/${table}`,
29
- metadata: {
30
+ meta: {
31
+ kind: "sqlite:table",
30
32
  description: `Table: ${table} (${schema.columns.length} columns)`,
31
33
  table,
32
34
  columnCount: schema.columns.length,
33
35
  primaryKey: schema.primaryKey,
34
- childrenCount: options?.rowCount
36
+ childrenCount: options?.rowCount || -1
35
37
  }
36
38
  };
37
39
  }
@@ -54,7 +56,7 @@ function buildMetaEntry(table, schema, pk, row, options) {
54
56
  foreignKeys: schema.foreignKeys.filter((fk) => Object.keys(row).includes(fk.from)),
55
57
  rowid: row.rowid
56
58
  },
57
- metadata: {
59
+ meta: {
58
60
  table,
59
61
  type: "meta"
60
62
  }
@@ -69,7 +71,7 @@ function buildActionsListEntry(table, pk, actions, options) {
69
71
  id: `${table}:${pk}:.actions:${action.name}`,
70
72
  path: `${basePath}/${table}/${pk}/.actions/${action.name}`,
71
73
  summary: action.name,
72
- metadata: {
74
+ meta: {
73
75
  kind: "afs:executable",
74
76
  kinds: ["afs:executable", "afs:node"],
75
77
  name: action.name,
@@ -87,7 +89,7 @@ function buildTableActionsListEntry(table, actions, options) {
87
89
  id: `${table}:.actions:${action.name}`,
88
90
  path: `${basePath}/${table}/.actions/${action.name}`,
89
91
  summary: action.name,
90
- metadata: {
92
+ meta: {
91
93
  kind: "afs:executable",
92
94
  kinds: ["afs:executable", "afs:node"],
93
95
  name: action.name,
@@ -105,7 +107,7 @@ function buildRootActionsListEntry(actions, options) {
105
107
  id: `:actions:${action.name}`,
106
108
  path: `${basePath}/.actions/${action.name}`,
107
109
  summary: action.name,
108
- metadata: {
110
+ meta: {
109
111
  kind: "afs:executable",
110
112
  kinds: ["afs:executable", "afs:node"],
111
113
  name: action.name,
@@ -130,7 +132,8 @@ function buildRootEntry(schemas, options) {
130
132
  return {
131
133
  id: "root",
132
134
  path: basePath === "" ? "/" : basePath,
133
- metadata: {
135
+ meta: {
136
+ kind: "sqlite:database",
134
137
  description: "SQLite database root",
135
138
  childrenCount: schemas.size,
136
139
  tableCount: schemas.size
@@ -1 +1 @@
1
- {"version":3,"file":"builder.mjs","names":[],"sources":["../../src/node/builder.ts"],"sourcesContent":["import type { AFSEntry } from \"@aigne/afs\";\nimport type { TableSchema } from \"../schema/types.js\";\n\n/**\n * Options for building an AFSEntry\n */\nexport interface BuildEntryOptions {\n /** Base path prefix (e.g., empty string or module mount path) */\n basePath?: string;\n}\n\n/**\n * Builds an AFSEntry from a database row\n */\nexport function buildRowEntry(\n table: string,\n schema: TableSchema,\n row: Record<string, unknown>,\n options?: BuildEntryOptions,\n): AFSEntry {\n const pkColumn = schema.primaryKey[0] ?? \"rowid\";\n const pk = String(row[pkColumn] ?? row.rowid);\n const basePath = options?.basePath ?? \"\";\n\n return {\n id: `${table}:${pk}`,\n path: `${basePath}/${table}/${pk}`,\n content: row,\n metadata: {\n table,\n primaryKey: pkColumn,\n primaryKeyValue: pk,\n },\n createdAt: parseDate(row.created_at ?? row.createdAt),\n updatedAt: parseDate(row.updated_at ?? row.updatedAt),\n };\n}\n\n/**\n * Builds an AFSEntry for a table listing\n */\nexport function buildTableEntry(\n table: string,\n schema: TableSchema,\n options?: BuildEntryOptions & { rowCount?: number },\n): AFSEntry {\n const basePath = options?.basePath ?? \"\";\n\n return {\n id: table,\n path: `${basePath}/${table}`,\n metadata: {\n description: `Table: ${table} (${schema.columns.length} columns)`,\n table,\n columnCount: schema.columns.length,\n primaryKey: schema.primaryKey,\n childrenCount: options?.rowCount,\n },\n };\n}\n\n/**\n * Builds an AFSEntry for row metadata (using @meta suffix)\n */\nexport function buildMetaEntry(\n table: string,\n schema: TableSchema,\n pk: string,\n row: Record<string, unknown>,\n options?: BuildEntryOptions,\n): AFSEntry {\n const basePath = options?.basePath ?? \"\";\n\n return {\n id: `${table}:${pk}:@meta`,\n path: `${basePath}/${table}/${pk}/@meta`,\n content: {\n table,\n primaryKey: schema.primaryKey[0] ?? \"rowid\",\n primaryKeyValue: pk,\n schema: {\n columns: schema.columns.map((c) => c.name),\n types: Object.fromEntries(schema.columns.map((c) => [c.name, c.type])),\n },\n foreignKeys: schema.foreignKeys.filter((fk) => Object.keys(row).includes(fk.from)),\n rowid: row.rowid,\n },\n metadata: {\n table,\n type: \"meta\",\n },\n };\n}\n\n/**\n * Builds an AFSEntry for row metadata (using .meta suffix - conformance standard)\n */\nexport function buildRowDotMetaEntry(\n table: string,\n schema: TableSchema,\n pk: string,\n _row: Record<string, unknown>,\n options?: BuildEntryOptions,\n): AFSEntry {\n const basePath = options?.basePath ?? \"\";\n\n return {\n id: `${table}:${pk}:.meta`,\n path: `${basePath}/${table}/${pk}/.meta`,\n metadata: {\n table,\n primaryKey: schema.primaryKey[0] ?? \"rowid\",\n primaryKeyValue: pk,\n columnCount: schema.columns.length,\n columns: schema.columns.map((c) => c.name),\n },\n };\n}\n\n/**\n * Action definition with optional schema\n */\nexport interface ActionDefinitionInfo {\n name: string;\n description?: string;\n inputSchema?: Record<string, unknown>;\n}\n\n/**\n * Builds AFSEntry for row-level actions list\n */\nexport function buildActionsListEntry(\n table: string,\n pk: string,\n actions: ActionDefinitionInfo[],\n options?: BuildEntryOptions,\n): AFSEntry[] {\n const basePath = options?.basePath ?? \"\";\n\n return actions.map((action) => ({\n id: `${table}:${pk}:.actions:${action.name}`,\n path: `${basePath}/${table}/${pk}/.actions/${action.name}`,\n summary: action.name,\n metadata: {\n kind: \"afs:executable\",\n kinds: [\"afs:executable\", \"afs:node\"],\n name: action.name,\n description: action.description ?? `Execute ${action.name} action on ${table}:${pk}`,\n inputSchema: action.inputSchema,\n },\n }));\n}\n\n/**\n * Builds AFSEntry for table-level actions list\n */\nexport function buildTableActionsListEntry(\n table: string,\n actions: ActionDefinitionInfo[],\n options?: BuildEntryOptions,\n): AFSEntry[] {\n const basePath = options?.basePath ?? \"\";\n\n return actions.map((action) => ({\n id: `${table}:.actions:${action.name}`,\n path: `${basePath}/${table}/.actions/${action.name}`,\n summary: action.name,\n metadata: {\n kind: \"afs:executable\",\n kinds: [\"afs:executable\", \"afs:node\"],\n name: action.name,\n description: action.description ?? `Execute ${action.name} action on table ${table}`,\n inputSchema: action.inputSchema,\n },\n }));\n}\n\n/**\n * Builds AFSEntry for root-level actions list\n */\nexport function buildRootActionsListEntry(\n actions: ActionDefinitionInfo[],\n options?: BuildEntryOptions,\n): AFSEntry[] {\n const basePath = options?.basePath ?? \"\";\n\n return actions.map((action) => ({\n id: `:actions:${action.name}`,\n path: `${basePath}/.actions/${action.name}`,\n summary: action.name,\n metadata: {\n kind: \"afs:executable\",\n kinds: [\"afs:executable\", \"afs:node\"],\n name: action.name,\n description: action.description ?? `Execute ${action.name} action`,\n inputSchema: action.inputSchema,\n },\n }));\n}\n\n/**\n * Builds a search result entry with highlights\n */\nexport function buildSearchEntry(\n table: string,\n schema: TableSchema,\n row: Record<string, unknown>,\n snippet?: string,\n options?: BuildEntryOptions,\n): AFSEntry {\n const entry = buildRowEntry(table, schema, row, options);\n\n if (snippet) {\n entry.summary = snippet;\n }\n\n return entry;\n}\n\n/**\n * Builds an AFSEntry for the root (database)\n */\nexport function buildRootEntry(\n schemas: Map<string, TableSchema>,\n options?: BuildEntryOptions,\n): AFSEntry {\n const basePath = options?.basePath ?? \"\";\n\n return {\n id: \"root\",\n path: basePath === \"\" ? \"/\" : basePath,\n metadata: {\n description: \"SQLite database root\",\n childrenCount: schemas.size,\n tableCount: schemas.size,\n },\n };\n}\n\n/**\n * Builds an AFSEntry for root metadata\n */\nexport function buildRootMetaEntry(\n schemas: Map<string, TableSchema>,\n options?: BuildEntryOptions,\n): AFSEntry {\n const basePath = options?.basePath ?? \"\";\n\n return {\n id: \"root:meta\",\n path: `${basePath}/.meta`,\n metadata: {\n description: \"SQLite database metadata\",\n tableCount: schemas.size,\n tables: Array.from(schemas.keys()),\n },\n };\n}\n\n/**\n * Builds an AFSEntry for table metadata (directory-level, not row-level)\n */\nexport function buildTableMetaEntry(\n table: string,\n schema: TableSchema,\n options?: BuildEntryOptions & { rowCount?: number },\n): AFSEntry {\n const basePath = options?.basePath ?? \"\";\n\n return {\n id: `${table}:meta`,\n path: `${basePath}/${table}/.meta`,\n metadata: {\n description: `Table metadata for: ${table}`,\n table,\n columnCount: schema.columns.length,\n primaryKey: schema.primaryKey,\n columns: schema.columns.map((c) => c.name),\n rowCount: options?.rowCount,\n },\n };\n}\n\n/**\n * Parses a date from various formats\n */\nfunction parseDate(value: unknown): Date | undefined {\n if (!value) return undefined;\n if (value instanceof Date) return value;\n if (typeof value === \"string\") return new Date(value);\n if (typeof value === \"number\") return new Date(value);\n return undefined;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"builder.mjs","names":[],"sources":["../../src/node/builder.ts"],"sourcesContent":["import type { AFSEntry } from \"@aigne/afs\";\nimport type { TableSchema } from \"../schema/types.js\";\n\n/**\n * Options for building an AFSEntry\n */\nexport interface BuildEntryOptions {\n /** Base path prefix (e.g., empty string or module mount path) */\n basePath?: string;\n}\n\n/**\n * Builds an AFSEntry from a database row\n */\nexport function buildRowEntry(\n table: string,\n schema: TableSchema,\n row: Record<string, unknown>,\n options?: BuildEntryOptions,\n): AFSEntry {\n const pkColumn = schema.primaryKey[0] ?? \"rowid\";\n const pk = String(row[pkColumn] ?? row.rowid);\n const basePath = options?.basePath ?? \"\";\n\n return {\n id: `${table}:${pk}`,\n path: `${basePath}/${table}/${pk}`,\n content: row,\n meta: {\n kind: \"sqlite:row\",\n table,\n primaryKey: pkColumn,\n primaryKeyValue: pk,\n },\n createdAt: parseDate(row.created_at ?? row.createdAt),\n updatedAt: parseDate(row.updated_at ?? row.updatedAt),\n };\n}\n\n/**\n * Builds an AFSEntry for a table listing\n */\nexport function buildTableEntry(\n table: string,\n schema: TableSchema,\n options?: BuildEntryOptions & { rowCount?: number },\n): AFSEntry {\n const basePath = options?.basePath ?? \"\";\n\n return {\n id: table,\n path: `${basePath}/${table}`,\n meta: {\n kind: \"sqlite:table\",\n description: `Table: ${table} (${schema.columns.length} columns)`,\n table,\n columnCount: schema.columns.length,\n primaryKey: schema.primaryKey,\n childrenCount: options?.rowCount || -1,\n },\n };\n}\n\n/**\n * Builds an AFSEntry for row metadata (using @meta suffix)\n */\nexport function buildMetaEntry(\n table: string,\n schema: TableSchema,\n pk: string,\n row: Record<string, unknown>,\n options?: BuildEntryOptions,\n): AFSEntry {\n const basePath = options?.basePath ?? \"\";\n\n return {\n id: `${table}:${pk}:@meta`,\n path: `${basePath}/${table}/${pk}/@meta`,\n content: {\n table,\n primaryKey: schema.primaryKey[0] ?? \"rowid\",\n primaryKeyValue: pk,\n schema: {\n columns: schema.columns.map((c) => c.name),\n types: Object.fromEntries(schema.columns.map((c) => [c.name, c.type])),\n },\n foreignKeys: schema.foreignKeys.filter((fk) => Object.keys(row).includes(fk.from)),\n rowid: row.rowid,\n },\n meta: {\n table,\n type: \"meta\",\n },\n };\n}\n\n/**\n * Builds an AFSEntry for row metadata (using .meta suffix - conformance standard)\n */\nexport function buildRowDotMetaEntry(\n table: string,\n schema: TableSchema,\n pk: string,\n _row: Record<string, unknown>,\n options?: BuildEntryOptions,\n): AFSEntry {\n const basePath = options?.basePath ?? \"\";\n\n return {\n id: `${table}:${pk}:.meta`,\n path: `${basePath}/${table}/${pk}/.meta`,\n meta: {\n table,\n primaryKey: schema.primaryKey[0] ?? \"rowid\",\n primaryKeyValue: pk,\n columnCount: schema.columns.length,\n columns: schema.columns.map((c) => c.name),\n },\n };\n}\n\n/**\n * Action definition with optional schema\n */\nexport interface ActionDefinitionInfo {\n name: string;\n description?: string;\n inputSchema?: Record<string, unknown>;\n}\n\n/**\n * Builds AFSEntry for row-level actions list\n */\nexport function buildActionsListEntry(\n table: string,\n pk: string,\n actions: ActionDefinitionInfo[],\n options?: BuildEntryOptions,\n): AFSEntry[] {\n const basePath = options?.basePath ?? \"\";\n\n return actions.map((action) => ({\n id: `${table}:${pk}:.actions:${action.name}`,\n path: `${basePath}/${table}/${pk}/.actions/${action.name}`,\n summary: action.name,\n meta: {\n kind: \"afs:executable\",\n kinds: [\"afs:executable\", \"afs:node\"],\n name: action.name,\n description: action.description ?? `Execute ${action.name} action on ${table}:${pk}`,\n inputSchema: action.inputSchema,\n },\n }));\n}\n\n/**\n * Builds AFSEntry for table-level actions list\n */\nexport function buildTableActionsListEntry(\n table: string,\n actions: ActionDefinitionInfo[],\n options?: BuildEntryOptions,\n): AFSEntry[] {\n const basePath = options?.basePath ?? \"\";\n\n return actions.map((action) => ({\n id: `${table}:.actions:${action.name}`,\n path: `${basePath}/${table}/.actions/${action.name}`,\n summary: action.name,\n meta: {\n kind: \"afs:executable\",\n kinds: [\"afs:executable\", \"afs:node\"],\n name: action.name,\n description: action.description ?? `Execute ${action.name} action on table ${table}`,\n inputSchema: action.inputSchema,\n },\n }));\n}\n\n/**\n * Builds AFSEntry for root-level actions list\n */\nexport function buildRootActionsListEntry(\n actions: ActionDefinitionInfo[],\n options?: BuildEntryOptions,\n): AFSEntry[] {\n const basePath = options?.basePath ?? \"\";\n\n return actions.map((action) => ({\n id: `:actions:${action.name}`,\n path: `${basePath}/.actions/${action.name}`,\n summary: action.name,\n meta: {\n kind: \"afs:executable\",\n kinds: [\"afs:executable\", \"afs:node\"],\n name: action.name,\n description: action.description ?? `Execute ${action.name} action`,\n inputSchema: action.inputSchema,\n },\n }));\n}\n\n/**\n * Builds a search result entry with highlights\n */\nexport function buildSearchEntry(\n table: string,\n schema: TableSchema,\n row: Record<string, unknown>,\n snippet?: string,\n options?: BuildEntryOptions,\n): AFSEntry {\n const entry = buildRowEntry(table, schema, row, options);\n\n if (snippet) {\n entry.summary = snippet;\n }\n\n return entry;\n}\n\n/**\n * Builds an AFSEntry for the root (database)\n */\nexport function buildRootEntry(\n schemas: Map<string, TableSchema>,\n options?: BuildEntryOptions,\n): AFSEntry {\n const basePath = options?.basePath ?? \"\";\n\n return {\n id: \"root\",\n path: basePath === \"\" ? \"/\" : basePath,\n meta: {\n kind: \"sqlite:database\",\n description: \"SQLite database root\",\n childrenCount: schemas.size,\n tableCount: schemas.size,\n },\n };\n}\n\n/**\n * Builds an AFSEntry for root metadata\n */\nexport function buildRootMetaEntry(\n schemas: Map<string, TableSchema>,\n options?: BuildEntryOptions,\n): AFSEntry {\n const basePath = options?.basePath ?? \"\";\n\n return {\n id: \"root:meta\",\n path: `${basePath}/.meta`,\n meta: {\n description: \"SQLite database metadata\",\n tableCount: schemas.size,\n tables: Array.from(schemas.keys()),\n },\n };\n}\n\n/**\n * Builds an AFSEntry for table metadata (directory-level, not row-level)\n */\nexport function buildTableMetaEntry(\n table: string,\n schema: TableSchema,\n options?: BuildEntryOptions & { rowCount?: number },\n): AFSEntry {\n const basePath = options?.basePath ?? \"\";\n\n return {\n id: `${table}:meta`,\n path: `${basePath}/${table}/.meta`,\n meta: {\n description: `Table metadata for: ${table}`,\n table,\n columnCount: schema.columns.length,\n primaryKey: schema.primaryKey,\n columns: schema.columns.map((c) => c.name),\n rowCount: options?.rowCount,\n },\n };\n}\n\n/**\n * Parses a date from various formats\n */\nfunction parseDate(value: unknown): Date | undefined {\n if (!value) return undefined;\n if (value instanceof Date) return value;\n if (typeof value === \"string\") return new Date(value);\n if (typeof value === \"number\") return new Date(value);\n return undefined;\n}\n"],"mappings":"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"}
@@ -4,13 +4,13 @@
4
4
  * Builds a SELECT query string for a single row by primary key
5
5
  */
6
6
  function buildSelectByPK(tableName, schema, pk) {
7
- return `SELECT * FROM "${tableName}" WHERE "${schema.primaryKey[0] ?? "rowid"}" = '${escapeSQLString(pk)}'`;
7
+ return `SELECT rowid, * FROM "${tableName}" WHERE "${schema.primaryKey[0] ?? "rowid"}" = '${escapeSQLString(pk)}'`;
8
8
  }
9
9
  /**
10
10
  * Builds a SELECT query string for listing rows with optional limit and offset
11
11
  */
12
12
  function buildSelectAll(tableName, options) {
13
- let query = `SELECT * FROM "${tableName}"`;
13
+ let query = `SELECT rowid, * FROM "${tableName}"`;
14
14
  if (options?.orderBy?.length) {
15
15
  const orderClauses = options.orderBy.map(([col, dir]) => `"${col}" ${dir.toUpperCase()}`);
16
16
  query += ` ORDER BY ${orderClauses.join(", ")}`;
@@ -1 +1 @@
1
- {"version":3,"file":"query-builder.d.cts","names":[],"sources":["../../src/operations/query-builder.ts"],"mappings":";;;;;AAKA;iBAAgB,eAAA,CAAgB,SAAA,UAAmB,MAAA,EAAQ,WAAA,EAAa,EAAA;;;;iBAQxD,cAAA,CACd,SAAA,UACA,OAAA;EACE,KAAA;EACA,MAAA;EACA,OAAA;AAAA;AALJ;;;AAAA,iBA6BgB,WAAA,CACd,SAAA,UACA,MAAA,EAAQ,WAAA,EACR,OAAA,EAAS,MAAA;;;;iBAmBK,WAAA,CACd,SAAA,UACA,MAAA,EAAQ,WAAA,EACR,EAAA,UACA,OAAA,EAAS,MAAA;;;;iBAsBK,WAAA,CAAY,SAAA,UAAmB,MAAA,EAAQ,WAAA,EAAa,EAAA;;;AA1BpE;iBAoEgB,iBAAA,CAAA"}
1
+ {"version":3,"file":"query-builder.d.cts","names":[],"sources":["../../src/operations/query-builder.ts"],"mappings":";;;;;AAKA;iBAAgB,eAAA,CAAgB,SAAA,UAAmB,MAAA,EAAQ,WAAA,EAAa,EAAA;;;;iBASxD,cAAA,CACd,SAAA,UACA,OAAA;EACE,KAAA;EACA,MAAA;EACA,OAAA;AAAA;AALJ;;;AAAA,iBA8BgB,WAAA,CACd,SAAA,UACA,MAAA,EAAQ,WAAA,EACR,OAAA,EAAS,MAAA;;;;iBAmBK,WAAA,CACd,SAAA,UACA,MAAA,EAAQ,WAAA,EACR,EAAA,UACA,OAAA,EAAS,MAAA;;;;iBAsBK,WAAA,CAAY,SAAA,UAAmB,MAAA,EAAQ,WAAA,EAAa,EAAA;;;AA1BpE;iBAoEgB,iBAAA,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"query-builder.d.mts","names":[],"sources":["../../src/operations/query-builder.ts"],"mappings":";;;;;AAKA;iBAAgB,eAAA,CAAgB,SAAA,UAAmB,MAAA,EAAQ,WAAA,EAAa,EAAA;;;;iBAQxD,cAAA,CACd,SAAA,UACA,OAAA;EACE,KAAA;EACA,MAAA;EACA,OAAA;AAAA;AALJ;;;AAAA,iBA6BgB,WAAA,CACd,SAAA,UACA,MAAA,EAAQ,WAAA,EACR,OAAA,EAAS,MAAA;;;;iBAmBK,WAAA,CACd,SAAA,UACA,MAAA,EAAQ,WAAA,EACR,EAAA,UACA,OAAA,EAAS,MAAA;;;;iBAsBK,WAAA,CAAY,SAAA,UAAmB,MAAA,EAAQ,WAAA,EAAa,EAAA;;;AA1BpE;iBAoEgB,iBAAA,CAAA"}
1
+ {"version":3,"file":"query-builder.d.mts","names":[],"sources":["../../src/operations/query-builder.ts"],"mappings":";;;;;AAKA;iBAAgB,eAAA,CAAgB,SAAA,UAAmB,MAAA,EAAQ,WAAA,EAAa,EAAA;;;;iBASxD,cAAA,CACd,SAAA,UACA,OAAA;EACE,KAAA;EACA,MAAA;EACA,OAAA;AAAA;AALJ;;;AAAA,iBA8BgB,WAAA,CACd,SAAA,UACA,MAAA,EAAQ,WAAA,EACR,OAAA,EAAS,MAAA;;;;iBAmBK,WAAA,CACd,SAAA,UACA,MAAA,EAAQ,WAAA,EACR,EAAA,UACA,OAAA,EAAS,MAAA;;;;iBAsBK,WAAA,CAAY,SAAA,UAAmB,MAAA,EAAQ,WAAA,EAAa,EAAA;;;AA1BpE;iBAoEgB,iBAAA,CAAA"}
@@ -3,13 +3,13 @@
3
3
  * Builds a SELECT query string for a single row by primary key
4
4
  */
5
5
  function buildSelectByPK(tableName, schema, pk) {
6
- return `SELECT * FROM "${tableName}" WHERE "${schema.primaryKey[0] ?? "rowid"}" = '${escapeSQLString(pk)}'`;
6
+ return `SELECT rowid, * FROM "${tableName}" WHERE "${schema.primaryKey[0] ?? "rowid"}" = '${escapeSQLString(pk)}'`;
7
7
  }
8
8
  /**
9
9
  * Builds a SELECT query string for listing rows with optional limit and offset
10
10
  */
11
11
  function buildSelectAll(tableName, options) {
12
- let query = `SELECT * FROM "${tableName}"`;
12
+ let query = `SELECT rowid, * FROM "${tableName}"`;
13
13
  if (options?.orderBy?.length) {
14
14
  const orderClauses = options.orderBy.map(([col, dir]) => `"${col}" ${dir.toUpperCase()}`);
15
15
  query += ` ORDER BY ${orderClauses.join(", ")}`;
@@ -1 +1 @@
1
- {"version":3,"file":"query-builder.mjs","names":[],"sources":["../../src/operations/query-builder.ts"],"sourcesContent":["import type { TableSchema } from \"../schema/types.js\";\n\n/**\n * Builds a SELECT query string for a single row by primary key\n */\nexport function buildSelectByPK(tableName: string, schema: TableSchema, pk: string): string {\n const pkColumn = schema.primaryKey[0] ?? \"rowid\";\n return `SELECT * FROM \"${tableName}\" WHERE \"${pkColumn}\" = '${escapeSQLString(pk)}'`;\n}\n\n/**\n * Builds a SELECT query string for listing rows with optional limit and offset\n */\nexport function buildSelectAll(\n tableName: string,\n options?: {\n limit?: number;\n offset?: number;\n orderBy?: [string, \"asc\" | \"desc\"][];\n },\n): string {\n let query = `SELECT * FROM \"${tableName}\"`;\n\n if (options?.orderBy?.length) {\n const orderClauses = options.orderBy.map(([col, dir]) => `\"${col}\" ${dir.toUpperCase()}`);\n query += ` ORDER BY ${orderClauses.join(\", \")}`;\n }\n\n if (options?.limit !== undefined) {\n query += ` LIMIT ${options.limit}`;\n }\n\n if (options?.offset !== undefined) {\n query += ` OFFSET ${options.offset}`;\n }\n\n return query;\n}\n\n/**\n * Builds an INSERT query string from content object\n */\nexport function buildInsert(\n tableName: string,\n schema: TableSchema,\n content: Record<string, unknown>,\n): string {\n // Filter to only valid columns\n const validColumns = new Set(schema.columns.map((c) => c.name));\n const entries = Object.entries(content).filter(([key]) => validColumns.has(key));\n\n if (entries.length === 0) {\n throw new Error(`No valid columns provided for INSERT into ${tableName}`);\n }\n\n const columns = entries.map(([key]) => `\"${key}\"`).join(\", \");\n const values = entries.map(([, value]) => formatValue(value)).join(\", \");\n\n return `INSERT INTO \"${tableName}\" (${columns}) VALUES (${values})`;\n}\n\n/**\n * Builds an UPDATE query string from content object\n */\nexport function buildUpdate(\n tableName: string,\n schema: TableSchema,\n pk: string,\n content: Record<string, unknown>,\n): string {\n const pkColumn = schema.primaryKey[0] ?? \"rowid\";\n\n // Filter to only valid columns, excluding PK\n const validColumns = new Set(schema.columns.map((c) => c.name));\n const entries = Object.entries(content).filter(\n ([key]) => validColumns.has(key) && key !== pkColumn,\n );\n\n if (entries.length === 0) {\n throw new Error(`No valid columns provided for UPDATE on ${tableName}`);\n }\n\n const setClauses = entries.map(([key, value]) => `\"${key}\" = ${formatValue(value)}`).join(\", \");\n\n return `UPDATE \"${tableName}\" SET ${setClauses} WHERE \"${pkColumn}\" = '${escapeSQLString(pk)}'`;\n}\n\n/**\n * Builds a DELETE query string by primary key\n */\nexport function buildDelete(tableName: string, schema: TableSchema, pk: string): string {\n const pkColumn = schema.primaryKey[0] ?? \"rowid\";\n return `DELETE FROM \"${tableName}\" WHERE \"${pkColumn}\" = '${escapeSQLString(pk)}'`;\n}\n\n/**\n * Formats a value for SQL insertion\n */\nexport function formatValue(value: unknown): string {\n if (value === null || value === undefined) {\n return \"NULL\";\n }\n\n if (typeof value === \"number\") {\n return String(value);\n }\n\n if (typeof value === \"boolean\") {\n return value ? \"1\" : \"0\";\n }\n\n if (value instanceof Date) {\n return `'${value.toISOString()}'`;\n }\n\n if (typeof value === \"object\") {\n return `'${escapeSQLString(JSON.stringify(value))}'`;\n }\n\n return `'${escapeSQLString(String(value))}'`;\n}\n\n/**\n * Escapes a string for safe SQL insertion\n */\nexport function escapeSQLString(str: string): string {\n return str.replace(/'/g, \"''\");\n}\n\n/**\n * Gets the last inserted rowid query string\n */\nexport function buildGetLastRowId(): string {\n return \"SELECT last_insert_rowid() as id\";\n}\n"],"mappings":";;;;AAKA,SAAgB,gBAAgB,WAAmB,QAAqB,IAAoB;AAE1F,QAAO,kBAAkB,UAAU,WADlB,OAAO,WAAW,MAAM,QACc,OAAO,gBAAgB,GAAG,CAAC;;;;;AAMpF,SAAgB,eACd,WACA,SAKQ;CACR,IAAI,QAAQ,kBAAkB,UAAU;AAExC,KAAI,SAAS,SAAS,QAAQ;EAC5B,MAAM,eAAe,QAAQ,QAAQ,KAAK,CAAC,KAAK,SAAS,IAAI,IAAI,IAAI,IAAI,aAAa,GAAG;AACzF,WAAS,aAAa,aAAa,KAAK,KAAK;;AAG/C,KAAI,SAAS,UAAU,OACrB,UAAS,UAAU,QAAQ;AAG7B,KAAI,SAAS,WAAW,OACtB,UAAS,WAAW,QAAQ;AAG9B,QAAO;;;;;AAMT,SAAgB,YACd,WACA,QACA,SACQ;CAER,MAAM,eAAe,IAAI,IAAI,OAAO,QAAQ,KAAK,MAAM,EAAE,KAAK,CAAC;CAC/D,MAAM,UAAU,OAAO,QAAQ,QAAQ,CAAC,QAAQ,CAAC,SAAS,aAAa,IAAI,IAAI,CAAC;AAEhF,KAAI,QAAQ,WAAW,EACrB,OAAM,IAAI,MAAM,6CAA6C,YAAY;AAM3E,QAAO,gBAAgB,UAAU,KAHjB,QAAQ,KAAK,CAAC,SAAS,IAAI,IAAI,GAAG,CAAC,KAAK,KAAK,CAGf,YAF/B,QAAQ,KAAK,GAAG,WAAW,YAAY,MAAM,CAAC,CAAC,KAAK,KAAK,CAEP;;;;;AAMnE,SAAgB,YACd,WACA,QACA,IACA,SACQ;CACR,MAAM,WAAW,OAAO,WAAW,MAAM;CAGzC,MAAM,eAAe,IAAI,IAAI,OAAO,QAAQ,KAAK,MAAM,EAAE,KAAK,CAAC;CAC/D,MAAM,UAAU,OAAO,QAAQ,QAAQ,CAAC,QACrC,CAAC,SAAS,aAAa,IAAI,IAAI,IAAI,QAAQ,SAC7C;AAED,KAAI,QAAQ,WAAW,EACrB,OAAM,IAAI,MAAM,2CAA2C,YAAY;AAKzE,QAAO,WAAW,UAAU,QAFT,QAAQ,KAAK,CAAC,KAAK,WAAW,IAAI,IAAI,MAAM,YAAY,MAAM,GAAG,CAAC,KAAK,KAAK,CAEhD,UAAU,SAAS,OAAO,gBAAgB,GAAG,CAAC;;;;;AAM/F,SAAgB,YAAY,WAAmB,QAAqB,IAAoB;AAEtF,QAAO,gBAAgB,UAAU,WADhB,OAAO,WAAW,MAAM,QACY,OAAO,gBAAgB,GAAG,CAAC;;;;;AAMlF,SAAgB,YAAY,OAAwB;AAClD,KAAI,UAAU,QAAQ,UAAU,OAC9B,QAAO;AAGT,KAAI,OAAO,UAAU,SACnB,QAAO,OAAO,MAAM;AAGtB,KAAI,OAAO,UAAU,UACnB,QAAO,QAAQ,MAAM;AAGvB,KAAI,iBAAiB,KACnB,QAAO,IAAI,MAAM,aAAa,CAAC;AAGjC,KAAI,OAAO,UAAU,SACnB,QAAO,IAAI,gBAAgB,KAAK,UAAU,MAAM,CAAC,CAAC;AAGpD,QAAO,IAAI,gBAAgB,OAAO,MAAM,CAAC,CAAC;;;;;AAM5C,SAAgB,gBAAgB,KAAqB;AACnD,QAAO,IAAI,QAAQ,MAAM,KAAK;;;;;AAMhC,SAAgB,oBAA4B;AAC1C,QAAO"}
1
+ {"version":3,"file":"query-builder.mjs","names":[],"sources":["../../src/operations/query-builder.ts"],"sourcesContent":["import type { TableSchema } from \"../schema/types.js\";\n\n/**\n * Builds a SELECT query string for a single row by primary key\n */\nexport function buildSelectByPK(tableName: string, schema: TableSchema, pk: string): string {\n const pkColumn = schema.primaryKey[0] ?? \"rowid\";\n // Include rowid explicitly for tables without explicit primary key\n return `SELECT rowid, * FROM \"${tableName}\" WHERE \"${pkColumn}\" = '${escapeSQLString(pk)}'`;\n}\n\n/**\n * Builds a SELECT query string for listing rows with optional limit and offset\n */\nexport function buildSelectAll(\n tableName: string,\n options?: {\n limit?: number;\n offset?: number;\n orderBy?: [string, \"asc\" | \"desc\"][];\n },\n): string {\n // Include rowid explicitly for tables without explicit primary key\n let query = `SELECT rowid, * FROM \"${tableName}\"`;\n\n if (options?.orderBy?.length) {\n const orderClauses = options.orderBy.map(([col, dir]) => `\"${col}\" ${dir.toUpperCase()}`);\n query += ` ORDER BY ${orderClauses.join(\", \")}`;\n }\n\n if (options?.limit !== undefined) {\n query += ` LIMIT ${options.limit}`;\n }\n\n if (options?.offset !== undefined) {\n query += ` OFFSET ${options.offset}`;\n }\n\n return query;\n}\n\n/**\n * Builds an INSERT query string from content object\n */\nexport function buildInsert(\n tableName: string,\n schema: TableSchema,\n content: Record<string, unknown>,\n): string {\n // Filter to only valid columns\n const validColumns = new Set(schema.columns.map((c) => c.name));\n const entries = Object.entries(content).filter(([key]) => validColumns.has(key));\n\n if (entries.length === 0) {\n throw new Error(`No valid columns provided for INSERT into ${tableName}`);\n }\n\n const columns = entries.map(([key]) => `\"${key}\"`).join(\", \");\n const values = entries.map(([, value]) => formatValue(value)).join(\", \");\n\n return `INSERT INTO \"${tableName}\" (${columns}) VALUES (${values})`;\n}\n\n/**\n * Builds an UPDATE query string from content object\n */\nexport function buildUpdate(\n tableName: string,\n schema: TableSchema,\n pk: string,\n content: Record<string, unknown>,\n): string {\n const pkColumn = schema.primaryKey[0] ?? \"rowid\";\n\n // Filter to only valid columns, excluding PK\n const validColumns = new Set(schema.columns.map((c) => c.name));\n const entries = Object.entries(content).filter(\n ([key]) => validColumns.has(key) && key !== pkColumn,\n );\n\n if (entries.length === 0) {\n throw new Error(`No valid columns provided for UPDATE on ${tableName}`);\n }\n\n const setClauses = entries.map(([key, value]) => `\"${key}\" = ${formatValue(value)}`).join(\", \");\n\n return `UPDATE \"${tableName}\" SET ${setClauses} WHERE \"${pkColumn}\" = '${escapeSQLString(pk)}'`;\n}\n\n/**\n * Builds a DELETE query string by primary key\n */\nexport function buildDelete(tableName: string, schema: TableSchema, pk: string): string {\n const pkColumn = schema.primaryKey[0] ?? \"rowid\";\n return `DELETE FROM \"${tableName}\" WHERE \"${pkColumn}\" = '${escapeSQLString(pk)}'`;\n}\n\n/**\n * Formats a value for SQL insertion\n */\nexport function formatValue(value: unknown): string {\n if (value === null || value === undefined) {\n return \"NULL\";\n }\n\n if (typeof value === \"number\") {\n return String(value);\n }\n\n if (typeof value === \"boolean\") {\n return value ? \"1\" : \"0\";\n }\n\n if (value instanceof Date) {\n return `'${value.toISOString()}'`;\n }\n\n if (typeof value === \"object\") {\n return `'${escapeSQLString(JSON.stringify(value))}'`;\n }\n\n return `'${escapeSQLString(String(value))}'`;\n}\n\n/**\n * Escapes a string for safe SQL insertion\n */\nexport function escapeSQLString(str: string): string {\n return str.replace(/'/g, \"''\");\n}\n\n/**\n * Gets the last inserted rowid query string\n */\nexport function buildGetLastRowId(): string {\n return \"SELECT last_insert_rowid() as id\";\n}\n"],"mappings":";;;;AAKA,SAAgB,gBAAgB,WAAmB,QAAqB,IAAoB;AAG1F,QAAO,yBAAyB,UAAU,WAFzB,OAAO,WAAW,MAAM,QAEqB,OAAO,gBAAgB,GAAG,CAAC;;;;;AAM3F,SAAgB,eACd,WACA,SAKQ;CAER,IAAI,QAAQ,yBAAyB,UAAU;AAE/C,KAAI,SAAS,SAAS,QAAQ;EAC5B,MAAM,eAAe,QAAQ,QAAQ,KAAK,CAAC,KAAK,SAAS,IAAI,IAAI,IAAI,IAAI,aAAa,GAAG;AACzF,WAAS,aAAa,aAAa,KAAK,KAAK;;AAG/C,KAAI,SAAS,UAAU,OACrB,UAAS,UAAU,QAAQ;AAG7B,KAAI,SAAS,WAAW,OACtB,UAAS,WAAW,QAAQ;AAG9B,QAAO;;;;;AAMT,SAAgB,YACd,WACA,QACA,SACQ;CAER,MAAM,eAAe,IAAI,IAAI,OAAO,QAAQ,KAAK,MAAM,EAAE,KAAK,CAAC;CAC/D,MAAM,UAAU,OAAO,QAAQ,QAAQ,CAAC,QAAQ,CAAC,SAAS,aAAa,IAAI,IAAI,CAAC;AAEhF,KAAI,QAAQ,WAAW,EACrB,OAAM,IAAI,MAAM,6CAA6C,YAAY;AAM3E,QAAO,gBAAgB,UAAU,KAHjB,QAAQ,KAAK,CAAC,SAAS,IAAI,IAAI,GAAG,CAAC,KAAK,KAAK,CAGf,YAF/B,QAAQ,KAAK,GAAG,WAAW,YAAY,MAAM,CAAC,CAAC,KAAK,KAAK,CAEP;;;;;AAMnE,SAAgB,YACd,WACA,QACA,IACA,SACQ;CACR,MAAM,WAAW,OAAO,WAAW,MAAM;CAGzC,MAAM,eAAe,IAAI,IAAI,OAAO,QAAQ,KAAK,MAAM,EAAE,KAAK,CAAC;CAC/D,MAAM,UAAU,OAAO,QAAQ,QAAQ,CAAC,QACrC,CAAC,SAAS,aAAa,IAAI,IAAI,IAAI,QAAQ,SAC7C;AAED,KAAI,QAAQ,WAAW,EACrB,OAAM,IAAI,MAAM,2CAA2C,YAAY;AAKzE,QAAO,WAAW,UAAU,QAFT,QAAQ,KAAK,CAAC,KAAK,WAAW,IAAI,IAAI,MAAM,YAAY,MAAM,GAAG,CAAC,KAAK,KAAK,CAEhD,UAAU,SAAS,OAAO,gBAAgB,GAAG,CAAC;;;;;AAM/F,SAAgB,YAAY,WAAmB,QAAqB,IAAoB;AAEtF,QAAO,gBAAgB,UAAU,WADhB,OAAO,WAAW,MAAM,QACY,OAAO,gBAAgB,GAAG,CAAC;;;;;AAMlF,SAAgB,YAAY,OAAwB;AAClD,KAAI,UAAU,QAAQ,UAAU,OAC9B,QAAO;AAGT,KAAI,OAAO,UAAU,SACnB,QAAO,OAAO,MAAM;AAGtB,KAAI,OAAO,UAAU,UACnB,QAAO,QAAQ,MAAM;AAGvB,KAAI,iBAAiB,KACnB,QAAO,IAAI,MAAM,aAAa,CAAC;AAGjC,KAAI,OAAO,UAAU,SACnB,QAAO,IAAI,gBAAgB,KAAK,UAAU,MAAM,CAAC,CAAC;AAGpD,QAAO,IAAI,gBAAgB,OAAO,MAAM,CAAC,CAAC;;;;;AAM5C,SAAgB,gBAAgB,KAAqB;AACnD,QAAO,IAAI,QAAQ,MAAM,KAAK;;;;;AAMhC,SAAgB,oBAA4B;AAC1C,QAAO"}
@@ -115,7 +115,7 @@ var FTSSearch = class {
115
115
  data: [],
116
116
  message: "No valid columns to search"
117
117
  };
118
- return { data: (await execAll(this.db, `SELECT * FROM "${tableName}" WHERE ${conditions} LIMIT ${limit}`)).map((row) => require_builder.buildSearchEntry(tableName, schema, row, void 0, buildOptions)) };
118
+ return { data: (await execAll(this.db, `SELECT rowid, * FROM "${tableName}" WHERE ${conditions} LIMIT ${limit}`)).map((row) => require_builder.buildSearchEntry(tableName, schema, row, void 0, buildOptions)) };
119
119
  }
120
120
  };
121
121
  /**
@@ -115,7 +115,7 @@ var FTSSearch = class {
115
115
  data: [],
116
116
  message: "No valid columns to search"
117
117
  };
118
- return { data: (await execAll(this.db, `SELECT * FROM "${tableName}" WHERE ${conditions} LIMIT ${limit}`)).map((row) => buildSearchEntry(tableName, schema, row, void 0, buildOptions)) };
118
+ return { data: (await execAll(this.db, `SELECT rowid, * FROM "${tableName}" WHERE ${conditions} LIMIT ${limit}`)).map((row) => buildSearchEntry(tableName, schema, row, void 0, buildOptions)) };
119
119
  }
120
120
  };
121
121
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"search.mjs","names":[],"sources":["../../src/operations/search.ts"],"sourcesContent":["import type { AFSEntry, AFSSearchOptions, AFSSearchResult } from \"@aigne/afs\";\nimport { sql } from \"@aigne/sqlite\";\nimport type { LibSQLDatabase } from \"drizzle-orm/libsql\";\nimport { type BuildEntryOptions, buildSearchEntry } from \"../node/builder.js\";\nimport type { SchemaService } from \"../schema/service.js\";\n\n/**\n * Executes a raw SQL query and returns all rows\n */\nasync function execAll<T>(db: LibSQLDatabase, query: string): Promise<T[]> {\n return db.all<T>(sql.raw(query)).execute();\n}\n\n/**\n * FTS5 search configuration for a table\n */\nexport interface FTSTableConfig {\n /** Columns to include in FTS index */\n columns: string[];\n /** Whether FTS table has been created */\n initialized?: boolean;\n}\n\n/**\n * FTS5 search configuration\n */\nexport interface FTSConfig {\n /** Whether FTS is enabled */\n enabled: boolean;\n /** Per-table FTS configuration */\n tables: Map<string, FTSTableConfig>;\n}\n\n/**\n * FTS5 Search operations for SQLite AFS\n */\nexport class FTSSearch {\n constructor(\n private db: LibSQLDatabase,\n private schemaService: SchemaService,\n private config: FTSConfig,\n private basePath: string = \"\",\n ) {}\n\n /**\n * Performs full-text search across configured tables\n */\n async search(\n query: string,\n options?: AFSSearchOptions & {\n /** Specific tables to search (defaults to all FTS-enabled tables) */\n tables?: string[];\n },\n ): Promise<AFSSearchResult> {\n if (!this.config.enabled) {\n return { data: [], message: \"Full-text search is not enabled\" };\n }\n\n const results: AFSEntry[] = [];\n const limit = options?.limit ?? 50;\n const buildOptions: BuildEntryOptions = { basePath: this.basePath };\n\n // Determine which tables to search\n const tablesToSearch = options?.tables\n ? options.tables.filter((t) => this.config.tables.has(t))\n : Array.from(this.config.tables.keys());\n\n // Escape and prepare the query for FTS5\n const ftsQuery = this.prepareFTSQuery(query, options?.caseSensitive);\n\n for (const tableName of tablesToSearch) {\n const tableConfig = this.config.tables.get(tableName);\n const schema = await this.schemaService.getSchema(tableName);\n\n if (!tableConfig || !schema) continue;\n\n const ftsTableName = `${tableName}_fts`;\n\n try {\n // Check if FTS table exists\n const ftsExists = await this.ftsTableExists(ftsTableName);\n if (!ftsExists) continue;\n\n // Get the first column for highlighting\n const highlightColumn = tableConfig.columns[0] ?? \"\";\n const highlightIndex = highlightColumn ? tableConfig.columns.indexOf(highlightColumn) : 0;\n\n // Build FTS query with highlight\n const rows = await execAll<Record<string, unknown> & { snippet?: string }>(\n this.db,\n `\n SELECT t.*, highlight(\"${ftsTableName}\", ${highlightIndex}, '<mark>', '</mark>') as snippet\n FROM \"${ftsTableName}\" fts\n JOIN \"${tableName}\" t ON fts.rowid = t.rowid\n WHERE \"${ftsTableName}\" MATCH '${ftsQuery}'\n LIMIT ${Math.ceil(limit / tablesToSearch.length)}\n `,\n );\n\n for (const row of rows) {\n const { snippet, ...rowData } = row;\n results.push(\n buildSearchEntry(\n tableName,\n schema,\n rowData,\n snippet as string | undefined,\n buildOptions,\n ),\n );\n }\n } catch (error) {\n // Log but continue with other tables\n console.warn(`FTS search failed for table ${tableName}:`, error);\n }\n\n // Stop if we have enough results\n if (results.length >= limit) break;\n }\n\n return {\n data: results.slice(0, limit),\n message: results.length === 0 ? `No results found for \"${query}\"` : undefined,\n };\n }\n\n /**\n * Searches within a specific table\n */\n async searchTable(\n tableName: string,\n query: string,\n options?: AFSSearchOptions,\n ): Promise<AFSSearchResult> {\n return this.search(query, { ...options, tables: [tableName] });\n }\n\n /**\n * Checks if FTS is configured for a table\n */\n hasFTS(tableName: string): boolean {\n return this.config.enabled && this.config.tables.has(tableName);\n }\n\n /**\n * Gets FTS configuration for a table\n */\n getFTSConfig(tableName: string): FTSTableConfig | undefined {\n return this.config.tables.get(tableName);\n }\n\n /**\n * Checks if an FTS table exists\n */\n private async ftsTableExists(ftsTableName: string): Promise<boolean> {\n const result = await execAll<{ name: string }>(\n this.db,\n `SELECT name FROM sqlite_master WHERE type = 'table' AND name = '${ftsTableName}'`,\n );\n return result.length > 0;\n }\n\n /**\n * Prepares a query string for FTS5\n * Handles special characters and case sensitivity\n */\n private prepareFTSQuery(query: string, _caseSensitive?: boolean): string {\n // Escape special FTS5 characters\n let prepared = query\n .replace(/\"/g, '\"\"') // Escape double quotes\n .replace(/'/g, \"''\"); // Escape single quotes\n\n // For case-insensitive search (default), we don't need to modify\n // FTS5 is case-insensitive by default for ASCII\n\n // If the query contains multiple words, search for the phrase\n if (prepared.includes(\" \") && !prepared.startsWith('\"')) {\n prepared = `\"${prepared}\"`;\n }\n\n return prepared;\n }\n\n /**\n * Simple search fallback when FTS is not available\n * Uses LIKE queries on specified columns\n */\n async simpleLikeSearch(\n tableName: string,\n query: string,\n columns: string[],\n options?: AFSSearchOptions,\n ): Promise<AFSSearchResult> {\n const schema = await this.schemaService.getSchema(tableName);\n if (!schema) {\n return { data: [], message: `Table '${tableName}' not found` };\n }\n\n const buildOptions: BuildEntryOptions = { basePath: this.basePath };\n const limit = options?.limit ?? 50;\n const escapedQuery = query.replace(/'/g, \"''\");\n\n // Build LIKE conditions for each column\n const conditions = columns\n .filter((col) => schema.columns.some((c) => c.name === col))\n .map((col) => `\"${col}\" LIKE '%${escapedQuery}%'`)\n .join(\" OR \");\n\n if (!conditions) {\n return { data: [], message: \"No valid columns to search\" };\n }\n\n const rows = await execAll<Record<string, unknown>>(\n this.db,\n `SELECT * FROM \"${tableName}\" WHERE ${conditions} LIMIT ${limit}`,\n );\n\n return {\n data: rows.map((row) => buildSearchEntry(tableName, schema, row, undefined, buildOptions)),\n };\n }\n}\n\n/**\n * Creates FTS configuration from options\n */\nexport function createFTSConfig(options?: {\n enabled?: boolean;\n tables?: Record<string, string[]>;\n}): FTSConfig {\n const config: FTSConfig = {\n enabled: options?.enabled ?? false,\n tables: new Map(),\n };\n\n if (options?.tables) {\n for (const [table, columns] of Object.entries(options.tables)) {\n config.tables.set(table, { columns });\n }\n }\n\n return config;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"search.mjs","names":[],"sources":["../../src/operations/search.ts"],"sourcesContent":["import type { AFSEntry, AFSSearchOptions, AFSSearchResult } from \"@aigne/afs\";\nimport { sql } from \"@aigne/sqlite\";\nimport type { LibSQLDatabase } from \"drizzle-orm/libsql\";\nimport { type BuildEntryOptions, buildSearchEntry } from \"../node/builder.js\";\nimport type { SchemaService } from \"../schema/service.js\";\n\n/**\n * Executes a raw SQL query and returns all rows\n */\nasync function execAll<T>(db: LibSQLDatabase, query: string): Promise<T[]> {\n return db.all<T>(sql.raw(query)).execute();\n}\n\n/**\n * FTS5 search configuration for a table\n */\nexport interface FTSTableConfig {\n /** Columns to include in FTS index */\n columns: string[];\n /** Whether FTS table has been created */\n initialized?: boolean;\n}\n\n/**\n * FTS5 search configuration\n */\nexport interface FTSConfig {\n /** Whether FTS is enabled */\n enabled: boolean;\n /** Per-table FTS configuration */\n tables: Map<string, FTSTableConfig>;\n}\n\n/**\n * FTS5 Search operations for SQLite AFS\n */\nexport class FTSSearch {\n constructor(\n private db: LibSQLDatabase,\n private schemaService: SchemaService,\n private config: FTSConfig,\n private basePath: string = \"\",\n ) {}\n\n /**\n * Performs full-text search across configured tables\n */\n async search(\n query: string,\n options?: AFSSearchOptions & {\n /** Specific tables to search (defaults to all FTS-enabled tables) */\n tables?: string[];\n },\n ): Promise<AFSSearchResult> {\n if (!this.config.enabled) {\n return { data: [], message: \"Full-text search is not enabled\" };\n }\n\n const results: AFSEntry[] = [];\n const limit = options?.limit ?? 50;\n const buildOptions: BuildEntryOptions = { basePath: this.basePath };\n\n // Determine which tables to search\n const tablesToSearch = options?.tables\n ? options.tables.filter((t) => this.config.tables.has(t))\n : Array.from(this.config.tables.keys());\n\n // Escape and prepare the query for FTS5\n const ftsQuery = this.prepareFTSQuery(query, options?.caseSensitive);\n\n for (const tableName of tablesToSearch) {\n const tableConfig = this.config.tables.get(tableName);\n const schema = await this.schemaService.getSchema(tableName);\n\n if (!tableConfig || !schema) continue;\n\n const ftsTableName = `${tableName}_fts`;\n\n try {\n // Check if FTS table exists\n const ftsExists = await this.ftsTableExists(ftsTableName);\n if (!ftsExists) continue;\n\n // Get the first column for highlighting\n const highlightColumn = tableConfig.columns[0] ?? \"\";\n const highlightIndex = highlightColumn ? tableConfig.columns.indexOf(highlightColumn) : 0;\n\n // Build FTS query with highlight\n const rows = await execAll<Record<string, unknown> & { snippet?: string }>(\n this.db,\n `\n SELECT t.*, highlight(\"${ftsTableName}\", ${highlightIndex}, '<mark>', '</mark>') as snippet\n FROM \"${ftsTableName}\" fts\n JOIN \"${tableName}\" t ON fts.rowid = t.rowid\n WHERE \"${ftsTableName}\" MATCH '${ftsQuery}'\n LIMIT ${Math.ceil(limit / tablesToSearch.length)}\n `,\n );\n\n for (const row of rows) {\n const { snippet, ...rowData } = row;\n results.push(\n buildSearchEntry(\n tableName,\n schema,\n rowData,\n snippet as string | undefined,\n buildOptions,\n ),\n );\n }\n } catch (error) {\n // Log but continue with other tables\n console.warn(`FTS search failed for table ${tableName}:`, error);\n }\n\n // Stop if we have enough results\n if (results.length >= limit) break;\n }\n\n return {\n data: results.slice(0, limit),\n message: results.length === 0 ? `No results found for \"${query}\"` : undefined,\n };\n }\n\n /**\n * Searches within a specific table\n */\n async searchTable(\n tableName: string,\n query: string,\n options?: AFSSearchOptions,\n ): Promise<AFSSearchResult> {\n return this.search(query, { ...options, tables: [tableName] });\n }\n\n /**\n * Checks if FTS is configured for a table\n */\n hasFTS(tableName: string): boolean {\n return this.config.enabled && this.config.tables.has(tableName);\n }\n\n /**\n * Gets FTS configuration for a table\n */\n getFTSConfig(tableName: string): FTSTableConfig | undefined {\n return this.config.tables.get(tableName);\n }\n\n /**\n * Checks if an FTS table exists\n */\n private async ftsTableExists(ftsTableName: string): Promise<boolean> {\n const result = await execAll<{ name: string }>(\n this.db,\n `SELECT name FROM sqlite_master WHERE type = 'table' AND name = '${ftsTableName}'`,\n );\n return result.length > 0;\n }\n\n /**\n * Prepares a query string for FTS5\n * Handles special characters and case sensitivity\n */\n private prepareFTSQuery(query: string, _caseSensitive?: boolean): string {\n // Escape special FTS5 characters\n let prepared = query\n .replace(/\"/g, '\"\"') // Escape double quotes\n .replace(/'/g, \"''\"); // Escape single quotes\n\n // For case-insensitive search (default), we don't need to modify\n // FTS5 is case-insensitive by default for ASCII\n\n // If the query contains multiple words, search for the phrase\n if (prepared.includes(\" \") && !prepared.startsWith('\"')) {\n prepared = `\"${prepared}\"`;\n }\n\n return prepared;\n }\n\n /**\n * Simple search fallback when FTS is not available\n * Uses LIKE queries on specified columns\n */\n async simpleLikeSearch(\n tableName: string,\n query: string,\n columns: string[],\n options?: AFSSearchOptions,\n ): Promise<AFSSearchResult> {\n const schema = await this.schemaService.getSchema(tableName);\n if (!schema) {\n return { data: [], message: `Table '${tableName}' not found` };\n }\n\n const buildOptions: BuildEntryOptions = { basePath: this.basePath };\n const limit = options?.limit ?? 50;\n const escapedQuery = query.replace(/'/g, \"''\");\n\n // Build LIKE conditions for each column\n const conditions = columns\n .filter((col) => schema.columns.some((c) => c.name === col))\n .map((col) => `\"${col}\" LIKE '%${escapedQuery}%'`)\n .join(\" OR \");\n\n if (!conditions) {\n return { data: [], message: \"No valid columns to search\" };\n }\n\n const rows = await execAll<Record<string, unknown>>(\n this.db,\n `SELECT rowid, * FROM \"${tableName}\" WHERE ${conditions} LIMIT ${limit}`,\n );\n\n return {\n data: rows.map((row) => buildSearchEntry(tableName, schema, row, undefined, buildOptions)),\n };\n }\n}\n\n/**\n * Creates FTS configuration from options\n */\nexport function createFTSConfig(options?: {\n enabled?: boolean;\n tables?: Record<string, string[]>;\n}): FTSConfig {\n const config: FTSConfig = {\n enabled: options?.enabled ?? false,\n tables: new Map(),\n };\n\n if (options?.tables) {\n for (const [table, columns] of Object.entries(options.tables)) {\n config.tables.set(table, { columns });\n }\n }\n\n return config;\n}\n"],"mappings":"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"}