js-bao 0.2.10 → 0.2.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/README.md +174 -0
  2. package/dist/BaseModel-5YQCROYE.js +17 -0
  3. package/dist/BaseModel-5YQCROYE.js.map +1 -0
  4. package/dist/BaseModel-FCNWDJBH.js +17 -0
  5. package/dist/BaseModel-FCNWDJBH.js.map +1 -0
  6. package/dist/BrowserDatabaseFactory-PXOTK2DQ.js +119 -0
  7. package/dist/BrowserDatabaseFactory-PXOTK2DQ.js.map +1 -0
  8. package/dist/BrowserDatabaseFactory-WD4VX2VZ.js +119 -0
  9. package/dist/BrowserDatabaseFactory-WD4VX2VZ.js.map +1 -0
  10. package/dist/IncludeResolver-RCKQGNPZ.js +385 -0
  11. package/dist/IncludeResolver-RCKQGNPZ.js.map +1 -0
  12. package/dist/IncludeResolver-WGSQDMS7.js +385 -0
  13. package/dist/IncludeResolver-WGSQDMS7.js.map +1 -0
  14. package/dist/NodeDatabaseFactory-J4Z36UF3.js +165 -0
  15. package/dist/NodeDatabaseFactory-J4Z36UF3.js.map +1 -0
  16. package/dist/NodeDatabaseFactory-QIEKAXBM.js +10 -0
  17. package/dist/NodeDatabaseFactory-QIEKAXBM.js.map +1 -0
  18. package/dist/NodeSqliteEngine-HJSAYE4E.js +383 -0
  19. package/dist/NodeSqliteEngine-HJSAYE4E.js.map +1 -0
  20. package/dist/NodeSqliteEngine-I5SLWLME.js +383 -0
  21. package/dist/NodeSqliteEngine-I5SLWLME.js.map +1 -0
  22. package/dist/browser.cjs +3779 -3370
  23. package/dist/browser.d.cts +18 -1
  24. package/dist/browser.d.ts +18 -1
  25. package/dist/browser.js +3750 -3341
  26. package/dist/chunk-3PZWHUZO.js +4153 -0
  27. package/dist/chunk-3PZWHUZO.js.map +1 -0
  28. package/dist/chunk-53MS4MN7.js +373 -0
  29. package/dist/chunk-53MS4MN7.js.map +1 -0
  30. package/dist/chunk-65G2P4GL.js +709 -0
  31. package/dist/chunk-65G2P4GL.js.map +1 -0
  32. package/dist/chunk-6UX3YSCW.js +4151 -0
  33. package/dist/chunk-6UX3YSCW.js.map +1 -0
  34. package/dist/chunk-DANSD6BE.js +709 -0
  35. package/dist/chunk-DANSD6BE.js.map +1 -0
  36. package/dist/chunk-DF3JEQXA.js +373 -0
  37. package/dist/chunk-DF3JEQXA.js.map +1 -0
  38. package/dist/chunk-GO3APTPX.js +61 -0
  39. package/dist/chunk-GO3APTPX.js.map +1 -0
  40. package/dist/chunk-ID4U6IQC.js +53 -0
  41. package/dist/chunk-ID4U6IQC.js.map +1 -0
  42. package/dist/chunk-RQVS3LVL.js +165 -0
  43. package/dist/chunk-RQVS3LVL.js.map +1 -0
  44. package/dist/client.cjs +837 -0
  45. package/dist/client.d.cts +1101 -0
  46. package/dist/client.d.ts +1101 -0
  47. package/dist/client.js +806 -0
  48. package/dist/cloudflare-do.cjs +3637 -0
  49. package/dist/cloudflare-do.d.cts +1366 -0
  50. package/dist/cloudflare-do.d.ts +1366 -0
  51. package/dist/cloudflare-do.js +3614 -0
  52. package/dist/cloudflare.cjs +1048 -0
  53. package/dist/cloudflare.d.cts +1381 -0
  54. package/dist/cloudflare.d.ts +1381 -0
  55. package/dist/cloudflare.js +1017 -0
  56. package/dist/codegen.cjs +259 -18
  57. package/dist/environment-TOTQICSE.js +17 -0
  58. package/dist/environment-TOTQICSE.js.map +1 -0
  59. package/dist/index.cjs +1906 -1493
  60. package/dist/index.d.cts +19 -2
  61. package/dist/index.d.ts +19 -2
  62. package/dist/index.js +1871 -1458
  63. package/dist/node.cjs +4779 -4366
  64. package/dist/node.d.cts +18 -1
  65. package/dist/node.d.ts +18 -1
  66. package/dist/node.js +4602 -4189
  67. package/package.json +41 -12
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/models/relationshipManager.ts","../src/models/ModelRegistry.ts"],"sourcesContent":["import * as Y from \"yjs\";\nimport { DatabaseEngine } from \"../engines/DatabaseEngine\";\nimport { BaseModel, Logger } from \"./BaseModel\";\nimport {\n RefersToRelationshipConfig,\n HasManyRelationshipConfig,\n HasManyThroughRelationshipConfig,\n} from \"../types/relationshipTypes\";\n\n// Helper type for the functions returned by generators\nexport type RelationshipMethod = (\n this: BaseModel,\n ...args: any[]\n) => Promise<any>;\n\nexport function generateRefersToMethod(\n _sourceModelClass: typeof BaseModel,\n config: RefersToRelationshipConfig,\n targetModelClass: typeof BaseModel\n): RelationshipMethod {\n return async function (this: BaseModel) {\n const relatedId = (this as any)[config.relatedIdField];\n if (relatedId === null || typeof relatedId === \"undefined\") return null;\n return (targetModelClass as any).find(relatedId as string);\n };\n}\n\nexport function generateHasManyMethod(\n _sourceModelClass: typeof BaseModel,\n config: HasManyRelationshipConfig,\n targetModelClass: typeof BaseModel,\n _dbEngine: DatabaseEngine\n): RelationshipMethod {\n return async function (\n this: BaseModel,\n paginationArgs?: {\n limit?: number;\n afterCursor?: string;\n beforeCursor?: string;\n direction?: \"forward\" | \"backward\";\n }\n ) {\n const {\n limit,\n afterCursor,\n beforeCursor,\n direction = \"forward\",\n } = paginationArgs || {};\n const {\n relatedIdField,\n orderByField = \"id\",\n orderDirection = \"ASC\",\n } = config;\n\n const targetSchema = (targetModelClass as any).getSchema();\n if (!targetSchema || !targetSchema.options || !targetSchema.options.name) {\n Logger.error(\n `[RelationshipManager] Target model ${targetModelClass.name} for hasMany relationship has no valid schema name.`\n );\n return { data: [], nextCursor: null, prevCursor: null };\n }\n\n // Build document filter\n const filter: any = { [relatedIdField]: this.id };\n\n // Build query options\n const queryOptions: any = {\n sort: { [orderByField]: orderDirection === \"ASC\" ? 1 : -1 },\n };\n\n // Only add limit if specified\n if (limit !== undefined) {\n queryOptions.limit = limit + 1;\n }\n\n // Handle cursor-based pagination\n if (direction === \"forward\" && afterCursor) {\n filter[orderByField] = {\n [orderDirection === \"ASC\" ? \"$gt\" : \"$lt\"]: afterCursor,\n };\n } else if (direction === \"backward\") {\n if (beforeCursor) {\n filter[orderByField] = {\n [orderDirection === \"ASC\" ? \"$lt\" : \"$gt\"]: beforeCursor,\n };\n }\n queryOptions.sort = { [orderByField]: orderDirection === \"ASC\" ? -1 : 1 }; // Reverse sort for backward\n }\n\n const result = await (targetModelClass as any).query(filter, queryOptions);\n const results = result.data;\n\n // Handle cursor generation\n let nextCursor: string | null = null;\n let prevCursor: string | null = null;\n\n // Determine if this is the first page\n const isFirstPage = direction === \"forward\" && !afterCursor;\n\n // Only handle pagination cursors if limit is specified\n if (limit !== undefined) {\n if (direction === \"forward\") {\n if (results.length > limit) {\n nextCursor = (results[limit - 1] as any)[orderByField] as string;\n results.pop();\n }\n // For forward pagination, set prevCursor only if NOT on first page\n if (results.length > 0 && !isFirstPage) {\n prevCursor = (results[0] as any)[orderByField] as string;\n }\n } else {\n // Backward pagination\n if (results.length > limit) {\n prevCursor = (results[limit - 1] as any)[orderByField] as string;\n results.pop();\n }\n results.reverse(); // Reverse results for backward pagination\n\n // For backward pagination, set nextCursor if we have results and started with a cursor\n if (results.length > 0 && beforeCursor) {\n nextCursor = (results[results.length - 1] as any)[\n orderByField\n ] as string;\n }\n\n // For backward pagination, set prevCursor to enable further backward navigation\n // Only set it if we have more results than requested (indicating there are more pages)\n if (results.length > 0 && !beforeCursor) {\n // If this is the first backward call and we got exactly the limit,\n // set prevCursor to the first result to enable getting previous pages\n if (results.length === limit) {\n prevCursor = (results[0] as any)[orderByField] as string;\n }\n }\n }\n }\n\n return { data: results, nextCursor, prevCursor };\n };\n}\n\nexport function generateHasManyThroughMethod(\n _sourceModelClass: typeof BaseModel,\n config: HasManyThroughRelationshipConfig,\n targetModelClass: typeof BaseModel,\n joinModelClass: typeof BaseModel,\n _dbEngine: DatabaseEngine\n): RelationshipMethod {\n return async function (\n this: BaseModel,\n paginationArgs?: {\n limit?: number;\n afterCursor?: string;\n beforeCursor?: string;\n direction?: \"forward\" | \"backward\";\n }\n ) {\n const {\n limit,\n afterCursor,\n beforeCursor,\n direction = \"forward\",\n } = paginationArgs || {};\n\n const joinSchema = (joinModelClass as any).getSchema();\n const targetSchema = (targetModelClass as any).getSchema();\n\n if (!joinSchema || !joinSchema.options || !joinSchema.options.name) {\n Logger.error(\n `[RelationshipManager] Join model ${joinModelClass.name} for hasManyThrough relationship has no valid schema name.`\n );\n return { data: [], nextCursor: null, prevCursor: null };\n }\n if (!targetSchema || !targetSchema.options || !targetSchema.options.name) {\n Logger.error(\n `[RelationshipManager] Target model ${targetModelClass.name} for hasManyThrough relationship has no valid schema name.`\n );\n return { data: [], nextCursor: null, prevCursor: null };\n }\n\n const {\n joinModelLocalField,\n joinModelRelatedField,\n joinModelOrderByField = \"id\",\n joinModelOrderDirection = \"ASC\",\n } = config;\n\n // Build document filter for join query\n const joinFilter: any = { [joinModelLocalField]: this.id };\n\n // Build query options for join query\n const joinQueryOptions: any = {\n sort: {\n [joinModelOrderByField]: joinModelOrderDirection === \"ASC\" ? 1 : -1,\n },\n projection: { [joinModelRelatedField]: 1, [joinModelOrderByField]: 1 },\n };\n\n // Only add limit if specified\n if (limit !== undefined) {\n joinQueryOptions.limit = limit + 1;\n }\n\n // Handle cursor-based pagination\n if (direction === \"forward\" && afterCursor) {\n joinFilter[joinModelOrderByField] = {\n [joinModelOrderDirection === \"ASC\" ? \"$gt\" : \"$lt\"]: afterCursor,\n };\n } else if (direction === \"backward\") {\n if (beforeCursor) {\n joinFilter[joinModelOrderByField] = {\n [joinModelOrderDirection === \"ASC\" ? \"$lt\" : \"$gt\"]: beforeCursor,\n };\n }\n joinQueryOptions.sort = {\n [joinModelOrderByField]: joinModelOrderDirection === \"ASC\" ? -1 : 1,\n }; // Reverse sort for backward\n }\n\n const joinResult = await (joinModelClass as any).query(\n joinFilter,\n joinQueryOptions\n );\n const joinResults = joinResult.data;\n\n let nextCursorFromJoin: string | null = null;\n let prevCursorFromJoin: string | null = null;\n\n // Determine if this is the first page\n const isFirstPage = direction === \"forward\" && !afterCursor;\n\n // Only handle pagination cursors if limit is specified\n if (limit !== undefined) {\n if (direction === \"forward\") {\n if (joinResults.length > limit) {\n nextCursorFromJoin = (joinResults[limit - 1] as any)[\n joinModelOrderByField\n ] as string;\n joinResults.pop();\n }\n // For forward pagination, set prevCursor only if NOT on first page\n if (joinResults.length > 0 && !isFirstPage) {\n prevCursorFromJoin = (joinResults[0] as any)[\n joinModelOrderByField\n ] as string;\n }\n } else {\n // Backward pagination\n if (joinResults.length > limit) {\n prevCursorFromJoin = (joinResults[limit - 1] as any)[\n joinModelOrderByField\n ] as string;\n joinResults.pop();\n }\n joinResults.reverse(); // Reverse results for backward pagination\n\n // For backward pagination, set nextCursor if we have results and started with a cursor\n if (joinResults.length > 0 && beforeCursor) {\n nextCursorFromJoin = (joinResults[joinResults.length - 1] as any)[\n joinModelOrderByField\n ] as string;\n }\n\n // For backward pagination, set prevCursor to enable further backward navigation\n // Only set it if we have more results than requested (indicating there are more pages)\n if (joinResults.length > 0 && !beforeCursor) {\n // If this is the first backward call and we got exactly the limit,\n // set prevCursor to the first result to enable getting previous pages\n if (joinResults.length === limit) {\n prevCursorFromJoin = (joinResults[0] as any)[\n joinModelOrderByField\n ] as string;\n }\n }\n }\n }\n\n const relatedIds = joinResults\n .map((r: any) => r[joinModelRelatedField])\n .filter((id: any): id is string => id != null && typeof id === \"string\");\n if (relatedIds.length === 0)\n return { data: [], nextCursor: null, prevCursor: null };\n\n const targetResult = await (targetModelClass as any).query({\n id: { $in: relatedIds },\n });\n\n return {\n data: targetResult.data,\n nextCursor: nextCursorFromJoin,\n prevCursor: prevCursorFromJoin,\n };\n };\n}\n\nexport function generateHasManyThroughAddMethod(\n _sourceModelClass: typeof BaseModel,\n config: HasManyThroughRelationshipConfig,\n _targetModelClass: typeof BaseModel, // Used to potentially validate the ID/instance passed\n joinModelClass: typeof BaseModel\n): RelationshipMethod {\n return async function (\n this: BaseModel,\n targetInstanceOrId: BaseModel | string\n ): Promise<void> {\n const targetId =\n typeof targetInstanceOrId === \"string\"\n ? targetInstanceOrId\n : targetInstanceOrId.id;\n if (!targetId) {\n Logger.error(\"[RelationshipManager.add] Target ID is missing.\");\n throw new Error(\"Target ID is missing for add operation.\");\n }\n\n const joinData: Record<string, any> = {};\n joinData[config.joinModelLocalField] = this.id;\n joinData[config.joinModelRelatedField] = targetId;\n\n // Get Y.Doc for transaction - prefer from source model's document context\n let yDoc: Y.Doc | null = null;\n let targetDocId: string | null = null;\n\n // Check if source model (this) has multi-document metadata\n const sourceModelConstructor = this.constructor as typeof BaseModel;\n const connectedDocuments = (sourceModelConstructor as any)\n .connectedDocuments;\n if ((this as any)._metaDocId && connectedDocuments) {\n targetDocId = (this as any)._metaDocId;\n if (targetDocId) {\n const documentInfo = connectedDocuments.get(targetDocId);\n if (documentInfo) {\n yDoc = documentInfo.yDoc;\n }\n }\n }\n\n // Fallback to join model's legacy document if multi-document isn't available\n if (!yDoc) {\n const legacyDocId = \"__legacy_default__\";\n const legacyDocInfo = (joinModelClass as any).connectedDocuments?.get(\n legacyDocId\n );\n if (legacyDocInfo) {\n yDoc = legacyDocInfo.yDoc;\n }\n }\n\n if (!yDoc) {\n throw new Error(\n `[${joinModelClass.name}] No Y.Doc is connected for this join model. Connect a document via initJsBao(...).connectDocument or call initializeForDocument(yDoc, db, docId, permissionHint) before managing relationships.`\n );\n }\n\n await yDoc.transact(async () => {\n // Optional: Check if link already exists to prevent duplicates,\n // if the join table doesn't have a unique constraint for the pair.\n // This would require a query.\n const newJoinInstance = new (joinModelClass as any)(joinData);\n // Use targetDocument parameter if we're in multi-document mode\n if (targetDocId) {\n await newJoinInstance.save({ targetDocument: targetDocId });\n } else {\n await newJoinInstance.save(); // Fallback to legacy mode\n }\n Logger.debug(\n `[RelationshipManager.add] Created join entry in ${config.joinModel}:`,\n newJoinInstance.toJSON()\n );\n }, `add-join-${config.joinModel}-${this.id}-${targetId}`);\n };\n}\n\nexport function generateHasManyThroughRemoveMethod(\n _sourceModelClass: typeof BaseModel,\n config: HasManyThroughRelationshipConfig,\n _targetModelClass: typeof BaseModel, // Used to potentially validate the ID/instance passed\n joinModelClass: typeof BaseModel\n): RelationshipMethod {\n return async function (\n this: BaseModel,\n targetInstanceOrId: BaseModel | string\n ): Promise<void> {\n const targetId =\n typeof targetInstanceOrId === \"string\"\n ? targetInstanceOrId\n : targetInstanceOrId.id;\n if (!targetId) {\n Logger.error(\"[RelationshipManager.remove] Target ID is missing.\");\n throw new Error(\"Target ID is missing for remove operation.\");\n }\n\n // Get Y.Doc for transaction - prefer from source model's document context\n let yDoc: Y.Doc | null = null;\n let targetDocId: string | null = null;\n\n // Check if source model (this) has multi-document metadata\n const sourceModelConstructor = this.constructor as typeof BaseModel;\n const connectedDocuments = (sourceModelConstructor as any)\n .connectedDocuments;\n if ((this as any)._metaDocId && connectedDocuments) {\n targetDocId = (this as any)._metaDocId;\n if (targetDocId) {\n const documentInfo = connectedDocuments.get(targetDocId);\n if (documentInfo) {\n yDoc = documentInfo.yDoc;\n }\n }\n }\n\n // Fallback to join model's legacy document if multi-document isn't available\n if (!yDoc) {\n const legacyDocId = \"__legacy_default__\";\n const legacyDocInfo = (joinModelClass as any).connectedDocuments?.get(\n legacyDocId\n );\n if (legacyDocInfo) {\n yDoc = legacyDocInfo.yDoc;\n }\n }\n\n if (!yDoc) {\n throw new Error(\n `[${joinModelClass.name}] No Y.Doc is connected for this join model. Connect a document via initJsBao(...).connectDocument or call initializeForDocument(yDoc, db, docId, permissionHint) before managing relationships.`\n );\n }\n\n await yDoc.transact(async () => {\n const joinRecordsResult = await (joinModelClass as any).query(\n {\n [config.joinModelLocalField]: this.id,\n [config.joinModelRelatedField]: targetId,\n },\n {\n limit: 1,\n projection: { id: 1 },\n }\n );\n\n if (joinRecordsResult.data.length > 0) {\n for (const record of joinRecordsResult.data) {\n // Assuming query returns instances or objects with an id,\n // we need a way to delete by ID or get the instance to call .delete()\n const instanceToDelete = await (joinModelClass as any).find(\n record.id\n );\n if (instanceToDelete) {\n await instanceToDelete.delete();\n Logger.debug(\n `[RelationshipManager.remove] Deleted join entry from ${config.joinModel} with ID: ${record.id}`\n );\n } else {\n Logger.warn(\n `[RelationshipManager.remove] Join entry with ID ${record.id} found by query but not in YMap for deletion.`\n );\n }\n }\n } else {\n Logger.debug(\n `[RelationshipManager.remove] No join entry found in ${config.joinModel} for localId: ${this.id}, relatedId: ${targetId}. No action taken.`\n );\n }\n }, `remove-join-${config.joinModel}-${this.id}-${targetId}`);\n };\n}\n\n// TODO:\n// - Add generateHasManyThroughRemoveMethod\n// These would handle creating/deleting records in the joinModel\n// and should occur within a yDoc.transact() block.\n","import * as Y from \"yjs\";\nimport { DatabaseEngine } from \"../engines/DatabaseEngine\";\nimport { ModelOptions, FieldOptions } from \"../types/ormTypes\";\nimport { BaseModel, Logger } from \"./BaseModel\";\nimport {\n RelationshipConfig,\n RefersToRelationshipConfig,\n HasManyRelationshipConfig,\n HasManyThroughRelationshipConfig,\n} from \"../types/relationshipTypes\";\nimport * as RelationshipManager from \"./relationshipManager\";\nimport { DocumentPermissionHint } from \"../types/documentTypes\";\n\n// Define the structure for stored model information\n// This might be simplified if ModelRegistry primarily deals with classes and options are elsewhere\nexport interface RegisteredModelInfo {\n class: typeof BaseModel;\n options: ModelOptions;\n fields: Map<string, FieldOptions>; // Assuming fields are accessible, e.g. via a static method on the class\n}\n\nexport class ModelRegistry {\n private static instance: ModelRegistry;\n // Stores globally registered model classes by their name (from @Model decorator)\n private models: Map<string, typeof BaseModel> = new Map();\n // Stores options for globally registered models (from @Model decorator)\n private modelOptions: Map<string, ModelOptions> = new Map();\n // Stores fields for globally registered models (from @Model decorator, or a static getter on class)\n // For simplicity, let's assume fields can be derived or are less critical for this registry part\n // private modelFields: Map<string, Map<string, FieldOptions>> = new Map();\n\n // Holds the subset of models explicitly set for the current initialization session\n private activeSessionModels: Map<string, typeof BaseModel> | null = null;\n private dbEngine: DatabaseEngine | null = null; // Store dbEngine for relationship methods\n\n private constructor() {}\n\n public static getInstance(): ModelRegistry {\n if (!ModelRegistry.instance) {\n ModelRegistry.instance = new ModelRegistry();\n }\n return ModelRegistry.instance;\n }\n\n public registerModel(\n modelClass: any,\n options: ModelOptions,\n fields: Map<string, FieldOptions>\n ): void {\n if (!options.name) {\n throw new Error(\n `[ModelRegistry] Model class is missing a name in its @Model options. Ensure the @Model decorator includes a 'name' property.`\n );\n }\n if (this.models.has(options.name)) {\n console.warn(\n `[ModelRegistry] Model \"${options.name}\" is already registered. Overwriting.`\n );\n }\n this.models.set(options.name, modelClass as typeof BaseModel);\n if (fields) {\n BaseModel.attachFieldAccessors(modelClass, fields);\n }\n this.modelOptions.set(options.name, options);\n // this.modelFields.set(options.name, fields); // If storing fields directly\n console.log(\n `[ModelRegistry] Model \"${options.name}\" registered successfully.`\n );\n }\n\n // Gets the class for a globally registered model\n public getModelClass(name: string): typeof BaseModel | undefined {\n return this.models.get(name);\n }\n\n public getModelOptions(name: string): ModelOptions | undefined {\n return this.modelOptions.get(name);\n }\n\n // This method might need to be adapted based on how fields are ultimately managed\n public getModelInfo(modelName: string): RegisteredModelInfo | undefined {\n const modelClass = this.models.get(modelName);\n const options = this.modelOptions.get(modelName);\n if (modelClass && options) {\n // Assuming fields can be accessed from the modelClass, e.g., a static getter\n const fields = (modelClass as any).getSchema\n ? (modelClass as any).getSchema().fields\n : new Map<string, FieldOptions>();\n return { class: modelClass, options, fields };\n }\n return undefined;\n }\n\n public getAllRegisteredModelsInfo(): RegisteredModelInfo[] {\n const infos: RegisteredModelInfo[] = [];\n for (const modelName of this.models.keys()) {\n const info = this.getModelInfo(modelName);\n if (info) {\n infos.push(info);\n }\n }\n return infos;\n }\n\n // Helper to get model name from class (assuming static property from @Model decorator)\n private getModelNameFromClass(\n modelClass: typeof BaseModel\n ): string | undefined {\n // Accessing a static property 'modelName' set by the @Model decorator\n return (modelClass as any).modelName;\n }\n\n public setExplicitModelsForSession(\n modelClasses?: (typeof BaseModel)[]\n ): void {\n if (modelClasses && modelClasses.length > 0) {\n this.activeSessionModels = new Map();\n modelClasses.forEach((modelClass) => {\n const modelName = this.getModelNameFromClass(modelClass);\n if (!modelName) {\n console.warn(\n `[ModelRegistry] A model class provided to setExplicitModelsForSession does not have a static 'modelName' property or it's undefined. It will be ignored. Ensure @Model decorator sets this.`\n );\n return;\n }\n if (\n !this.models.has(modelName) ||\n this.models.get(modelName) !== modelClass\n ) {\n console.warn(\n `[ModelRegistry] Model class with name ${modelName} provided to setExplicitModelsForSession was not found in the global decorator-based registry or does not match. It will be ignored. Ensure the model file is imported and the @Model decorator has run correctly.`\n );\n return;\n }\n // Ensure activeSessionModels is not null before calling set\n if (this.activeSessionModels) {\n this.activeSessionModels.set(modelName, modelClass);\n }\n });\n\n // Defensive check for this.activeSessionModels before accessing .keys()\n let sessionModelNamesMessage =\n \"none (no models were successfully added or session map is null)\";\n if (this.activeSessionModels) {\n const currentSessionModelKeys = Array.from(\n this.activeSessionModels.keys()\n );\n if (currentSessionModelKeys.length > 0) {\n sessionModelNamesMessage = currentSessionModelKeys.join(\", \");\n } else {\n sessionModelNamesMessage =\n \"none (session map initialized but no models added)\";\n }\n }\n Logger.debug(\n `[ModelRegistry] Explicit models set for session: ${sessionModelNamesMessage}`\n );\n } else if (modelClasses && modelClasses.length === 0) {\n // Explicitly an empty array: session should have NO models active\n this.activeSessionModels = new Map();\n Logger.debug(\n \"[ModelRegistry] Explicitly no models for session (empty array passed).\"\n );\n } else {\n // modelClasses is undefined: session should use all globally registered models\n this.activeSessionModels = null;\n console.log(\n \"[ModelRegistry] No explicit models specified for session (undefined), will use all decorator-registered models.\"\n );\n }\n this.validateSessionModels();\n }\n\n public async initializeAll(\n yDoc: Y.Doc,\n dbEngine: DatabaseEngine\n ): Promise<void> {\n Logger.debug(\"[ModelRegistry] Attempting to initialize models...\");\n this.dbEngine = dbEngine; // Store dbEngine instance\n\n const modelsToInitialize = this.activeSessionModels || this.models;\n\n if (modelsToInitialize.size === 0) {\n console.warn(\n \"[ModelRegistry] No models to initialize (either no explicit models set for session or no models globally registered via @Model decorator).\"\n );\n return;\n }\n\n console.log(\n `[ModelRegistry] Initializing models: ${Array.from(\n modelsToInitialize.keys()\n ).join(\", \")}`\n );\n\n for (const [modelName, modelClass] of modelsToInitialize.entries()) {\n if (modelClass && typeof modelClass.initialize === \"function\") {\n Logger.debug(`[ModelRegistry] Initializing model: ${modelName}`);\n await modelClass.initialize(yDoc, dbEngine); // Assumes BaseModel has a static initialize\n } else {\n const staticModelName = (modelClass as any)?.modelName || \"unknown\";\n console.warn(\n `[ModelRegistry] Model ${staticModelName} (class name: ${modelClass?.name}) does not have a static initialize method or class is not defined.`\n );\n }\n }\n Logger.debug(\"[ModelRegistry] Model initialization phase complete.\");\n }\n\n // New method to initialize models for a specific document\n public async initializeAllForDocument(\n yDoc: Y.Doc,\n dbEngine: DatabaseEngine,\n docId: string,\n permissionHint: DocumentPermissionHint\n ): Promise<void> {\n Logger.debug(\n `[ModelRegistry] Initializing models for document ${docId}...`\n );\n this.dbEngine = dbEngine; // Store dbEngine instance\n\n const modelsToInitialize = this.activeSessionModels || this.models;\n\n if (modelsToInitialize.size === 0) {\n Logger.warn(\n \"[ModelRegistry] No models to initialize for document (either no explicit models set for session or no models globally registered via @Model decorator).\"\n );\n return;\n }\n\n Logger.debug(\n `[ModelRegistry] Initializing models for document ${docId}: ${Array.from(\n modelsToInitialize.keys()\n ).join(\", \")}`\n );\n\n for (const [modelName, modelClass] of modelsToInitialize.entries()) {\n if (\n modelClass &&\n typeof modelClass.initializeForDocument === \"function\"\n ) {\n Logger.debug(\n `[ModelRegistry] Initializing model ${modelName} for document ${docId}`\n );\n await modelClass.initializeForDocument(\n yDoc,\n dbEngine,\n docId,\n permissionHint\n );\n } else {\n const staticModelName = (modelClass as any)?.modelName || \"unknown\";\n console.warn(\n `[ModelRegistry] Model ${staticModelName} (class name: ${modelClass?.name}) does not have a static initializeForDocument method or class is not defined.`\n );\n }\n }\n\n // Initialize relationships after all models are set up for this document\n await this.initializeRelationships();\n\n Logger.debug(\n `[ModelRegistry] Model initialization complete for document ${docId}`\n );\n }\n\n // New method to remove data from a disconnected document\n public async removeDocumentData(\n docId: string,\n dbEngine: DatabaseEngine\n ): Promise<void> {\n Logger.debug(`[ModelRegistry] Removing data for document ${docId}...`);\n\n const modelsToCleanup = this.activeSessionModels || this.models;\n\n if (modelsToCleanup.size === 0) {\n console.warn(\n \"[ModelRegistry] No models to cleanup for document (either no explicit models set for session or no models globally registered via @Model decorator).\"\n );\n return;\n }\n\n // Remove from database using _meta_doc_id filter\n for (const [modelName, modelClass] of modelsToCleanup.entries()) {\n try {\n Logger.debug(\n `[ModelRegistry] Removing ${modelName} data for document ${docId}`\n );\n\n // Delete all records with this document ID from the database\n await dbEngine.deleteByDocumentId(modelName, docId);\n\n // Clean up YMap data for this document if the model has the method\n if (\n modelClass &&\n typeof modelClass.cleanupDocumentData === \"function\"\n ) {\n await modelClass.cleanupDocumentData(docId);\n }\n } catch (error) {\n console.error(\n `[ModelRegistry] Error removing ${modelName} data for document ${docId}:`,\n error\n );\n }\n }\n\n Logger.debug(`[ModelRegistry] Data removal complete for document ${docId}`);\n }\n\n // New method to initialize relationships\n public async initializeRelationships(): Promise<void> {\n if (!this.dbEngine) {\n console.error(\n \"[ModelRegistry] DB engine not available for initializing relationships. Ensure initializeAll has been called.\"\n );\n return;\n }\n const dbEngine = this.dbEngine; // Use stored dbEngine\n\n Logger.debug(\n \"[ModelRegistry] Initializing relationships for active models...\"\n );\n const activeModels = this.getActiveModels();\n\n for (const [modelName, modelClass] of activeModels.entries()) {\n const modelSchema = (modelClass as any).getSchema\n ? (modelClass as any).getSchema()\n : null;\n const relationshipsConfig = modelSchema?.options?.relationships as\n | Record<string, RelationshipConfig>\n | undefined;\n\n if (relationshipsConfig) {\n Logger.debug(\n `[ModelRegistry] Setting up relationships for ${modelName}`\n );\n for (const relName in relationshipsConfig) {\n const config = relationshipsConfig[relName];\n // Ensure model and targetModelClass are valid before proceeding\n if (!config.model) {\n throw new Error(\n `[ModelRegistry] Relationship \"${relName}\" on model \"${modelName}\" is missing a target model name.`\n );\n }\n const targetModelClass = this.getModelClass(config.model);\n\n if (!targetModelClass) {\n throw new Error(\n `[ModelRegistry] Relationship \"${relName}\" on model \"${modelName}\" refers to an unknown model \"${config.model}\". Ensure \"${config.model}\" is registered and included in the session.`\n );\n }\n\n // Check if targetModelClass has getSchema method\n if (typeof (targetModelClass as any).getSchema !== \"function\") {\n throw new Error(\n `[ModelRegistry] Target model \"${config.model}\" for relationship \"${relName}\" on \"${modelName}\" does not have a getSchema method.`\n );\n }\n\n switch (config.type) {\n case \"refersTo\":\n Logger.debug(\n ` - Adding '${relName}' (refersTo ${config.model}) to ${modelName}`\n );\n const refersToMethod = RelationshipManager.generateRefersToMethod(\n modelClass,\n config as RefersToRelationshipConfig,\n targetModelClass\n );\n this.addPrototypeMethod(modelClass, relName, refersToMethod);\n break;\n case \"hasMany\":\n Logger.debug(\n ` - Adding '${relName}' (hasMany ${config.model}) to ${modelName}`\n );\n const hasManyMethod = RelationshipManager.generateHasManyMethod(\n modelClass,\n config as HasManyRelationshipConfig,\n targetModelClass,\n dbEngine\n );\n this.addPrototypeMethod(modelClass, relName, hasManyMethod);\n break;\n case \"hasManyThrough\":\n const joinModelName = (config as HasManyThroughRelationshipConfig)\n .joinModel;\n const joinModelClass = this.getModelClass(joinModelName);\n if (!joinModelClass) {\n throw new Error(\n `[ModelRegistry] Join model \"${joinModelName}\" for relationship \"${relName}\" on model \"${modelName}\" not found. Ensure it is registered and included in the session.`\n );\n }\n // Check if joinModelClass has getSchema method\n if (typeof (joinModelClass as any).getSchema !== \"function\") {\n throw new Error(\n `[ModelRegistry] Join model \"${joinModelName}\" for relationship \"${relName}\" on \"${modelName}\" does not have a getSchema method.`\n );\n }\n Logger.debug(\n ` - Adding '${relName}' (hasManyThrough ${config.model} via ${joinModelName}) to ${modelName}`\n );\n const hasManyThroughFetchMethod =\n RelationshipManager.generateHasManyThroughMethod(\n modelClass,\n config as HasManyThroughRelationshipConfig,\n targetModelClass,\n joinModelClass,\n dbEngine\n );\n this.addPrototypeMethod(\n modelClass,\n relName,\n hasManyThroughFetchMethod\n );\n\n // Add helper methods: add<RelNameSingular> and remove<RelNameSingular>\n const relNameSingular = config.model.endsWith(\"s\")\n ? config.model.slice(0, -1)\n : config.model; // Use target model name for singularization logic\n const capitalizedSingularRelName =\n relNameSingular.charAt(0).toUpperCase() +\n relNameSingular.slice(1);\n\n const addMethodName = `add${capitalizedSingularRelName}`;\n const addMethodLogic =\n RelationshipManager.generateHasManyThroughAddMethod(\n modelClass,\n config as HasManyThroughRelationshipConfig,\n targetModelClass,\n joinModelClass\n );\n this.addPrototypeMethod(\n modelClass,\n addMethodName,\n addMethodLogic\n );\n Logger.debug(\n ` - Adding '${addMethodName}' helper to ${modelName} (for relationship ${relName})`\n );\n\n const removeMethodName = `remove${capitalizedSingularRelName}`;\n const removeMethodLogic =\n RelationshipManager.generateHasManyThroughRemoveMethod(\n modelClass,\n config as HasManyThroughRelationshipConfig,\n targetModelClass,\n joinModelClass\n );\n this.addPrototypeMethod(\n modelClass,\n removeMethodName,\n removeMethodLogic\n );\n Logger.debug(\n ` - Adding '${removeMethodName}' helper to ${modelName} (for relationship ${relName})`\n );\n break;\n default:\n console.warn(\n `[ModelRegistry] Unknown relationship type \"${\n (config as any).type\n }\" for ${relName} on ${modelName}. Skipping.`\n );\n }\n }\n }\n }\n Logger.debug(\"[ModelRegistry] Relationship initialization phase complete.\");\n }\n\n // Helper to add methods to prototype\n private addPrototypeMethod(\n modelClass: typeof BaseModel,\n methodName: string,\n methodLogic: Function\n ) {\n Object.defineProperty(modelClass.prototype, methodName, {\n value: methodLogic,\n writable: true,\n enumerable: false, // Keep it clean, like other prototype methods\n configurable: true,\n });\n }\n\n public clearSessionState(): void {\n this.activeSessionModels = null;\n Logger.debug(\n \"[ModelRegistry] Session state cleared (activeSessionModels reset).\"\n );\n }\n\n public getActiveModels(): Map<string, typeof BaseModel> {\n return this.activeSessionModels || this.models;\n }\n private validateSessionModels(): void {\n const activeModels = this.getActiveModels();\n if (!activeModels || activeModels.size === 0) {\n return; // No models to validate\n }\n\n for (const [modelName, modelClass] of activeModels.entries()) {\n const modelSchema = (modelClass as any).getSchema\n ? (modelClass as any).getSchema()\n : null;\n const relationships = modelSchema?.options?.relationships as\n | Record<string, RelationshipConfig>\n | undefined;\n\n if (relationships) {\n for (const relName in relationships) {\n const config = relationships[relName];\n const targetModelName = config.model;\n\n // Check if the target model is active\n if (!activeModels.has(targetModelName)) {\n throw new Error(\n `[ModelRegistry] Validation Error: Model \"${modelName}\" has a relationship \"${relName}\" that refers to model \"${targetModelName}\", but \"${targetModelName}\" is not active in the current session. Please include it in the 'models' array during initialization.`\n );\n }\n\n // If it's a hasManyThrough, also check the join model\n if (config.type === \"hasManyThrough\") {\n const joinModelName = (config as HasManyThroughRelationshipConfig)\n .joinModel;\n if (!activeModels.has(joinModelName)) {\n throw new Error(\n `[ModelRegistry] Validation Error: Model \"${modelName}\" has a relationship \"${relName}\" that uses join model \"${joinModelName}\", but \"${joinModelName}\" is not active in the current session. Please include it in the 'models' array during initialization.`\n );\n }\n }\n }\n }\n }\n }\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,373 @@
1
+ import {
2
+ Logger,
3
+ quoteIdentifier
4
+ } from "./chunk-3PZWHUZO.js";
5
+
6
+ // src/engines/SqljsEngine.ts
7
+ import initSqlJs from "sql.js";
8
+ import { Mutex } from "async-mutex";
9
+ var SQL_WASM_URL = "/sql-wasm.wasm";
10
+ var TransactionalSQLJSOperations = class {
11
+ db;
12
+ engine;
13
+ // For helper methods, changed type to SqljsEngine
14
+ constructor(db, engine) {
15
+ this.db = db;
16
+ this.engine = engine;
17
+ }
18
+ async insert(modelName, data) {
19
+ if (!this.db) throw new Error("SQL.js DB not available in transaction");
20
+ const tableName = this.engine.getTableName(modelName);
21
+ const quotedTableName = quoteIdentifier(tableName);
22
+ const columns = Object.keys(data);
23
+ const quotedColumns = columns.map((column) => quoteIdentifier(column));
24
+ const placeholders = columns.map(() => "?").join(", ");
25
+ const values = Object.values(data);
26
+ const insertSQL = `INSERT OR REPLACE INTO ${quotedTableName} (${quotedColumns.join(
27
+ ", "
28
+ )}) VALUES (${placeholders});`;
29
+ this.db.run(insertSQL, values);
30
+ }
31
+ async delete(modelName, id) {
32
+ if (!this.db) throw new Error("SQL.js DB not available in transaction");
33
+ const tableName = this.engine.getTableName(modelName);
34
+ const deleteSQL = `DELETE FROM ${quoteIdentifier(tableName)} WHERE ${quoteIdentifier(
35
+ "id"
36
+ )} = ?;`;
37
+ this.db.run(deleteSQL, [id]);
38
+ }
39
+ async query(sql, params) {
40
+ if (!this.db) throw new Error("SQL.js DB not available in transaction");
41
+ const results = [];
42
+ const stmt = this.db.prepare(sql);
43
+ if (params) {
44
+ stmt.bind(params);
45
+ }
46
+ while (stmt.step()) {
47
+ results.push(stmt.getAsObject());
48
+ }
49
+ stmt.free();
50
+ return results;
51
+ }
52
+ };
53
+ var SqljsEngine = class _SqljsEngine {
54
+ static SQL = null;
55
+ db = null;
56
+ tableNames = /* @__PURE__ */ new Set();
57
+ numOpenTransactions = 0;
58
+ mutex = new Mutex();
59
+ readyPromise;
60
+ constructor(options) {
61
+ Logger.debug("[SqljsEngine] Constructor called. Initializing...");
62
+ this.numOpenTransactions = 0;
63
+ this.readyPromise = this.initialize(options);
64
+ }
65
+ // Make readyPromise accessible if DatabaseFactory wants to await it,
66
+ // though direct call to initialize from constructor and awaiting it is simpler here.
67
+ async ensureReady() {
68
+ return this.readyPromise;
69
+ }
70
+ async initialize(engineOptions) {
71
+ Logger.info("[SqljsEngine] Initializing SQL.js engine...");
72
+ try {
73
+ if (!_SqljsEngine.SQL) {
74
+ const locateFileConfig = engineOptions?.locateFile || ((_file) => engineOptions?.wasmURL || SQL_WASM_URL);
75
+ Logger.debug(
76
+ "[SqljsEngine] Attempting to load SQL.js WASM from:",
77
+ locateFileConfig("sql-wasm.wasm")
78
+ );
79
+ _SqljsEngine.SQL = await initSqlJs({
80
+ locateFile: locateFileConfig
81
+ });
82
+ Logger.info("[SqljsEngine] SQL.js WASM loaded successfully.");
83
+ }
84
+ this.db = new _SqljsEngine.SQL.Database();
85
+ Logger.info("[SqljsEngine] SQL.js Database initialized in memory.");
86
+ this.updateTableNames();
87
+ } catch (error) {
88
+ Logger.error("[SqljsEngine] Error during SQL.js initialization:", error);
89
+ throw error;
90
+ }
91
+ }
92
+ updateTableNames() {
93
+ if (!this.db) return;
94
+ const results = this.db.exec(
95
+ "SELECT name FROM sqlite_master WHERE type='table';"
96
+ );
97
+ this.tableNames.clear();
98
+ if (results.length > 0 && results[0].values) {
99
+ results[0].values.forEach(
100
+ (row) => this.tableNames.add(row[0])
101
+ );
102
+ }
103
+ }
104
+ getTableName(modelName) {
105
+ return `model_${modelName.toLowerCase()}`;
106
+ }
107
+ mapTypeToSQL(type) {
108
+ switch (type.toLowerCase()) {
109
+ case "string":
110
+ return "TEXT";
111
+ case "number":
112
+ return "REAL";
113
+ case "boolean":
114
+ return "INTEGER";
115
+ case "date":
116
+ return "TEXT";
117
+ default:
118
+ return "TEXT";
119
+ }
120
+ }
121
+ async createTable(modelName, schema, _options) {
122
+ await this.readyPromise;
123
+ if (!this.db) throw new Error("SQL.js not initialized for createTable");
124
+ const tableName = this.getTableName(modelName);
125
+ const quotedTableName = quoteIdentifier(tableName);
126
+ const idColumn = quoteIdentifier("id");
127
+ const typeColumn = quoteIdentifier("type");
128
+ if (this.tableNames.has(tableName)) {
129
+ return;
130
+ }
131
+ const columns = Array.from(schema.entries()).filter(([field]) => field !== "id" && field !== "type").map(
132
+ ([field, fieldOptions]) => `${quoteIdentifier(field)} ${this.mapTypeToSQL(fieldOptions.type)}`
133
+ );
134
+ const metadataColumns = [
135
+ `${quoteIdentifier("_meta_doc_id")} TEXT`,
136
+ `${quoteIdentifier("_meta_permission_hint")} TEXT`
137
+ ];
138
+ const createTableSQL = `CREATE TABLE IF NOT EXISTS ${quotedTableName} (
139
+ ${idColumn} TEXT PRIMARY KEY,
140
+ ${typeColumn} TEXT,
141
+ ${columns.join(", ")}${columns.length > 0 ? ", " : ""}${metadataColumns.join(", ")}
142
+ );`;
143
+ this.db.run(createTableSQL);
144
+ for (const [field, fieldOptions] of schema.entries()) {
145
+ if (fieldOptions && fieldOptions.indexed && field !== "id") {
146
+ const indexName = `idx_${tableName}_${field}`;
147
+ const createIndexSQL = `CREATE INDEX IF NOT EXISTS ${quoteIdentifier(
148
+ indexName
149
+ )} ON ${quotedTableName} (${quoteIdentifier(field)});`;
150
+ this.db.run(createIndexSQL);
151
+ }
152
+ }
153
+ const docIdIndexName = `idx_${tableName}_meta_doc_id`;
154
+ const docIdIndexSQL = `CREATE INDEX IF NOT EXISTS ${quoteIdentifier(
155
+ docIdIndexName
156
+ )} ON ${quotedTableName} (${quoteIdentifier("_meta_doc_id")});`;
157
+ this.db.run(docIdIndexSQL);
158
+ this.updateTableNames();
159
+ }
160
+ async createStringSetJunctionTable(modelName, fieldName) {
161
+ await this.readyPromise;
162
+ if (!this.db)
163
+ throw new Error(
164
+ "SQL.js not initialized for createStringSetJunctionTable"
165
+ );
166
+ const junctionTableName = `${this.getTableName(modelName)}_${fieldName}`;
167
+ const quotedJunctionTable = quoteIdentifier(junctionTableName);
168
+ const foreignKeyColumn = `${modelName.toLowerCase()}_id`;
169
+ const quotedForeignKey = quoteIdentifier(foreignKeyColumn);
170
+ const quotedIdColumn = quoteIdentifier("id");
171
+ const quotedValueColumn = quoteIdentifier("value");
172
+ if (this.tableNames.has(junctionTableName)) {
173
+ Logger.debug(
174
+ `[SqljsEngine] StringSet junction table ${junctionTableName} already exists, skipping creation.`
175
+ );
176
+ return;
177
+ }
178
+ const createTableSQL = `CREATE TABLE IF NOT EXISTS ${quotedJunctionTable} (
179
+ ${quotedIdColumn} TEXT PRIMARY KEY,
180
+ ${quotedForeignKey} TEXT NOT NULL,
181
+ ${quotedValueColumn} TEXT NOT NULL,
182
+ UNIQUE(${quotedForeignKey}, ${quotedValueColumn})
183
+ );`;
184
+ Logger.info(
185
+ `[SqljsEngine] Creating StringSet junction table ${junctionTableName} for ${modelName}.${fieldName}`
186
+ );
187
+ this.db.run(createTableSQL);
188
+ const indexName = `idx_${junctionTableName}_${modelName.toLowerCase()}_id_value`;
189
+ const indexSQL = `CREATE INDEX IF NOT EXISTS ${quoteIdentifier(
190
+ indexName
191
+ )} ON ${quotedJunctionTable} (${quotedForeignKey}, ${quotedValueColumn});`;
192
+ this.db.run(indexSQL);
193
+ this.updateTableNames();
194
+ Logger.info(
195
+ `[SqljsEngine] StringSet junction table ${junctionTableName} created successfully.`
196
+ );
197
+ }
198
+ async insertStringSetValues(modelName, fieldName, recordId, values) {
199
+ await this.readyPromise;
200
+ if (!this.db)
201
+ throw new Error("SQL.js not initialized for insertStringSetValues");
202
+ if (values.length === 0) return;
203
+ const junctionTableName = `${this.getTableName(modelName)}_${fieldName}`;
204
+ const modelIdColumn = `${modelName.toLowerCase()}_id`;
205
+ const quotedJunctionTable = quoteIdentifier(junctionTableName);
206
+ const quotedIdColumn = quoteIdentifier("id");
207
+ const quotedModelIdColumn = quoteIdentifier(modelIdColumn);
208
+ const quotedValueColumn = quoteIdentifier("value");
209
+ for (const value of values) {
210
+ const insertSQL = `INSERT OR IGNORE INTO ${quotedJunctionTable} (${quotedIdColumn}, ${quotedModelIdColumn}, ${quotedValueColumn}) VALUES (?, ?, ?);`;
211
+ const junctionId = `${recordId}_${value}`;
212
+ this.db.run(insertSQL, [junctionId, recordId, value]);
213
+ }
214
+ }
215
+ async removeStringSetValues(modelName, fieldName, recordId, values) {
216
+ await this.readyPromise;
217
+ if (!this.db)
218
+ throw new Error("SQL.js not initialized for removeStringSetValues");
219
+ if (values.length === 0) return;
220
+ const junctionTableName = `${this.getTableName(modelName)}_${fieldName}`;
221
+ const modelIdColumn = `${modelName.toLowerCase()}_id`;
222
+ const quotedJunctionTable = quoteIdentifier(junctionTableName);
223
+ const quotedModelIdColumn = quoteIdentifier(modelIdColumn);
224
+ const quotedValueColumn = quoteIdentifier("value");
225
+ for (const value of values) {
226
+ const deleteSQL = `DELETE FROM ${quotedJunctionTable} WHERE ${quotedModelIdColumn} = ? AND ${quotedValueColumn} = ?;`;
227
+ this.db.run(deleteSQL, [recordId, value]);
228
+ }
229
+ }
230
+ async insert(modelName, data) {
231
+ await this.readyPromise;
232
+ if (!this.db) throw new Error("SQL.js not initialized for insert");
233
+ const tableName = this.getTableName(modelName);
234
+ const quotedTableName = quoteIdentifier(tableName);
235
+ const columns = Object.keys(data);
236
+ const quotedColumns = columns.map((column) => quoteIdentifier(column));
237
+ const placeholders = columns.map(() => "?").join(", ");
238
+ const values = Object.values(data);
239
+ const insertSQL = `INSERT OR REPLACE INTO ${quotedTableName} (${quotedColumns.join(
240
+ ", "
241
+ )}) VALUES (${placeholders});`;
242
+ this.db.run(insertSQL, values);
243
+ }
244
+ async delete(modelName, id) {
245
+ await this.readyPromise;
246
+ if (!this.db) throw new Error("SQL.js not initialized for delete");
247
+ const tableName = this.getTableName(modelName);
248
+ const deleteSQL = `DELETE FROM ${quoteIdentifier(tableName)} WHERE ${quoteIdentifier(
249
+ "id"
250
+ )} = ?;`;
251
+ this.db.run(deleteSQL, [id]);
252
+ }
253
+ async deleteByDocumentId(modelName, docId) {
254
+ await this.readyPromise;
255
+ if (!this.db)
256
+ throw new Error("SQL.js not initialized for deleteByDocumentId");
257
+ const tableName = this.getTableName(modelName);
258
+ const quotedTableName = quoteIdentifier(tableName);
259
+ if (!this.tableNames.has(tableName)) {
260
+ Logger.debug(
261
+ `[SqljsEngine] Skipping deleteByDocumentId for ${tableName}; table does not exist.`
262
+ );
263
+ return;
264
+ }
265
+ const deleteSQL = `DELETE FROM ${quotedTableName} WHERE ${quoteIdentifier(
266
+ "_meta_doc_id"
267
+ )} = ?;`;
268
+ this.db.run(deleteSQL, [docId]);
269
+ for (const existingTableName of this.tableNames) {
270
+ if (existingTableName.startsWith(`${tableName}_`)) {
271
+ const quotedExistingTable = quoteIdentifier(existingTableName);
272
+ const quotedForeignKey = quoteIdentifier(`${modelName.toLowerCase()}_id`);
273
+ const junctionDeleteSQL = `DELETE FROM ${quotedExistingTable} WHERE ${quotedForeignKey} IN (
274
+ SELECT ${quoteIdentifier("id")} FROM ${quotedTableName} WHERE ${quoteIdentifier(
275
+ "_meta_doc_id"
276
+ )} = ?
277
+ );`;
278
+ try {
279
+ this.db.run(junctionDeleteSQL, [docId]);
280
+ const rowsCleared = this.db.getRowsModified();
281
+ Logger.info(
282
+ `[SqljsEngine] Cleared junction table ${existingTableName} for document ${docId}; removed ${rowsCleared} rows.`
283
+ );
284
+ } catch (error) {
285
+ Logger.warn(
286
+ `[SqljsEngine] Warning: Could not clean up junction table ${existingTableName}:`,
287
+ error
288
+ );
289
+ }
290
+ }
291
+ }
292
+ }
293
+ async query(sql, params) {
294
+ await this.readyPromise;
295
+ if (!this.db) throw new Error("SQL.js not initialized for query");
296
+ const results = [];
297
+ const stmt = this.db.prepare(sql);
298
+ if (params) {
299
+ stmt.bind(params);
300
+ }
301
+ while (stmt.step()) {
302
+ results.push(stmt.getAsObject());
303
+ }
304
+ stmt.free();
305
+ return results;
306
+ }
307
+ async withTransaction(callback) {
308
+ await this.readyPromise;
309
+ if (!this.db)
310
+ throw new Error("SQL.js Database instance not available for transaction");
311
+ let transactionStartedHere = false;
312
+ await this.mutex.runExclusive(async () => {
313
+ if (this.numOpenTransactions === 0) {
314
+ if (!this.db) throw new Error("SQL.js DB not available for BEGIN");
315
+ this.db.run("BEGIN TRANSACTION");
316
+ transactionStartedHere = true;
317
+ }
318
+ this.numOpenTransactions++;
319
+ });
320
+ const transactionalOps = new TransactionalSQLJSOperations(this.db, this);
321
+ try {
322
+ const result = await callback(transactionalOps);
323
+ await this.mutex.runExclusive(async () => {
324
+ this.numOpenTransactions--;
325
+ if (this.numOpenTransactions === 0) {
326
+ if (!this.db) throw new Error("SQL.js DB not available for COMMIT");
327
+ this.db.run("COMMIT");
328
+ }
329
+ });
330
+ return result;
331
+ } catch (error) {
332
+ Logger.error("[SqljsEngine] Error in transaction, rolling back:", error);
333
+ await this.mutex.runExclusive(async () => {
334
+ if (this.db && this.numOpenTransactions > 0 && transactionStartedHere) {
335
+ try {
336
+ if (!this.db)
337
+ throw new Error("SQL.js DB not available for ROLLBACK");
338
+ this.db.run("ROLLBACK");
339
+ } catch (rollbackError) {
340
+ Logger.error("[SqljsEngine] Error during ROLLBACK:", rollbackError);
341
+ }
342
+ }
343
+ this.numOpenTransactions = 0;
344
+ });
345
+ throw error;
346
+ }
347
+ }
348
+ async close() {
349
+ await this.readyPromise;
350
+ if (this.db) {
351
+ this.db.close();
352
+ this.db = null;
353
+ _SqljsEngine.SQL = null;
354
+ }
355
+ }
356
+ async getTableSchema(_tableName) {
357
+ return void 0;
358
+ }
359
+ async destroy() {
360
+ if (this.db) {
361
+ this.db.close();
362
+ Logger.info("[SqljsEngine] Database closed.");
363
+ }
364
+ }
365
+ getLastErrorMessage() {
366
+ return void 0;
367
+ }
368
+ };
369
+
370
+ export {
371
+ SqljsEngine
372
+ };
373
+ //# sourceMappingURL=chunk-DF3JEQXA.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/engines/SqljsEngine.ts"],"sourcesContent":["import initSqlJs, {\n type SqlJsStatic,\n type Database as SQLJsDB,\n type SqlValue,\n} from \"sql.js\";\nimport {\n DatabaseEngine,\n ITransactionalDatabaseOperations,\n} from \"./DatabaseEngine\"; // Adjusted path\nimport { ModelOptions } from \"../types/ormTypes\"; // Adjusted path\nimport { Logger } from \"../models/BaseModel\"; // Import Logger\nimport { Mutex } from \"async-mutex\";\nimport { quoteIdentifier } from \"../utils/sql\";\n\nexport interface SQLJSEngineOptions {\n wasmURL?: string;\n locateFile?: (file: string) => string;\n}\n\n// IMPORTANT: For this engine to work, the sql-wasm.wasm file must be publicly available.\n// By default, this engine expects it at the root path: /sql-wasm.wasm\n// Library users need to ensure their bundler (Webpack, Vite, etc.) makes this file\n// available at the expected location, or this path needs to be configurable.\n// For Vite, placing sql-wasm.wasm in the `public` directory usually works.\n// Future enhancement: Allow passing wasmURL or locateFile via DatabaseConfig.options.\nconst SQL_WASM_URL = \"/sql-wasm.wasm\";\n\n// Helper class for operations within a SQL.js transaction\nclass TransactionalSQLJSOperations implements ITransactionalDatabaseOperations {\n private db: SQLJsDB;\n private engine: SqljsEngine; // For helper methods, changed type to SqljsEngine\n\n constructor(db: SQLJsDB, engine: SqljsEngine) {\n // Changed type to SqljsEngine\n this.db = db;\n this.engine = engine;\n }\n\n async insert(modelName: string, data: any): Promise<void> {\n if (!this.db) throw new Error(\"SQL.js DB not available in transaction\");\n const tableName = this.engine.getTableName(modelName);\n const quotedTableName = quoteIdentifier(tableName);\n const columns = Object.keys(data);\n const quotedColumns = columns.map((column) => quoteIdentifier(column));\n const placeholders = columns.map(() => \"?\").join(\", \");\n const values = Object.values(data);\n const insertSQL = `INSERT OR REPLACE INTO ${quotedTableName} (${quotedColumns.join(\n \", \"\n )}) VALUES (${placeholders});`;\n this.db.run(insertSQL, values as SqlValue[]);\n }\n\n async delete(modelName: string, id: string): Promise<void> {\n if (!this.db) throw new Error(\"SQL.js DB not available in transaction\");\n const tableName = this.engine.getTableName(modelName);\n const deleteSQL = `DELETE FROM ${quoteIdentifier(tableName)} WHERE ${quoteIdentifier(\n \"id\"\n )} = ?;`;\n this.db.run(deleteSQL, [id as SqlValue]);\n }\n\n async query<T extends Record<string, any>>(\n sql: string,\n params?: any[]\n ): Promise<T[]> {\n if (!this.db) throw new Error(\"SQL.js DB not available in transaction\");\n // console.log(\"[TransactionalSQLJSOps] Executing SQL:\", sql, params);\n const results: T[] = [];\n const stmt = this.db.prepare(sql);\n if (params) {\n stmt.bind(params as SqlValue[]);\n }\n while (stmt.step()) {\n results.push(stmt.getAsObject() as T);\n }\n stmt.free();\n return results;\n }\n}\n\nexport class SqljsEngine implements DatabaseEngine {\n private static SQL: SqlJsStatic | null = null;\n private db: SQLJsDB | null = null;\n private tableNames: Set<string> = new Set();\n private numOpenTransactions: number = 0;\n private mutex: Mutex = new Mutex();\n private readyPromise: Promise<void>;\n\n constructor(options?: SQLJSEngineOptions) {\n Logger.debug(\"[SqljsEngine] Constructor called. Initializing...\");\n this.numOpenTransactions = 0;\n // The traditional getInstance pattern for singleton async init is tricky with a factory.\n // The factory will create the instance, and we initialize here.\n // The factory should await this readyPromise.\n this.readyPromise = this.initialize(options);\n }\n\n // Make readyPromise accessible if DatabaseFactory wants to await it,\n // though direct call to initialize from constructor and awaiting it is simpler here.\n public async ensureReady(): Promise<void> {\n return this.readyPromise;\n }\n\n private async initialize(engineOptions?: SQLJSEngineOptions): Promise<void> {\n Logger.info(\"[SqljsEngine] Initializing SQL.js engine...\");\n try {\n if (!SqljsEngine.SQL) {\n const locateFileConfig =\n engineOptions?.locateFile ||\n ((_file: string) => engineOptions?.wasmURL || SQL_WASM_URL);\n Logger.debug(\n \"[SqljsEngine] Attempting to load SQL.js WASM from:\",\n locateFileConfig(\"sql-wasm.wasm\")\n );\n SqljsEngine.SQL = await initSqlJs({\n locateFile: locateFileConfig,\n });\n Logger.info(\"[SqljsEngine] SQL.js WASM loaded successfully.\");\n }\n this.db = new SqljsEngine.SQL.Database();\n Logger.info(\"[SqljsEngine] SQL.js Database initialized in memory.\");\n this.updateTableNames();\n } catch (error) {\n Logger.error(\"[SqljsEngine] Error during SQL.js initialization:\", error);\n throw error; // Re-throw to fail fast if WASM can't load\n }\n }\n\n private updateTableNames(): void {\n if (!this.db) return;\n const results = this.db.exec(\n \"SELECT name FROM sqlite_master WHERE type='table';\"\n );\n this.tableNames.clear();\n if (results.length > 0 && results[0].values) {\n results[0].values.forEach((row: any) =>\n this.tableNames.add(row[0] as string)\n );\n }\n // console.log(\"[SqljsEngine] Existing tables:\", Array.from(this.tableNames));\n }\n\n public getTableName(modelName: string): string {\n return `model_${modelName.toLowerCase()}`;\n }\n\n private mapTypeToSQL(type: string): string {\n switch (type.toLowerCase()) {\n case \"string\":\n return \"TEXT\";\n case \"number\":\n return \"REAL\";\n case \"boolean\":\n return \"INTEGER\";\n case \"date\":\n return \"TEXT\";\n default:\n return \"TEXT\";\n }\n }\n\n async createTable(\n modelName: string,\n schema: Map<string, any>,\n _options: ModelOptions // options from model decorator, _ to indicate not directly used here\n ): Promise<void> {\n await this.readyPromise; // Ensure initialization is complete\n if (!this.db) throw new Error(\"SQL.js not initialized for createTable\");\n const tableName = this.getTableName(modelName);\n const quotedTableName = quoteIdentifier(tableName);\n const idColumn = quoteIdentifier(\"id\");\n const typeColumn = quoteIdentifier(\"type\");\n if (this.tableNames.has(tableName)) {\n // console.log(\n // `[SqljsEngine] Table ${tableName} already exists, skipping creation.`\n // );\n return;\n }\n const columns = Array.from(schema.entries())\n .filter(([field]) => field !== \"id\" && field !== \"type\") // id and type are standard\n .map(\n ([field, fieldOptions]) =>\n `${quoteIdentifier(field)} ${this.mapTypeToSQL(fieldOptions.type)}`\n );\n\n // Add metadata fields for multi-document support\n const metadataColumns = [\n `${quoteIdentifier(\"_meta_doc_id\")} TEXT`,\n `${quoteIdentifier(\"_meta_permission_hint\")} TEXT`,\n ];\n\n const createTableSQL = `CREATE TABLE IF NOT EXISTS ${quotedTableName} (\n ${idColumn} TEXT PRIMARY KEY, \n ${typeColumn} TEXT, \n ${columns.join(\", \")}${\n columns.length > 0 ? \", \" : \"\"\n }${metadataColumns.join(\", \")}\n );`;\n // console.log(\"[SqljsEngine] Executing SQL for createTable:\", createTableSQL);\n this.db.run(createTableSQL);\n\n // Create indexes for fields marked as indexed: true\n for (const [field, fieldOptions] of schema.entries()) {\n // Ensure fieldOptions exists and has the indexed property.\n // field !== \"id\" because 'id' is already the PRIMARY KEY and thus implicitly indexed.\n if (fieldOptions && fieldOptions.indexed && field !== \"id\") {\n const indexName = `idx_${tableName}_${field}`;\n const createIndexSQL = `CREATE INDEX IF NOT EXISTS ${quoteIdentifier(\n indexName\n )} ON ${quotedTableName} (${quoteIdentifier(field)});`;\n // console.log(`[SqljsEngine] Creating index ${indexName} on table ${tableName} for field ${field}: ${createIndexSQL}`);\n this.db.run(createIndexSQL);\n }\n }\n\n // Create index on _meta_doc_id for efficient document-based queries\n const docIdIndexName = `idx_${tableName}_meta_doc_id`;\n const docIdIndexSQL = `CREATE INDEX IF NOT EXISTS ${quoteIdentifier(\n docIdIndexName\n )} ON ${quotedTableName} (${quoteIdentifier(\"_meta_doc_id\")});`;\n this.db.run(docIdIndexSQL);\n\n this.updateTableNames();\n // console.log(`[SqljsEngine] Table ${tableName} created.`);\n }\n\n async createStringSetJunctionTable(\n modelName: string,\n fieldName: string\n ): Promise<void> {\n await this.readyPromise;\n if (!this.db)\n throw new Error(\n \"SQL.js not initialized for createStringSetJunctionTable\"\n );\n\n const junctionTableName = `${this.getTableName(modelName)}_${fieldName}`;\n const quotedJunctionTable = quoteIdentifier(junctionTableName);\n const foreignKeyColumn = `${modelName.toLowerCase()}_id`;\n const quotedForeignKey = quoteIdentifier(foreignKeyColumn);\n const quotedIdColumn = quoteIdentifier(\"id\");\n const quotedValueColumn = quoteIdentifier(\"value\");\n\n if (this.tableNames.has(junctionTableName)) {\n Logger.debug(\n `[SqljsEngine] StringSet junction table ${junctionTableName} already exists, skipping creation.`\n );\n return; // Table already exists\n }\n\n const createTableSQL = `CREATE TABLE IF NOT EXISTS ${quotedJunctionTable} (\n ${quotedIdColumn} TEXT PRIMARY KEY,\n ${quotedForeignKey} TEXT NOT NULL,\n ${quotedValueColumn} TEXT NOT NULL,\n UNIQUE(${quotedForeignKey}, ${quotedValueColumn})\n );`;\n\n Logger.info(\n `[SqljsEngine] Creating StringSet junction table ${junctionTableName} for ${modelName}.${fieldName}`\n );\n this.db.run(createTableSQL);\n\n // Create index for efficient lookups\n const indexName = `idx_${junctionTableName}_${modelName.toLowerCase()}_id_value`;\n const indexSQL = `CREATE INDEX IF NOT EXISTS ${quoteIdentifier(\n indexName\n )} ON ${quotedJunctionTable} (${quotedForeignKey}, ${quotedValueColumn});`;\n this.db.run(indexSQL);\n\n this.updateTableNames();\n Logger.info(\n `[SqljsEngine] StringSet junction table ${junctionTableName} created successfully.`\n );\n }\n\n async insertStringSetValues(\n modelName: string,\n fieldName: string,\n recordId: string,\n values: string[]\n ): Promise<void> {\n await this.readyPromise;\n if (!this.db)\n throw new Error(\"SQL.js not initialized for insertStringSetValues\");\n\n if (values.length === 0) return;\n\n const junctionTableName = `${this.getTableName(modelName)}_${fieldName}`;\n const modelIdColumn = `${modelName.toLowerCase()}_id`;\n const quotedJunctionTable = quoteIdentifier(junctionTableName);\n const quotedIdColumn = quoteIdentifier(\"id\");\n const quotedModelIdColumn = quoteIdentifier(modelIdColumn);\n const quotedValueColumn = quoteIdentifier(\"value\");\n\n for (const value of values) {\n const insertSQL = `INSERT OR IGNORE INTO ${quotedJunctionTable} (${quotedIdColumn}, ${quotedModelIdColumn}, ${quotedValueColumn}) VALUES (?, ?, ?);`;\n const junctionId = `${recordId}_${value}`;\n this.db.run(insertSQL, [junctionId, recordId, value]);\n }\n }\n\n async removeStringSetValues(\n modelName: string,\n fieldName: string,\n recordId: string,\n values: string[]\n ): Promise<void> {\n await this.readyPromise;\n if (!this.db)\n throw new Error(\"SQL.js not initialized for removeStringSetValues\");\n\n if (values.length === 0) return;\n\n const junctionTableName = `${this.getTableName(modelName)}_${fieldName}`;\n const modelIdColumn = `${modelName.toLowerCase()}_id`;\n const quotedJunctionTable = quoteIdentifier(junctionTableName);\n const quotedModelIdColumn = quoteIdentifier(modelIdColumn);\n const quotedValueColumn = quoteIdentifier(\"value\");\n\n for (const value of values) {\n const deleteSQL = `DELETE FROM ${quotedJunctionTable} WHERE ${quotedModelIdColumn} = ? AND ${quotedValueColumn} = ?;`;\n this.db.run(deleteSQL, [recordId, value]);\n }\n }\n\n async insert(modelName: string, data: any): Promise<void> {\n await this.readyPromise;\n if (!this.db) throw new Error(\"SQL.js not initialized for insert\");\n const tableName = this.getTableName(modelName);\n const quotedTableName = quoteIdentifier(tableName);\n const columns = Object.keys(data);\n const quotedColumns = columns.map((column) => quoteIdentifier(column));\n const placeholders = columns.map(() => \"?\").join(\", \");\n const values = Object.values(data);\n const insertSQL = `INSERT OR REPLACE INTO ${quotedTableName} (${quotedColumns.join(\n \", \"\n )}) VALUES (${placeholders});`;\n this.db.run(insertSQL, values as SqlValue[]);\n }\n\n async delete(modelName: string, id: string): Promise<void> {\n await this.readyPromise;\n if (!this.db) throw new Error(\"SQL.js not initialized for delete\");\n const tableName = this.getTableName(modelName);\n const deleteSQL = `DELETE FROM ${quoteIdentifier(tableName)} WHERE ${quoteIdentifier(\n \"id\"\n )} = ?;`;\n this.db.run(deleteSQL, [id as SqlValue]);\n }\n\n async deleteByDocumentId(modelName: string, docId: string): Promise<void> {\n await this.readyPromise;\n if (!this.db)\n throw new Error(\"SQL.js not initialized for deleteByDocumentId\");\n const tableName = this.getTableName(modelName);\n const quotedTableName = quoteIdentifier(tableName);\n\n if (!this.tableNames.has(tableName)) {\n Logger.debug(\n `[SqljsEngine] Skipping deleteByDocumentId for ${tableName}; table does not exist.`\n );\n return;\n }\n\n // Delete all records with the specified document ID\n const deleteSQL = `DELETE FROM ${quotedTableName} WHERE ${quoteIdentifier(\n \"_meta_doc_id\"\n )} = ?;`;\n this.db.run(deleteSQL, [docId as SqlValue]);\n\n // Also clean up StringSet junction tables\n for (const existingTableName of this.tableNames) {\n if (existingTableName.startsWith(`${tableName}_`)) {\n // This is likely a StringSet junction table\n const quotedExistingTable = quoteIdentifier(existingTableName);\n const quotedForeignKey = quoteIdentifier(`${modelName.toLowerCase()}_id`);\n const junctionDeleteSQL = `DELETE FROM ${quotedExistingTable} WHERE ${quotedForeignKey} IN (\n SELECT ${quoteIdentifier(\"id\")} FROM ${quotedTableName} WHERE ${quoteIdentifier(\n \"_meta_doc_id\"\n )} = ?\n );`;\n try {\n this.db.run(junctionDeleteSQL, [docId as SqlValue]);\n const rowsCleared = this.db.getRowsModified();\n Logger.info(\n `[SqljsEngine] Cleared junction table ${existingTableName} for document ${docId}; removed ${rowsCleared} rows.`\n );\n } catch (error) {\n Logger.warn(\n `[SqljsEngine] Warning: Could not clean up junction table ${existingTableName}:`,\n error\n );\n }\n }\n }\n }\n\n async query<T extends Record<string, any>>(\n sql: string,\n params?: any[]\n ): Promise<T[]> {\n await this.readyPromise;\n if (!this.db) throw new Error(\"SQL.js not initialized for query\");\n // console.log(\"[SqljsEngine] Executing direct query:\", sql, params);\n const results: T[] = [];\n const stmt = this.db.prepare(sql);\n if (params) {\n stmt.bind(params as SqlValue[]);\n }\n while (stmt.step()) {\n results.push(stmt.getAsObject() as T);\n }\n stmt.free();\n return results;\n }\n\n async withTransaction<T>(\n callback: (transactionalOps: ITransactionalDatabaseOperations) => Promise<T>\n ): Promise<T> {\n await this.readyPromise;\n if (!this.db)\n throw new Error(\"SQL.js Database instance not available for transaction\");\n\n let transactionStartedHere = false;\n await this.mutex.runExclusive(async () => {\n if (this.numOpenTransactions === 0) {\n // console.log(\"[SqljsEngine] Beginning transaction...\");\n if (!this.db) throw new Error(\"SQL.js DB not available for BEGIN\");\n this.db.run(\"BEGIN TRANSACTION\");\n transactionStartedHere = true;\n }\n this.numOpenTransactions++;\n // console.log(\n // \"[SqljsEngine] Transaction opened/nested, numOpenTransactions:\",\n // this.numOpenTransactions\n // );\n });\n\n const transactionalOps = new TransactionalSQLJSOperations(this.db, this);\n\n try {\n const result = await callback(transactionalOps);\n await this.mutex.runExclusive(async () => {\n this.numOpenTransactions--;\n // console.log(\n // \"[SqljsEngine] Transaction finishing, numOpenTransactions:\",\n // this.numOpenTransactions\n // );\n if (this.numOpenTransactions === 0) {\n // console.log(\"[SqljsEngine] Committing transaction...\");\n if (!this.db) throw new Error(\"SQL.js DB not available for COMMIT\");\n this.db.run(\"COMMIT\");\n }\n });\n return result;\n } catch (error) {\n Logger.error(\"[SqljsEngine] Error in transaction, rolling back:\", error);\n await this.mutex.runExclusive(async () => {\n if (this.db && this.numOpenTransactions > 0 && transactionStartedHere) {\n try {\n // console.log(\"[SqljsEngine] Rolling back transaction...\");\n if (!this.db)\n throw new Error(\"SQL.js DB not available for ROLLBACK\");\n this.db.run(\"ROLLBACK\");\n // console.log(\"[SqljsEngine] Rollback successful.\");\n } catch (rollbackError) {\n Logger.error(\"[SqljsEngine] Error during ROLLBACK:\", rollbackError);\n }\n }\n this.numOpenTransactions = 0; // Reset counter for this transaction context\n // console.log(\"[SqljsEngine] Transaction counter reset after error.\");\n });\n throw error;\n }\n }\n\n async close(): Promise<void> {\n await this.readyPromise;\n if (this.db) {\n // console.log(\"[SqljsEngine] Closing SQL.js database...\");\n this.db.close();\n this.db = null;\n SqljsEngine.SQL = null; // Allow re-init if a new instance is made and wasm needs to be reloaded.\n // console.log(\"[SqljsEngine] SQL.js database closed.\");\n }\n }\n\n async getTableSchema(_tableName: string): Promise<any> {\n // Implementation for SQL.js to get table schema (e.g., PRAGMA table_info)\n // This is a placeholder and needs actual implementation\n return undefined; // Placeholder\n }\n\n async destroy(): Promise<void> {\n if (this.db) {\n this.db.close();\n Logger.info(\"[SqljsEngine] Database closed.\");\n // Reset internal state if necessary, e.g., this.db = null;\n // this.db = null; // Assuming sql.js doesn't reuse the instance after close\n // and we'd create a new one upon re-init.\n }\n // No explicit ready state to reset here as ensureReady re-initializes if db is null.\n }\n\n getLastErrorMessage(): string | undefined {\n // SQL.js typically throws errors rather than setting a last error message property.\n // So, this method might not be directly applicable unless we cache errors.\n // For now, returning undefined as per the basic contract.\n return undefined;\n }\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,61 @@
1
+ // src/utils/environment.ts
2
+ function detectEnvironment() {
3
+ if (typeof process !== "undefined" && process.versions && process.versions.node) {
4
+ return "node";
5
+ }
6
+ if (typeof window !== "undefined" && typeof document !== "undefined") {
7
+ return "browser";
8
+ }
9
+ if (typeof self !== "undefined" && typeof self.importScripts === "function") {
10
+ return "browser";
11
+ }
12
+ return "unknown";
13
+ }
14
+ function isNode() {
15
+ return detectEnvironment() === "node";
16
+ }
17
+ function isBrowser() {
18
+ return detectEnvironment() === "browser";
19
+ }
20
+ async function isNodeModuleAvailable(moduleName) {
21
+ if (!isNode()) {
22
+ return false;
23
+ }
24
+ try {
25
+ await import(
26
+ /* @vite-ignore */
27
+ moduleName
28
+ );
29
+ return true;
30
+ } catch {
31
+ return false;
32
+ }
33
+ }
34
+ var features = {
35
+ get hasWebWorkers() {
36
+ return isBrowser() && typeof Worker !== "undefined";
37
+ },
38
+ get hasFileSystem() {
39
+ return isNode();
40
+ },
41
+ get hasWebAssembly() {
42
+ return typeof WebAssembly !== "undefined";
43
+ },
44
+ async hasBetterSqlite3() {
45
+ return await isNodeModuleAvailable("better-sqlite3");
46
+ }
47
+ };
48
+ var constants = {
49
+ DEFAULT_NODE_SQLITE_PATH: ":memory:",
50
+ DEFAULT_BROWSER_WASM_PATH: "/sql-wasm.wasm"
51
+ };
52
+
53
+ export {
54
+ detectEnvironment,
55
+ isNode,
56
+ isBrowser,
57
+ isNodeModuleAvailable,
58
+ features,
59
+ constants
60
+ };
61
+ //# sourceMappingURL=chunk-GO3APTPX.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils/environment.ts"],"sourcesContent":["/**\n * Runtime environment detection utilities\n */\n\nexport type RuntimeEnvironment = \"browser\" | \"node\" | \"unknown\";\n\n/**\n * Detects the current runtime environment\n */\nexport function detectEnvironment(): RuntimeEnvironment {\n // Check for Node.js environment\n if (\n typeof process !== \"undefined\" &&\n process.versions &&\n process.versions.node\n ) {\n return \"node\";\n }\n\n // Check for browser environment\n if (typeof window !== \"undefined\" && typeof document !== \"undefined\") {\n return \"browser\";\n }\n\n // Check for Web Worker environment\n if (\n typeof self !== \"undefined\" &&\n typeof (self as any).importScripts === \"function\"\n ) {\n return \"browser\";\n }\n\n return \"unknown\";\n}\n\n/**\n * Checks if currently running in Node.js\n */\nexport function isNode(): boolean {\n return detectEnvironment() === \"node\";\n}\n\n/**\n * Checks if currently running in browser\n */\nexport function isBrowser(): boolean {\n return detectEnvironment() === \"browser\";\n}\n\n/**\n * Checks if a Node.js module is available\n */\nexport async function isNodeModuleAvailable(\n moduleName: string\n): Promise<boolean> {\n if (!isNode()) {\n return false;\n }\n\n try {\n // @ts-ignore\n await import(/* @vite-ignore */ moduleName);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Environment-specific feature detection\n */\nexport const features = {\n get hasWebWorkers(): boolean {\n return isBrowser() && typeof Worker !== \"undefined\";\n },\n\n get hasFileSystem(): boolean {\n return isNode();\n },\n\n get hasWebAssembly(): boolean {\n return typeof WebAssembly !== \"undefined\";\n },\n\n async hasBetterSqlite3(): Promise<boolean> {\n return await isNodeModuleAvailable(\"better-sqlite3\");\n },\n};\n\n/**\n * Environment-specific constants\n */\nexport const constants = {\n DEFAULT_NODE_SQLITE_PATH: \":memory:\",\n DEFAULT_BROWSER_WASM_PATH: \"/sql-wasm.wasm\",\n};\n"],"mappings":";AASO,SAAS,oBAAwC;AAEtD,MACE,OAAO,YAAY,eACnB,QAAQ,YACR,QAAQ,SAAS,MACjB;AACA,WAAO;AAAA,EACT;AAGA,MAAI,OAAO,WAAW,eAAe,OAAO,aAAa,aAAa;AACpE,WAAO;AAAA,EACT;AAGA,MACE,OAAO,SAAS,eAChB,OAAQ,KAAa,kBAAkB,YACvC;AACA,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAKO,SAAS,SAAkB;AAChC,SAAO,kBAAkB,MAAM;AACjC;AAKO,SAAS,YAAqB;AACnC,SAAO,kBAAkB,MAAM;AACjC;AAKA,eAAsB,sBACpB,YACkB;AAClB,MAAI,CAAC,OAAO,GAAG;AACb,WAAO;AAAA,EACT;AAEA,MAAI;AAEF,UAAM;AAAA;AAAA,MAA0B;AAAA;AAChC,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAKO,IAAM,WAAW;AAAA,EACtB,IAAI,gBAAyB;AAC3B,WAAO,UAAU,KAAK,OAAO,WAAW;AAAA,EAC1C;AAAA,EAEA,IAAI,gBAAyB;AAC3B,WAAO,OAAO;AAAA,EAChB;AAAA,EAEA,IAAI,iBAA0B;AAC5B,WAAO,OAAO,gBAAgB;AAAA,EAChC;AAAA,EAEA,MAAM,mBAAqC;AACzC,WAAO,MAAM,sBAAsB,gBAAgB;AAAA,EACrD;AACF;AAKO,IAAM,YAAY;AAAA,EACvB,0BAA0B;AAAA,EAC1B,2BAA2B;AAC7B;","names":[]}