@rozenite/sqlite-plugin 2.2.0 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/devtools/assets/{panel-B2O8mY15.js → panel-CLyprPq_.js} +41 -41
  3. package/dist/devtools/panel.html +1 -1
  4. package/dist/react-native/cjs/package.json +3 -0
  5. package/dist/react-native/cjs/react-native.js +37 -0
  6. package/dist/react-native/cjs/src/react-native/adapters/expo-sqlite.js +121 -0
  7. package/dist/react-native/cjs/src/react-native/adapters/generic.js +33 -0
  8. package/dist/react-native/cjs/src/react-native/adapters/index.js +7 -0
  9. package/dist/react-native/cjs/src/react-native/sqlite-view.js +11 -0
  10. package/dist/react-native/cjs/src/react-native/useRozeniteSqlitePlugin.js +178 -0
  11. package/dist/react-native/cjs/src/react-native/useSqliteAgentTools.js +115 -0
  12. package/dist/react-native/cjs/src/shared/bridge-values.js +126 -0
  13. package/dist/react-native/cjs/src/shared/protocol.js +4 -0
  14. package/dist/react-native/cjs/src/shared/sql.js +339 -0
  15. package/dist/react-native/cjs/src/shared/types.js +2 -0
  16. package/dist/react-native/package.json +3 -0
  17. package/dist/react-native/react-native.d.ts +15 -0
  18. package/dist/react-native/react-native.js +43 -0
  19. package/dist/react-native/src/react-native/adapters/expo-sqlite.d.ts +28 -0
  20. package/dist/react-native/src/react-native/adapters/expo-sqlite.js +117 -0
  21. package/dist/react-native/src/react-native/adapters/generic.d.ts +19 -0
  22. package/dist/react-native/src/react-native/adapters/generic.js +29 -0
  23. package/dist/react-native/src/react-native/adapters/index.d.ts +2 -0
  24. package/dist/react-native/src/react-native/adapters/index.js +2 -0
  25. package/dist/react-native/src/react-native/sqlite-view.d.ts +5 -0
  26. package/dist/react-native/src/react-native/sqlite-view.js +7 -0
  27. package/dist/react-native/src/react-native/useRozeniteSqlitePlugin.d.ts +6 -0
  28. package/dist/react-native/src/react-native/useRozeniteSqlitePlugin.js +174 -0
  29. package/dist/react-native/src/react-native/useSqliteAgentTools.d.ts +2 -0
  30. package/dist/react-native/src/react-native/useSqliteAgentTools.js +111 -0
  31. package/dist/react-native/src/shared/bridge-values.d.ts +3 -0
  32. package/dist/react-native/src/shared/bridge-values.js +120 -0
  33. package/dist/react-native/src/shared/protocol.d.ts +38 -0
  34. package/dist/react-native/src/shared/protocol.js +1 -0
  35. package/dist/react-native/src/shared/sql.d.ts +14 -0
  36. package/dist/react-native/src/shared/sql.js +328 -0
  37. package/dist/react-native/src/shared/types.d.ts +56 -0
  38. package/dist/react-native/src/shared/types.js +1 -0
  39. package/dist/rozenite.json +1 -1
  40. package/package.json +12 -11
  41. package/react-native.ts +8 -1
  42. package/rozenite.config.ts +1 -0
  43. package/src/__tests__/release-bundle.test.ts +32 -0
  44. package/dist/react-native/chunks/bridge-values.require.cjs +0 -2
  45. package/dist/react-native/chunks/bridge-values.require.js +0 -61
  46. package/dist/react-native/chunks/index.require.cjs +0 -1
  47. package/dist/react-native/chunks/index.require.js +0 -107
  48. package/dist/react-native/chunks/sql.require.cjs +0 -4
  49. package/dist/react-native/chunks/sql.require.js +0 -219
  50. package/dist/react-native/chunks/useRozeniteSqlitePlugin.require.cjs +0 -1
  51. package/dist/react-native/chunks/useRozeniteSqlitePlugin.require.js +0 -283
  52. package/dist/react-native/index.cjs +0 -1
  53. package/dist/react-native/index.d.ts +0 -208
  54. package/dist/react-native/index.js +0 -22
