@aigne/afs-sqlite 1.1.0-beta.1 → 1.11.0-beta
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +51 -36
- package/dist/index.cjs +1324 -0
- package/dist/index.d.cts +758 -0
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.mts +758 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +1299 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +31 -44
- package/CHANGELOG.md +0 -61
- package/lib/cjs/actions/built-in.d.ts +0 -5
- package/lib/cjs/actions/built-in.js +0 -165
- package/lib/cjs/actions/registry.d.ts +0 -49
- package/lib/cjs/actions/registry.js +0 -102
- package/lib/cjs/actions/types.d.ts +0 -51
- package/lib/cjs/actions/types.js +0 -2
- package/lib/cjs/config.d.ts +0 -89
- package/lib/cjs/config.js +0 -33
- package/lib/cjs/index.d.ts +0 -13
- package/lib/cjs/index.js +0 -47
- package/lib/cjs/node/builder.d.ts +0 -43
- package/lib/cjs/node/builder.js +0 -187
- package/lib/cjs/operations/crud.d.ts +0 -64
- package/lib/cjs/operations/crud.js +0 -225
- package/lib/cjs/operations/query-builder.d.ts +0 -37
- package/lib/cjs/operations/query-builder.js +0 -102
- package/lib/cjs/operations/search.d.ts +0 -75
- package/lib/cjs/operations/search.js +0 -172
- package/lib/cjs/package.json +0 -3
- package/lib/cjs/router/path-router.d.ts +0 -38
- package/lib/cjs/router/path-router.js +0 -90
- package/lib/cjs/router/types.d.ts +0 -30
- package/lib/cjs/router/types.js +0 -2
- package/lib/cjs/schema/introspector.d.ts +0 -48
- package/lib/cjs/schema/introspector.js +0 -186
- package/lib/cjs/schema/types.d.ts +0 -104
- package/lib/cjs/schema/types.js +0 -13
- package/lib/cjs/sqlite-afs.d.ts +0 -144
- package/lib/cjs/sqlite-afs.js +0 -337
- package/lib/dts/actions/built-in.d.ts +0 -5
- package/lib/dts/actions/registry.d.ts +0 -49
- package/lib/dts/actions/types.d.ts +0 -51
- package/lib/dts/config.d.ts +0 -89
- package/lib/dts/index.d.ts +0 -13
- package/lib/dts/node/builder.d.ts +0 -43
- package/lib/dts/operations/crud.d.ts +0 -64
- package/lib/dts/operations/query-builder.d.ts +0 -37
- package/lib/dts/operations/search.d.ts +0 -75
- package/lib/dts/router/path-router.d.ts +0 -38
- package/lib/dts/router/types.d.ts +0 -30
- package/lib/dts/schema/introspector.d.ts +0 -48
- package/lib/dts/schema/types.d.ts +0 -104
- package/lib/dts/sqlite-afs.d.ts +0 -144
- package/lib/esm/actions/built-in.d.ts +0 -5
- package/lib/esm/actions/built-in.js +0 -162
- package/lib/esm/actions/registry.d.ts +0 -49
- package/lib/esm/actions/registry.js +0 -98
- package/lib/esm/actions/types.d.ts +0 -51
- package/lib/esm/actions/types.js +0 -1
- package/lib/esm/config.d.ts +0 -89
- package/lib/esm/config.js +0 -30
- package/lib/esm/index.d.ts +0 -13
- package/lib/esm/index.js +0 -17
- package/lib/esm/node/builder.d.ts +0 -43
- package/lib/esm/node/builder.js +0 -177
- package/lib/esm/operations/crud.d.ts +0 -64
- package/lib/esm/operations/crud.js +0 -221
- package/lib/esm/operations/query-builder.d.ts +0 -37
- package/lib/esm/operations/query-builder.js +0 -92
- package/lib/esm/operations/search.d.ts +0 -75
- package/lib/esm/operations/search.js +0 -167
- package/lib/esm/package.json +0 -3
- package/lib/esm/router/path-router.d.ts +0 -38
- package/lib/esm/router/path-router.js +0 -83
- package/lib/esm/router/types.d.ts +0 -30
- package/lib/esm/router/types.js +0 -1
- package/lib/esm/schema/introspector.d.ts +0 -48
- package/lib/esm/schema/introspector.js +0 -182
- package/lib/esm/schema/types.d.ts +0 -104
- package/lib/esm/schema/types.js +0 -10
- package/lib/esm/sqlite-afs.d.ts +0 -144
- package/lib/esm/sqlite-afs.js +0 -333
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["execAll","execRun","execAll","execRun","execAll"],"sources":["../src/actions/built-in.ts","../src/actions/registry.ts","../src/config.ts","../src/node/builder.ts","../src/operations/query-builder.ts","../src/operations/crud.ts","../src/operations/search.ts","../src/router/path-router.ts","../src/schema/types.ts","../src/schema/introspector.ts","../src/sqlite-afs.ts"],"sourcesContent":["import { sql } from \"@aigne/sqlite\";\nimport type { LibSQLDatabase } from \"drizzle-orm/libsql\";\nimport type { ActionsRegistry } from \"./registry.js\";\nimport type { ActionContext, ActionResult } from \"./types.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 * Executes a raw SQL query (for INSERT, UPDATE, DELETE)\n */\nasync function execRun(db: LibSQLDatabase, query: string): Promise<void> {\n await db.run(sql.raw(query)).execute();\n}\n\n/**\n * Registers built-in actions to the registry\n */\nexport function registerBuiltInActions(registry: ActionsRegistry): void {\n // Refresh schema action (table level)\n registry.register({\n name: \"refresh\",\n description: \"Refresh the schema cache for this module\",\n tableLevel: true,\n rowLevel: false,\n handler: async (ctx: ActionContext): Promise<ActionResult> => {\n await ctx.module.refreshSchema();\n return {\n success: true,\n message: \"Schema refreshed successfully\",\n };\n },\n });\n\n // Export table action (table level)\n registry.register({\n name: \"export\",\n description: \"Export table data in specified format (json, csv)\",\n tableLevel: true,\n rowLevel: false,\n inputSchema: {\n type: \"object\",\n properties: {\n format: {\n type: \"string\",\n enum: [\"json\", \"csv\"],\n default: \"json\",\n },\n },\n },\n handler: async (ctx: ActionContext, params): Promise<ActionResult> => {\n const format = (params.format as string) ?? \"json\";\n const data = await ctx.module.exportTable(ctx.table, format);\n return {\n success: true,\n data,\n };\n },\n });\n\n // Count rows action (table level)\n registry.register({\n name: \"count\",\n description: \"Get the total row count for this table\",\n tableLevel: true,\n rowLevel: false,\n handler: async (ctx: ActionContext): Promise<ActionResult> => {\n const result = await execAll<{ count: number }>(\n ctx.db,\n `SELECT COUNT(*) as count FROM \"${ctx.table}\"`,\n );\n return {\n success: true,\n data: { count: result[0]?.count ?? 0 },\n };\n },\n });\n\n // Duplicate row action (row level)\n registry.register({\n name: \"duplicate\",\n description: \"Create a copy of this row\",\n tableLevel: false,\n rowLevel: true,\n handler: async (ctx: ActionContext): Promise<ActionResult> => {\n if (!ctx.row) {\n return { success: false, message: \"Row data not available\" };\n }\n\n const schema = ctx.schemas.get(ctx.table);\n if (!schema) {\n return { success: false, message: `Table '${ctx.table}' not found` };\n }\n\n // Create a copy without the primary key\n const pkColumn = schema.primaryKey[0] ?? \"rowid\";\n const rowCopy = { ...ctx.row };\n delete rowCopy[pkColumn];\n delete rowCopy.rowid;\n\n // Build insert query\n const columns = Object.keys(rowCopy);\n const values = columns.map((col) => formatValueForSQL(rowCopy[col]));\n\n await execRun(\n ctx.db,\n `INSERT INTO \"${ctx.table}\" (${columns.map((c) => `\"${c}\"`).join(\", \")}) VALUES (${values.join(\", \")})`,\n );\n\n // Get the new row's ID\n const lastIdResult = await execAll<{ id: number }>(\n ctx.db,\n \"SELECT last_insert_rowid() as id\",\n );\n\n return {\n success: true,\n data: { newId: lastIdResult[0]?.id },\n message: \"Row duplicated successfully\",\n };\n },\n });\n\n // Validate row action (row level)\n registry.register({\n name: \"validate\",\n description: \"Validate row data against schema constraints\",\n tableLevel: false,\n rowLevel: true,\n handler: async (ctx: ActionContext): Promise<ActionResult> => {\n if (!ctx.row) {\n return { success: false, message: \"Row data not available\" };\n }\n\n const schema = ctx.schemas.get(ctx.table);\n if (!schema) {\n return { success: false, message: `Table '${ctx.table}' not found` };\n }\n\n const errors: string[] = [];\n\n // Check NOT NULL constraints\n for (const col of schema.columns) {\n if (col.notnull && (ctx.row[col.name] === null || ctx.row[col.name] === undefined)) {\n errors.push(`Column '${col.name}' cannot be null`);\n }\n }\n\n // Check foreign key references\n for (const fk of schema.foreignKeys) {\n const value = ctx.row[fk.from];\n if (value !== null && value !== undefined) {\n const refResult = await execAll<{ count: number }>(\n ctx.db,\n `SELECT COUNT(*) as count FROM \"${fk.table}\" WHERE \"${fk.to}\" = '${String(value).replace(/'/g, \"''\")}'`,\n );\n if (refResult[0]?.count === 0) {\n errors.push(\n `Foreign key violation: ${fk.from} references non-existent ${fk.table}.${fk.to}`,\n );\n }\n }\n }\n\n return {\n success: errors.length === 0,\n data: { errors, valid: errors.length === 0 },\n message: errors.length > 0 ? `Validation failed: ${errors.join(\"; \")}` : \"Row is valid\",\n };\n },\n });\n}\n\n/**\n * Formats a value for SQL insertion\n */\nfunction formatValueForSQL(value: unknown): string {\n if (value === null || value === undefined) {\n return \"NULL\";\n }\n if (typeof value === \"number\") {\n return String(value);\n }\n if (typeof value === \"boolean\") {\n return value ? \"1\" : \"0\";\n }\n if (value instanceof Date) {\n return `'${value.toISOString()}'`;\n }\n if (typeof value === \"object\") {\n return `'${JSON.stringify(value).replace(/'/g, \"''\")}'`;\n }\n return `'${String(value).replace(/'/g, \"''\")}'`;\n}\n","import type { ActionContext, ActionDefinition, ActionHandler, ActionResult } from \"./types.js\";\n\n/**\n * Registry for managing action handlers\n */\nexport class ActionsRegistry {\n private handlers = new Map<string, ActionDefinition>();\n\n /**\n * Registers an action handler\n */\n register(definition: ActionDefinition): void {\n this.handlers.set(definition.name, definition);\n }\n\n /**\n * Registers a simple action with just name and handler\n */\n registerSimple(\n name: string,\n handler: ActionHandler,\n options?: {\n description?: string;\n tableLevel?: boolean;\n rowLevel?: boolean;\n },\n ): void {\n this.register({\n name,\n handler,\n description: options?.description,\n tableLevel: options?.tableLevel ?? false,\n rowLevel: options?.rowLevel ?? true,\n });\n }\n\n /**\n * Unregisters an action\n */\n unregister(name: string): boolean {\n return this.handlers.delete(name);\n }\n\n /**\n * Checks if an action is registered\n */\n has(name: string): boolean {\n return this.handlers.has(name);\n }\n\n /**\n * Gets an action definition\n */\n get(name: string): ActionDefinition | undefined {\n return this.handlers.get(name);\n }\n\n /**\n * Lists all registered actions\n */\n list(options?: { tableLevel?: boolean; rowLevel?: boolean }): ActionDefinition[] {\n const actions = Array.from(this.handlers.values());\n\n if (options?.tableLevel !== undefined || options?.rowLevel !== undefined) {\n return actions.filter((a) => {\n if (options.tableLevel && !a.tableLevel) return false;\n if (options.rowLevel && !a.rowLevel) return false;\n return true;\n });\n }\n\n return actions;\n }\n\n /**\n * Lists action names\n */\n listNames(options?: { tableLevel?: boolean; rowLevel?: boolean }): string[] {\n return this.list(options).map((a) => a.name);\n }\n\n /**\n * Executes an action\n */\n async execute(\n name: string,\n ctx: ActionContext,\n params: Record<string, unknown> = {},\n ): Promise<ActionResult> {\n const definition = this.handlers.get(name);\n\n if (!definition) {\n return {\n success: false,\n message: `Unknown action: ${name}`,\n };\n }\n\n // Validate action level\n if (ctx.pk && !definition.rowLevel) {\n return {\n success: false,\n message: `Action '${name}' is not available at row level`,\n };\n }\n\n if (!ctx.pk && !definition.tableLevel) {\n return {\n success: false,\n message: `Action '${name}' is not available at table level`,\n };\n }\n\n try {\n return await definition.handler(ctx, params);\n } catch (error) {\n return {\n success: false,\n message: error instanceof Error ? error.message : String(error),\n };\n }\n }\n}\n","import { type AFSAccessMode, accessModeSchema } from \"@aigne/afs\";\nimport { z } from \"zod\";\n\n/**\n * FTS (Full-Text Search) configuration schema\n */\nexport const ftsConfigSchema = z\n .object({\n enabled: z.boolean().default(true).describe(\"Whether FTS is enabled\"),\n tables: z\n .record(z.array(z.string()))\n .optional()\n .describe(\"Map of table name to columns to index for FTS\"),\n })\n .optional();\n\n/**\n * SQLite AFS module configuration schema\n */\nexport const sqliteAFSConfigSchema = z.object({\n url: z.string().describe(\"SQLite database URL (file:./path or :memory:)\"),\n name: z.string().optional().describe(\"Module name, defaults to 'sqlite-afs'\"),\n description: z.string().optional().describe(\"Description of this module\"),\n accessMode: accessModeSchema,\n tables: z\n .array(z.string())\n .optional()\n .describe(\"Whitelist of tables to expose (if not specified, all tables are exposed)\"),\n excludeTables: z.array(z.string()).optional().describe(\"Tables to exclude from exposure\"),\n fts: ftsConfigSchema,\n wal: z.boolean().optional().default(true).describe(\"Enable WAL mode for better concurrency\"),\n});\n\n/**\n * SQLite AFS module configuration type\n */\nexport type SQLiteAFSConfig = z.infer<typeof sqliteAFSConfigSchema>;\n\n/**\n * SQLite AFS module options (after parsing)\n */\nexport interface SQLiteAFSOptions {\n /** SQLite database URL */\n url: string;\n /** Module name */\n name?: string;\n /** Module description */\n description?: string;\n /** Access mode */\n accessMode?: AFSAccessMode;\n /** Tables to expose */\n tables?: string[];\n /** Tables to exclude */\n excludeTables?: string[];\n /** FTS configuration */\n fts?: {\n enabled?: boolean;\n tables?: Record<string, string[]>;\n };\n /** Enable WAL mode */\n wal?: boolean;\n}\n","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 description: `Table: ${table} (${schema.columns.length} columns)`,\n metadata: {\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 table schema\n */\nexport function buildSchemaEntry(\n table: string,\n schema: TableSchema,\n options?: BuildEntryOptions,\n): AFSEntry {\n const basePath = options?.basePath ?? \"\";\n\n return {\n id: `${table}:@schema`,\n path: `${basePath}/${table}/@schema`,\n description: `Schema for table: ${table}`,\n content: {\n name: schema.name,\n columns: schema.columns.map((col) => ({\n name: col.name,\n type: col.type,\n nullable: !col.notnull,\n primaryKey: col.pk > 0,\n defaultValue: col.dfltValue,\n })),\n primaryKey: schema.primaryKey,\n foreignKeys: schema.foreignKeys.map((fk) => ({\n column: fk.from,\n references: {\n table: fk.table,\n column: fk.to,\n },\n onUpdate: fk.onUpdate,\n onDelete: fk.onDelete,\n })),\n indexes: schema.indexes.map((idx) => ({\n name: idx.name,\n unique: idx.unique,\n origin: idx.origin,\n })),\n },\n metadata: {\n table,\n type: \"schema\",\n },\n };\n}\n\n/**\n * Builds an AFSEntry for an attribute (single column value)\n */\nexport function buildAttributeEntry(\n table: string,\n pk: string,\n column: string,\n value: unknown,\n options?: BuildEntryOptions,\n): AFSEntry {\n const basePath = options?.basePath ?? \"\";\n\n return {\n id: `${table}:${pk}:@attr:${column}`,\n path: `${basePath}/${table}/${pk}/@attr/${column}`,\n content: value,\n metadata: {\n table,\n primaryKeyValue: pk,\n column,\n type: \"attribute\",\n },\n };\n}\n\n/**\n * Builds an AFSEntry listing all attributes for a row\n */\nexport function buildAttributeListEntry(\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 schema.columns.map((col) => ({\n id: `${table}:${pk}:@attr:${col.name}`,\n path: `${basePath}/${table}/${pk}/@attr/${col.name}`,\n summary: col.name,\n description: `${col.type}${col.notnull ? \" NOT NULL\" : \"\"}`,\n content: row[col.name],\n metadata: {\n column: col.name,\n type: col.type,\n },\n }));\n}\n\n/**\n * Builds an AFSEntry for row metadata\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 AFSEntry for actions list\n */\nexport function buildActionsListEntry(\n table: string,\n pk: string,\n actions: string[],\n options?: BuildEntryOptions,\n): AFSEntry[] {\n const basePath = options?.basePath ?? \"\";\n\n return actions.map((action) => ({\n id: `${table}:${pk}:@actions:${action}`,\n path: `${basePath}/${table}/${pk}/@actions/${action}`,\n summary: action,\n metadata: {\n execute: {\n name: action,\n description: `Execute ${action} action on ${table}:${pk}`,\n },\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 * 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","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","import type {\n AFSDeleteResult,\n AFSEntry,\n AFSListOptions,\n AFSListResult,\n AFSReadResult,\n AFSWriteResult,\n} from \"@aigne/afs\";\nimport { sql } from \"@aigne/sqlite\";\nimport type { LibSQLDatabase } from \"drizzle-orm/libsql\";\nimport {\n type BuildEntryOptions,\n buildAttributeEntry,\n buildAttributeListEntry,\n buildMetaEntry,\n buildRowEntry,\n buildSchemaEntry,\n buildTableEntry,\n} from \"../node/builder.js\";\nimport type { TableSchema } from \"../schema/types.js\";\nimport {\n buildDelete,\n buildGetLastRowId,\n buildInsert,\n buildSelectAll,\n buildSelectByPK,\n buildUpdate,\n} from \"./query-builder.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 * Executes a raw SQL query (for INSERT, UPDATE, DELETE)\n */\nasync function execRun(db: LibSQLDatabase, query: string): Promise<void> {\n await db.run(sql.raw(query)).execute();\n}\n\n/**\n * CRUD operations for SQLite AFS\n */\nexport class CRUDOperations {\n constructor(\n private db: LibSQLDatabase,\n private schemas: Map<string, TableSchema>,\n private basePath: string = \"\",\n ) {}\n\n /**\n * Lists all tables\n */\n async listTables(): Promise<AFSListResult> {\n const entries: AFSEntry[] = [];\n const buildOptions: BuildEntryOptions = { basePath: this.basePath };\n\n for (const [name, schema] of this.schemas) {\n // Get row count for each table\n const countResult = await execAll<{ count: number }>(\n this.db,\n `SELECT COUNT(*) as count FROM \"${name}\"`,\n );\n const rowCount = countResult[0]?.count ?? 0;\n\n entries.push(buildTableEntry(name, schema, { ...buildOptions, rowCount }));\n }\n\n return { data: entries };\n }\n\n /**\n * Lists rows in a table\n */\n async listTable(table: string, options?: AFSListOptions): Promise<AFSListResult> {\n const schema = this.schemas.get(table);\n if (!schema) {\n return { data: [], message: `Table '${table}' not found` };\n }\n\n const buildOptions: BuildEntryOptions = { basePath: this.basePath };\n\n const queryStr = buildSelectAll(table, {\n limit: options?.limit ?? 100,\n orderBy: options?.orderBy,\n });\n\n const rows = await execAll<Record<string, unknown>>(this.db, queryStr);\n\n const entries = rows.map((row) => buildRowEntry(table, schema, row, buildOptions));\n\n return { data: entries };\n }\n\n /**\n * Reads a single row by primary key\n */\n async readRow(table: string, pk: string): Promise<AFSReadResult> {\n const schema = this.schemas.get(table);\n if (!schema) {\n return { message: `Table '${table}' not found` };\n }\n\n const buildOptions: BuildEntryOptions = { basePath: this.basePath };\n\n const rows = await execAll<Record<string, unknown>>(\n this.db,\n buildSelectByPK(table, schema, pk),\n );\n\n const row = rows[0];\n if (!row) {\n return { message: `Row with pk '${pk}' not found in table '${table}'` };\n }\n\n return { data: buildRowEntry(table, schema, row, buildOptions) };\n }\n\n /**\n * Gets table schema\n */\n getSchema(table: string): AFSReadResult {\n const schema = this.schemas.get(table);\n if (!schema) {\n return { message: `Table '${table}' not found` };\n }\n\n const buildOptions: BuildEntryOptions = { basePath: this.basePath };\n return { data: buildSchemaEntry(table, schema, buildOptions) };\n }\n\n /**\n * Lists attributes (columns) for a row\n */\n async listAttributes(table: string, pk: string): Promise<AFSListResult> {\n const schema = this.schemas.get(table);\n if (!schema) {\n return { data: [], message: `Table '${table}' not found` };\n }\n\n const buildOptions: BuildEntryOptions = { basePath: this.basePath };\n\n const rows = await execAll<Record<string, unknown>>(\n this.db,\n buildSelectByPK(table, schema, pk),\n );\n\n const row = rows[0];\n if (!row) {\n return { data: [], message: `Row with pk '${pk}' not found` };\n }\n\n return {\n data: buildAttributeListEntry(table, schema, pk, row, buildOptions),\n };\n }\n\n /**\n * Gets a single attribute (column value) for a row\n */\n async getAttribute(table: string, pk: string, column: string): Promise<AFSReadResult> {\n const schema = this.schemas.get(table);\n if (!schema) {\n return { message: `Table '${table}' not found` };\n }\n\n // Validate column exists\n const colInfo = schema.columns.find((c) => c.name === column);\n if (!colInfo) {\n return { message: `Column '${column}' not found in table '${table}'` };\n }\n\n const buildOptions: BuildEntryOptions = { basePath: this.basePath };\n\n const rows = await execAll<Record<string, unknown>>(\n this.db,\n buildSelectByPK(table, schema, pk),\n );\n\n if (rows.length === 0) {\n return { message: `Row with pk '${pk}' not found` };\n }\n\n return {\n data: buildAttributeEntry(table, pk, column, rows[0]?.[column], buildOptions),\n };\n }\n\n /**\n * Gets row metadata\n */\n async getMeta(table: string, pk: string): Promise<AFSReadResult> {\n const schema = this.schemas.get(table);\n if (!schema) {\n return { message: `Table '${table}' not found` };\n }\n\n const buildOptions: BuildEntryOptions = { basePath: this.basePath };\n\n const rows = await execAll<Record<string, unknown>>(\n this.db,\n buildSelectByPK(table, schema, pk),\n );\n\n const row = rows[0];\n if (!row) {\n return { message: `Row with pk '${pk}' not found` };\n }\n\n return { data: buildMetaEntry(table, schema, pk, row, buildOptions) };\n }\n\n /**\n * Creates a new row in a table\n */\n async createRow(table: string, content: Record<string, unknown>): Promise<AFSWriteResult> {\n const schema = this.schemas.get(table);\n if (!schema) {\n throw new Error(`Table '${table}' not found`);\n }\n\n const buildOptions: BuildEntryOptions = { basePath: this.basePath };\n\n // Insert the row\n await execRun(this.db, buildInsert(table, schema, content));\n\n // Get the last inserted rowid\n const lastIdResult = await execAll<{ id: number }>(this.db, buildGetLastRowId());\n const lastId = lastIdResult[0]?.id;\n\n if (lastId === undefined) {\n throw new Error(\"Failed to get last inserted row ID\");\n }\n\n // Fetch the inserted row\n const pkColumn = schema.primaryKey[0] ?? \"rowid\";\n const pk = content[pkColumn] !== undefined ? String(content[pkColumn]) : String(lastId);\n\n const rows = await execAll<Record<string, unknown>>(\n this.db,\n buildSelectByPK(table, schema, pk),\n );\n\n const row = rows[0];\n if (!row) {\n throw new Error(\"Failed to fetch inserted row\");\n }\n\n return { data: buildRowEntry(table, schema, row, buildOptions) };\n }\n\n /**\n * Updates an existing row\n */\n async updateRow(\n table: string,\n pk: string,\n content: Record<string, unknown>,\n ): Promise<AFSWriteResult> {\n const schema = this.schemas.get(table);\n if (!schema) {\n throw new Error(`Table '${table}' not found`);\n }\n\n const buildOptions: BuildEntryOptions = { basePath: this.basePath };\n\n // Update the row\n await execRun(this.db, buildUpdate(table, schema, pk, content));\n\n // Fetch the updated row\n const rows = await execAll<Record<string, unknown>>(\n this.db,\n buildSelectByPK(table, schema, pk),\n );\n\n const row = rows[0];\n if (!row) {\n throw new Error(`Row with pk '${pk}' not found after update`);\n }\n\n return { data: buildRowEntry(table, schema, row, buildOptions) };\n }\n\n /**\n * Deletes a row by primary key\n */\n async deleteRow(table: string, pk: string): Promise<AFSDeleteResult> {\n const schema = this.schemas.get(table);\n if (!schema) {\n throw new Error(`Table '${table}' not found`);\n }\n\n // Check if row exists first\n const existing = await execAll<Record<string, unknown>>(\n this.db,\n buildSelectByPK(table, schema, pk),\n );\n\n if (existing.length === 0) {\n return { message: `Row with pk '${pk}' not found in table '${table}'` };\n }\n\n // Delete the row\n await execRun(this.db, buildDelete(table, schema, pk));\n\n return { message: `Deleted row '${pk}' from table '${table}'` };\n }\n\n /**\n * Checks if a table exists\n */\n hasTable(table: string): boolean {\n return this.schemas.has(table);\n }\n\n /**\n * Gets the schema for a table\n */\n getTableSchema(table: string): TableSchema | undefined {\n return this.schemas.get(table);\n }\n\n /**\n * Updates the schemas map (after refresh)\n */\n setSchemas(schemas: Map<string, TableSchema>): void {\n this.schemas = schemas;\n }\n}\n","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 { TableSchema } from \"../schema/types.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 schemas: Map<string, TableSchema>,\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 = this.schemas.get(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 * Updates the schemas map (after refresh)\n */\n setSchemas(schemas: Map<string, TableSchema>): void {\n this.schemas = schemas;\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 = this.schemas.get(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","import { createRouter, type RadixRouter } from \"radix3\";\nimport type { RouteData, RouteMatch, RouteParams } from \"./types.js\";\n\nexport type { RouteData };\n\n/**\n * Creates a radix3 router for SQLite AFS path routing\n *\n * Routes:\n * - / → listTables\n * - /:table → listTable\n * - /:table/new → createRow\n * - /:table/@schema → getSchema\n * - /:table/:pk → readRow\n * - /:table/:pk/@attr → listAttributes\n * - /:table/:pk/@attr/:column → getAttribute\n * - /:table/:pk/@meta → getMeta\n * - /:table/:pk/@actions → listActions\n * - /:table/:pk/@actions/:action → executeAction\n */\nexport function createPathRouter(): RadixRouter<RouteData> {\n return createRouter<RouteData>({\n routes: {\n // Root - list all tables\n \"/\": { action: \"listTables\" },\n\n // Table-level routes\n \"/:table\": { action: \"listTable\" },\n \"/:table/new\": { action: \"createRow\" },\n \"/:table/@schema\": { action: \"getSchema\" },\n\n // Row-level routes\n \"/:table/:pk\": { action: \"readRow\" },\n \"/:table/:pk/@attr\": { action: \"listAttributes\" },\n \"/:table/:pk/@attr/:column\": { action: \"getAttribute\" },\n \"/:table/:pk/@meta\": { action: \"getMeta\" },\n \"/:table/:pk/@actions\": { action: \"listActions\" },\n \"/:table/:pk/@actions/:action\": { action: \"executeAction\" },\n },\n });\n}\n\n/**\n * Parses a path and returns the matched route with params\n * @param router - The radix3 router instance\n * @param path - The path to match\n * @returns RouteMatch if matched, undefined otherwise\n */\nexport function matchPath(router: RadixRouter<RouteData>, path: string): RouteMatch | undefined {\n const result = router.lookup(path);\n if (!result) return undefined;\n\n return {\n action: result.action,\n params: (result.params ?? {}) as RouteParams,\n };\n}\n\n/**\n * Builds a path from components\n */\nexport function buildPath(table?: string, pk?: string, suffix?: string): string {\n const parts = [\"/\"];\n if (table) parts.push(table);\n if (pk) parts.push(pk);\n if (suffix) parts.push(suffix);\n return parts.join(\"/\").replace(/\\/+/g, \"/\");\n}\n\n/**\n * Checks if a path segment is a virtual path (@attr, @meta, @actions, @schema)\n */\nexport function isVirtualPath(segment: string): boolean {\n return segment.startsWith(\"@\");\n}\n\n/**\n * Gets the type of virtual path\n */\nexport function getVirtualPathType(segment: string): \"attr\" | \"meta\" | \"actions\" | \"schema\" | null {\n if (segment === \"@attr\") return \"attr\";\n if (segment === \"@meta\") return \"meta\";\n if (segment === \"@actions\") return \"actions\";\n if (segment === \"@schema\") return \"schema\";\n return null;\n}\n","/**\n * Column information from SQLite PRAGMA table_info\n */\nexport interface ColumnInfo {\n /** Column name */\n name: string;\n /** SQLite type (INTEGER, TEXT, REAL, BLOB, etc.) */\n type: string;\n /** Whether the column has NOT NULL constraint */\n notnull: boolean;\n /** Whether this column is part of the primary key */\n pk: number;\n /** Default value for the column */\n dfltValue: unknown;\n}\n\n/**\n * Foreign key information from SQLite PRAGMA foreign_key_list\n */\nexport interface ForeignKeyInfo {\n /** Foreign key id */\n id: number;\n /** Sequence number for composite foreign keys */\n seq: number;\n /** Referenced table */\n table: string;\n /** Column in this table */\n from: string;\n /** Column in referenced table */\n to: string;\n /** ON UPDATE action */\n onUpdate: string;\n /** ON DELETE action */\n onDelete: string;\n /** MATCH clause */\n match: string;\n}\n\n/**\n * Index information from SQLite PRAGMA index_list\n */\nexport interface IndexInfo {\n /** Index sequence number */\n seq: number;\n /** Index name */\n name: string;\n /** Whether this is a unique index */\n unique: boolean;\n /** Origin of the index (c = CREATE INDEX, u = UNIQUE constraint, pk = PRIMARY KEY) */\n origin: string;\n /** Whether the index is partial */\n partial: boolean;\n}\n\n/**\n * Complete schema information for a single table\n */\nexport interface TableSchema {\n /** Table name */\n name: string;\n /** Column definitions */\n columns: ColumnInfo[];\n /** Primary key column names */\n primaryKey: string[];\n /** Foreign key relationships */\n foreignKeys: ForeignKeyInfo[];\n /** Indexes on this table */\n indexes: IndexInfo[];\n}\n\n/**\n * Raw PRAGMA table_info result row\n */\nexport interface PragmaTableInfoRow {\n cid: number;\n name: string;\n type: string;\n notnull: number;\n dflt_value: unknown;\n pk: number;\n}\n\n/**\n * Raw PRAGMA foreign_key_list result row\n */\nexport interface PragmaForeignKeyRow {\n id: number;\n seq: number;\n table: string;\n from: string;\n to: string;\n on_update: string;\n on_delete: string;\n match: string;\n}\n\n/**\n * Raw PRAGMA index_list result row\n */\nexport interface PragmaIndexListRow {\n seq: number;\n name: string;\n unique: number;\n origin: string;\n partial: number;\n}\n\n/**\n * System tables that should be excluded from introspection\n */\nexport const SYSTEM_TABLES = [\n \"sqlite_sequence\",\n \"sqlite_stat1\",\n \"sqlite_stat2\",\n \"sqlite_stat3\",\n \"sqlite_stat4\",\n] as const;\n","import { sql } from \"@aigne/sqlite\";\nimport type { LibSQLDatabase } from \"drizzle-orm/libsql\";\nimport {\n type ColumnInfo,\n type ForeignKeyInfo,\n type IndexInfo,\n type PragmaForeignKeyRow,\n type PragmaIndexListRow,\n type PragmaTableInfoRow,\n SYSTEM_TABLES,\n type TableSchema,\n} from \"./types.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 * Executes a raw SQL query (for INSERT, UPDATE, DELETE)\n */\nasync function execRun(db: LibSQLDatabase, query: string): Promise<void> {\n await db.run(sql.raw(query)).execute();\n}\n\n/**\n * Maps raw PRAGMA table_info row to ColumnInfo\n */\nfunction mapColumn(row: PragmaTableInfoRow): ColumnInfo {\n return {\n name: row.name,\n type: row.type,\n notnull: row.notnull === 1,\n pk: row.pk,\n dfltValue: row.dflt_value,\n };\n}\n\n/**\n * Maps raw PRAGMA foreign_key_list row to ForeignKeyInfo\n */\nfunction mapForeignKey(row: PragmaForeignKeyRow): ForeignKeyInfo {\n return {\n id: row.id,\n seq: row.seq,\n table: row.table,\n from: row.from,\n to: row.to,\n onUpdate: row.on_update,\n onDelete: row.on_delete,\n match: row.match,\n };\n}\n\n/**\n * Maps raw PRAGMA index_list row to IndexInfo\n */\nfunction mapIndex(row: PragmaIndexListRow): IndexInfo {\n return {\n seq: row.seq,\n name: row.name,\n unique: row.unique === 1,\n origin: row.origin,\n partial: row.partial === 1,\n };\n}\n\n/**\n * Schema introspector that uses SQLite PRAGMA queries to discover database schema\n */\nexport class SchemaIntrospector {\n /**\n * Introspects all tables in the database\n * @param db - Drizzle database instance\n * @param options - Introspection options\n * @returns Map of table name to TableSchema\n */\n async introspect(\n db: LibSQLDatabase,\n options?: {\n /** Whitelist of tables to include */\n tables?: string[];\n /** Tables to exclude */\n excludeTables?: string[];\n },\n ): Promise<Map<string, TableSchema>> {\n const schemas = new Map<string, TableSchema>();\n\n // Get all user tables (exclude system tables and FTS tables)\n const tablesResult = await execAll<{ name: string }>(\n db,\n `\n SELECT name FROM sqlite_master\n WHERE type = 'table'\n AND name NOT LIKE 'sqlite_%'\n AND name NOT LIKE '%_fts%'\n ORDER BY name\n `,\n );\n\n for (const { name } of tablesResult) {\n // Skip system tables\n if (SYSTEM_TABLES.includes(name as (typeof SYSTEM_TABLES)[number])) {\n continue;\n }\n\n // Apply whitelist filter\n if (options?.tables && !options.tables.includes(name)) {\n continue;\n }\n\n // Apply exclude filter\n if (options?.excludeTables?.includes(name)) {\n continue;\n }\n\n const schema = await this.introspectTable(db, name);\n schemas.set(name, schema);\n }\n\n return schemas;\n }\n\n /**\n * Introspects a single table\n * @param db - Drizzle database instance\n * @param tableName - Name of the table to introspect\n * @returns TableSchema for the specified table\n */\n async introspectTable(db: LibSQLDatabase, tableName: string): Promise<TableSchema> {\n // Get column information\n const columnsResult = await execAll<PragmaTableInfoRow>(\n db,\n `PRAGMA table_info(\"${tableName}\")`,\n );\n const columns = columnsResult.map(mapColumn);\n\n // Get primary key columns (pk > 0 indicates part of primary key)\n const primaryKey = columns.filter((c) => c.pk > 0).map((c) => c.name);\n\n // Get foreign keys\n const fksResult = await execAll<PragmaForeignKeyRow>(\n db,\n `PRAGMA foreign_key_list(\"${tableName}\")`,\n );\n const foreignKeys = fksResult.map(mapForeignKey);\n\n // Get indexes\n const indexesResult = await execAll<PragmaIndexListRow>(\n db,\n `PRAGMA index_list(\"${tableName}\")`,\n );\n const indexes = indexesResult.map(mapIndex);\n\n return {\n name: tableName,\n columns,\n primaryKey,\n foreignKeys,\n indexes,\n };\n }\n\n /**\n * Gets the primary key column name for a table\n * Returns the first PK column, or 'rowid' if no explicit PK\n */\n getPrimaryKeyColumn(schema: TableSchema): string {\n if (schema.primaryKey.length > 0 && schema.primaryKey[0]) {\n return schema.primaryKey[0];\n }\n // SQLite tables without explicit PK use rowid\n return \"rowid\";\n }\n\n /**\n * Checks if a table has FTS (Full-Text Search) enabled\n */\n async hasFTS(db: LibSQLDatabase, tableName: string): Promise<boolean> {\n const ftsTableName = `${tableName}_fts`;\n const result = await execAll<{ name: string }>(\n db,\n `\n SELECT name FROM sqlite_master\n WHERE type = 'table'\n AND name = '${ftsTableName}'\n `,\n );\n return result.length > 0;\n }\n\n /**\n * Creates FTS5 table for full-text search on specified columns\n */\n async createFTS(\n db: LibSQLDatabase,\n tableName: string,\n columns: string[],\n options?: {\n /** Content table (defaults to tableName) */\n contentTable?: string;\n /** Content rowid column (defaults to 'rowid') */\n contentRowid?: string;\n },\n ): Promise<void> {\n const ftsTableName = `${tableName}_fts`;\n const contentTable = options?.contentTable ?? tableName;\n const contentRowid = options?.contentRowid ?? \"rowid\";\n const columnList = columns.join(\", \");\n\n // Create FTS5 virtual table\n await execRun(\n db,\n `\n CREATE VIRTUAL TABLE IF NOT EXISTS \"${ftsTableName}\" USING fts5(\n ${columnList},\n content=\"${contentTable}\",\n content_rowid=\"${contentRowid}\"\n )\n `,\n );\n\n // Create triggers to keep FTS in sync\n await execRun(\n db,\n `\n CREATE TRIGGER IF NOT EXISTS \"${tableName}_ai\" AFTER INSERT ON \"${tableName}\" BEGIN\n INSERT INTO \"${ftsTableName}\"(rowid, ${columnList}) VALUES (new.${contentRowid}, ${columns.map((c) => `new.\"${c}\"`).join(\", \")});\n END\n `,\n );\n\n await execRun(\n db,\n `\n CREATE TRIGGER IF NOT EXISTS \"${tableName}_ad\" AFTER DELETE ON \"${tableName}\" BEGIN\n INSERT INTO \"${ftsTableName}\"(\"${ftsTableName}\", rowid, ${columnList}) VALUES ('delete', old.${contentRowid}, ${columns.map((c) => `old.\"${c}\"`).join(\", \")});\n END\n `,\n );\n\n await execRun(\n db,\n `\n CREATE TRIGGER IF NOT EXISTS \"${tableName}_au\" AFTER UPDATE ON \"${tableName}\" BEGIN\n INSERT INTO \"${ftsTableName}\"(\"${ftsTableName}\", rowid, ${columnList}) VALUES ('delete', old.${contentRowid}, ${columns.map((c) => `old.\"${c}\"`).join(\", \")});\n INSERT INTO \"${ftsTableName}\"(rowid, ${columnList}) VALUES (new.${contentRowid}, ${columns.map((c) => `new.\"${c}\"`).join(\", \")});\n END\n `,\n );\n }\n\n /**\n * Rebuilds FTS index for a table (useful after bulk inserts)\n */\n async rebuildFTS(db: LibSQLDatabase, tableName: string): Promise<void> {\n const ftsTableName = `${tableName}_fts`;\n await execRun(db, `INSERT INTO \"${ftsTableName}\"(\"${ftsTableName}\") VALUES ('rebuild')`);\n }\n}\n","import type {\n AFSAccessMode,\n AFSDeleteOptions,\n AFSDeleteResult,\n AFSExecOptions,\n AFSExecResult,\n AFSListOptions,\n AFSListResult,\n AFSModule,\n AFSModuleClass,\n AFSModuleLoadParams,\n AFSReadOptions,\n AFSReadResult,\n AFSRoot,\n AFSSearchOptions,\n AFSSearchResult,\n AFSWriteEntryPayload,\n AFSWriteOptions,\n AFSWriteResult,\n} from \"@aigne/afs\";\nimport { initDatabase } from \"@aigne/sqlite\";\nimport type { LibSQLDatabase } from \"drizzle-orm/libsql\";\nimport type { RadixRouter } from \"radix3\";\nimport { registerBuiltInActions } from \"./actions/built-in.js\";\nimport { ActionsRegistry } from \"./actions/registry.js\";\nimport type { ActionContext } from \"./actions/types.js\";\nimport { type SQLiteAFSOptions, sqliteAFSConfigSchema } from \"./config.js\";\nimport { buildActionsListEntry } from \"./node/builder.js\";\nimport { CRUDOperations } from \"./operations/crud.js\";\nimport { createFTSConfig, type FTSConfig, FTSSearch } from \"./operations/search.js\";\nimport { createPathRouter, matchPath, type RouteData } from \"./router/path-router.js\";\nimport { SchemaIntrospector } from \"./schema/introspector.js\";\nimport type { TableSchema } from \"./schema/types.js\";\n\n/**\n * SQLite AFS Module\n *\n * Exposes SQLite databases as AFS nodes with full CRUD support,\n * schema introspection, FTS5 search, and virtual paths (@attr, @meta, @actions).\n */\nexport class SQLiteAFS implements AFSModule {\n readonly name: string;\n readonly description: string;\n readonly accessMode: AFSAccessMode;\n\n private db!: Awaited<ReturnType<typeof initDatabase>>;\n private schemas = new Map<string, TableSchema>();\n private router!: RadixRouter<RouteData>;\n private crud!: CRUDOperations;\n private ftsSearch!: FTSSearch;\n private actions: ActionsRegistry;\n private ftsConfig: FTSConfig;\n private initialized = false;\n\n constructor(private options: SQLiteAFSOptions) {\n this.name = options.name ?? \"sqlite-afs\";\n this.description = options.description ?? `SQLite database: ${options.url}`;\n this.accessMode = options.accessMode ?? \"readwrite\";\n this.ftsConfig = createFTSConfig(options.fts);\n this.actions = new ActionsRegistry();\n registerBuiltInActions(this.actions);\n }\n\n /**\n * Returns the Zod schema for configuration validation\n */\n static schema() {\n return sqliteAFSConfigSchema;\n }\n\n /**\n * Loads a module instance from configuration\n */\n static async load({ parsed }: AFSModuleLoadParams): Promise<SQLiteAFS> {\n const validated = sqliteAFSConfigSchema.parse(parsed);\n return new SQLiteAFS(validated);\n }\n\n /**\n * Called when the module is mounted to AFS\n */\n async onMount(_afs: AFSRoot): Promise<void> {\n await this.initialize();\n }\n\n /**\n * Initializes the database connection and introspects schema\n */\n private async initialize(): Promise<void> {\n if (this.initialized) return;\n\n // Initialize database connection\n this.db = await initDatabase({\n url: this.options.url,\n wal: this.options.wal ?? true,\n });\n\n // Cast db to LibSQLDatabase for operations\n const db = this.db as unknown as LibSQLDatabase;\n\n // Introspect database schema\n const introspector = new SchemaIntrospector();\n this.schemas = await introspector.introspect(db, {\n tables: this.options.tables,\n excludeTables: this.options.excludeTables,\n });\n\n // Initialize components\n this.router = createPathRouter();\n this.crud = new CRUDOperations(db, this.schemas, \"\");\n this.ftsSearch = new FTSSearch(db, this.schemas, this.ftsConfig, \"\");\n\n this.initialized = true;\n }\n\n /**\n * Ensures the module is initialized\n */\n private async ensureInitialized(): Promise<void> {\n if (!this.initialized) {\n await this.initialize();\n }\n }\n\n /**\n * Lists entries at a path\n */\n async list(path: string, options?: AFSListOptions): Promise<AFSListResult> {\n await this.ensureInitialized();\n\n const match = matchPath(this.router, path);\n if (!match) {\n return { data: [] };\n }\n\n switch (match.action) {\n case \"listTables\":\n return this.crud.listTables();\n\n case \"listTable\":\n if (!match.params.table) return { data: [] };\n return this.crud.listTable(match.params.table, options);\n\n case \"listAttributes\":\n if (!match.params.table || !match.params.pk) return { data: [] };\n return this.crud.listAttributes(match.params.table, match.params.pk);\n\n case \"listActions\":\n if (!match.params.table || !match.params.pk) return { data: [] };\n return this.listActions(match.params.table, match.params.pk);\n\n default:\n return { data: [] };\n }\n }\n\n /**\n * Reads an entry at a path\n */\n async read(path: string, _options?: AFSReadOptions): Promise<AFSReadResult> {\n await this.ensureInitialized();\n\n const match = matchPath(this.router, path);\n if (!match) {\n return {};\n }\n\n switch (match.action) {\n case \"readRow\":\n if (!match.params.table || !match.params.pk) return {};\n return this.crud.readRow(match.params.table, match.params.pk);\n\n case \"getSchema\":\n if (!match.params.table) return {};\n return this.crud.getSchema(match.params.table);\n\n case \"getAttribute\":\n if (!match.params.table || !match.params.pk || !match.params.column) return {};\n return this.crud.getAttribute(match.params.table, match.params.pk, match.params.column);\n\n case \"getMeta\":\n if (!match.params.table || !match.params.pk) return {};\n return this.crud.getMeta(match.params.table, match.params.pk);\n\n default:\n return {};\n }\n }\n\n /**\n * Writes an entry at a path\n */\n async write(\n path: string,\n content: AFSWriteEntryPayload,\n _options?: AFSWriteOptions,\n ): Promise<AFSWriteResult> {\n await this.ensureInitialized();\n\n if (this.accessMode === \"readonly\") {\n throw new Error(\"Module is in readonly mode\");\n }\n\n const match = matchPath(this.router, path);\n if (!match) {\n throw new Error(`Invalid path: ${path}`);\n }\n\n switch (match.action) {\n case \"createRow\":\n if (!match.params.table) {\n throw new Error(\"Table name required for create\");\n }\n return this.crud.createRow(match.params.table, content.content ?? content);\n\n case \"readRow\":\n if (!match.params.table || !match.params.pk) {\n throw new Error(\"Table and primary key required for update\");\n }\n return this.crud.updateRow(match.params.table, match.params.pk, content.content ?? content);\n\n case \"executeAction\":\n if (!match.params.table || !match.params.action) {\n throw new Error(\"Table and action name required\");\n }\n return this.executeAction(\n match.params.table,\n match.params.pk,\n match.params.action,\n content.content ?? content,\n );\n\n default:\n throw new Error(`Write not supported for path: ${path}`);\n }\n }\n\n /**\n * Deletes an entry at a path\n */\n async delete(path: string, _options?: AFSDeleteOptions): Promise<AFSDeleteResult> {\n await this.ensureInitialized();\n\n if (this.accessMode === \"readonly\") {\n throw new Error(\"Module is in readonly mode\");\n }\n\n const match = matchPath(this.router, path);\n if (!match || match.action !== \"readRow\") {\n throw new Error(`Delete not supported for path: ${path}`);\n }\n\n if (!match.params.table || !match.params.pk) {\n throw new Error(\"Table and primary key required for delete\");\n }\n\n return this.crud.deleteRow(match.params.table, match.params.pk);\n }\n\n /**\n * Searches for entries matching a query\n */\n async search(path: string, query: string, options?: AFSSearchOptions): Promise<AFSSearchResult> {\n await this.ensureInitialized();\n\n // If path specifies a table, search only that table\n const match = matchPath(this.router, path);\n if (match?.params.table) {\n return this.ftsSearch.searchTable(match.params.table, query, options);\n }\n\n // Otherwise search all FTS-enabled tables\n return this.ftsSearch.search(query, options);\n }\n\n /**\n * Executes a module operation\n */\n async exec(\n path: string,\n args: Record<string, unknown>,\n _options: AFSExecOptions,\n ): Promise<AFSExecResult> {\n await this.ensureInitialized();\n\n const match = matchPath(this.router, path);\n if (match?.action === \"executeAction\" && match.params.table && match.params.action) {\n const result = await this.executeAction(\n match.params.table,\n match.params.pk,\n match.params.action,\n args,\n );\n return { data: result.data as unknown as Record<string, unknown> };\n }\n\n throw new Error(`Exec not supported for path: ${path}`);\n }\n\n /**\n * Lists available actions for a row\n */\n private listActions(table: string, pk: string): AFSListResult {\n const actionNames = this.actions.listNames({ rowLevel: true });\n return {\n data: buildActionsListEntry(table, pk, actionNames, { basePath: \"\" }),\n };\n }\n\n /**\n * Executes an action\n */\n private async executeAction(\n table: string,\n pk: string | undefined,\n actionName: string,\n params: Record<string, unknown>,\n ): Promise<AFSWriteResult> {\n const schema = this.schemas.get(table);\n if (!schema) {\n throw new Error(`Table '${table}' not found`);\n }\n\n // Get row data if pk is provided\n let row: Record<string, unknown> | undefined;\n if (pk) {\n const readResult = await this.crud.readRow(table, pk);\n row = readResult.data?.content as Record<string, unknown> | undefined;\n }\n\n const ctx: ActionContext = {\n db: this.db as unknown as LibSQLDatabase,\n schemas: this.schemas,\n table,\n pk,\n row,\n module: {\n refreshSchema: () => this.refreshSchema(),\n exportTable: (t, f) => this.exportTable(t, f),\n },\n };\n\n const result = await this.actions.execute(actionName, ctx, params);\n\n if (!result.success) {\n throw new Error(result.message ?? \"Action failed\");\n }\n\n return {\n data: {\n id: `${table}:${pk ?? \"\"}:@actions:${actionName}`,\n path: pk ? `/${table}/${pk}/@actions/${actionName}` : `/${table}/@actions/${actionName}`,\n content: result.data,\n },\n };\n }\n\n /**\n * Refreshes the schema cache\n */\n async refreshSchema(): Promise<void> {\n const db = this.db as unknown as LibSQLDatabase;\n const introspector = new SchemaIntrospector();\n this.schemas = await introspector.introspect(db, {\n tables: this.options.tables,\n excludeTables: this.options.excludeTables,\n });\n this.crud.setSchemas(this.schemas);\n this.ftsSearch.setSchemas(this.schemas);\n }\n\n /**\n * Exports table data in specified format\n */\n async exportTable(table: string, format: string): Promise<unknown> {\n const listResult = await this.crud.listTable(table, { limit: 10000 });\n\n if (format === \"csv\") {\n const schema = this.schemas.get(table);\n if (!schema) throw new Error(`Table '${table}' not found`);\n\n const headers = schema.columns.map((c) => c.name).join(\",\");\n const rows = listResult.data.map((entry) => {\n const content = entry.content as Record<string, unknown>;\n return schema.columns\n .map((c) => {\n const val = content[c.name];\n if (val === null || val === undefined) return \"\";\n if (typeof val === \"string\" && (val.includes(\",\") || val.includes('\"'))) {\n return `\"${val.replace(/\"/g, '\"\"')}\"`;\n }\n return String(val);\n })\n .join(\",\");\n });\n\n return `${headers}\\n${rows.join(\"\\n\")}`;\n }\n\n // Default: JSON\n return listResult.data.map((entry) => entry.content);\n }\n\n /**\n * Registers a custom action\n */\n registerAction(\n name: string,\n handler: (ctx: ActionContext, params: Record<string, unknown>) => Promise<unknown>,\n options?: {\n description?: string;\n tableLevel?: boolean;\n rowLevel?: boolean;\n },\n ): void {\n this.actions.registerSimple(\n name,\n async (ctx, params) => ({\n success: true,\n data: await handler(ctx, params),\n }),\n options,\n );\n }\n\n /**\n * Gets table schemas (for external access)\n */\n getSchemas(): Map<string, TableSchema> {\n return this.schemas;\n }\n\n /**\n * Gets the database instance (for advanced operations)\n */\n getDatabase(): LibSQLDatabase {\n return this.db as unknown as LibSQLDatabase;\n }\n}\n\n// Type check to ensure SQLiteAFS implements AFSModuleClass\nconst _typeCheck: AFSModuleClass<SQLiteAFS, SQLiteAFSOptions> = SQLiteAFS;\n"],"mappings":";;;;;;;;;AAQA,eAAeA,UAAW,IAAoB,OAA6B;AACzE,QAAO,GAAG,IAAO,IAAI,IAAI,MAAM,CAAC,CAAC,SAAS;;;;;AAM5C,eAAeC,UAAQ,IAAoB,OAA8B;AACvE,OAAM,GAAG,IAAI,IAAI,IAAI,MAAM,CAAC,CAAC,SAAS;;;;;AAMxC,SAAgB,uBAAuB,UAAiC;AAEtE,UAAS,SAAS;EAChB,MAAM;EACN,aAAa;EACb,YAAY;EACZ,UAAU;EACV,SAAS,OAAO,QAA8C;AAC5D,SAAM,IAAI,OAAO,eAAe;AAChC,UAAO;IACL,SAAS;IACT,SAAS;IACV;;EAEJ,CAAC;AAGF,UAAS,SAAS;EAChB,MAAM;EACN,aAAa;EACb,YAAY;EACZ,UAAU;EACV,aAAa;GACX,MAAM;GACN,YAAY,EACV,QAAQ;IACN,MAAM;IACN,MAAM,CAAC,QAAQ,MAAM;IACrB,SAAS;IACV,EACF;GACF;EACD,SAAS,OAAO,KAAoB,WAAkC;GACpE,MAAM,SAAU,OAAO,UAAqB;AAE5C,UAAO;IACL,SAAS;IACT,MAHW,MAAM,IAAI,OAAO,YAAY,IAAI,OAAO,OAAO;IAI3D;;EAEJ,CAAC;AAGF,UAAS,SAAS;EAChB,MAAM;EACN,aAAa;EACb,YAAY;EACZ,UAAU;EACV,SAAS,OAAO,QAA8C;AAK5D,UAAO;IACL,SAAS;IACT,MAAM,EAAE,QANK,MAAMD,UACnB,IAAI,IACJ,kCAAkC,IAAI,MAAM,GAC7C,EAGuB,IAAI,SAAS,GAAG;IACvC;;EAEJ,CAAC;AAGF,UAAS,SAAS;EAChB,MAAM;EACN,aAAa;EACb,YAAY;EACZ,UAAU;EACV,SAAS,OAAO,QAA8C;AAC5D,OAAI,CAAC,IAAI,IACP,QAAO;IAAE,SAAS;IAAO,SAAS;IAA0B;GAG9D,MAAM,SAAS,IAAI,QAAQ,IAAI,IAAI,MAAM;AACzC,OAAI,CAAC,OACH,QAAO;IAAE,SAAS;IAAO,SAAS,UAAU,IAAI,MAAM;IAAc;GAItE,MAAM,WAAW,OAAO,WAAW,MAAM;GACzC,MAAM,UAAU,EAAE,GAAG,IAAI,KAAK;AAC9B,UAAO,QAAQ;AACf,UAAO,QAAQ;GAGf,MAAM,UAAU,OAAO,KAAK,QAAQ;GACpC,MAAM,SAAS,QAAQ,KAAK,QAAQ,kBAAkB,QAAQ,KAAK,CAAC;AAEpE,SAAMC,UACJ,IAAI,IACJ,gBAAgB,IAAI,MAAM,KAAK,QAAQ,KAAK,MAAM,IAAI,EAAE,GAAG,CAAC,KAAK,KAAK,CAAC,YAAY,OAAO,KAAK,KAAK,CAAC,GACtG;AAQD,UAAO;IACL,SAAS;IACT,MAAM,EAAE,QAPW,MAAMD,UACzB,IAAI,IACJ,mCACD,EAI6B,IAAI,IAAI;IACpC,SAAS;IACV;;EAEJ,CAAC;AAGF,UAAS,SAAS;EAChB,MAAM;EACN,aAAa;EACb,YAAY;EACZ,UAAU;EACV,SAAS,OAAO,QAA8C;AAC5D,OAAI,CAAC,IAAI,IACP,QAAO;IAAE,SAAS;IAAO,SAAS;IAA0B;GAG9D,MAAM,SAAS,IAAI,QAAQ,IAAI,IAAI,MAAM;AACzC,OAAI,CAAC,OACH,QAAO;IAAE,SAAS;IAAO,SAAS,UAAU,IAAI,MAAM;IAAc;GAGtE,MAAM,SAAmB,EAAE;AAG3B,QAAK,MAAM,OAAO,OAAO,QACvB,KAAI,IAAI,YAAY,IAAI,IAAI,IAAI,UAAU,QAAQ,IAAI,IAAI,IAAI,UAAU,QACtE,QAAO,KAAK,WAAW,IAAI,KAAK,kBAAkB;AAKtD,QAAK,MAAM,MAAM,OAAO,aAAa;IACnC,MAAM,QAAQ,IAAI,IAAI,GAAG;AACzB,QAAI,UAAU,QAAQ,UAAU,QAK9B;UAJkB,MAAMA,UACtB,IAAI,IACJ,kCAAkC,GAAG,MAAM,WAAW,GAAG,GAAG,OAAO,OAAO,MAAM,CAAC,QAAQ,MAAM,KAAK,CAAC,GACtG,EACa,IAAI,UAAU,EAC1B,QAAO,KACL,0BAA0B,GAAG,KAAK,2BAA2B,GAAG,MAAM,GAAG,GAAG,KAC7E;;;AAKP,UAAO;IACL,SAAS,OAAO,WAAW;IAC3B,MAAM;KAAE;KAAQ,OAAO,OAAO,WAAW;KAAG;IAC5C,SAAS,OAAO,SAAS,IAAI,sBAAsB,OAAO,KAAK,KAAK,KAAK;IAC1E;;EAEJ,CAAC;;;;;AAMJ,SAAS,kBAAkB,OAAwB;AACjD,KAAI,UAAU,QAAQ,UAAU,OAC9B,QAAO;AAET,KAAI,OAAO,UAAU,SACnB,QAAO,OAAO,MAAM;AAEtB,KAAI,OAAO,UAAU,UACnB,QAAO,QAAQ,MAAM;AAEvB,KAAI,iBAAiB,KACnB,QAAO,IAAI,MAAM,aAAa,CAAC;AAEjC,KAAI,OAAO,UAAU,SACnB,QAAO,IAAI,KAAK,UAAU,MAAM,CAAC,QAAQ,MAAM,KAAK,CAAC;AAEvD,QAAO,IAAI,OAAO,MAAM,CAAC,QAAQ,MAAM,KAAK,CAAC;;;;;;;;AC/L/C,IAAa,kBAAb,MAA6B;CAC3B,AAAQ,2BAAW,IAAI,KAA+B;;;;CAKtD,SAAS,YAAoC;AAC3C,OAAK,SAAS,IAAI,WAAW,MAAM,WAAW;;;;;CAMhD,eACE,MACA,SACA,SAKM;AACN,OAAK,SAAS;GACZ;GACA;GACA,aAAa,SAAS;GACtB,YAAY,SAAS,cAAc;GACnC,UAAU,SAAS,YAAY;GAChC,CAAC;;;;;CAMJ,WAAW,MAAuB;AAChC,SAAO,KAAK,SAAS,OAAO,KAAK;;;;;CAMnC,IAAI,MAAuB;AACzB,SAAO,KAAK,SAAS,IAAI,KAAK;;;;;CAMhC,IAAI,MAA4C;AAC9C,SAAO,KAAK,SAAS,IAAI,KAAK;;;;;CAMhC,KAAK,SAA4E;EAC/E,MAAM,UAAU,MAAM,KAAK,KAAK,SAAS,QAAQ,CAAC;AAElD,MAAI,SAAS,eAAe,UAAa,SAAS,aAAa,OAC7D,QAAO,QAAQ,QAAQ,MAAM;AAC3B,OAAI,QAAQ,cAAc,CAAC,EAAE,WAAY,QAAO;AAChD,OAAI,QAAQ,YAAY,CAAC,EAAE,SAAU,QAAO;AAC5C,UAAO;IACP;AAGJ,SAAO;;;;;CAMT,UAAU,SAAkE;AAC1E,SAAO,KAAK,KAAK,QAAQ,CAAC,KAAK,MAAM,EAAE,KAAK;;;;;CAM9C,MAAM,QACJ,MACA,KACA,SAAkC,EAAE,EACb;EACvB,MAAM,aAAa,KAAK,SAAS,IAAI,KAAK;AAE1C,MAAI,CAAC,WACH,QAAO;GACL,SAAS;GACT,SAAS,mBAAmB;GAC7B;AAIH,MAAI,IAAI,MAAM,CAAC,WAAW,SACxB,QAAO;GACL,SAAS;GACT,SAAS,WAAW,KAAK;GAC1B;AAGH,MAAI,CAAC,IAAI,MAAM,CAAC,WAAW,WACzB,QAAO;GACL,SAAS;GACT,SAAS,WAAW,KAAK;GAC1B;AAGH,MAAI;AACF,UAAO,MAAM,WAAW,QAAQ,KAAK,OAAO;WACrC,OAAO;AACd,UAAO;IACL,SAAS;IACT,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;IAChE;;;;;;;;;;ACjHP,MAAa,kBAAkB,EAC5B,OAAO;CACN,SAAS,EAAE,SAAS,CAAC,QAAQ,KAAK,CAAC,SAAS,yBAAyB;CACrE,QAAQ,EACL,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC,CAC3B,UAAU,CACV,SAAS,gDAAgD;CAC7D,CAAC,CACD,UAAU;;;;AAKb,MAAa,wBAAwB,EAAE,OAAO;CAC5C,KAAK,EAAE,QAAQ,CAAC,SAAS,gDAAgD;CACzE,MAAM,EAAE,QAAQ,CAAC,UAAU,CAAC,SAAS,wCAAwC;CAC7E,aAAa,EAAE,QAAQ,CAAC,UAAU,CAAC,SAAS,6BAA6B;CACzE,YAAY;CACZ,QAAQ,EACL,MAAM,EAAE,QAAQ,CAAC,CACjB,UAAU,CACV,SAAS,2EAA2E;CACvF,eAAe,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC,UAAU,CAAC,SAAS,kCAAkC;CACzF,KAAK;CACL,KAAK,EAAE,SAAS,CAAC,UAAU,CAAC,QAAQ,KAAK,CAAC,SAAS,yCAAyC;CAC7F,CAAC;;;;;;;ACjBF,SAAgB,cACd,OACA,QACA,KACA,SACU;CACV,MAAM,WAAW,OAAO,WAAW,MAAM;CACzC,MAAM,KAAK,OAAO,IAAI,aAAa,IAAI,MAAM;CAC7C,MAAM,WAAW,SAAS,YAAY;AAEtC,QAAO;EACL,IAAI,GAAG,MAAM,GAAG;EAChB,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG;EAC9B,SAAS;EACT,UAAU;GACR;GACA,YAAY;GACZ,iBAAiB;GAClB;EACD,WAAW,UAAU,IAAI,cAAc,IAAI,UAAU;EACrD,WAAW,UAAU,IAAI,cAAc,IAAI,UAAU;EACtD;;;;;AAMH,SAAgB,gBACd,OACA,QACA,SACU;AAGV,QAAO;EACL,IAAI;EACJ,MAAM,GAJS,SAAS,YAAY,GAIlB,GAAG;EACrB,aAAa,UAAU,MAAM,IAAI,OAAO,QAAQ,OAAO;EACvD,UAAU;GACR;GACA,aAAa,OAAO,QAAQ;GAC5B,YAAY,OAAO;GACnB,eAAe,SAAS;GACzB;EACF;;;;;AAMH,SAAgB,iBACd,OACA,QACA,SACU;CACV,MAAM,WAAW,SAAS,YAAY;AAEtC,QAAO;EACL,IAAI,GAAG,MAAM;EACb,MAAM,GAAG,SAAS,GAAG,MAAM;EAC3B,aAAa,qBAAqB;EAClC,SAAS;GACP,MAAM,OAAO;GACb,SAAS,OAAO,QAAQ,KAAK,SAAS;IACpC,MAAM,IAAI;IACV,MAAM,IAAI;IACV,UAAU,CAAC,IAAI;IACf,YAAY,IAAI,KAAK;IACrB,cAAc,IAAI;IACnB,EAAE;GACH,YAAY,OAAO;GACnB,aAAa,OAAO,YAAY,KAAK,QAAQ;IAC3C,QAAQ,GAAG;IACX,YAAY;KACV,OAAO,GAAG;KACV,QAAQ,GAAG;KACZ;IACD,UAAU,GAAG;IACb,UAAU,GAAG;IACd,EAAE;GACH,SAAS,OAAO,QAAQ,KAAK,SAAS;IACpC,MAAM,IAAI;IACV,QAAQ,IAAI;IACZ,QAAQ,IAAI;IACb,EAAE;GACJ;EACD,UAAU;GACR;GACA,MAAM;GACP;EACF;;;;;AAMH,SAAgB,oBACd,OACA,IACA,QACA,OACA,SACU;CACV,MAAM,WAAW,SAAS,YAAY;AAEtC,QAAO;EACL,IAAI,GAAG,MAAM,GAAG,GAAG,SAAS;EAC5B,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,GAAG,SAAS;EAC1C,SAAS;EACT,UAAU;GACR;GACA,iBAAiB;GACjB;GACA,MAAM;GACP;EACF;;;;;AAMH,SAAgB,wBACd,OACA,QACA,IACA,KACA,SACY;CACZ,MAAM,WAAW,SAAS,YAAY;AAEtC,QAAO,OAAO,QAAQ,KAAK,SAAS;EAClC,IAAI,GAAG,MAAM,GAAG,GAAG,SAAS,IAAI;EAChC,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,GAAG,SAAS,IAAI;EAC9C,SAAS,IAAI;EACb,aAAa,GAAG,IAAI,OAAO,IAAI,UAAU,cAAc;EACvD,SAAS,IAAI,IAAI;EACjB,UAAU;GACR,QAAQ,IAAI;GACZ,MAAM,IAAI;GACX;EACF,EAAE;;;;;AAML,SAAgB,eACd,OACA,QACA,IACA,KACA,SACU;CACV,MAAM,WAAW,SAAS,YAAY;AAEtC,QAAO;EACL,IAAI,GAAG,MAAM,GAAG,GAAG;EACnB,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,GAAG;EACjC,SAAS;GACP;GACA,YAAY,OAAO,WAAW,MAAM;GACpC,iBAAiB;GACjB,QAAQ;IACN,SAAS,OAAO,QAAQ,KAAK,MAAM,EAAE,KAAK;IAC1C,OAAO,OAAO,YAAY,OAAO,QAAQ,KAAK,MAAM,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC;IACvE;GACD,aAAa,OAAO,YAAY,QAAQ,OAAO,OAAO,KAAK,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC;GAClF,OAAO,IAAI;GACZ;EACD,UAAU;GACR;GACA,MAAM;GACP;EACF;;;;;AAMH,SAAgB,sBACd,OACA,IACA,SACA,SACY;CACZ,MAAM,WAAW,SAAS,YAAY;AAEtC,QAAO,QAAQ,KAAK,YAAY;EAC9B,IAAI,GAAG,MAAM,GAAG,GAAG,YAAY;EAC/B,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,GAAG,YAAY;EAC7C,SAAS;EACT,UAAU,EACR,SAAS;GACP,MAAM;GACN,aAAa,WAAW,OAAO,aAAa,MAAM,GAAG;GACtD,EACF;EACF,EAAE;;;;;AAML,SAAgB,iBACd,OACA,QACA,KACA,SACA,SACU;CACV,MAAM,QAAQ,cAAc,OAAO,QAAQ,KAAK,QAAQ;AAExD,KAAI,QACF,OAAM,UAAU;AAGlB,QAAO;;;;;AAMT,SAAS,UAAU,OAAkC;AACnD,KAAI,CAAC,MAAO,QAAO;AACnB,KAAI,iBAAiB,KAAM,QAAO;AAClC,KAAI,OAAO,UAAU,SAAU,QAAO,IAAI,KAAK,MAAM;AACrD,KAAI,OAAO,UAAU,SAAU,QAAO,IAAI,KAAK,MAAM;;;;;;;;AC3OvD,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;;;;;;;;ACrGT,eAAeE,UAAW,IAAoB,OAA6B;AACzE,QAAO,GAAG,IAAO,IAAI,IAAI,MAAM,CAAC,CAAC,SAAS;;;;;AAM5C,eAAeC,UAAQ,IAAoB,OAA8B;AACvE,OAAM,GAAG,IAAI,IAAI,IAAI,MAAM,CAAC,CAAC,SAAS;;;;;AAMxC,IAAa,iBAAb,MAA4B;CAC1B,YACE,AAAQ,IACR,AAAQ,SACR,AAAQ,WAAmB,IAC3B;EAHQ;EACA;EACA;;;;;CAMV,MAAM,aAAqC;EACzC,MAAM,UAAsB,EAAE;EAC9B,MAAM,eAAkC,EAAE,UAAU,KAAK,UAAU;AAEnE,OAAK,MAAM,CAAC,MAAM,WAAW,KAAK,SAAS;GAMzC,MAAM,YAJc,MAAMD,UACxB,KAAK,IACL,kCAAkC,KAAK,GACxC,EAC4B,IAAI,SAAS;AAE1C,WAAQ,KAAK,gBAAgB,MAAM,QAAQ;IAAE,GAAG;IAAc;IAAU,CAAC,CAAC;;AAG5E,SAAO,EAAE,MAAM,SAAS;;;;;CAM1B,MAAM,UAAU,OAAe,SAAkD;EAC/E,MAAM,SAAS,KAAK,QAAQ,IAAI,MAAM;AACtC,MAAI,CAAC,OACH,QAAO;GAAE,MAAM,EAAE;GAAE,SAAS,UAAU,MAAM;GAAc;EAG5D,MAAM,eAAkC,EAAE,UAAU,KAAK,UAAU;EAEnE,MAAM,WAAW,eAAe,OAAO;GACrC,OAAO,SAAS,SAAS;GACzB,SAAS,SAAS;GACnB,CAAC;AAMF,SAAO,EAAE,OAJI,MAAMA,UAAiC,KAAK,IAAI,SAAS,EAEjD,KAAK,QAAQ,cAAc,OAAO,QAAQ,KAAK,aAAa,CAAC,EAE1D;;;;;CAM1B,MAAM,QAAQ,OAAe,IAAoC;EAC/D,MAAM,SAAS,KAAK,QAAQ,IAAI,MAAM;AACtC,MAAI,CAAC,OACH,QAAO,EAAE,SAAS,UAAU,MAAM,cAAc;EAGlD,MAAM,eAAkC,EAAE,UAAU,KAAK,UAAU;EAOnE,MAAM,OALO,MAAMA,UACjB,KAAK,IACL,gBAAgB,OAAO,QAAQ,GAAG,CACnC,EAEgB;AACjB,MAAI,CAAC,IACH,QAAO,EAAE,SAAS,gBAAgB,GAAG,wBAAwB,MAAM,IAAI;AAGzE,SAAO,EAAE,MAAM,cAAc,OAAO,QAAQ,KAAK,aAAa,EAAE;;;;;CAMlE,UAAU,OAA8B;EACtC,MAAM,SAAS,KAAK,QAAQ,IAAI,MAAM;AACtC,MAAI,CAAC,OACH,QAAO,EAAE,SAAS,UAAU,MAAM,cAAc;AAIlD,SAAO,EAAE,MAAM,iBAAiB,OAAO,QADC,EAAE,UAAU,KAAK,UAAU,CACP,EAAE;;;;;CAMhE,MAAM,eAAe,OAAe,IAAoC;EACtE,MAAM,SAAS,KAAK,QAAQ,IAAI,MAAM;AACtC,MAAI,CAAC,OACH,QAAO;GAAE,MAAM,EAAE;GAAE,SAAS,UAAU,MAAM;GAAc;EAG5D,MAAM,eAAkC,EAAE,UAAU,KAAK,UAAU;EAOnE,MAAM,OALO,MAAMA,UACjB,KAAK,IACL,gBAAgB,OAAO,QAAQ,GAAG,CACnC,EAEgB;AACjB,MAAI,CAAC,IACH,QAAO;GAAE,MAAM,EAAE;GAAE,SAAS,gBAAgB,GAAG;GAAc;AAG/D,SAAO,EACL,MAAM,wBAAwB,OAAO,QAAQ,IAAI,KAAK,aAAa,EACpE;;;;;CAMH,MAAM,aAAa,OAAe,IAAY,QAAwC;EACpF,MAAM,SAAS,KAAK,QAAQ,IAAI,MAAM;AACtC,MAAI,CAAC,OACH,QAAO,EAAE,SAAS,UAAU,MAAM,cAAc;AAKlD,MAAI,CADY,OAAO,QAAQ,MAAM,MAAM,EAAE,SAAS,OAAO,CAE3D,QAAO,EAAE,SAAS,WAAW,OAAO,wBAAwB,MAAM,IAAI;EAGxE,MAAM,eAAkC,EAAE,UAAU,KAAK,UAAU;EAEnE,MAAM,OAAO,MAAMA,UACjB,KAAK,IACL,gBAAgB,OAAO,QAAQ,GAAG,CACnC;AAED,MAAI,KAAK,WAAW,EAClB,QAAO,EAAE,SAAS,gBAAgB,GAAG,cAAc;AAGrD,SAAO,EACL,MAAM,oBAAoB,OAAO,IAAI,QAAQ,KAAK,KAAK,SAAS,aAAa,EAC9E;;;;;CAMH,MAAM,QAAQ,OAAe,IAAoC;EAC/D,MAAM,SAAS,KAAK,QAAQ,IAAI,MAAM;AACtC,MAAI,CAAC,OACH,QAAO,EAAE,SAAS,UAAU,MAAM,cAAc;EAGlD,MAAM,eAAkC,EAAE,UAAU,KAAK,UAAU;EAOnE,MAAM,OALO,MAAMA,UACjB,KAAK,IACL,gBAAgB,OAAO,QAAQ,GAAG,CACnC,EAEgB;AACjB,MAAI,CAAC,IACH,QAAO,EAAE,SAAS,gBAAgB,GAAG,cAAc;AAGrD,SAAO,EAAE,MAAM,eAAe,OAAO,QAAQ,IAAI,KAAK,aAAa,EAAE;;;;;CAMvE,MAAM,UAAU,OAAe,SAA2D;EACxF,MAAM,SAAS,KAAK,QAAQ,IAAI,MAAM;AACtC,MAAI,CAAC,OACH,OAAM,IAAI,MAAM,UAAU,MAAM,aAAa;EAG/C,MAAM,eAAkC,EAAE,UAAU,KAAK,UAAU;AAGnE,QAAMC,UAAQ,KAAK,IAAI,YAAY,OAAO,QAAQ,QAAQ,CAAC;EAI3D,MAAM,UADe,MAAMD,UAAwB,KAAK,IAAI,mBAAmB,CAAC,EACpD,IAAI;AAEhC,MAAI,WAAW,OACb,OAAM,IAAI,MAAM,qCAAqC;EAIvD,MAAM,WAAW,OAAO,WAAW,MAAM;EACzC,MAAM,KAAK,QAAQ,cAAc,SAAY,OAAO,QAAQ,UAAU,GAAG,OAAO,OAAO;EAOvF,MAAM,OALO,MAAMA,UACjB,KAAK,IACL,gBAAgB,OAAO,QAAQ,GAAG,CACnC,EAEgB;AACjB,MAAI,CAAC,IACH,OAAM,IAAI,MAAM,+BAA+B;AAGjD,SAAO,EAAE,MAAM,cAAc,OAAO,QAAQ,KAAK,aAAa,EAAE;;;;;CAMlE,MAAM,UACJ,OACA,IACA,SACyB;EACzB,MAAM,SAAS,KAAK,QAAQ,IAAI,MAAM;AACtC,MAAI,CAAC,OACH,OAAM,IAAI,MAAM,UAAU,MAAM,aAAa;EAG/C,MAAM,eAAkC,EAAE,UAAU,KAAK,UAAU;AAGnE,QAAMC,UAAQ,KAAK,IAAI,YAAY,OAAO,QAAQ,IAAI,QAAQ,CAAC;EAQ/D,MAAM,OALO,MAAMD,UACjB,KAAK,IACL,gBAAgB,OAAO,QAAQ,GAAG,CACnC,EAEgB;AACjB,MAAI,CAAC,IACH,OAAM,IAAI,MAAM,gBAAgB,GAAG,0BAA0B;AAG/D,SAAO,EAAE,MAAM,cAAc,OAAO,QAAQ,KAAK,aAAa,EAAE;;;;;CAMlE,MAAM,UAAU,OAAe,IAAsC;EACnE,MAAM,SAAS,KAAK,QAAQ,IAAI,MAAM;AACtC,MAAI,CAAC,OACH,OAAM,IAAI,MAAM,UAAU,MAAM,aAAa;AAS/C,OALiB,MAAMA,UACrB,KAAK,IACL,gBAAgB,OAAO,QAAQ,GAAG,CACnC,EAEY,WAAW,EACtB,QAAO,EAAE,SAAS,gBAAgB,GAAG,wBAAwB,MAAM,IAAI;AAIzE,QAAMC,UAAQ,KAAK,IAAI,YAAY,OAAO,QAAQ,GAAG,CAAC;AAEtD,SAAO,EAAE,SAAS,gBAAgB,GAAG,gBAAgB,MAAM,IAAI;;;;;CAMjE,SAAS,OAAwB;AAC/B,SAAO,KAAK,QAAQ,IAAI,MAAM;;;;;CAMhC,eAAe,OAAwC;AACrD,SAAO,KAAK,QAAQ,IAAI,MAAM;;;;;CAMhC,WAAW,SAAyC;AAClD,OAAK,UAAU;;;;;;;;;AChUnB,eAAeC,UAAW,IAAoB,OAA6B;AACzE,QAAO,GAAG,IAAO,IAAI,IAAI,MAAM,CAAC,CAAC,SAAS;;;;;AA0B5C,IAAa,YAAb,MAAuB;CACrB,YACE,AAAQ,IACR,AAAQ,SACR,AAAQ,QACR,AAAQ,WAAmB,IAC3B;EAJQ;EACA;EACA;EACA;;;;;CAMV,MAAM,OACJ,OACA,SAI0B;AAC1B,MAAI,CAAC,KAAK,OAAO,QACf,QAAO;GAAE,MAAM,EAAE;GAAE,SAAS;GAAmC;EAGjE,MAAM,UAAsB,EAAE;EAC9B,MAAM,QAAQ,SAAS,SAAS;EAChC,MAAM,eAAkC,EAAE,UAAU,KAAK,UAAU;EAGnE,MAAM,iBAAiB,SAAS,SAC5B,QAAQ,OAAO,QAAQ,MAAM,KAAK,OAAO,OAAO,IAAI,EAAE,CAAC,GACvD,MAAM,KAAK,KAAK,OAAO,OAAO,MAAM,CAAC;EAGzC,MAAM,WAAW,KAAK,gBAAgB,OAAO,SAAS,cAAc;AAEpE,OAAK,MAAM,aAAa,gBAAgB;GACtC,MAAM,cAAc,KAAK,OAAO,OAAO,IAAI,UAAU;GACrD,MAAM,SAAS,KAAK,QAAQ,IAAI,UAAU;AAE1C,OAAI,CAAC,eAAe,CAAC,OAAQ;GAE7B,MAAM,eAAe,GAAG,UAAU;AAElC,OAAI;AAGF,QAAI,CADc,MAAM,KAAK,eAAe,aAAa,CACzC;IAGhB,MAAM,kBAAkB,YAAY,QAAQ,MAAM;IAClD,MAAM,iBAAiB,kBAAkB,YAAY,QAAQ,QAAQ,gBAAgB,GAAG;IAGxF,MAAM,OAAO,MAAMA,UACjB,KAAK,IACL;qCAC2B,aAAa,KAAK,eAAe;oBAClD,aAAa;oBACb,UAAU;qBACT,aAAa,WAAW,SAAS;oBAClC,KAAK,KAAK,QAAQ,eAAe,OAAO,CAAC;YAEpD;AAED,SAAK,MAAM,OAAO,MAAM;KACtB,MAAM,EAAE,SAAS,GAAG,YAAY;AAChC,aAAQ,KACN,iBACE,WACA,QACA,SACA,SACA,aACD,CACF;;YAEI,OAAO;AAEd,YAAQ,KAAK,+BAA+B,UAAU,IAAI,MAAM;;AAIlE,OAAI,QAAQ,UAAU,MAAO;;AAG/B,SAAO;GACL,MAAM,QAAQ,MAAM,GAAG,MAAM;GAC7B,SAAS,QAAQ,WAAW,IAAI,yBAAyB,MAAM,KAAK;GACrE;;;;;CAMH,MAAM,YACJ,WACA,OACA,SAC0B;AAC1B,SAAO,KAAK,OAAO,OAAO;GAAE,GAAG;GAAS,QAAQ,CAAC,UAAU;GAAE,CAAC;;;;;CAMhE,OAAO,WAA4B;AACjC,SAAO,KAAK,OAAO,WAAW,KAAK,OAAO,OAAO,IAAI,UAAU;;;;;CAMjE,aAAa,WAA+C;AAC1D,SAAO,KAAK,OAAO,OAAO,IAAI,UAAU;;;;;CAM1C,MAAc,eAAe,cAAwC;AAKnE,UAJe,MAAMA,UACnB,KAAK,IACL,mEAAmE,aAAa,GACjF,EACa,SAAS;;;;;;CAOzB,AAAQ,gBAAgB,OAAe,gBAAkC;EAEvE,IAAI,WAAW,MACZ,QAAQ,MAAM,OAAK,CACnB,QAAQ,MAAM,KAAK;AAMtB,MAAI,SAAS,SAAS,IAAI,IAAI,CAAC,SAAS,WAAW,KAAI,CACrD,YAAW,IAAI,SAAS;AAG1B,SAAO;;;;;CAMT,WAAW,SAAyC;AAClD,OAAK,UAAU;;;;;;CAOjB,MAAM,iBACJ,WACA,OACA,SACA,SAC0B;EAC1B,MAAM,SAAS,KAAK,QAAQ,IAAI,UAAU;AAC1C,MAAI,CAAC,OACH,QAAO;GAAE,MAAM,EAAE;GAAE,SAAS,UAAU,UAAU;GAAc;EAGhE,MAAM,eAAkC,EAAE,UAAU,KAAK,UAAU;EACnE,MAAM,QAAQ,SAAS,SAAS;EAChC,MAAM,eAAe,MAAM,QAAQ,MAAM,KAAK;EAG9C,MAAM,aAAa,QAChB,QAAQ,QAAQ,OAAO,QAAQ,MAAM,MAAM,EAAE,SAAS,IAAI,CAAC,CAC3D,KAAK,QAAQ,IAAI,IAAI,WAAW,aAAa,IAAI,CACjD,KAAK,OAAO;AAEf,MAAI,CAAC,WACH,QAAO;GAAE,MAAM,EAAE;GAAE,SAAS;GAA8B;AAQ5D,SAAO,EACL,OANW,MAAMA,UACjB,KAAK,IACL,kBAAkB,UAAU,UAAU,WAAW,SAAS,QAC3D,EAGY,KAAK,QAAQ,iBAAiB,WAAW,QAAQ,KAAK,QAAW,aAAa,CAAC,EAC3F;;;;;;AAOL,SAAgB,gBAAgB,SAGlB;CACZ,MAAM,SAAoB;EACxB,SAAS,SAAS,WAAW;EAC7B,wBAAQ,IAAI,KAAK;EAClB;AAED,KAAI,SAAS,OACX,MAAK,MAAM,CAAC,OAAO,YAAY,OAAO,QAAQ,QAAQ,OAAO,CAC3D,QAAO,OAAO,IAAI,OAAO,EAAE,SAAS,CAAC;AAIzC,QAAO;;;;;;;;;;;;;;;;;;;;ACpOT,SAAgB,mBAA2C;AACzD,QAAO,aAAwB,EAC7B,QAAQ;EAEN,KAAK,EAAE,QAAQ,cAAc;EAG7B,WAAW,EAAE,QAAQ,aAAa;EAClC,eAAe,EAAE,QAAQ,aAAa;EACtC,mBAAmB,EAAE,QAAQ,aAAa;EAG1C,eAAe,EAAE,QAAQ,WAAW;EACpC,qBAAqB,EAAE,QAAQ,kBAAkB;EACjD,6BAA6B,EAAE,QAAQ,gBAAgB;EACvD,qBAAqB,EAAE,QAAQ,WAAW;EAC1C,wBAAwB,EAAE,QAAQ,eAAe;EACjD,gCAAgC,EAAE,QAAQ,iBAAiB;EAC5D,EACF,CAAC;;;;;;;;AASJ,SAAgB,UAAU,QAAgC,MAAsC;CAC9F,MAAM,SAAS,OAAO,OAAO,KAAK;AAClC,KAAI,CAAC,OAAQ,QAAO;AAEpB,QAAO;EACL,QAAQ,OAAO;EACf,QAAS,OAAO,UAAU,EAAE;EAC7B;;;;;AAMH,SAAgB,UAAU,OAAgB,IAAa,QAAyB;CAC9E,MAAM,QAAQ,CAAC,IAAI;AACnB,KAAI,MAAO,OAAM,KAAK,MAAM;AAC5B,KAAI,GAAI,OAAM,KAAK,GAAG;AACtB,KAAI,OAAQ,OAAM,KAAK,OAAO;AAC9B,QAAO,MAAM,KAAK,IAAI,CAAC,QAAQ,QAAQ,IAAI;;;;;AAM7C,SAAgB,cAAc,SAA0B;AACtD,QAAO,QAAQ,WAAW,IAAI;;;;;AAMhC,SAAgB,mBAAmB,SAAgE;AACjG,KAAI,YAAY,QAAS,QAAO;AAChC,KAAI,YAAY,QAAS,QAAO;AAChC,KAAI,YAAY,WAAY,QAAO;AACnC,KAAI,YAAY,UAAW,QAAO;AAClC,QAAO;;;;;;;;AC0BT,MAAa,gBAAgB;CAC3B;CACA;CACA;CACA;CACA;CACD;;;;;;;ACpGD,eAAe,QAAW,IAAoB,OAA6B;AACzE,QAAO,GAAG,IAAO,IAAI,IAAI,MAAM,CAAC,CAAC,SAAS;;;;;AAM5C,eAAe,QAAQ,IAAoB,OAA8B;AACvE,OAAM,GAAG,IAAI,IAAI,IAAI,MAAM,CAAC,CAAC,SAAS;;;;;AAMxC,SAAS,UAAU,KAAqC;AACtD,QAAO;EACL,MAAM,IAAI;EACV,MAAM,IAAI;EACV,SAAS,IAAI,YAAY;EACzB,IAAI,IAAI;EACR,WAAW,IAAI;EAChB;;;;;AAMH,SAAS,cAAc,KAA0C;AAC/D,QAAO;EACL,IAAI,IAAI;EACR,KAAK,IAAI;EACT,OAAO,IAAI;EACX,MAAM,IAAI;EACV,IAAI,IAAI;EACR,UAAU,IAAI;EACd,UAAU,IAAI;EACd,OAAO,IAAI;EACZ;;;;;AAMH,SAAS,SAAS,KAAoC;AACpD,QAAO;EACL,KAAK,IAAI;EACT,MAAM,IAAI;EACV,QAAQ,IAAI,WAAW;EACvB,QAAQ,IAAI;EACZ,SAAS,IAAI,YAAY;EAC1B;;;;;AAMH,IAAa,qBAAb,MAAgC;;;;;;;CAO9B,MAAM,WACJ,IACA,SAMmC;EACnC,MAAM,0BAAU,IAAI,KAA0B;EAG9C,MAAM,eAAe,MAAM,QACzB,IACA;;;;;;MAOD;AAED,OAAK,MAAM,EAAE,UAAU,cAAc;AAEnC,OAAI,cAAc,SAAS,KAAuC,CAChE;AAIF,OAAI,SAAS,UAAU,CAAC,QAAQ,OAAO,SAAS,KAAK,CACnD;AAIF,OAAI,SAAS,eAAe,SAAS,KAAK,CACxC;GAGF,MAAM,SAAS,MAAM,KAAK,gBAAgB,IAAI,KAAK;AACnD,WAAQ,IAAI,MAAM,OAAO;;AAG3B,SAAO;;;;;;;;CAST,MAAM,gBAAgB,IAAoB,WAAyC;EAMjF,MAAM,WAJgB,MAAM,QAC1B,IACA,sBAAsB,UAAU,IACjC,EAC6B,IAAI,UAAU;AAmB5C,SAAO;GACL,MAAM;GACN;GACA,YAnBiB,QAAQ,QAAQ,MAAM,EAAE,KAAK,EAAE,CAAC,KAAK,MAAM,EAAE,KAAK;GAoBnE,cAjBgB,MAAM,QACtB,IACA,4BAA4B,UAAU,IACvC,EAC6B,IAAI,cAAc;GAc9C,UAXoB,MAAM,QAC1B,IACA,sBAAsB,UAAU,IACjC,EAC6B,IAAI,SAAS;GAQ1C;;;;;;CAOH,oBAAoB,QAA6B;AAC/C,MAAI,OAAO,WAAW,SAAS,KAAK,OAAO,WAAW,GACpD,QAAO,OAAO,WAAW;AAG3B,SAAO;;;;;CAMT,MAAM,OAAO,IAAoB,WAAqC;AAUpE,UARe,MAAM,QACnB,IACA;;;oBAHmB,GAAG,UAAU,MAML;MAE5B,EACa,SAAS;;;;;CAMzB,MAAM,UACJ,IACA,WACA,SACA,SAMe;EACf,MAAM,eAAe,GAAG,UAAU;EAClC,MAAM,eAAe,SAAS,gBAAgB;EAC9C,MAAM,eAAe,SAAS,gBAAgB;EAC9C,MAAM,aAAa,QAAQ,KAAK,KAAK;AAGrC,QAAM,QACJ,IACA;4CACsC,aAAa;UAC/C,WAAW;mBACF,aAAa;yBACP,aAAa;;MAGjC;AAGD,QAAM,QACJ,IACA;sCACgC,UAAU,wBAAwB,UAAU;uBAC3D,aAAa,WAAW,WAAW,gBAAgB,aAAa,IAAI,QAAQ,KAAK,MAAM,QAAQ,EAAE,GAAG,CAAC,KAAK,KAAK,CAAC;;MAGlI;AAED,QAAM,QACJ,IACA;sCACgC,UAAU,wBAAwB,UAAU;uBAC3D,aAAa,KAAK,aAAa,YAAY,WAAW,0BAA0B,aAAa,IAAI,QAAQ,KAAK,MAAM,QAAQ,EAAE,GAAG,CAAC,KAAK,KAAK,CAAC;;MAG/J;AAED,QAAM,QACJ,IACA;sCACgC,UAAU,wBAAwB,UAAU;uBAC3D,aAAa,KAAK,aAAa,YAAY,WAAW,0BAA0B,aAAa,IAAI,QAAQ,KAAK,MAAM,QAAQ,EAAE,GAAG,CAAC,KAAK,KAAK,CAAC;uBAC7I,aAAa,WAAW,WAAW,gBAAgB,aAAa,IAAI,QAAQ,KAAK,MAAM,QAAQ,EAAE,GAAG,CAAC,KAAK,KAAK,CAAC;;MAGlI;;;;;CAMH,MAAM,WAAW,IAAoB,WAAkC;EACrE,MAAM,eAAe,GAAG,UAAU;AAClC,QAAM,QAAQ,IAAI,gBAAgB,aAAa,KAAK,aAAa,uBAAuB;;;;;;;;;;;;AC3N5F,IAAa,YAAb,MAAa,UAA+B;CAC1C,AAAS;CACT,AAAS;CACT,AAAS;CAET,AAAQ;CACR,AAAQ,0BAAU,IAAI,KAA0B;CAChD,AAAQ;CACR,AAAQ;CACR,AAAQ;CACR,AAAQ;CACR,AAAQ;CACR,AAAQ,cAAc;CAEtB,YAAY,AAAQ,SAA2B;EAA3B;AAClB,OAAK,OAAO,QAAQ,QAAQ;AAC5B,OAAK,cAAc,QAAQ,eAAe,oBAAoB,QAAQ;AACtE,OAAK,aAAa,QAAQ,cAAc;AACxC,OAAK,YAAY,gBAAgB,QAAQ,IAAI;AAC7C,OAAK,UAAU,IAAI,iBAAiB;AACpC,yBAAuB,KAAK,QAAQ;;;;;CAMtC,OAAO,SAAS;AACd,SAAO;;;;;CAMT,aAAa,KAAK,EAAE,UAAmD;AAErE,SAAO,IAAI,UADO,sBAAsB,MAAM,OAAO,CACtB;;;;;CAMjC,MAAM,QAAQ,MAA8B;AAC1C,QAAM,KAAK,YAAY;;;;;CAMzB,MAAc,aAA4B;AACxC,MAAI,KAAK,YAAa;AAGtB,OAAK,KAAK,MAAM,aAAa;GAC3B,KAAK,KAAK,QAAQ;GAClB,KAAK,KAAK,QAAQ,OAAO;GAC1B,CAAC;EAGF,MAAM,KAAK,KAAK;AAIhB,OAAK,UAAU,MADM,IAAI,oBAAoB,CACX,WAAW,IAAI;GAC/C,QAAQ,KAAK,QAAQ;GACrB,eAAe,KAAK,QAAQ;GAC7B,CAAC;AAGF,OAAK,SAAS,kBAAkB;AAChC,OAAK,OAAO,IAAI,eAAe,IAAI,KAAK,SAAS,GAAG;AACpD,OAAK,YAAY,IAAI,UAAU,IAAI,KAAK,SAAS,KAAK,WAAW,GAAG;AAEpE,OAAK,cAAc;;;;;CAMrB,MAAc,oBAAmC;AAC/C,MAAI,CAAC,KAAK,YACR,OAAM,KAAK,YAAY;;;;;CAO3B,MAAM,KAAK,MAAc,SAAkD;AACzE,QAAM,KAAK,mBAAmB;EAE9B,MAAM,QAAQ,UAAU,KAAK,QAAQ,KAAK;AAC1C,MAAI,CAAC,MACH,QAAO,EAAE,MAAM,EAAE,EAAE;AAGrB,UAAQ,MAAM,QAAd;GACE,KAAK,aACH,QAAO,KAAK,KAAK,YAAY;GAE/B,KAAK;AACH,QAAI,CAAC,MAAM,OAAO,MAAO,QAAO,EAAE,MAAM,EAAE,EAAE;AAC5C,WAAO,KAAK,KAAK,UAAU,MAAM,OAAO,OAAO,QAAQ;GAEzD,KAAK;AACH,QAAI,CAAC,MAAM,OAAO,SAAS,CAAC,MAAM,OAAO,GAAI,QAAO,EAAE,MAAM,EAAE,EAAE;AAChE,WAAO,KAAK,KAAK,eAAe,MAAM,OAAO,OAAO,MAAM,OAAO,GAAG;GAEtE,KAAK;AACH,QAAI,CAAC,MAAM,OAAO,SAAS,CAAC,MAAM,OAAO,GAAI,QAAO,EAAE,MAAM,EAAE,EAAE;AAChE,WAAO,KAAK,YAAY,MAAM,OAAO,OAAO,MAAM,OAAO,GAAG;GAE9D,QACE,QAAO,EAAE,MAAM,EAAE,EAAE;;;;;;CAOzB,MAAM,KAAK,MAAc,UAAmD;AAC1E,QAAM,KAAK,mBAAmB;EAE9B,MAAM,QAAQ,UAAU,KAAK,QAAQ,KAAK;AAC1C,MAAI,CAAC,MACH,QAAO,EAAE;AAGX,UAAQ,MAAM,QAAd;GACE,KAAK;AACH,QAAI,CAAC,MAAM,OAAO,SAAS,CAAC,MAAM,OAAO,GAAI,QAAO,EAAE;AACtD,WAAO,KAAK,KAAK,QAAQ,MAAM,OAAO,OAAO,MAAM,OAAO,GAAG;GAE/D,KAAK;AACH,QAAI,CAAC,MAAM,OAAO,MAAO,QAAO,EAAE;AAClC,WAAO,KAAK,KAAK,UAAU,MAAM,OAAO,MAAM;GAEhD,KAAK;AACH,QAAI,CAAC,MAAM,OAAO,SAAS,CAAC,MAAM,OAAO,MAAM,CAAC,MAAM,OAAO,OAAQ,QAAO,EAAE;AAC9E,WAAO,KAAK,KAAK,aAAa,MAAM,OAAO,OAAO,MAAM,OAAO,IAAI,MAAM,OAAO,OAAO;GAEzF,KAAK;AACH,QAAI,CAAC,MAAM,OAAO,SAAS,CAAC,MAAM,OAAO,GAAI,QAAO,EAAE;AACtD,WAAO,KAAK,KAAK,QAAQ,MAAM,OAAO,OAAO,MAAM,OAAO,GAAG;GAE/D,QACE,QAAO,EAAE;;;;;;CAOf,MAAM,MACJ,MACA,SACA,UACyB;AACzB,QAAM,KAAK,mBAAmB;AAE9B,MAAI,KAAK,eAAe,WACtB,OAAM,IAAI,MAAM,6BAA6B;EAG/C,MAAM,QAAQ,UAAU,KAAK,QAAQ,KAAK;AAC1C,MAAI,CAAC,MACH,OAAM,IAAI,MAAM,iBAAiB,OAAO;AAG1C,UAAQ,MAAM,QAAd;GACE,KAAK;AACH,QAAI,CAAC,MAAM,OAAO,MAChB,OAAM,IAAI,MAAM,iCAAiC;AAEnD,WAAO,KAAK,KAAK,UAAU,MAAM,OAAO,OAAO,QAAQ,WAAW,QAAQ;GAE5E,KAAK;AACH,QAAI,CAAC,MAAM,OAAO,SAAS,CAAC,MAAM,OAAO,GACvC,OAAM,IAAI,MAAM,4CAA4C;AAE9D,WAAO,KAAK,KAAK,UAAU,MAAM,OAAO,OAAO,MAAM,OAAO,IAAI,QAAQ,WAAW,QAAQ;GAE7F,KAAK;AACH,QAAI,CAAC,MAAM,OAAO,SAAS,CAAC,MAAM,OAAO,OACvC,OAAM,IAAI,MAAM,iCAAiC;AAEnD,WAAO,KAAK,cACV,MAAM,OAAO,OACb,MAAM,OAAO,IACb,MAAM,OAAO,QACb,QAAQ,WAAW,QACpB;GAEH,QACE,OAAM,IAAI,MAAM,iCAAiC,OAAO;;;;;;CAO9D,MAAM,OAAO,MAAc,UAAuD;AAChF,QAAM,KAAK,mBAAmB;AAE9B,MAAI,KAAK,eAAe,WACtB,OAAM,IAAI,MAAM,6BAA6B;EAG/C,MAAM,QAAQ,UAAU,KAAK,QAAQ,KAAK;AAC1C,MAAI,CAAC,SAAS,MAAM,WAAW,UAC7B,OAAM,IAAI,MAAM,kCAAkC,OAAO;AAG3D,MAAI,CAAC,MAAM,OAAO,SAAS,CAAC,MAAM,OAAO,GACvC,OAAM,IAAI,MAAM,4CAA4C;AAG9D,SAAO,KAAK,KAAK,UAAU,MAAM,OAAO,OAAO,MAAM,OAAO,GAAG;;;;;CAMjE,MAAM,OAAO,MAAc,OAAe,SAAsD;AAC9F,QAAM,KAAK,mBAAmB;EAG9B,MAAM,QAAQ,UAAU,KAAK,QAAQ,KAAK;AAC1C,MAAI,OAAO,OAAO,MAChB,QAAO,KAAK,UAAU,YAAY,MAAM,OAAO,OAAO,OAAO,QAAQ;AAIvE,SAAO,KAAK,UAAU,OAAO,OAAO,QAAQ;;;;;CAM9C,MAAM,KACJ,MACA,MACA,UACwB;AACxB,QAAM,KAAK,mBAAmB;EAE9B,MAAM,QAAQ,UAAU,KAAK,QAAQ,KAAK;AAC1C,MAAI,OAAO,WAAW,mBAAmB,MAAM,OAAO,SAAS,MAAM,OAAO,OAO1E,QAAO,EAAE,OANM,MAAM,KAAK,cACxB,MAAM,OAAO,OACb,MAAM,OAAO,IACb,MAAM,OAAO,QACb,KACD,EACqB,MAA4C;AAGpE,QAAM,IAAI,MAAM,gCAAgC,OAAO;;;;;CAMzD,AAAQ,YAAY,OAAe,IAA2B;AAE5D,SAAO,EACL,MAAM,sBAAsB,OAAO,IAFjB,KAAK,QAAQ,UAAU,EAAE,UAAU,MAAM,CAAC,EAER,EAAE,UAAU,IAAI,CAAC,EACtE;;;;;CAMH,MAAc,cACZ,OACA,IACA,YACA,QACyB;AAEzB,MAAI,CADW,KAAK,QAAQ,IAAI,MAAM,CAEpC,OAAM,IAAI,MAAM,UAAU,MAAM,aAAa;EAI/C,IAAI;AACJ,MAAI,GAEF,QADmB,MAAM,KAAK,KAAK,QAAQ,OAAO,GAAG,EACpC,MAAM;EAGzB,MAAM,MAAqB;GACzB,IAAI,KAAK;GACT,SAAS,KAAK;GACd;GACA;GACA;GACA,QAAQ;IACN,qBAAqB,KAAK,eAAe;IACzC,cAAc,GAAG,MAAM,KAAK,YAAY,GAAG,EAAE;IAC9C;GACF;EAED,MAAM,SAAS,MAAM,KAAK,QAAQ,QAAQ,YAAY,KAAK,OAAO;AAElE,MAAI,CAAC,OAAO,QACV,OAAM,IAAI,MAAM,OAAO,WAAW,gBAAgB;AAGpD,SAAO,EACL,MAAM;GACJ,IAAI,GAAG,MAAM,GAAG,MAAM,GAAG,YAAY;GACrC,MAAM,KAAK,IAAI,MAAM,GAAG,GAAG,YAAY,eAAe,IAAI,MAAM,YAAY;GAC5E,SAAS,OAAO;GACjB,EACF;;;;;CAMH,MAAM,gBAA+B;EACnC,MAAM,KAAK,KAAK;AAEhB,OAAK,UAAU,MADM,IAAI,oBAAoB,CACX,WAAW,IAAI;GAC/C,QAAQ,KAAK,QAAQ;GACrB,eAAe,KAAK,QAAQ;GAC7B,CAAC;AACF,OAAK,KAAK,WAAW,KAAK,QAAQ;AAClC,OAAK,UAAU,WAAW,KAAK,QAAQ;;;;;CAMzC,MAAM,YAAY,OAAe,QAAkC;EACjE,MAAM,aAAa,MAAM,KAAK,KAAK,UAAU,OAAO,EAAE,OAAO,KAAO,CAAC;AAErE,MAAI,WAAW,OAAO;GACpB,MAAM,SAAS,KAAK,QAAQ,IAAI,MAAM;AACtC,OAAI,CAAC,OAAQ,OAAM,IAAI,MAAM,UAAU,MAAM,aAAa;AAiB1D,UAAO,GAfS,OAAO,QAAQ,KAAK,MAAM,EAAE,KAAK,CAAC,KAAK,IAAI,CAezC,IAdL,WAAW,KAAK,KAAK,UAAU;IAC1C,MAAM,UAAU,MAAM;AACtB,WAAO,OAAO,QACX,KAAK,MAAM;KACV,MAAM,MAAM,QAAQ,EAAE;AACtB,SAAI,QAAQ,QAAQ,QAAQ,OAAW,QAAO;AAC9C,SAAI,OAAO,QAAQ,aAAa,IAAI,SAAS,IAAI,IAAI,IAAI,SAAS,KAAI,EACpE,QAAO,IAAI,IAAI,QAAQ,MAAM,OAAK,CAAC;AAErC,YAAO,OAAO,IAAI;MAClB,CACD,KAAK,IAAI;KACZ,CAEyB,KAAK,KAAK;;AAIvC,SAAO,WAAW,KAAK,KAAK,UAAU,MAAM,QAAQ;;;;;CAMtD,eACE,MACA,SACA,SAKM;AACN,OAAK,QAAQ,eACX,MACA,OAAO,KAAK,YAAY;GACtB,SAAS;GACT,MAAM,MAAM,QAAQ,KAAK,OAAO;GACjC,GACD,QACD;;;;;CAMH,aAAuC;AACrC,SAAO,KAAK;;;;;CAMd,cAA8B;AAC5B,SAAO,KAAK"}
|
package/package.json
CHANGED
|
@@ -1,71 +1,58 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aigne/afs-sqlite",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.11.0-beta",
|
|
4
4
|
"description": "AIGNE AFS module for SQLite database storage with schema introspection",
|
|
5
|
+
"license": "Elastic-2.0",
|
|
5
6
|
"publishConfig": {
|
|
6
7
|
"access": "public"
|
|
7
8
|
},
|
|
8
|
-
"author": "Arcblock <blocklet@arcblock.io> https://github.com/
|
|
9
|
-
"homepage": "https://
|
|
10
|
-
"license": "Elastic-2.0",
|
|
9
|
+
"author": "Arcblock <blocklet@arcblock.io> https://github.com/arcblock",
|
|
10
|
+
"homepage": "https://github.com/arcblock/afs",
|
|
11
11
|
"repository": {
|
|
12
12
|
"type": "git",
|
|
13
|
-
"url": "git+https://github.com/
|
|
13
|
+
"url": "git+https://github.com/arcblock/afs"
|
|
14
14
|
},
|
|
15
15
|
"bugs": {
|
|
16
|
-
"url": "https://github.com/
|
|
16
|
+
"url": "https://github.com/arcblock/afs/issues"
|
|
17
17
|
},
|
|
18
|
-
"files": [
|
|
19
|
-
"lib/cjs",
|
|
20
|
-
"lib/dts",
|
|
21
|
-
"lib/esm",
|
|
22
|
-
"LICENSE",
|
|
23
|
-
"README.md",
|
|
24
|
-
"CHANGELOG.md"
|
|
25
|
-
],
|
|
26
18
|
"type": "module",
|
|
27
|
-
"main": "./
|
|
28
|
-
"module": "./
|
|
29
|
-
"types": "./
|
|
19
|
+
"main": "./dist/index.cjs",
|
|
20
|
+
"module": "./dist/index.mjs",
|
|
21
|
+
"types": "./dist/index.d.cts",
|
|
30
22
|
"exports": {
|
|
31
23
|
".": {
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
"types": "./lib/dts/index.d.ts"
|
|
24
|
+
"require": "./dist/index.cjs",
|
|
25
|
+
"import": "./dist/index.mjs"
|
|
35
26
|
},
|
|
36
|
-
"./*":
|
|
37
|
-
"import": "./lib/esm/*",
|
|
38
|
-
"require": "./lib/cjs/*",
|
|
39
|
-
"types": "./lib/dts/*"
|
|
40
|
-
}
|
|
41
|
-
},
|
|
42
|
-
"typesVersions": {
|
|
43
|
-
"*": {
|
|
44
|
-
".": [
|
|
45
|
-
"./lib/dts/index.d.ts"
|
|
46
|
-
]
|
|
47
|
-
}
|
|
27
|
+
"./*": "./*"
|
|
48
28
|
},
|
|
29
|
+
"files": [
|
|
30
|
+
"dist",
|
|
31
|
+
"LICENSE",
|
|
32
|
+
"README.md",
|
|
33
|
+
"CHANGELOG.md"
|
|
34
|
+
],
|
|
49
35
|
"dependencies": {
|
|
36
|
+
"@aigne/sqlite": "^0.4.9",
|
|
37
|
+
"drizzle-orm": "^0.44.5",
|
|
50
38
|
"radix3": "^1.1.2",
|
|
51
39
|
"zod": "^3.25.67",
|
|
52
|
-
"@aigne/afs": "^1.
|
|
53
|
-
"@aigne/sqlite": "^0.4.9-beta.2"
|
|
40
|
+
"@aigne/afs": "^1.11.0-beta"
|
|
54
41
|
},
|
|
55
42
|
"devDependencies": {
|
|
56
|
-
"@types/bun": "^1.
|
|
57
|
-
"drizzle-orm": "^0.44.2",
|
|
43
|
+
"@types/bun": "^1.3.6",
|
|
58
44
|
"npm-run-all": "^4.1.5",
|
|
59
|
-
"rimraf": "^6.
|
|
60
|
-
"
|
|
61
|
-
"
|
|
45
|
+
"rimraf": "^6.1.2",
|
|
46
|
+
"tsdown": "0.20.0-beta.3",
|
|
47
|
+
"typescript": "5.9.2",
|
|
48
|
+
"@aigne/scripts": "0.0.0",
|
|
49
|
+
"@aigne/typescript-config": "0.0.0"
|
|
62
50
|
},
|
|
63
51
|
"scripts": {
|
|
64
|
-
"
|
|
65
|
-
"
|
|
66
|
-
"clean": "rimraf
|
|
52
|
+
"build": "tsdown",
|
|
53
|
+
"check-types": "tsc --noEmit",
|
|
54
|
+
"clean": "rimraf dist coverage",
|
|
67
55
|
"test": "bun test",
|
|
68
|
-
"test:coverage": "bun test --coverage --coverage-reporter=lcov --coverage-reporter=text"
|
|
69
|
-
"postbuild": "node ../../scripts/post-build-lib.mjs"
|
|
56
|
+
"test:coverage": "bun test --coverage --coverage-reporter=lcov --coverage-reporter=text"
|
|
70
57
|
}
|
|
71
58
|
}
|
package/CHANGELOG.md
DELETED
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
# Changelog
|
|
2
|
-
|
|
3
|
-
## [1.1.0-beta.1](https://github.com/AIGNE-io/aigne-framework/compare/afs-sqlite-v1.0.1-beta.1...afs-sqlite-v1.1.0-beta.1) (2026-01-16)
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
### Features
|
|
7
|
-
|
|
8
|
-
* **afs:** add generic AFS adapter for sqlite databases ([#908](https://github.com/AIGNE-io/aigne-framework/issues/908)) ([b9b5a8f](https://github.com/AIGNE-io/aigne-framework/commit/b9b5a8fc2680e8e3ae7f28dd720b0089520981b9))
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
### Bug Fixes
|
|
12
|
-
|
|
13
|
-
* update @aigne/afs-sqlite release config ([ef0f254](https://github.com/AIGNE-io/aigne-framework/commit/ef0f2547920e0e95545c57c7dd55ff059b5a2e7a))
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
### Dependencies
|
|
17
|
-
|
|
18
|
-
* The following workspace dependencies were updated
|
|
19
|
-
* dependencies
|
|
20
|
-
* @aigne/afs bumped to 1.4.0-beta.11
|
|
21
|
-
* devDependencies
|
|
22
|
-
* @aigne/test-utils bumped to 0.5.69-beta.25
|
|
23
|
-
|
|
24
|
-
## [1.0.1-beta.1](https://github.com/AIGNE-io/aigne-framework/compare/afs-sqlite-v1.0.1-beta...afs-sqlite-v1.0.1-beta.1) (2026-01-16)
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
### Dependencies
|
|
28
|
-
|
|
29
|
-
* The following workspace dependencies were updated
|
|
30
|
-
* dependencies
|
|
31
|
-
* @aigne/afs bumped to 1.4.0-beta.10
|
|
32
|
-
* devDependencies
|
|
33
|
-
* @aigne/test-utils bumped to 0.5.69-beta.24
|
|
34
|
-
|
|
35
|
-
## [1.0.1-beta](https://github.com/AIGNE-io/aigne-framework/compare/afs-sqlite-v1.0.0...afs-sqlite-v1.0.1-beta) (2026-01-15)
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
### Dependencies
|
|
39
|
-
|
|
40
|
-
* The following workspace dependencies were updated
|
|
41
|
-
* devDependencies
|
|
42
|
-
* @aigne/test-utils bumped to 0.5.69-beta.23
|
|
43
|
-
|
|
44
|
-
## 1.0.0 (2026-01-15)
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
### Features
|
|
48
|
-
|
|
49
|
-
* **afs:** add generic AFS adapter for sqlite databases ([#908](https://github.com/AIGNE-io/aigne-framework/issues/908)) ([b9b5a8f](https://github.com/AIGNE-io/aigne-framework/commit/b9b5a8fc2680e8e3ae7f28dd720b0089520981b9))
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
### Bug Fixes
|
|
53
|
-
|
|
54
|
-
* update @aigne/afs-sqlite release config ([ef0f254](https://github.com/AIGNE-io/aigne-framework/commit/ef0f2547920e0e95545c57c7dd55ff059b5a2e7a))
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
### Dependencies
|
|
58
|
-
|
|
59
|
-
* The following workspace dependencies were updated
|
|
60
|
-
* devDependencies
|
|
61
|
-
* @aigne/test-utils bumped to 0.5.69-beta.22
|
|
@@ -1,165 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.registerBuiltInActions = registerBuiltInActions;
|
|
4
|
-
const sqlite_1 = require("@aigne/sqlite");
|
|
5
|
-
/**
|
|
6
|
-
* Executes a raw SQL query and returns all rows
|
|
7
|
-
*/
|
|
8
|
-
async function execAll(db, query) {
|
|
9
|
-
return db.all(sqlite_1.sql.raw(query)).execute();
|
|
10
|
-
}
|
|
11
|
-
/**
|
|
12
|
-
* Executes a raw SQL query (for INSERT, UPDATE, DELETE)
|
|
13
|
-
*/
|
|
14
|
-
async function execRun(db, query) {
|
|
15
|
-
await db.run(sqlite_1.sql.raw(query)).execute();
|
|
16
|
-
}
|
|
17
|
-
/**
|
|
18
|
-
* Registers built-in actions to the registry
|
|
19
|
-
*/
|
|
20
|
-
function registerBuiltInActions(registry) {
|
|
21
|
-
// Refresh schema action (table level)
|
|
22
|
-
registry.register({
|
|
23
|
-
name: "refresh",
|
|
24
|
-
description: "Refresh the schema cache for this module",
|
|
25
|
-
tableLevel: true,
|
|
26
|
-
rowLevel: false,
|
|
27
|
-
handler: async (ctx) => {
|
|
28
|
-
await ctx.module.refreshSchema();
|
|
29
|
-
return {
|
|
30
|
-
success: true,
|
|
31
|
-
message: "Schema refreshed successfully",
|
|
32
|
-
};
|
|
33
|
-
},
|
|
34
|
-
});
|
|
35
|
-
// Export table action (table level)
|
|
36
|
-
registry.register({
|
|
37
|
-
name: "export",
|
|
38
|
-
description: "Export table data in specified format (json, csv)",
|
|
39
|
-
tableLevel: true,
|
|
40
|
-
rowLevel: false,
|
|
41
|
-
inputSchema: {
|
|
42
|
-
type: "object",
|
|
43
|
-
properties: {
|
|
44
|
-
format: {
|
|
45
|
-
type: "string",
|
|
46
|
-
enum: ["json", "csv"],
|
|
47
|
-
default: "json",
|
|
48
|
-
},
|
|
49
|
-
},
|
|
50
|
-
},
|
|
51
|
-
handler: async (ctx, params) => {
|
|
52
|
-
const format = params.format ?? "json";
|
|
53
|
-
const data = await ctx.module.exportTable(ctx.table, format);
|
|
54
|
-
return {
|
|
55
|
-
success: true,
|
|
56
|
-
data,
|
|
57
|
-
};
|
|
58
|
-
},
|
|
59
|
-
});
|
|
60
|
-
// Count rows action (table level)
|
|
61
|
-
registry.register({
|
|
62
|
-
name: "count",
|
|
63
|
-
description: "Get the total row count for this table",
|
|
64
|
-
tableLevel: true,
|
|
65
|
-
rowLevel: false,
|
|
66
|
-
handler: async (ctx) => {
|
|
67
|
-
const result = await execAll(ctx.db, `SELECT COUNT(*) as count FROM "${ctx.table}"`);
|
|
68
|
-
return {
|
|
69
|
-
success: true,
|
|
70
|
-
data: { count: result[0]?.count ?? 0 },
|
|
71
|
-
};
|
|
72
|
-
},
|
|
73
|
-
});
|
|
74
|
-
// Duplicate row action (row level)
|
|
75
|
-
registry.register({
|
|
76
|
-
name: "duplicate",
|
|
77
|
-
description: "Create a copy of this row",
|
|
78
|
-
tableLevel: false,
|
|
79
|
-
rowLevel: true,
|
|
80
|
-
handler: async (ctx) => {
|
|
81
|
-
if (!ctx.row) {
|
|
82
|
-
return { success: false, message: "Row data not available" };
|
|
83
|
-
}
|
|
84
|
-
const schema = ctx.schemas.get(ctx.table);
|
|
85
|
-
if (!schema) {
|
|
86
|
-
return { success: false, message: `Table '${ctx.table}' not found` };
|
|
87
|
-
}
|
|
88
|
-
// Create a copy without the primary key
|
|
89
|
-
const pkColumn = schema.primaryKey[0] ?? "rowid";
|
|
90
|
-
const rowCopy = { ...ctx.row };
|
|
91
|
-
delete rowCopy[pkColumn];
|
|
92
|
-
delete rowCopy.rowid;
|
|
93
|
-
// Build insert query
|
|
94
|
-
const columns = Object.keys(rowCopy);
|
|
95
|
-
const values = columns.map((col) => formatValueForSQL(rowCopy[col]));
|
|
96
|
-
await execRun(ctx.db, `INSERT INTO "${ctx.table}" (${columns.map((c) => `"${c}"`).join(", ")}) VALUES (${values.join(", ")})`);
|
|
97
|
-
// Get the new row's ID
|
|
98
|
-
const lastIdResult = await execAll(ctx.db, "SELECT last_insert_rowid() as id");
|
|
99
|
-
return {
|
|
100
|
-
success: true,
|
|
101
|
-
data: { newId: lastIdResult[0]?.id },
|
|
102
|
-
message: "Row duplicated successfully",
|
|
103
|
-
};
|
|
104
|
-
},
|
|
105
|
-
});
|
|
106
|
-
// Validate row action (row level)
|
|
107
|
-
registry.register({
|
|
108
|
-
name: "validate",
|
|
109
|
-
description: "Validate row data against schema constraints",
|
|
110
|
-
tableLevel: false,
|
|
111
|
-
rowLevel: true,
|
|
112
|
-
handler: async (ctx) => {
|
|
113
|
-
if (!ctx.row) {
|
|
114
|
-
return { success: false, message: "Row data not available" };
|
|
115
|
-
}
|
|
116
|
-
const schema = ctx.schemas.get(ctx.table);
|
|
117
|
-
if (!schema) {
|
|
118
|
-
return { success: false, message: `Table '${ctx.table}' not found` };
|
|
119
|
-
}
|
|
120
|
-
const errors = [];
|
|
121
|
-
// Check NOT NULL constraints
|
|
122
|
-
for (const col of schema.columns) {
|
|
123
|
-
if (col.notnull && (ctx.row[col.name] === null || ctx.row[col.name] === undefined)) {
|
|
124
|
-
errors.push(`Column '${col.name}' cannot be null`);
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
// Check foreign key references
|
|
128
|
-
for (const fk of schema.foreignKeys) {
|
|
129
|
-
const value = ctx.row[fk.from];
|
|
130
|
-
if (value !== null && value !== undefined) {
|
|
131
|
-
const refResult = await execAll(ctx.db, `SELECT COUNT(*) as count FROM "${fk.table}" WHERE "${fk.to}" = '${String(value).replace(/'/g, "''")}'`);
|
|
132
|
-
if (refResult[0]?.count === 0) {
|
|
133
|
-
errors.push(`Foreign key violation: ${fk.from} references non-existent ${fk.table}.${fk.to}`);
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
return {
|
|
138
|
-
success: errors.length === 0,
|
|
139
|
-
data: { errors, valid: errors.length === 0 },
|
|
140
|
-
message: errors.length > 0 ? `Validation failed: ${errors.join("; ")}` : "Row is valid",
|
|
141
|
-
};
|
|
142
|
-
},
|
|
143
|
-
});
|
|
144
|
-
}
|
|
145
|
-
/**
|
|
146
|
-
* Formats a value for SQL insertion
|
|
147
|
-
*/
|
|
148
|
-
function formatValueForSQL(value) {
|
|
149
|
-
if (value === null || value === undefined) {
|
|
150
|
-
return "NULL";
|
|
151
|
-
}
|
|
152
|
-
if (typeof value === "number") {
|
|
153
|
-
return String(value);
|
|
154
|
-
}
|
|
155
|
-
if (typeof value === "boolean") {
|
|
156
|
-
return value ? "1" : "0";
|
|
157
|
-
}
|
|
158
|
-
if (value instanceof Date) {
|
|
159
|
-
return `'${value.toISOString()}'`;
|
|
160
|
-
}
|
|
161
|
-
if (typeof value === "object") {
|
|
162
|
-
return `'${JSON.stringify(value).replace(/'/g, "''")}'`;
|
|
163
|
-
}
|
|
164
|
-
return `'${String(value).replace(/'/g, "''")}'`;
|
|
165
|
-
}
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import type { ActionContext, ActionDefinition, ActionHandler, ActionResult } from "./types.js";
|
|
2
|
-
/**
|
|
3
|
-
* Registry for managing action handlers
|
|
4
|
-
*/
|
|
5
|
-
export declare class ActionsRegistry {
|
|
6
|
-
private handlers;
|
|
7
|
-
/**
|
|
8
|
-
* Registers an action handler
|
|
9
|
-
*/
|
|
10
|
-
register(definition: ActionDefinition): void;
|
|
11
|
-
/**
|
|
12
|
-
* Registers a simple action with just name and handler
|
|
13
|
-
*/
|
|
14
|
-
registerSimple(name: string, handler: ActionHandler, options?: {
|
|
15
|
-
description?: string;
|
|
16
|
-
tableLevel?: boolean;
|
|
17
|
-
rowLevel?: boolean;
|
|
18
|
-
}): void;
|
|
19
|
-
/**
|
|
20
|
-
* Unregisters an action
|
|
21
|
-
*/
|
|
22
|
-
unregister(name: string): boolean;
|
|
23
|
-
/**
|
|
24
|
-
* Checks if an action is registered
|
|
25
|
-
*/
|
|
26
|
-
has(name: string): boolean;
|
|
27
|
-
/**
|
|
28
|
-
* Gets an action definition
|
|
29
|
-
*/
|
|
30
|
-
get(name: string): ActionDefinition | undefined;
|
|
31
|
-
/**
|
|
32
|
-
* Lists all registered actions
|
|
33
|
-
*/
|
|
34
|
-
list(options?: {
|
|
35
|
-
tableLevel?: boolean;
|
|
36
|
-
rowLevel?: boolean;
|
|
37
|
-
}): ActionDefinition[];
|
|
38
|
-
/**
|
|
39
|
-
* Lists action names
|
|
40
|
-
*/
|
|
41
|
-
listNames(options?: {
|
|
42
|
-
tableLevel?: boolean;
|
|
43
|
-
rowLevel?: boolean;
|
|
44
|
-
}): string[];
|
|
45
|
-
/**
|
|
46
|
-
* Executes an action
|
|
47
|
-
*/
|
|
48
|
-
execute(name: string, ctx: ActionContext, params?: Record<string, unknown>): Promise<ActionResult>;
|
|
49
|
-
}
|