@@ -22,7 +22,7 @@
22
22
  <script>
23
23
  var __ROZENITE_PANEL__ = true;
24
24
  </script>
25
- <script type="module" crossorigin src="../devtools/assets/panel-B2O8mY15.js"></script>
25
+ <script type="module" crossorigin src="../devtools/assets/panel-CLyprPq_.js"></script>
26
26
  <link rel="stylesheet" crossorigin href="../devtools/assets/panel-BarPLQ4-.css">
27
27
  </head>
28
28
  <body>
@@ -0,0 +1,3 @@
1
+ {
2
+ "type": "commonjs"
3
+ }
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.formatSqliteError = exports.decodeSqliteBridgeValue = exports.statementReturnsRows = exports.splitSqlStatements = exports.normalizeSingleStatementSql = exports.classifySqlStatement = exports.useRozeniteSqlitePlugin = exports.createExpoSqliteAdapter = exports.createSqliteAdapter = void 0;
4
+ const isDev = process.env.NODE_ENV !== 'production';
5
+ const isWeb = typeof window !== 'undefined' && window.navigator.product !== 'ReactNative';
6
+ const isServer = typeof window === 'undefined' && typeof lynx === 'undefined';
7
+ if (isDev && !isWeb && !isServer) {
8
+ exports.createSqliteAdapter = require('./src/react-native/adapters').createSqliteAdapter;
9
+ exports.createExpoSqliteAdapter = require('./src/react-native/adapters').createExpoSqliteAdapter;
10
+ exports.useRozeniteSqlitePlugin =
11
+ require('./src/react-native/useRozeniteSqlitePlugin').useRozeniteSqlitePlugin;
12
+ exports.classifySqlStatement = require('./src/shared/sql').classifySqlStatement;
13
+ exports.normalizeSingleStatementSql = require('./src/shared/sql').normalizeSingleStatementSql;
14
+ exports.splitSqlStatements = require('./src/shared/sql').splitSqlStatements;
15
+ exports.statementReturnsRows = require('./src/shared/sql').statementReturnsRows;
16
+ exports.decodeSqliteBridgeValue = require('./src/shared/bridge-values').decodeSqliteBridgeValue;
17
+ exports.formatSqliteError = require('./src/shared/bridge-values').formatSqliteError;
18
+ }
19
+ else {
20
+ exports.createSqliteAdapter = (options) => ({
21
+ id: options.adapterId ?? 'sqlite',
22
+ name: options.adapterName ?? 'SQLite',
23
+ databases: [],
24
+ });
25
+ exports.createExpoSqliteAdapter = (options) => ({
26
+ id: options.adapterId ?? 'expo-sqlite',
27
+ name: options.adapterName ?? 'Expo SQLite',
28
+ databases: [],
29
+ });
30
+ exports.useRozeniteSqlitePlugin = () => null;
31
+ exports.classifySqlStatement = () => 'other';
32
+ exports.normalizeSingleStatementSql = (sql) => sql;
33
+ exports.splitSqlStatements = () => [];
34
+ exports.statementReturnsRows = (_type) => false;
35
+ exports.decodeSqliteBridgeValue = (value) => value;
36
+ exports.formatSqliteError = () => 'Unknown SQLite error.';
37
+ }
@@ -0,0 +1,121 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createExpoSqliteAdapter = void 0;
4
+ const sql_1 = require("../../shared/sql");
5
+ const bridge_values_1 = require("../../shared/bridge-values");
6
+ const generic_1 = require("./generic");
7
+ const now = () => typeof performance !== 'undefined' && typeof performance.now === 'function'
8
+ ? performance.now()
9
+ : Date.now();
10
+ const safeError = (error) => (0, bridge_values_1.formatSqliteError)(error);
11
+ const createExecuteStatementsError = (message, options = {}) => Object.assign(new Error(message), options);
12
+ const toBridgeSafeValue = (value) => {
13
+ if (value == null ||
14
+ typeof value === 'string' ||
15
+ typeof value === 'number' ||
16
+ typeof value === 'boolean') {
17
+ return value;
18
+ }
19
+ if (value instanceof Uint8Array) {
20
+ return Array.from(value);
21
+ }
22
+ if (value instanceof ArrayBuffer) {
23
+ return Array.from(new Uint8Array(value));
24
+ }
25
+ if (Array.isArray(value)) {
26
+ return value.map(toBridgeSafeValue);
27
+ }
28
+ if (typeof value === 'object') {
29
+ return Object.fromEntries(Object.entries(value).map(([key, nestedValue]) => [key, toBridgeSafeValue(nestedValue)]));
30
+ }
31
+ return String(value);
32
+ };
33
+ const normalizeRows = (rows) => rows.map((row) => Object.fromEntries(Object.entries(row).map(([key, value]) => [key, toBridgeSafeValue(value)])));
34
+ const executeSingleStatement = async (database, { sql, params }) => {
35
+ const normalizedSql = (0, sql_1.normalizeSingleStatementSql)(sql);
36
+ const statementType = (0, sql_1.classifySqlStatement)(normalizedSql);
37
+ const startedAt = now();
38
+ const decodedParams = params === undefined ? undefined : (0, bridge_values_1.decodeSqliteBridgeValue)(params);
39
+ if ((0, sql_1.statementReturnsRows)(statementType)) {
40
+ const rows = normalizeRows(decodedParams === undefined
41
+ ? await database.getAllAsync(normalizedSql)
42
+ : await database.getAllAsync(normalizedSql, decodedParams));
43
+ const durationMs = now() - startedAt;
44
+ return {
45
+ rows,
46
+ columns: Object.keys(rows[0] ?? {}),
47
+ metadata: {
48
+ statementType,
49
+ rowCount: rows.length,
50
+ changes: null,
51
+ lastInsertRowId: null,
52
+ durationMs,
53
+ },
54
+ };
55
+ }
56
+ const result = decodedParams === undefined
57
+ ? await database.runAsync(normalizedSql)
58
+ : await database.runAsync(normalizedSql, decodedParams);
59
+ const durationMs = now() - startedAt;
60
+ return {
61
+ rows: [],
62
+ columns: [],
63
+ metadata: {
64
+ statementType,
65
+ rowCount: 0,
66
+ changes: typeof result.changes === 'number' ? result.changes : null,
67
+ lastInsertRowId: typeof result.lastInsertRowId === 'number' ? result.lastInsertRowId : null,
68
+ durationMs,
69
+ },
70
+ };
71
+ };
72
+ const createExpoExecuteStatementsRunner = (database) => {
73
+ return async (statements) => {
74
+ const results = [];
75
+ for (let index = 0; index < statements.length; index += 1) {
76
+ try {
77
+ results.push(await executeSingleStatement(database, statements[index]));
78
+ }
79
+ catch (error) {
80
+ throw createExecuteStatementsError(safeError(error), {
81
+ completedResults: results,
82
+ failedStatementIndex: index,
83
+ cause: error,
84
+ });
85
+ }
86
+ }
87
+ return results;
88
+ };
89
+ };
90
+ const resolveDatabaseConfig = (config) => ('database' in config ? config : { database: config });
91
+ const createExpoSqliteAdapter = (options) => {
92
+ const genericOptions = 'databases' in options
93
+ ? {
94
+ adapterId: options.adapterId ?? 'expo-sqlite',
95
+ adapterName: options.adapterName ?? 'Expo SQLite',
96
+ databases: Object.fromEntries(Object.entries(options.databases).map(([key, config]) => {
97
+ const resolved = resolveDatabaseConfig(config);
98
+ return [
99
+ key,
100
+ {
101
+ name: resolved.name ?? key,
102
+ executeStatements: createExpoExecuteStatementsRunner(resolved.database),
103
+ },
104
+ ];
105
+ })),
106
+ }
107
+ : {
108
+ adapterId: options.adapterId ?? 'expo-sqlite',
109
+ adapterName: options.adapterName ?? 'Expo SQLite',
110
+ databaseName: options.databaseName,
111
+ database: (() => {
112
+ const resolved = resolveDatabaseConfig(options.database);
113
+ return {
114
+ name: resolved.name ?? options.databaseName,
115
+ executeStatements: createExpoExecuteStatementsRunner(resolved.database),
116
+ };
117
+ })(),
118
+ };
119
+ return (0, generic_1.createSqliteAdapter)(genericOptions);
120
+ };
121
+ exports.createExpoSqliteAdapter = createExpoSqliteAdapter;
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createSqliteAdapter = void 0;
4
+ const slugify = (value) => value
5
+ .trim()
6
+ .toLowerCase()
7
+ .replace(/[^a-z0-9]+/g, '-')
8
+ .replace(/^-+|-+$/g, '') || 'database';
9
+ const createDatabaseId = (adapterId, seed, index) => `${adapterId}__${slugify(seed)}__${index.toString(36)}`;
10
+ const resolveDatabaseConfig = (config) => typeof config === 'function' ? { executeStatements: config } : config;
11
+ const toDatabaseNode = (adapterId, databaseKey, config, index, fallbackName) => {
12
+ const resolved = resolveDatabaseConfig(config);
13
+ const name = resolved.name ?? fallbackName ?? databaseKey;
14
+ return {
15
+ id: createDatabaseId(adapterId, `${databaseKey}-${name}`, index),
16
+ name,
17
+ executeStatements: resolved.executeStatements,
18
+ };
19
+ };
20
+ const createSqliteAdapter = (options) => {
21
+ const { adapterId = 'sqlite', adapterName = 'SQLite' } = options;
22
+ const databases = 'databases' in options
23
+ ? Object.entries(options.databases).map(([key, config], index) => toDatabaseNode(adapterId, key, config, index))
24
+ : [
25
+ toDatabaseNode(adapterId, options.databaseName ?? 'default', options.database, 0, options.databaseName ?? 'Default Database'),
26
+ ];
27
+ return {
28
+ id: adapterId,
29
+ name: adapterName,
30
+ databases,
31
+ };
32
+ };
33
+ exports.createSqliteAdapter = createSqliteAdapter;
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createExpoSqliteAdapter = exports.createSqliteAdapter = void 0;
4
+ var generic_1 = require("./generic");
5
+ Object.defineProperty(exports, "createSqliteAdapter", { enumerable: true, get: function () { return generic_1.createSqliteAdapter; } });
6
+ var expo_sqlite_1 = require("./expo-sqlite");
7
+ Object.defineProperty(exports, "createExpoSqliteAdapter", { enumerable: true, get: function () { return expo_sqlite_1.createExpoSqliteAdapter; } });
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createSqliteDatabaseViews = void 0;
4
+ const createSqliteDatabaseViews = (adapters) => adapters.flatMap((adapter) => adapter.databases.map((database) => ({
5
+ id: database.id,
6
+ name: database.name,
7
+ adapterId: adapter.id,
8
+ adapterName: adapter.name,
9
+ executeStatements: database.executeStatements,
10
+ })));
11
+ exports.createSqliteDatabaseViews = createSqliteDatabaseViews;
@@ -0,0 +1,178 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.useRozeniteSqlitePlugin = void 0;
4
+ const plugin_bridge_1 = require("@rozenite/plugin-bridge");
5
+ const react_1 = require("react");
6
+ const bridge_values_1 = require("../shared/bridge-values");
7
+ const protocol_1 = require("../shared/protocol");
8
+ const sql_1 = require("../shared/sql");
9
+ const sqlite_view_1 = require("./sqlite-view");
10
+ const useSqliteAgentTools_1 = require("./useSqliteAgentTools");
11
+ const safeError = (error) => (0, bridge_values_1.formatSqliteError)(error);
12
+ const isExecuteStatementsError = (error) => error instanceof Error && ('completedResults' in error || 'failedStatementIndex' in error);
13
+ const useRozeniteSqlitePlugin = ({ adapters }) => {
14
+ const views = (0, react_1.useMemo)(() => (0, sqlite_view_1.createSqliteDatabaseViews)(adapters), [adapters]);
15
+ (0, useSqliteAgentTools_1.useSqliteAgentTools)(views);
16
+ const client = (0, plugin_bridge_1.useRozeniteDevToolsClient)({
17
+ pluginId: protocol_1.PLUGIN_ID,
18
+ });
19
+ const subscriptionsRef = (0, react_1.useRef)([]);
20
+ const databaseQueuesRef = (0, react_1.useRef)(new Map());
21
+ (0, react_1.useEffect)(() => {
22
+ if (!client) {
23
+ return;
24
+ }
25
+ const enqueueDatabaseTask = async (databaseId, task) => {
26
+ const queue = databaseQueuesRef.current.get(databaseId) ?? Promise.resolve();
27
+ const next = queue.catch(() => undefined).then(task);
28
+ databaseQueuesRef.current.set(databaseId, next.then(() => undefined, () => undefined));
29
+ return next;
30
+ };
31
+ const resolveDatabase = (databaseId) => {
32
+ const database = views.find((view) => view.id === databaseId);
33
+ if (!database) {
34
+ throw new Error(`Unknown database "${databaseId}".`);
35
+ }
36
+ return database;
37
+ };
38
+ const executeStatements = async (databaseId, statements) => {
39
+ const database = resolveDatabase(databaseId);
40
+ const normalizedStatements = statements.map(({ sql, params }) => ({
41
+ sql: (0, sql_1.normalizeSingleStatementSql)(sql),
42
+ params,
43
+ }));
44
+ const results = await database.executeStatements(normalizedStatements);
45
+ if (results.length !== normalizedStatements.length) {
46
+ throw new Error(`Expected ${normalizedStatements.length} statement result(s), received ${results.length}.`);
47
+ }
48
+ return {
49
+ inputs: normalizedStatements,
50
+ results,
51
+ };
52
+ };
53
+ const executeSingleQuery = async (databaseId, sql, params) => {
54
+ const execution = await executeStatements(databaseId, [
55
+ {
56
+ sql,
57
+ params,
58
+ },
59
+ ]);
60
+ const result = execution.results[0];
61
+ if (!result) {
62
+ throw new Error('The query completed without a result payload.');
63
+ }
64
+ return result;
65
+ };
66
+ client.send('sqlite:ready', { timestamp: Date.now() });
67
+ subscriptionsRef.current.push(client.onMessage('sqlite:list-databases', ({ requestId }) => {
68
+ client.send('sqlite:list-databases:result', {
69
+ requestId,
70
+ databases: views.map(({ id, name, adapterId, adapterName }) => ({
71
+ id,
72
+ name,
73
+ adapterId,
74
+ adapterName,
75
+ })),
76
+ });
77
+ }));
78
+ subscriptionsRef.current.push(client.onMessage('sqlite:query', async ({ requestId, databaseId, sql, params }) => {
79
+ try {
80
+ const result = await enqueueDatabaseTask(databaseId, () => executeSingleQuery(databaseId, sql, params));
81
+ client.send('sqlite:query:result', {
82
+ requestId,
83
+ databaseId,
84
+ result,
85
+ });
86
+ }
87
+ catch (error) {
88
+ client.send('sqlite:query:result', {
89
+ requestId,
90
+ databaseId,
91
+ error: safeError(error),
92
+ });
93
+ }
94
+ }));
95
+ subscriptionsRef.current.push(client.onMessage('sqlite:execute-script', async ({ requestId, databaseId, sql }) => {
96
+ try {
97
+ const result = await enqueueDatabaseTask(databaseId, async () => {
98
+ const statementSegments = (0, sql_1.splitSqlStatements)(sql);
99
+ if (statementSegments.length === 0) {
100
+ throw new Error('Query cannot be empty.');
101
+ }
102
+ const statementInputs = statementSegments.map((statement) => ({
103
+ sql: statement.text,
104
+ }));
105
+ try {
106
+ const execution = await executeStatements(databaseId, statementInputs);
107
+ return {
108
+ statements: statementSegments.map((statement, index) => ({
109
+ index,
110
+ start: statement.start,
111
+ end: statement.end,
112
+ input: execution.inputs[index],
113
+ execution: {
114
+ input: execution.inputs[index],
115
+ result: execution.results[index],
116
+ },
117
+ })),
118
+ totalStatementCount: statementSegments.length,
119
+ failedStatementIndex: null,
120
+ };
121
+ }
122
+ catch (error) {
123
+ if (!isExecuteStatementsError(error)) {
124
+ throw error;
125
+ }
126
+ const failedStatementIndex = Math.max(0, Math.min(typeof error.failedStatementIndex === 'number'
127
+ ? error.failedStatementIndex
128
+ : (error.completedResults?.length ?? 0), statementSegments.length - 1));
129
+ const completedResults = (error.completedResults ?? []).slice(0, failedStatementIndex);
130
+ const completedStatements = completedResults.map((queryResult, index) => ({
131
+ index,
132
+ start: statementSegments[index].start,
133
+ end: statementSegments[index].end,
134
+ input: statementInputs[index],
135
+ execution: {
136
+ input: statementInputs[index],
137
+ result: queryResult,
138
+ },
139
+ }));
140
+ return {
141
+ statements: [
142
+ ...completedStatements,
143
+ {
144
+ index: failedStatementIndex,
145
+ start: statementSegments[failedStatementIndex].start,
146
+ end: statementSegments[failedStatementIndex].end,
147
+ input: statementInputs[failedStatementIndex],
148
+ error: safeError(error),
149
+ },
150
+ ],
151
+ totalStatementCount: statementSegments.length,
152
+ failedStatementIndex,
153
+ };
154
+ }
155
+ });
156
+ client.send('sqlite:execute-script:result', {
157
+ requestId,
158
+ databaseId,
159
+ result,
160
+ });
161
+ }
162
+ catch (error) {
163
+ client.send('sqlite:execute-script:result', {
164
+ requestId,
165
+ databaseId,
166
+ error: safeError(error),
167
+ });
168
+ }
169
+ }));
170
+ return () => {
171
+ subscriptionsRef.current.forEach((subscription) => subscription.remove());
172
+ subscriptionsRef.current = [];
173
+ databaseQueuesRef.current.clear();
174
+ };
175
+ }, [client, views]);
176
+ return client;
177
+ };
178
+ exports.useRozeniteSqlitePlugin = useRozeniteSqlitePlugin;
@@ -0,0 +1,115 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.useSqliteAgentTools = void 0;
4
+ const react_1 = require("react");
5
+ const agent_bridge_1 = require("@rozenite/agent-bridge");
6
+ const bridge_values_1 = require("../shared/bridge-values");
7
+ const sql_1 = require("../shared/sql");
8
+ const pluginId = '@rozenite/sqlite-plugin';
9
+ const listDatabasesTool = {
10
+ name: 'list-databases',
11
+ description: 'List all registered SQLite databases.',
12
+ inputSchema: { type: 'object', properties: {} },
13
+ };
14
+ const executeSqlTool = {
15
+ name: 'execute-sql',
16
+ description: 'Execute one or more SQL statements against a database. Supports SELECT, INSERT, UPDATE, DELETE, PRAGMA, DDL, and multi-statement scripts. Returns per-statement results including rows, columns, and metadata. Statements are executed in order and stop on first error.',
17
+ inputSchema: {
18
+ type: 'object',
19
+ properties: {
20
+ databaseId: {
21
+ type: 'string',
22
+ description: 'Database ID from list-databases.',
23
+ },
24
+ sql: {
25
+ type: 'string',
26
+ description: 'SQL to execute. May contain multiple semicolon-separated statements.',
27
+ },
28
+ },
29
+ required: ['databaseId', 'sql'],
30
+ },
31
+ };
32
+ const isExecuteStatementsError = (error) => error instanceof Error && ('completedResults' in error || 'failedStatementIndex' in error);
33
+ const useSqliteAgentTools = (views) => {
34
+ const resolveDatabase = (0, react_1.useCallback)((databaseId) => {
35
+ const database = views.find((view) => view.id === databaseId);
36
+ if (!database) {
37
+ const available = views.map((v) => v.id).join(', ');
38
+ throw new Error(`Unknown databaseId "${databaseId}". Available: ${available || '(none)'}`);
39
+ }
40
+ return database;
41
+ }, [views]);
42
+ (0, agent_bridge_1.useRozenitePluginAgentTool)({
43
+ pluginId,
44
+ tool: listDatabasesTool,
45
+ handler: () => ({
46
+ databases: views.map(({ id, name, adapterId, adapterName }) => ({
47
+ id,
48
+ name,
49
+ adapterId,
50
+ adapterName,
51
+ })),
52
+ }),
53
+ });
54
+ (0, agent_bridge_1.useRozenitePluginAgentTool)({
55
+ pluginId,
56
+ tool: executeSqlTool,
57
+ handler: async ({ databaseId, sql }) => {
58
+ const database = resolveDatabase(databaseId);
59
+ const statementSegments = (0, sql_1.splitSqlStatements)(sql);
60
+ if (statementSegments.length === 0) {
61
+ throw new Error('SQL cannot be empty.');
62
+ }
63
+ const statementInputs = statementSegments.map((segment) => ({
64
+ sql: (0, sql_1.normalizeSingleStatementSql)(segment.text),
65
+ }));
66
+ try {
67
+ const results = await database.executeStatements(statementInputs);
68
+ return {
69
+ databaseId,
70
+ totalStatementCount: statementSegments.length,
71
+ failedStatementIndex: null,
72
+ statements: statementSegments.map((_, index) => {
73
+ const result = results[index];
74
+ return {
75
+ index,
76
+ sql: statementInputs[index].sql,
77
+ rows: result.rows,
78
+ columns: result.columns,
79
+ metadata: result.metadata,
80
+ };
81
+ }),
82
+ };
83
+ }
84
+ catch (error) {
85
+ if (!isExecuteStatementsError(error)) {
86
+ throw new Error((0, bridge_values_1.formatSqliteError)(error));
87
+ }
88
+ const failedStatementIndex = Math.max(0, Math.min(typeof error.failedStatementIndex === 'number'
89
+ ? error.failedStatementIndex
90
+ : (error.completedResults?.length ?? 0), statementSegments.length - 1));
91
+ const completedResults = (error.completedResults ?? []).slice(0, failedStatementIndex);
92
+ return {
93
+ databaseId,
94
+ totalStatementCount: statementSegments.length,
95
+ failedStatementIndex,
96
+ statements: [
97
+ ...completedResults.map((result, index) => ({
98
+ index,
99
+ sql: statementInputs[index].sql,
100
+ rows: result.rows,
101
+ columns: result.columns,
102
+ metadata: result.metadata,
103
+ })),
104
+ {
105
+ index: failedStatementIndex,
106
+ sql: statementInputs[failedStatementIndex].sql,
107
+ error: (0, bridge_values_1.formatSqliteError)(error),
108
+ },
109
+ ],
110
+ };
111
+ }
112
+ },
113
+ });
114
+ };
115
+ exports.useSqliteAgentTools = useSqliteAgentTools;
@@ -0,0 +1,126 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.formatSqliteError = exports.decodeSqliteBridgeValue = exports.encodeSqliteBridgeValue = void 0;
4
+ const SQLITE_BRIDGE_BINARY_TYPE = '__rozeniteSqliteBinary';
5
+ const isRecord = (value) => !!value && typeof value === 'object';
6
+ const isEncodedBinaryValue = (value) => isRecord(value) &&
7
+ value[SQLITE_BRIDGE_BINARY_TYPE] === true &&
8
+ Array.isArray(value.data) &&
9
+ value.data.every((item) => typeof item === 'number');
10
+ const encodeSqliteBridgeValue = (value) => {
11
+ if (value == null ||
12
+ typeof value === 'string' ||
13
+ typeof value === 'number' ||
14
+ typeof value === 'boolean') {
15
+ return value;
16
+ }
17
+ if (value instanceof Uint8Array) {
18
+ return {
19
+ [SQLITE_BRIDGE_BINARY_TYPE]: true,
20
+ data: Array.from(value),
21
+ };
22
+ }
23
+ if (value instanceof ArrayBuffer) {
24
+ return {
25
+ [SQLITE_BRIDGE_BINARY_TYPE]: true,
26
+ data: Array.from(new Uint8Array(value)),
27
+ };
28
+ }
29
+ if (Array.isArray(value)) {
30
+ return value.map(exports.encodeSqliteBridgeValue);
31
+ }
32
+ if (isRecord(value)) {
33
+ return Object.fromEntries(Object.entries(value).map(([key, nestedValue]) => [
34
+ key,
35
+ (0, exports.encodeSqliteBridgeValue)(nestedValue),
36
+ ]));
37
+ }
38
+ return String(value);
39
+ };
40
+ exports.encodeSqliteBridgeValue = encodeSqliteBridgeValue;
41
+ const decodeSqliteBridgeValue = (value) => {
42
+ if (value == null ||
43
+ typeof value === 'string' ||
44
+ typeof value === 'number' ||
45
+ typeof value === 'boolean') {
46
+ return value;
47
+ }
48
+ if (isEncodedBinaryValue(value)) {
49
+ return new Uint8Array(value.data);
50
+ }
51
+ if (Array.isArray(value)) {
52
+ return value.map(exports.decodeSqliteBridgeValue);
53
+ }
54
+ if (isRecord(value)) {
55
+ return Object.fromEntries(Object.entries(value).map(([key, nestedValue]) => [
56
+ key,
57
+ (0, exports.decodeSqliteBridgeValue)(nestedValue),
58
+ ]));
59
+ }
60
+ return value;
61
+ };
62
+ exports.decodeSqliteBridgeValue = decodeSqliteBridgeValue;
63
+ const getStringField = (value, key) => {
64
+ if (!isRecord(value)) {
65
+ return null;
66
+ }
67
+ const field = value[key];
68
+ if (typeof field !== 'string') {
69
+ return null;
70
+ }
71
+ const trimmed = field.trim();
72
+ return trimmed ? trimmed : null;
73
+ };
74
+ const stringifyFallback = (value) => {
75
+ try {
76
+ return JSON.stringify(value);
77
+ }
78
+ catch {
79
+ return String(value);
80
+ }
81
+ };
82
+ const describeError = (error) => {
83
+ if (error instanceof Error) {
84
+ const code = getStringField(error, 'code');
85
+ const reason = getStringField(error, 'reason');
86
+ const message = error.message.trim();
87
+ const detailParts = [message || null, reason].filter((part, index, parts) => !!part && parts.indexOf(part) === index);
88
+ const detail = detailParts.join(' | ') || error.name;
89
+ return code ? `[${code}] ${detail}` : detail;
90
+ }
91
+ if (isRecord(error)) {
92
+ const code = getStringField(error, 'code');
93
+ const message = getStringField(error, 'message');
94
+ const reason = getStringField(error, 'reason');
95
+ const detail = message ?? reason ?? stringifyFallback(error);
96
+ return code ? `[${code}] ${detail}` : detail;
97
+ }
98
+ if (typeof error === 'string') {
99
+ return error.trim() || null;
100
+ }
101
+ if (error == null) {
102
+ return null;
103
+ }
104
+ return stringifyFallback(error);
105
+ };
106
+ const getCause = (error) => {
107
+ if (!isRecord(error)) {
108
+ return undefined;
109
+ }
110
+ return error.cause;
111
+ };
112
+ const formatSqliteError = (error) => {
113
+ const visited = new Set();
114
+ const parts = [];
115
+ let current = error;
116
+ while (current !== undefined && current !== null && !visited.has(current)) {
117
+ visited.add(current);
118
+ const description = describeError(current);
119
+ if (description && !parts.includes(description)) {
120
+ parts.push(description);
121
+ }
122
+ current = getCause(current);
123
+ }
124
+ return parts.join('\nCaused by: ') || 'Unknown SQLite error.';
125
+ };
126
+ exports.formatSqliteError = formatSqliteError;
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PLUGIN_ID = void 0;
4
+ exports.PLUGIN_ID = '@rozenite/sqlite-plugin';