ofplatform-electron 0.1.0-alpha.0 → 0.1.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapters/db/SQLiteAdapter.d.ts +6 -0
- package/dist/adapters/db/SQLiteExecutor.d.ts +0 -1
- package/dist/adapters/db/SQLiteQueryBuilder.d.ts +5 -0
- package/dist/adapters/http/ElectronHttpAdapter.d.ts +32 -0
- package/dist/adapters/http/index.d.ts +2 -1
- package/dist/adapters/socket/ElectronSocketAdapter.d.ts +79 -0
- package/dist/adapters/socket/index.d.ts +2 -1
- package/dist/index.esm.js +2 -2
- package/dist/index.js +2 -2
- package/package.json +6 -5
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
import type { ColumnDefinition, DbAdapter, LiteralValue, QueryOptions, TableSchema } from 'ofcore';
|
|
2
2
|
export interface SQLiteAdapterOptions {
|
|
3
3
|
dbPath: string;
|
|
4
|
+
tableNamePrefix?: string;
|
|
5
|
+
tableNameMapper?: (tableName: string) => string;
|
|
4
6
|
}
|
|
5
7
|
export declare class SQLiteAdapter implements DbAdapter {
|
|
6
8
|
private readonly executor;
|
|
7
9
|
private savepointDepth;
|
|
8
10
|
private readonly schemaMap;
|
|
11
|
+
private readonly tableNamePrefix;
|
|
12
|
+
private tableNameResolver?;
|
|
9
13
|
constructor(options: SQLiteAdapterOptions);
|
|
14
|
+
setTableNameResolver(resolver: (logicalTableName: string) => string): void;
|
|
15
|
+
resolveTableName(tableName: string): string;
|
|
10
16
|
getSchemaVersion(): Promise<number>;
|
|
11
17
|
setSchemaVersion(version: number): Promise<void>;
|
|
12
18
|
addTable(table: TableSchema): Promise<void>;
|
|
@@ -11,7 +11,6 @@ export declare class SQLiteExecutor {
|
|
|
11
11
|
escapeIdentifier(id: string): string;
|
|
12
12
|
mapType(type: string): string;
|
|
13
13
|
parseRow<T>(row: any, columnMap: Record<string, ColumnDefinition>): T;
|
|
14
|
-
denormalizeRow<T = Record<string, unknown>>(row: any, mainAlias?: string): T;
|
|
15
14
|
buildFilter(expr: FilterExpression, mainAlias?: string): import("./SQLiteQueryBuilder").BuiltQuery;
|
|
16
15
|
buildGroupBy(groupBy?: GroupBySpec[], mainAlias?: string): string;
|
|
17
16
|
buildSort(sorts?: SortSpec[], mainAlias?: string): string;
|
|
@@ -2,6 +2,11 @@ import type { FilterExpression, GroupBySpec, LiteralValue, QueryOptions, SortSpe
|
|
|
2
2
|
export interface BuiltQuery {
|
|
3
3
|
sql: string;
|
|
4
4
|
params: any[];
|
|
5
|
+
projectionMap?: Array<{
|
|
6
|
+
key: string;
|
|
7
|
+
alias: string;
|
|
8
|
+
field: string;
|
|
9
|
+
}>;
|
|
5
10
|
}
|
|
6
11
|
export declare class SQLiteQueryBuilder {
|
|
7
12
|
private static escapeIdentifier;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { HttpAdapter, HttpRequest, HttpResponse } from 'ofcore';
|
|
2
|
+
export type ElectronFetchImplementation = (input: string, init?: RequestInit) => Promise<Response>;
|
|
3
|
+
export interface ElectronHttpAdapterOptions {
|
|
4
|
+
/**
|
|
5
|
+
* Override the fetch implementation.
|
|
6
|
+
* Defaults to `globalThis.fetch`, which is available in:
|
|
7
|
+
* - Electron renderer process (Chromium)
|
|
8
|
+
* - Electron main process (Node.js 18+)
|
|
9
|
+
*
|
|
10
|
+
* Useful for unit testing or when a custom agent (e.g. proxy, mTLS) is needed.
|
|
11
|
+
*/
|
|
12
|
+
fetch?: ElectronFetchImplementation;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Electron HTTP adapter backed by the Fetch API.
|
|
16
|
+
*
|
|
17
|
+
* Works in both the renderer and main process of an Electron application.
|
|
18
|
+
* In the renderer the Chromium `fetch` is used; in the main process Node.js
|
|
19
|
+
* 18+ exposes `globalThis.fetch` using the same API surface.
|
|
20
|
+
*
|
|
21
|
+
* Features:
|
|
22
|
+
* - Query parameter serialisation (null/undefined values are omitted)
|
|
23
|
+
* - Automatic `content-type: application/json` for requests with a body
|
|
24
|
+
* - Timeout support via `AbortController`
|
|
25
|
+
* - Response body parsed as JSON when `content-type` indicates JSON,
|
|
26
|
+
* otherwise returns raw text
|
|
27
|
+
*/
|
|
28
|
+
export declare class ElectronHttpAdapter implements HttpAdapter {
|
|
29
|
+
private readonly fetchImpl;
|
|
30
|
+
constructor(options?: ElectronHttpAdapterOptions);
|
|
31
|
+
request<T = unknown>(request: HttpRequest): Promise<HttpResponse<T>>;
|
|
32
|
+
}
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
export
|
|
1
|
+
export * from './ElectronHttpAdapter';
|
|
2
|
+
export declare const OFPLATFORM_ELECTRON_HTTP_ADAPTERS_READY = true;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import type { SocketAdapter, SocketConnectOptions, SocketEventHandler } from 'ofcore';
|
|
2
|
+
export interface ElectronWebSocketMessage {
|
|
3
|
+
event: string;
|
|
4
|
+
payload: unknown;
|
|
5
|
+
}
|
|
6
|
+
export interface ElectronSocketAdapterOptions {
|
|
7
|
+
/**
|
|
8
|
+
* Enable automatic reconnection on unexpected connection loss.
|
|
9
|
+
* @default true
|
|
10
|
+
*/
|
|
11
|
+
reconnect?: boolean;
|
|
12
|
+
/**
|
|
13
|
+
* Maximum number of reconnection attempts before giving up.
|
|
14
|
+
* @default 5
|
|
15
|
+
*/
|
|
16
|
+
maxReconnectAttempts?: number;
|
|
17
|
+
/**
|
|
18
|
+
* Initial delay between reconnection attempts in milliseconds.
|
|
19
|
+
* Grows exponentially on each subsequent attempt.
|
|
20
|
+
* @default 500
|
|
21
|
+
*/
|
|
22
|
+
reconnectDelayMs?: number;
|
|
23
|
+
/**
|
|
24
|
+
* Maximum delay cap for exponential backoff in milliseconds.
|
|
25
|
+
* @default 30000
|
|
26
|
+
*/
|
|
27
|
+
maxReconnectDelayMs?: number;
|
|
28
|
+
/**
|
|
29
|
+
* Override the WebSocket constructor. Defaults to `globalThis.WebSocket`.
|
|
30
|
+
*
|
|
31
|
+
* In the Electron renderer this is the Chromium WebSocket.
|
|
32
|
+
* In the Electron main process this requires Node.js 21+ or a polyfill
|
|
33
|
+
* (e.g. the `ws` package). Pass the constructor explicitly when running
|
|
34
|
+
* in the main process on older runtimes.
|
|
35
|
+
*/
|
|
36
|
+
webSocket?: typeof WebSocket;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Electron WebSocket adapter implementing the `SocketAdapter` contract.
|
|
40
|
+
*
|
|
41
|
+
* ## Message protocol
|
|
42
|
+
* All messages on the wire are JSON-encoded `ElectronWebSocketMessage` objects:
|
|
43
|
+
* ```json
|
|
44
|
+
* { "event": "<event-name>", "payload": <any> }
|
|
45
|
+
* ```
|
|
46
|
+
*
|
|
47
|
+
* ## Headers limitation
|
|
48
|
+
* The WebSocket handshake does not support arbitrary HTTP headers in browser
|
|
49
|
+
* environments. Authentication tokens should be passed via
|
|
50
|
+
* `SocketConnectOptions.query` (e.g. `?token=...`) or via an HTTP-only cookie.
|
|
51
|
+
*
|
|
52
|
+
* ## Reconnection
|
|
53
|
+
* Unexpected disconnections trigger exponential-backoff reconnection unless
|
|
54
|
+
* `options.reconnect` is `false` or the maximum attempt count is reached.
|
|
55
|
+
* All existing subscriptions survive reconnection automatically.
|
|
56
|
+
*/
|
|
57
|
+
export declare class ElectronSocketAdapter implements SocketAdapter {
|
|
58
|
+
private ws;
|
|
59
|
+
private connectionOptions;
|
|
60
|
+
private readonly listeners;
|
|
61
|
+
private reconnectAttempts;
|
|
62
|
+
private reconnectTimeout;
|
|
63
|
+
private intentionalClose;
|
|
64
|
+
private readonly reconnect;
|
|
65
|
+
private readonly maxReconnectAttempts;
|
|
66
|
+
private readonly reconnectDelayMs;
|
|
67
|
+
private readonly maxReconnectDelayMs;
|
|
68
|
+
private readonly WebSocketCtor;
|
|
69
|
+
constructor(options?: ElectronSocketAdapterOptions);
|
|
70
|
+
connect(options: SocketConnectOptions): Promise<void>;
|
|
71
|
+
disconnect(): Promise<void>;
|
|
72
|
+
subscribe(eventName: string, handler: SocketEventHandler): () => void;
|
|
73
|
+
publish(eventName: string, payload: unknown): Promise<void>;
|
|
74
|
+
isConnected(): boolean;
|
|
75
|
+
private openConnection;
|
|
76
|
+
private handleMessage;
|
|
77
|
+
private scheduleReconnect;
|
|
78
|
+
private clearReconnectTimeout;
|
|
79
|
+
}
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
export
|
|
1
|
+
export * from './ElectronSocketAdapter';
|
|
2
|
+
export declare const OFPLATFORM_ELECTRON_SOCKET_ADAPTERS_READY = true;
|
package/dist/index.esm.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import w from"better-sqlite3";var g=class{static escapeIdentifier(e){if(!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(e))throw new Error(`Invalid identifier: "${e}"`);return`"${e}"`}static normalizeValue(e){return e==null?null:typeof e=="boolean"?e?1:0:e instanceof Date?e.toISOString():Array.isArray(e)||typeof e=="object"&&e!==null?JSON.stringify(e):e}static buildValueExpr(e,t){if(e.type==="column"){let r=e.tableAlias||t;return{sql:`${this.escapeIdentifier(r)}.${this.escapeIdentifier(e.field)}`,params:[]}}return{sql:"?",params:[this.normalizeValue(e.value)]}}static buildFieldCondition(e,t){if("field"in e){let n=e.alias||t,s=`${this.escapeIdentifier(n)}.${this.escapeIdentifier(e.field)}`,a=e.operator||"=";if(a==="BETWEEN"){if(!Array.isArray(e.value)||e.value.length!==2)throw new Error("BETWEEN requires value tuple [min,max]");return{sql:`${s} BETWEEN ? AND ?`,params:[this.normalizeValue(e.value[0]),this.normalizeValue(e.value[1])]}}if(a==="IN"||a==="NOT IN"){if(!Array.isArray(e.value))throw new Error(`${a} requires array value`);return e.value.length===0?{sql:a==="IN"?"FALSE":"TRUE",params:[]}:{sql:`${s} ${a} (${e.value.map(()=>"?").join(", ")})`,params:e.value.map(l=>this.normalizeValue(l))}}if(a==="IS NULL"||a==="IS NOT NULL")return{sql:`${s} ${a}`,params:[]};if(a==="LIKE"){let c=("likeMode"in e?e.likeMode:"default")==="case-sensitive"?" COLLATE BINARY":"";return{sql:`${s} LIKE${c} ?`,params:[this.normalizeValue(e.value)]}}return{sql:`${s} ${a} ?`,params:[this.normalizeValue(e.value)]}}let r=this.buildValueExpr(e.left,t);if(e.operator==="IS NULL"||e.operator==="IS NOT NULL")return{sql:`${r.sql} ${e.operator}`,params:r.params};let i=this.buildValueExpr(e.right,t);if(e.operator==="IN"||e.operator==="NOT IN"){if(e.right.type!=="literal"||!Array.isArray(e.right.value))throw new Error(`${e.operator} requires literal array on right side`);return e.right.value.length===0?{sql:e.operator==="IN"?"FALSE":"TRUE",params:[]}:{sql:`${r.sql} ${e.operator} (${e.right.value.map(()=>"?").join(", ")})`,params:[...r.params,...e.right.value.map(n=>this.normalizeValue(n))]}}if(e.operator==="BETWEEN"){if(e.right.type!=="literal"||!Array.isArray(e.right.value)||e.right.value.length!==2)throw new Error("BETWEEN requires literal tuple [min,max] on right side");return{sql:`${r.sql} BETWEEN ? AND ?`,params:[...r.params,this.normalizeValue(e.right.value[0]),this.normalizeValue(e.right.value[1])]}}if(e.operator==="LIKE"){let n=e.likeMode==="case-sensitive"?" COLLATE BINARY":"";return{sql:`${r.sql} LIKE${n} ${i.sql}`,params:[...r.params,...i.params]}}return{sql:`${r.sql} ${e.operator} ${i.sql}`,params:[...r.params,...i.params]}}static buildFilter(e,t="t0"){let r=e.and;if(Array.isArray(r)){let n=r.map(s=>this.buildFilter(s,t));return{sql:n.map(s=>`(${s.sql})`).join(" AND "),params:n.flatMap(s=>s.params)}}let i=e.or;if(Array.isArray(i)){let n=i.map(s=>this.buildFilter(s,t));return{sql:n.map(s=>`(${s.sql})`).join(" OR "),params:n.flatMap(s=>s.params)}}if(e!==null&&typeof e=="object"&&!Array.isArray(e)){if("left"in e||"field"in e)return this.buildFieldCondition(e,t);let n=Object.entries(e);if(n.length===0)return{sql:"TRUE",params:[]};let s=n.map(([a,l])=>({sql:`${`${this.escapeIdentifier(t)}.${this.escapeIdentifier(a)}`} = ?`,params:[this.normalizeValue(l)]}));return{sql:s.map(a=>`(${a.sql})`).join(" AND "),params:s.flatMap(a=>a.params)}}throw new Error(`Invalid filter expression: ${JSON.stringify(e)}`)}static buildGroupBy(e,t="t0"){return!e||!e.length?"":` GROUP BY ${e.map(i=>{let n=typeof i.field=="string"?{tableAlias:t,field:i.field}:i.field;return`${this.escapeIdentifier(n.tableAlias)}.${this.escapeIdentifier(n.field)}`}).join(", ")}`}static buildSort(e,t="t0"){return!e||!e.length?"":e.map(r=>{let i=typeof r.field=="string"?{tableAlias:t,field:r.field}:r.field;return`${this.escapeIdentifier(i.tableAlias)}.${this.escapeIdentifier(i.field)} ${r.direction.toUpperCase()}`}).join(", ")}static buildSelect(e,t){var m;let r=t,i=(t==null?void 0:t.mainAlias)||"t0",n=(t==null?void 0:t.joins)||[],s=[],a=[],l=[];if(t!=null&&t.aggregates&&t.aggregates.length>0)t.groupBy&&t.groupBy.forEach(o=>{let u=typeof o.field=="string"?{tableAlias:i,field:o.field}:o.field;l.push(`${this.escapeIdentifier(u.tableAlias)}.${this.escapeIdentifier(u.field)} AS ${this.escapeIdentifier(`${u.tableAlias}_${u.field}`)}`)}),t.aggregates.forEach(o=>{let u=typeof o.field=="string"?{tableAlias:i,field:o.field}:o.field,f=`${this.escapeIdentifier(u.tableAlias)}.${this.escapeIdentifier(u.field)}`;l.push(`${o.function}(${f}) AS ${this.escapeIdentifier(o.as)}`)});else if(t!=null&&t.fields){let o=0;for(let[u,f]of Object.entries(t.fields))for(let h of f){let d=((m=r==null?void 0:r.resultShape)!=null?m:"flat")==="nested"?`__c${o++}`:`${u}_${h}`;a.push({key:d,alias:u,field:h}),l.push(`${this.escapeIdentifier(u)}.${this.escapeIdentifier(h)} AS ${this.escapeIdentifier(d)}`)}}else l.push(`${this.escapeIdentifier(i)}.*`);let c=`SELECT ${l.join(", ")} FROM ${this.escapeIdentifier(e)} AS ${this.escapeIdentifier(i)}`;if(n.forEach(o=>{let u=(o.type||"inner").toUpperCase();if(u==="RIGHT"||u==="FULL")throw new Error(`SQLite adapter does not support ${u} JOIN`);let f=[];o.conditions.forEach(h=>{let y=this.buildValueExpr(h.left,i),d=this.buildValueExpr(h.right,i);f.push(`${y.sql} ${h.operator} ${d.sql}`),s.push(...y.params,...d.params)}),c+=` ${u} JOIN ${this.escapeIdentifier(o.table)} AS ${this.escapeIdentifier(o.alias)} ON ${f.join(" AND ")}`}),t!=null&&t.filters){let o=this.buildFilter(t.filters,i);o.sql&&o.sql!=="TRUE"&&(c+=` WHERE ${o.sql}`,s.push(...o.params))}if(t!=null&&t.aggregates&&t.aggregates.length>0){if(c+=this.buildGroupBy(t.groupBy,i),t.having){let o=this.buildFilter(t.having,i);o.sql&&o.sql!=="TRUE"&&(c+=` HAVING ${o.sql}`,s.push(...o.params))}return{sql:c,params:s,projectionMap:a.length?a:void 0}}if(c+=this.buildGroupBy(t==null?void 0:t.groupBy,i),t!=null&&t.having){let o=this.buildFilter(t.having,i);o.sql&&o.sql!=="TRUE"&&(c+=` HAVING ${o.sql}`,s.push(...o.params))}if(t!=null&&t.sort&&t.sort.length){let o=this.buildSort(t.sort,i);o&&(c+=` ORDER BY ${o}`)}return(t==null?void 0:t.limit)!==void 0&&(c+=" LIMIT ?",s.push(t.limit)),(t==null?void 0:t.offset)!==void 0&&(c+=" OFFSET ?",s.push(t.offset)),{sql:c,params:s,projectionMap:a.length?a:void 0}}static buildInsert(e,t){let r=Object.keys(t),i=r.map(l=>this.escapeIdentifier(l)).join(", "),n=r.map(()=>"?").join(", "),s=r.map(l=>this.normalizeValue(t[l]));return{sql:`INSERT INTO ${this.escapeIdentifier(e)} (${i}) VALUES (${n})`,params:s}}static buildUpdate(e,t,r){let i=Object.keys(r);if(!i.length)throw new Error("Cannot build UPDATE query with empty updates payload");let n=i.map(l=>`${this.escapeIdentifier(l)} = ?`).join(", "),s=i.map(l=>this.normalizeValue(r[l]));return{sql:`UPDATE ${this.escapeIdentifier(e)} SET ${n} WHERE id = ?`,params:[...s,t]}}static buildDelete(e,t){return{sql:`DELETE FROM ${this.escapeIdentifier(e)} WHERE id = ?`,params:[t]}}};var b=class{constructor(e){this.db=new w(e)}initMetaTable(){this.db.exec(`
|
|
2
2
|
CREATE TABLE IF NOT EXISTS _meta (
|
|
3
3
|
key TEXT PRIMARY KEY,
|
|
4
4
|
value TEXT
|
|
@@ -6,4 +6,4 @@ import A from"better-sqlite3";var c=class{static escapeIdentifier(e){if(!/^[a-zA
|
|
|
6
6
|
CREATE TABLE IF NOT EXISTS schema_version (
|
|
7
7
|
version INTEGER NOT NULL
|
|
8
8
|
);
|
|
9
|
-
`)}run(e,t=[]){return this.db.prepare(e).run(...t)}get(e,t=[]){return this.db.prepare(e).get(...t)}all(e,t=[]){return this.db.prepare(e).all(...t)}transaction(e){return this.db.transaction(e)()}escapeIdentifier(e){if(!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(e))throw new Error(`Invalid identifier: "${e}"`);return`"${e}"`}mapType(e){switch(e){case"string":return"TEXT";case"string[]":return"TEXT";case"number":return"REAL";case"boolean":return"INTEGER";case"json":return"TEXT";case"date":return"TEXT";default:return"TEXT"}}parseRow(e,t){let r={};for(let[n,i]of Object.entries(e!=null?e:{})){let s=t[n],o=i;if(i!=null&&s){if(s.type==="boolean")o=!!i;else if(s.type==="date"&&typeof i=="string"){let a=new Date(i);Number.isNaN(a.getTime())||(o=a)}else if((s.type==="json"||s.type==="string[]")&&typeof i=="string")try{o=JSON.parse(i)}catch(a){}}r[n]=o}return r}denormalizeRow(e,t="t0"){let r={},n={};for(let[i,s]of Object.entries(e!=null?e:{})){if(!i.includes("_")){r[i]=s;continue}let[o,a]=i.split("_",2);if(!o||!a){r[i]=s;continue}o===t?r[a]=s:(n[o]||(n[o]={}),n[o][a]=s)}return{...r,...n}}buildFilter(e,t="t0"){return c.buildFilter(e,t)}buildGroupBy(e,t="t0"){return c.buildGroupBy(e,t)}buildSort(e,t="t0"){return c.buildSort(e,t)}buildSelect(e,t){return c.buildSelect(e,t)}buildInsert(e,t){return c.buildInsert(e,t)}buildUpdate(e,t,r){return c.buildUpdate(e,t,r)}buildDelete(e,t){return c.buildDelete(e,t)}};var E=class{constructor(e){this.savepointDepth=0;this.schemaMap=new Map;this.executor=new d(e.dbPath),this.executor.initMetaTable()}async getSchemaVersion(){let e=this.executor.get("SELECT version FROM schema_version LIMIT 1");return e?e.version:(this.executor.run("INSERT INTO schema_version (version) VALUES (?)",[0]),0)}async setSchemaVersion(e){if(!this.executor.get("SELECT 1 FROM schema_version LIMIT 1")){this.executor.run("INSERT INTO schema_version (version) VALUES (?)",[e]);return}this.executor.run("UPDATE schema_version SET version = ?",[e])}async addTable(e){let t=e.columns.map(r=>{let n=`${this.executor.escapeIdentifier(r.name)} ${this.executor.mapType(r.type)}`;return r.isOptional||(n+=" NOT NULL"),r.name==="id"&&(n+=" PRIMARY KEY"),n}).join(", ");this.executor.run(`CREATE TABLE IF NOT EXISTS ${this.executor.escapeIdentifier(e.name)} (${t})`);for(let r of e.columns){if(!r.isIndexed)continue;let n=`idx_${e.name}_${r.name}`;this.executor.run(`CREATE INDEX IF NOT EXISTS ${this.executor.escapeIdentifier(n)} ON ${this.executor.escapeIdentifier(e.name)}(${this.executor.escapeIdentifier(r.name)})`)}this.schemaMap.set(e.name,e)}async addColumn(e,t){if(this.executor.all(`PRAGMA table_info(${this.executor.escapeIdentifier(e)})`).some(s=>s.name===t.name))return;let n=`ALTER TABLE ${this.executor.escapeIdentifier(e)} ADD COLUMN ${this.executor.escapeIdentifier(t.name)} ${this.executor.mapType(t.type)}`;if(!t.isOptional){let s=t.type==="boolean"?"0":t.type==="number"?"0.0":"''";n+=` DEFAULT ${s} NOT NULL`}if(this.executor.run(n),t.isIndexed){let s=`idx_${e}_${t.name}`;this.executor.run(`CREATE INDEX IF NOT EXISTS ${this.executor.escapeIdentifier(s)} ON ${this.executor.escapeIdentifier(e)}(${this.executor.escapeIdentifier(t.name)})`)}let i=this.schemaMap.get(e);i&&!i.columns.find(s=>s.name===t.name)&&(i.columns.push(t),this.schemaMap.set(e,i))}async get(e,t){var s;let r,n;return typeof t=="string"?n={id:t}:(r=t,n=r.filters),(s=(await this.query(e,{...r,filters:n,limit:1}))[0])!=null?s:null}async query(e,t){var a;let{sql:r,params:n}=this.executor.buildSelect(e,t),i=this.executor.all(r,n);if((a=t==null?void 0:t.aggregates)!=null&&a.length||t!=null&&t.fields)return i;let s=this.schemaMap.get(e);if(!s)return i;let o=Object.fromEntries(s.columns.map(l=>[l.name,l]));return i.map(l=>{let u=this.executor.denormalizeRow(l);return this.executor.parseRow(u,o)})}async create(e,t){var u,p;let{sql:r,params:n}=this.executor.buildInsert(e,t),i=this.executor.run(r,n),s=(p=t==null?void 0:t.id)!=null?p:(u=i.lastInsertRowid)==null?void 0:u.toString(),o=s?{...t,id:s}:{...t},a=this.schemaMap.get(e);if(!a)return o;let l=Object.fromEntries(a.columns.map(h=>[h.name,h]));return this.executor.parseRow(o,l)}async update(e,t,r){if(!Object.keys(r).length){let o=await this.get(e,t);if(!o)throw new Error(`Record not found: ${e}#${t}`);return o}let{sql:n,params:i}=this.executor.buildUpdate(e,t,r);this.executor.run(n,i);let s=await this.get(e,t);if(!s)throw new Error(`Record not found after update: ${e}#${t}`);return s}async delete(e,t){let{sql:r,params:n}=this.executor.buildDelete(e,t);this.executor.run(r,n)}async bulkCreate(e,t){return t.length?this.transaction(async r=>{let n=[];for(let i of t)n.push(await r.create(e,i));return n}):[]}async bulkUpdate(e,t){return t.length?this.transaction(async r=>{let n=[];for(let i of t)Object.keys(i.updates).length&&n.push(await r.update(e,i.id,i.updates));return n}):[]}async transaction(e){let t=this.savepointDepth===0,r=t?"BEGIN IMMEDIATE":`SAVEPOINT sp${this.savepointDepth}`;this.executor.run(r),this.savepointDepth+=1;try{let n=await e(this),i=t?"COMMIT":`RELEASE SAVEPOINT sp${this.savepointDepth-1}`;return this.executor.run(i),n}catch(n){let i=t?"ROLLBACK":`ROLLBACK TO SAVEPOINT sp${this.savepointDepth-1}`;try{this.executor.run(i)}catch(s){}throw n}finally{this.savepointDepth-=1}}};import{createHash as S}from"node:crypto";var y=class{getEnvVar(e){return process.env[e]}isOnline(){return typeof navigator!="undefined"&&typeof navigator.onLine!="undefined"?navigator.onLine:!0}async hashPin(e){return S("sha256").update(e).digest("hex")}async verifyPin(e,t){return await this.hashPin(e)===t}};var T=class{constructor(e){this.options=e}configure(e){}createChannel(e){}localNotification(e){this.options.notify(e)}};import b from"node:fs/promises";import x from"node:path";var I=class{constructor(e){this.options=e}getDocumentPath(e){return x.join(this.options.documentsPath,e)}async writeFile(e,t){await b.writeFile(e,t,"utf8")}async share(e){var t,r;await((r=(t=this.options).revealFile)==null?void 0:r.call(t,e))}};var J=!1;var K=!1;import m from"node:fs";import N from"node:path";var $=class{constructor(e){var r;let t=(r=e.fileName)!=null?r:"storage.json";m.mkdirSync(e.storageDir,{recursive:!0}),this.filePath=N.join(e.storageDir,t);try{this.data=JSON.parse(m.readFileSync(this.filePath,"utf-8"))}catch{this.data={}}}async getItem(e){let t=this.data[e];return t!==void 0?t:null}async setItem(e,t){this.data[e]=t,await m.promises.writeFile(this.filePath,JSON.stringify(this.data,null,2),"utf-8")}async removeItem(e){delete this.data[e],await m.promises.writeFile(this.filePath,JSON.stringify(this.data,null,2),"utf-8")}};var ie={platform:"electron",ready:!1,notes:"Scaffold only. Add concrete adapters (db/http/socket/storage) in this package."};export{I as ElectronExportAdapter,T as ElectronNotificationAdapter,y as ElectronPlatformAdapter,$ as ElectronStorageAdapter,J as OFPLATFORM_ELECTRON_HTTP_ADAPTERS_READY,K as OFPLATFORM_ELECTRON_SOCKET_ADAPTERS_READY,ie as OFPLATFORM_ELECTRON_STATUS,E as SQLiteAdapter,d as SQLiteExecutor,c as SQLiteQueryBuilder};
|
|
9
|
+
`)}run(e,t=[]){return this.db.prepare(e).run(...t)}get(e,t=[]){return this.db.prepare(e).get(...t)}all(e,t=[]){return this.db.prepare(e).all(...t)}transaction(e){return this.db.transaction(e)()}escapeIdentifier(e){if(!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(e))throw new Error(`Invalid identifier: "${e}"`);return`"${e}"`}mapType(e){switch(e){case"string":return"TEXT";case"string[]":return"TEXT";case"number":return"REAL";case"boolean":return"INTEGER";case"json":return"TEXT";case"date":return"TEXT";default:return"TEXT"}}parseRow(e,t){let r={};for(let[i,n]of Object.entries(e!=null?e:{})){let s=t[i],a=n;if(n!=null&&s){if(s.type==="boolean")a=!!n;else if(s.type==="date"&&typeof n=="string"){let l=new Date(n);Number.isNaN(l.getTime())||(a=l)}else if((s.type==="json"||s.type==="string[]")&&typeof n=="string")try{a=JSON.parse(n)}catch(l){}}r[i]=a}return r}buildFilter(e,t="t0"){return g.buildFilter(e,t)}buildGroupBy(e,t="t0"){return g.buildGroupBy(e,t)}buildSort(e,t="t0"){return g.buildSort(e,t)}buildSelect(e,t){return g.buildSelect(e,t)}buildInsert(e,t){return g.buildInsert(e,t)}buildUpdate(e,t,r){return g.buildUpdate(e,t,r)}buildDelete(e,t){return g.buildDelete(e,t)}};var S=class{constructor(e){this.savepointDepth=0;this.schemaMap=new Map;var t;this.executor=new b(e.dbPath),this.executor.initMetaTable(),this.tableNamePrefix=(t=e.tableNamePrefix)!=null?t:"",this.tableNameResolver=e.tableNameMapper}setTableNameResolver(e){this.tableNameResolver=e}resolveTableName(e){return this.tableNameResolver?String(this.tableNameResolver(e)||"").trim()||e:!this.tableNamePrefix||e.startsWith(this.tableNamePrefix)?e:`${this.tableNamePrefix}${e}`}async getSchemaVersion(){let e=this.executor.get("SELECT version FROM schema_version LIMIT 1");return e?e.version:(this.executor.run("INSERT INTO schema_version (version) VALUES (?)",[0]),0)}async setSchemaVersion(e){if(!this.executor.get("SELECT 1 FROM schema_version LIMIT 1")){this.executor.run("INSERT INTO schema_version (version) VALUES (?)",[e]);return}this.executor.run("UPDATE schema_version SET version = ?",[e])}async addTable(e){let t=this.resolveTableName(e.name),r=e.columns.map(i=>{let n=`${this.executor.escapeIdentifier(i.name)} ${this.executor.mapType(i.type)}`;return i.isOptional||(n+=" NOT NULL"),i.name==="id"&&(n+=" PRIMARY KEY"),n}).join(", ");this.executor.run(`CREATE TABLE IF NOT EXISTS ${this.executor.escapeIdentifier(t)} (${r})`);for(let i of e.columns){if(!i.isIndexed)continue;let n=`idx_${t}_${i.name}`;this.executor.run(`CREATE INDEX IF NOT EXISTS ${this.executor.escapeIdentifier(n)} ON ${this.executor.escapeIdentifier(t)}(${this.executor.escapeIdentifier(i.name)})`)}this.schemaMap.set(e.name,e)}async addColumn(e,t){let r=this.resolveTableName(e);if(this.executor.all(`PRAGMA table_info(${this.executor.escapeIdentifier(r)})`).some(a=>a.name===t.name))return;let n=`ALTER TABLE ${this.executor.escapeIdentifier(r)} ADD COLUMN ${this.executor.escapeIdentifier(t.name)} ${this.executor.mapType(t.type)}`;if(!t.isOptional){let a=t.type==="boolean"?"0":t.type==="number"?"0.0":"''";n+=` DEFAULT ${a} NOT NULL`}if(this.executor.run(n),t.isIndexed){let a=`idx_${r}_${t.name}`;this.executor.run(`CREATE INDEX IF NOT EXISTS ${this.executor.escapeIdentifier(a)} ON ${this.executor.escapeIdentifier(r)}(${this.executor.escapeIdentifier(t.name)})`)}let s=this.schemaMap.get(e);s&&!s.columns.find(a=>a.name===t.name)&&(s.columns.push(t),this.schemaMap.set(e,s))}async get(e,t){var s;let r,i;return typeof t=="string"?i={id:t}:(r=t,i=r.filters),(s=(await this.query(e,{...r,filters:i,limit:1}))[0])!=null?s:null}async query(e,t){var o,u,f;let r=this.resolveTableName(e),i=(o=t==null?void 0:t.joins)!=null&&o.length?{...t,joins:t.joins.map(h=>({...h,table:this.resolveTableName(h.table)}))}:t,{sql:n,params:s,projectionMap:a}=this.executor.buildSelect(r,i),l=this.executor.all(n,s);if((u=t==null?void 0:t.aggregates)!=null&&u.length)return l;if(t!=null&&t.fields)return((f=t==null?void 0:t.resultShape)!=null?f:"flat")==="nested"&&(a!=null&&a.length)?l.map(y=>{let d={};for(let E of a)d[E.alias]||(d[E.alias]={}),d[E.alias][E.field]=y[E.key];return d}):l;let c=this.schemaMap.get(e);if(!c)return l;let m=Object.fromEntries(c.columns.map(h=>[h.name,h]));return l.map(h=>this.executor.parseRow(h,m))}async create(e,t){var o,u;let r=this.resolveTableName(e),{sql:i,params:n}=this.executor.buildInsert(r,t),s=this.executor.run(i,n),a=(u=t==null?void 0:t.id)!=null?u:(o=s.lastInsertRowid)==null?void 0:o.toString(),l=a?{...t,id:a}:{...t},c=this.schemaMap.get(e);if(!c)return l;let m=Object.fromEntries(c.columns.map(f=>[f.name,f]));return this.executor.parseRow(l,m)}async update(e,t,r){if(!Object.keys(r).length){let l=await this.get(e,t);if(!l)throw new Error(`Record not found: ${e}#${t}`);return l}let i=this.resolveTableName(e),{sql:n,params:s}=this.executor.buildUpdate(i,t,r);this.executor.run(n,s);let a=await this.get(e,t);if(!a)throw new Error(`Record not found after update: ${e}#${t}`);return a}async delete(e,t){let r=this.resolveTableName(e),{sql:i,params:n}=this.executor.buildDelete(r,t);this.executor.run(i,n)}async bulkCreate(e,t){return t.length?this.transaction(async r=>{let i=[];for(let n of t)i.push(await r.create(e,n));return i}):[]}async bulkUpdate(e,t){return t.length?this.transaction(async r=>{let i=[];for(let n of t)Object.keys(n.updates).length&&i.push(await r.update(e,n.id,n.updates));return i}):[]}async transaction(e){let t=this.savepointDepth===0,r=t?"BEGIN IMMEDIATE":`SAVEPOINT sp${this.savepointDepth}`;this.executor.run(r),this.savepointDepth+=1;try{let i=await e(this),n=t?"COMMIT":`RELEASE SAVEPOINT sp${this.savepointDepth-1}`;return this.executor.run(n),i}catch(i){let n=t?"ROLLBACK":`ROLLBACK TO SAVEPOINT sp${this.savepointDepth-1}`;try{this.executor.run(n)}catch(s){}throw i}finally{this.savepointDepth-=1}}};import{createHash as R}from"node:crypto";var v=class{getEnvVar(e){return process.env[e]}isOnline(){return typeof navigator!="undefined"&&typeof navigator.onLine!="undefined"?navigator.onLine:!0}async hashPin(e){return R("sha256").update(e).digest("hex")}async verifyPin(e,t){return await this.hashPin(e)===t}};var A=class{constructor(e){this.options=e}configure(e){}createChannel(e){}localNotification(e){this.options.notify(e)}};import N from"node:fs/promises";import k from"node:path";var I=class{constructor(e){this.options=e}getDocumentPath(e){return k.join(this.options.documentsPath,e)}async writeFile(e,t){await N.writeFile(e,t,"utf8")}async share(e){var t,r;await((r=(t=this.options).revealFile)==null?void 0:r.call(t,e))}};function P(p,e){if(!e||Object.keys(e).length===0)return p;let t=new URLSearchParams;for(let[i,n]of Object.entries(e))n!=null&&t.set(i,String(n));let r=t.toString();return r?p.includes("?")?`${p}&${r}`:`${p}?${r}`:p}var x=class{constructor(e={}){let t=e.fetch;if(t)this.fetchImpl=t;else{let r=globalThis.fetch;if(typeof r!="function")throw new Error("ElectronHttpAdapter: globalThis.fetch is not available. Pass a fetch implementation via options.fetch, or ensure the app is running on Electron \u2265 20 / Node.js \u2265 18.");this.fetchImpl=r}}async request(e){var n,s;let t=P(e.url,e.query),r=typeof AbortController!="undefined"?new AbortController:null,i=r&&e.timeoutMs?setTimeout(()=>r.abort(),e.timeoutMs):null;try{let a=e.body!==void 0&&e.body!==null,l={...(n=e.headers)!=null?n:{}};a&&!l["content-type"]&&!l["Content-Type"]&&(l["content-type"]="application/json");let c=await this.fetchImpl(t,{method:e.method,headers:l,body:a?JSON.stringify(e.body):void 0,signal:r==null?void 0:r.signal}),m={};c.headers.forEach((f,h)=>{m[h.toLowerCase()]=f});let u=((s=m["content-type"])!=null?s:"").includes("application/json")?await c.json():await c.text();return{status:c.status,headers:m,data:u}}finally{i!==null&&clearTimeout(i)}}};var ie=!0;function L(p){let e=p.query;if(!e||Object.keys(e).length===0)return p.url;let r=new URLSearchParams(e).toString();return p.url.includes("?")?`${p.url}&${r}`:`${p.url}?${r}`}var $=class{constructor(e={}){this.ws=null;this.connectionOptions=null;this.listeners=new Map;this.reconnectAttempts=0;this.reconnectTimeout=null;this.intentionalClose=!1;var r,i,n,s,a;this.reconnect=(r=e.reconnect)!=null?r:!0,this.maxReconnectAttempts=Math.max(0,(i=e.maxReconnectAttempts)!=null?i:5),this.reconnectDelayMs=Math.max(0,(n=e.reconnectDelayMs)!=null?n:500),this.maxReconnectDelayMs=Math.max(this.reconnectDelayMs,(s=e.maxReconnectDelayMs)!=null?s:3e4);let t=(a=e.webSocket)!=null?a:globalThis.WebSocket;if(typeof t!="function")throw new Error("ElectronSocketAdapter: globalThis.WebSocket is not available. Pass a WebSocket constructor via options.webSocket. In the Electron main process you can use the `ws` package.");this.WebSocketCtor=t}connect(e){return this.connectionOptions=e,this.intentionalClose=!1,this.reconnectAttempts=0,this.openConnection(e)}async disconnect(){this.intentionalClose=!0,this.clearReconnectTimeout(),this.ws&&(this.ws.close(1e3,"client disconnect"),this.ws=null)}subscribe(e,t){return this.listeners.has(e)||this.listeners.set(e,new Set),this.listeners.get(e).add(t),()=>{let r=this.listeners.get(e);r&&(r.delete(t),r.size===0&&this.listeners.delete(e))}}async publish(e,t){var i,n;if(!this.ws||this.ws.readyState!==this.ws.OPEN)throw new Error(`ElectronSocketAdapter: cannot publish "${e}" \u2014 not connected (readyState=${(n=(i=this.ws)==null?void 0:i.readyState)!=null?n:"null"}).`);let r={event:e,payload:t};this.ws.send(JSON.stringify(r))}isConnected(){return this.ws!==null&&this.ws.readyState===this.ws.OPEN}openConnection(e){return new Promise((t,r)=>{let i=L(e),n;try{n=new this.WebSocketCtor(i)}catch(s){r(s instanceof Error?s:new Error(String(s)));return}n.onopen=()=>{this.ws=n,this.reconnectAttempts=0,t()},n.onerror=()=>{this.ws||r(new Error("ElectronSocketAdapter: connection failed"))},n.onclose=()=>{this.ws===n&&(this.ws=null),!this.intentionalClose&&this.reconnect&&this.connectionOptions&&this.reconnectAttempts<this.maxReconnectAttempts&&this.scheduleReconnect()},n.onmessage=s=>{this.handleMessage(s.data)}})}handleMessage(e){if(typeof e!="string")return;let t;try{t=JSON.parse(e)}catch{return}if(typeof t!="object"||t===null||typeof t.event!="string")return;let{event:r,payload:i}=t,n=this.listeners.get(r);if(n)for(let s of n)try{s(i)}catch{}}scheduleReconnect(){this.clearReconnectTimeout();let e=++this.reconnectAttempts,t=Math.min(this.reconnectDelayMs*Math.pow(2,e-1),this.maxReconnectDelayMs);this.reconnectTimeout=setTimeout(()=>{!this.intentionalClose&&this.connectionOptions&&this.openConnection(this.connectionOptions).catch(()=>{})},t)}clearReconnectTimeout(){this.reconnectTimeout!==null&&(clearTimeout(this.reconnectTimeout),this.reconnectTimeout=null)}};var oe=!0;import T from"node:fs";import C from"node:path";var O=class{constructor(e){var r;let t=(r=e.fileName)!=null?r:"storage.json";T.mkdirSync(e.storageDir,{recursive:!0}),this.filePath=C.join(e.storageDir,t);try{this.data=JSON.parse(T.readFileSync(this.filePath,"utf-8"))}catch{this.data={}}}async getItem(e){let t=this.data[e];return t!==void 0?t:null}async setItem(e,t){this.data[e]=t,await T.promises.writeFile(this.filePath,JSON.stringify(this.data,null,2),"utf-8")}async removeItem(e){delete this.data[e],await T.promises.writeFile(this.filePath,JSON.stringify(this.data,null,2),"utf-8")}};var de={platform:"electron",ready:!0,notes:"All adapter domains implemented: SQLiteAdapter (db), ElectronHttpAdapter (http), ElectronSocketAdapter (socket), ElectronStorageAdapter (storage), ElectronPlatformAdapter (platform), ElectronExportAdapter + ElectronNotificationAdapter (desktop)."};export{I as ElectronExportAdapter,x as ElectronHttpAdapter,A as ElectronNotificationAdapter,v as ElectronPlatformAdapter,$ as ElectronSocketAdapter,O as ElectronStorageAdapter,ie as OFPLATFORM_ELECTRON_HTTP_ADAPTERS_READY,oe as OFPLATFORM_ELECTRON_SOCKET_ADAPTERS_READY,de as OFPLATFORM_ELECTRON_STATUS,S as SQLiteAdapter,b as SQLiteExecutor,g as SQLiteQueryBuilder};
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var D=Object.create;var v=Object.defineProperty;var q=Object.getOwnPropertyDescriptor;var F=Object.getOwnPropertyNames;var j=Object.getPrototypeOf,V=Object.prototype.hasOwnProperty;var B=(c,e)=>{for(var t in e)v(c,t,{get:e[t],enumerable:!0})},N=(c,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of F(e))!V.call(c,i)&&i!==t&&v(c,i,{get:()=>e[i],enumerable:!(r=q(e,i))||r.enumerable});return c};var b=(c,e,t)=>(t=c!=null?D(j(c)):{},N(e||!c||!c.__esModule?v(t,"default",{value:c,enumerable:!0}):t,c)),W=c=>N(v({},"__esModule",{value:!0}),c);var G={};B(G,{ElectronExportAdapter:()=>$,ElectronHttpAdapter:()=>O,ElectronNotificationAdapter:()=>x,ElectronPlatformAdapter:()=>I,ElectronSocketAdapter:()=>w,ElectronStorageAdapter:()=>R,OFPLATFORM_ELECTRON_HTTP_ADAPTERS_READY:()=>U,OFPLATFORM_ELECTRON_SOCKET_ADAPTERS_READY:()=>H,OFPLATFORM_ELECTRON_STATUS:()=>z,SQLiteAdapter:()=>A,SQLiteExecutor:()=>T,SQLiteQueryBuilder:()=>m});module.exports=W(G);var k=b(require("better-sqlite3"));var m=class{static escapeIdentifier(e){if(!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(e))throw new Error(`Invalid identifier: "${e}"`);return`"${e}"`}static normalizeValue(e){return e==null?null:typeof e=="boolean"?e?1:0:e instanceof Date?e.toISOString():Array.isArray(e)||typeof e=="object"&&e!==null?JSON.stringify(e):e}static buildValueExpr(e,t){if(e.type==="column"){let r=e.tableAlias||t;return{sql:`${this.escapeIdentifier(r)}.${this.escapeIdentifier(e.field)}`,params:[]}}return{sql:"?",params:[this.normalizeValue(e.value)]}}static buildFieldCondition(e,t){if("field"in e){let n=e.alias||t,s=`${this.escapeIdentifier(n)}.${this.escapeIdentifier(e.field)}`,a=e.operator||"=";if(a==="BETWEEN"){if(!Array.isArray(e.value)||e.value.length!==2)throw new Error("BETWEEN requires value tuple [min,max]");return{sql:`${s} BETWEEN ? AND ?`,params:[this.normalizeValue(e.value[0]),this.normalizeValue(e.value[1])]}}if(a==="IN"||a==="NOT IN"){if(!Array.isArray(e.value))throw new Error(`${a} requires array value`);return e.value.length===0?{sql:a==="IN"?"FALSE":"TRUE",params:[]}:{sql:`${s} ${a} (${e.value.map(()=>"?").join(", ")})`,params:e.value.map(l=>this.normalizeValue(l))}}if(a==="IS NULL"||a==="IS NOT NULL")return{sql:`${s} ${a}`,params:[]};if(a==="LIKE"){let u=("likeMode"in e?e.likeMode:"default")==="case-sensitive"?" COLLATE BINARY":"";return{sql:`${s} LIKE${u} ?`,params:[this.normalizeValue(e.value)]}}return{sql:`${s} ${a} ?`,params:[this.normalizeValue(e.value)]}}let r=this.buildValueExpr(e.left,t);if(e.operator==="IS NULL"||e.operator==="IS NOT NULL")return{sql:`${r.sql} ${e.operator}`,params:r.params};let i=this.buildValueExpr(e.right,t);if(e.operator==="IN"||e.operator==="NOT IN"){if(e.right.type!=="literal"||!Array.isArray(e.right.value))throw new Error(`${e.operator} requires literal array on right side`);return e.right.value.length===0?{sql:e.operator==="IN"?"FALSE":"TRUE",params:[]}:{sql:`${r.sql} ${e.operator} (${e.right.value.map(()=>"?").join(", ")})`,params:[...r.params,...e.right.value.map(n=>this.normalizeValue(n))]}}if(e.operator==="BETWEEN"){if(e.right.type!=="literal"||!Array.isArray(e.right.value)||e.right.value.length!==2)throw new Error("BETWEEN requires literal tuple [min,max] on right side");return{sql:`${r.sql} BETWEEN ? AND ?`,params:[...r.params,this.normalizeValue(e.right.value[0]),this.normalizeValue(e.right.value[1])]}}if(e.operator==="LIKE"){let n=e.likeMode==="case-sensitive"?" COLLATE BINARY":"";return{sql:`${r.sql} LIKE${n} ${i.sql}`,params:[...r.params,...i.params]}}return{sql:`${r.sql} ${e.operator} ${i.sql}`,params:[...r.params,...i.params]}}static buildFilter(e,t="t0"){let r=e.and;if(Array.isArray(r)){let n=r.map(s=>this.buildFilter(s,t));return{sql:n.map(s=>`(${s.sql})`).join(" AND "),params:n.flatMap(s=>s.params)}}let i=e.or;if(Array.isArray(i)){let n=i.map(s=>this.buildFilter(s,t));return{sql:n.map(s=>`(${s.sql})`).join(" OR "),params:n.flatMap(s=>s.params)}}if(e!==null&&typeof e=="object"&&!Array.isArray(e)){if("left"in e||"field"in e)return this.buildFieldCondition(e,t);let n=Object.entries(e);if(n.length===0)return{sql:"TRUE",params:[]};let s=n.map(([a,l])=>({sql:`${`${this.escapeIdentifier(t)}.${this.escapeIdentifier(a)}`} = ?`,params:[this.normalizeValue(l)]}));return{sql:s.map(a=>`(${a.sql})`).join(" AND "),params:s.flatMap(a=>a.params)}}throw new Error(`Invalid filter expression: ${JSON.stringify(e)}`)}static buildGroupBy(e,t="t0"){return!e||!e.length?"":` GROUP BY ${e.map(i=>{let n=typeof i.field=="string"?{tableAlias:t,field:i.field}:i.field;return`${this.escapeIdentifier(n.tableAlias)}.${this.escapeIdentifier(n.field)}`}).join(", ")}`}static buildSort(e,t="t0"){return!e||!e.length?"":e.map(r=>{let i=typeof r.field=="string"?{tableAlias:t,field:r.field}:r.field;return`${this.escapeIdentifier(i.tableAlias)}.${this.escapeIdentifier(i.field)} ${r.direction.toUpperCase()}`}).join(", ")}static buildSelect(e,t){var d;let r=t,i=(t==null?void 0:t.mainAlias)||"t0",n=(t==null?void 0:t.joins)||[],s=[],a=[],l=[];if(t!=null&&t.aggregates&&t.aggregates.length>0)t.groupBy&&t.groupBy.forEach(o=>{let p=typeof o.field=="string"?{tableAlias:i,field:o.field}:o.field;l.push(`${this.escapeIdentifier(p.tableAlias)}.${this.escapeIdentifier(p.field)} AS ${this.escapeIdentifier(`${p.tableAlias}_${p.field}`)}`)}),t.aggregates.forEach(o=>{let p=typeof o.field=="string"?{tableAlias:i,field:o.field}:o.field,f=`${this.escapeIdentifier(p.tableAlias)}.${this.escapeIdentifier(p.field)}`;l.push(`${o.function}(${f}) AS ${this.escapeIdentifier(o.as)}`)});else if(t!=null&&t.fields){let o=0;for(let[p,f]of Object.entries(t.fields))for(let h of f){let g=((d=r==null?void 0:r.resultShape)!=null?d:"flat")==="nested"?`__c${o++}`:`${p}_${h}`;a.push({key:g,alias:p,field:h}),l.push(`${this.escapeIdentifier(p)}.${this.escapeIdentifier(h)} AS ${this.escapeIdentifier(g)}`)}}else l.push(`${this.escapeIdentifier(i)}.*`);let u=`SELECT ${l.join(", ")} FROM ${this.escapeIdentifier(e)} AS ${this.escapeIdentifier(i)}`;if(n.forEach(o=>{let p=(o.type||"inner").toUpperCase();if(p==="RIGHT"||p==="FULL")throw new Error(`SQLite adapter does not support ${p} JOIN`);let f=[];o.conditions.forEach(h=>{let y=this.buildValueExpr(h.left,i),g=this.buildValueExpr(h.right,i);f.push(`${y.sql} ${h.operator} ${g.sql}`),s.push(...y.params,...g.params)}),u+=` ${p} JOIN ${this.escapeIdentifier(o.table)} AS ${this.escapeIdentifier(o.alias)} ON ${f.join(" AND ")}`}),t!=null&&t.filters){let o=this.buildFilter(t.filters,i);o.sql&&o.sql!=="TRUE"&&(u+=` WHERE ${o.sql}`,s.push(...o.params))}if(t!=null&&t.aggregates&&t.aggregates.length>0){if(u+=this.buildGroupBy(t.groupBy,i),t.having){let o=this.buildFilter(t.having,i);o.sql&&o.sql!=="TRUE"&&(u+=` HAVING ${o.sql}`,s.push(...o.params))}return{sql:u,params:s,projectionMap:a.length?a:void 0}}if(u+=this.buildGroupBy(t==null?void 0:t.groupBy,i),t!=null&&t.having){let o=this.buildFilter(t.having,i);o.sql&&o.sql!=="TRUE"&&(u+=` HAVING ${o.sql}`,s.push(...o.params))}if(t!=null&&t.sort&&t.sort.length){let o=this.buildSort(t.sort,i);o&&(u+=` ORDER BY ${o}`)}return(t==null?void 0:t.limit)!==void 0&&(u+=" LIMIT ?",s.push(t.limit)),(t==null?void 0:t.offset)!==void 0&&(u+=" OFFSET ?",s.push(t.offset)),{sql:u,params:s,projectionMap:a.length?a:void 0}}static buildInsert(e,t){let r=Object.keys(t),i=r.map(l=>this.escapeIdentifier(l)).join(", "),n=r.map(()=>"?").join(", "),s=r.map(l=>this.normalizeValue(t[l]));return{sql:`INSERT INTO ${this.escapeIdentifier(e)} (${i}) VALUES (${n})`,params:s}}static buildUpdate(e,t,r){let i=Object.keys(r);if(!i.length)throw new Error("Cannot build UPDATE query with empty updates payload");let n=i.map(l=>`${this.escapeIdentifier(l)} = ?`).join(", "),s=i.map(l=>this.normalizeValue(r[l]));return{sql:`UPDATE ${this.escapeIdentifier(e)} SET ${n} WHERE id = ?`,params:[...s,t]}}static buildDelete(e,t){return{sql:`DELETE FROM ${this.escapeIdentifier(e)} WHERE id = ?`,params:[t]}}};var T=class{constructor(e){this.db=new k.default(e)}initMetaTable(){this.db.exec(`
|
|
2
2
|
CREATE TABLE IF NOT EXISTS _meta (
|
|
3
3
|
key TEXT PRIMARY KEY,
|
|
4
4
|
value TEXT
|
|
@@ -6,4 +6,4 @@
|
|
|
6
6
|
CREATE TABLE IF NOT EXISTS schema_version (
|
|
7
7
|
version INTEGER NOT NULL
|
|
8
8
|
);
|
|
9
|
-
`)}run(e,t=[]){return this.db.prepare(e).run(...t)}get(e,t=[]){return this.db.prepare(e).get(...t)}all(e,t=[]){return this.db.prepare(e).all(...t)}transaction(e){return this.db.transaction(e)()}escapeIdentifier(e){if(!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(e))throw new Error(`Invalid identifier: "${e}"`);return`"${e}"`}mapType(e){switch(e){case"string":return"TEXT";case"string[]":return"TEXT";case"number":return"REAL";case"boolean":return"INTEGER";case"json":return"TEXT";case"date":return"TEXT";default:return"TEXT"}}parseRow(e,t){let r={};for(let[i,s]of Object.entries(e!=null?e:{})){let a=t[i],o=s;if(s!=null&&a){if(a.type==="boolean")o=!!s;else if(a.type==="date"&&typeof s=="string"){let n=new Date(s);Number.isNaN(n.getTime())||(o=n)}else if((a.type==="json"||a.type==="string[]")&&typeof s=="string")try{o=JSON.parse(s)}catch(n){}}r[i]=o}return r}denormalizeRow(e,t="t0"){let r={},i={};for(let[s,a]of Object.entries(e!=null?e:{})){if(!s.includes("_")){r[s]=a;continue}let[o,n]=s.split("_",2);if(!o||!n){r[s]=a;continue}o===t?r[n]=a:(i[o]||(i[o]={}),i[o][n]=a)}return{...r,...i}}buildFilter(e,t="t0"){return f.buildFilter(e,t)}buildGroupBy(e,t="t0"){return f.buildGroupBy(e,t)}buildSort(e,t="t0"){return f.buildSort(e,t)}buildSelect(e,t){return f.buildSelect(e,t)}buildInsert(e,t){return f.buildInsert(e,t)}buildUpdate(e,t,r){return f.buildUpdate(e,t,r)}buildDelete(e,t){return f.buildDelete(e,t)}};var y=class{constructor(e){this.savepointDepth=0;this.schemaMap=new Map;this.executor=new m(e.dbPath),this.executor.initMetaTable()}async getSchemaVersion(){let e=this.executor.get("SELECT version FROM schema_version LIMIT 1");return e?e.version:(this.executor.run("INSERT INTO schema_version (version) VALUES (?)",[0]),0)}async setSchemaVersion(e){if(!this.executor.get("SELECT 1 FROM schema_version LIMIT 1")){this.executor.run("INSERT INTO schema_version (version) VALUES (?)",[e]);return}this.executor.run("UPDATE schema_version SET version = ?",[e])}async addTable(e){let t=e.columns.map(r=>{let i=`${this.executor.escapeIdentifier(r.name)} ${this.executor.mapType(r.type)}`;return r.isOptional||(i+=" NOT NULL"),r.name==="id"&&(i+=" PRIMARY KEY"),i}).join(", ");this.executor.run(`CREATE TABLE IF NOT EXISTS ${this.executor.escapeIdentifier(e.name)} (${t})`);for(let r of e.columns){if(!r.isIndexed)continue;let i=`idx_${e.name}_${r.name}`;this.executor.run(`CREATE INDEX IF NOT EXISTS ${this.executor.escapeIdentifier(i)} ON ${this.executor.escapeIdentifier(e.name)}(${this.executor.escapeIdentifier(r.name)})`)}this.schemaMap.set(e.name,e)}async addColumn(e,t){if(this.executor.all(`PRAGMA table_info(${this.executor.escapeIdentifier(e)})`).some(a=>a.name===t.name))return;let i=`ALTER TABLE ${this.executor.escapeIdentifier(e)} ADD COLUMN ${this.executor.escapeIdentifier(t.name)} ${this.executor.mapType(t.type)}`;if(!t.isOptional){let a=t.type==="boolean"?"0":t.type==="number"?"0.0":"''";i+=` DEFAULT ${a} NOT NULL`}if(this.executor.run(i),t.isIndexed){let a=`idx_${e}_${t.name}`;this.executor.run(`CREATE INDEX IF NOT EXISTS ${this.executor.escapeIdentifier(a)} ON ${this.executor.escapeIdentifier(e)}(${this.executor.escapeIdentifier(t.name)})`)}let s=this.schemaMap.get(e);s&&!s.columns.find(a=>a.name===t.name)&&(s.columns.push(t),this.schemaMap.set(e,s))}async get(e,t){var a;let r,i;return typeof t=="string"?i={id:t}:(r=t,i=r.filters),(a=(await this.query(e,{...r,filters:i,limit:1}))[0])!=null?a:null}async query(e,t){var n;let{sql:r,params:i}=this.executor.buildSelect(e,t),s=this.executor.all(r,i);if((n=t==null?void 0:t.aggregates)!=null&&n.length||t!=null&&t.fields)return s;let a=this.schemaMap.get(e);if(!a)return s;let o=Object.fromEntries(a.columns.map(l=>[l.name,l]));return s.map(l=>{let c=this.executor.denormalizeRow(l);return this.executor.parseRow(c,o)})}async create(e,t){var c,p;let{sql:r,params:i}=this.executor.buildInsert(e,t),s=this.executor.run(r,i),a=(p=t==null?void 0:t.id)!=null?p:(c=s.lastInsertRowid)==null?void 0:c.toString(),o=a?{...t,id:a}:{...t},n=this.schemaMap.get(e);if(!n)return o;let l=Object.fromEntries(n.columns.map(h=>[h.name,h]));return this.executor.parseRow(o,l)}async update(e,t,r){if(!Object.keys(r).length){let o=await this.get(e,t);if(!o)throw new Error(`Record not found: ${e}#${t}`);return o}let{sql:i,params:s}=this.executor.buildUpdate(e,t,r);this.executor.run(i,s);let a=await this.get(e,t);if(!a)throw new Error(`Record not found after update: ${e}#${t}`);return a}async delete(e,t){let{sql:r,params:i}=this.executor.buildDelete(e,t);this.executor.run(r,i)}async bulkCreate(e,t){return t.length?this.transaction(async r=>{let i=[];for(let s of t)i.push(await r.create(e,s));return i}):[]}async bulkUpdate(e,t){return t.length?this.transaction(async r=>{let i=[];for(let s of t)Object.keys(s.updates).length&&i.push(await r.update(e,s.id,s.updates));return i}):[]}async transaction(e){let t=this.savepointDepth===0,r=t?"BEGIN IMMEDIATE":`SAVEPOINT sp${this.savepointDepth}`;this.executor.run(r),this.savepointDepth+=1;try{let i=await e(this),s=t?"COMMIT":`RELEASE SAVEPOINT sp${this.savepointDepth-1}`;return this.executor.run(s),i}catch(i){let s=t?"ROLLBACK":`ROLLBACK TO SAVEPOINT sp${this.savepointDepth-1}`;try{this.executor.run(s)}catch(a){}throw i}finally{this.savepointDepth-=1}}};var N=require("node:crypto"),T=class{getEnvVar(e){return process.env[e]}isOnline(){return typeof navigator!="undefined"&&typeof navigator.onLine!="undefined"?navigator.onLine:!0}async hashPin(e){return(0,N.createHash)("sha256").update(e).digest("hex")}async verifyPin(e,t){return await this.hashPin(e)===t}};var I=class{constructor(e){this.options=e}configure(e){}createChannel(e){}localNotification(e){this.options.notify(e)}};var O=d(require("node:fs/promises")),v=d(require("node:path")),$=class{constructor(e){this.options=e}getDocumentPath(e){return v.default.join(this.options.documentsPath,e)}async writeFile(e,t){await O.default.writeFile(e,t,"utf8")}async share(e){var t,r;await((r=(t=this.options).revealFile)==null?void 0:r.call(t,e))}};var ie=!1;var ae=!1;var g=d(require("node:fs")),R=d(require("node:path")),A=class{constructor(e){var r;let t=(r=e.fileName)!=null?r:"storage.json";g.default.mkdirSync(e.storageDir,{recursive:!0}),this.filePath=R.default.join(e.storageDir,t);try{this.data=JSON.parse(g.default.readFileSync(this.filePath,"utf-8"))}catch{this.data={}}}async getItem(e){let t=this.data[e];return t!==void 0?t:null}async setItem(e,t){this.data[e]=t,await g.default.promises.writeFile(this.filePath,JSON.stringify(this.data,null,2),"utf-8")}async removeItem(e){delete this.data[e],await g.default.promises.writeFile(this.filePath,JSON.stringify(this.data,null,2),"utf-8")}};var V={platform:"electron",ready:!1,notes:"Scaffold only. Add concrete adapters (db/http/socket/storage) in this package."};0&&(module.exports={ElectronExportAdapter,ElectronNotificationAdapter,ElectronPlatformAdapter,ElectronStorageAdapter,OFPLATFORM_ELECTRON_HTTP_ADAPTERS_READY,OFPLATFORM_ELECTRON_SOCKET_ADAPTERS_READY,OFPLATFORM_ELECTRON_STATUS,SQLiteAdapter,SQLiteExecutor,SQLiteQueryBuilder});
|
|
9
|
+
`)}run(e,t=[]){return this.db.prepare(e).run(...t)}get(e,t=[]){return this.db.prepare(e).get(...t)}all(e,t=[]){return this.db.prepare(e).all(...t)}transaction(e){return this.db.transaction(e)()}escapeIdentifier(e){if(!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(e))throw new Error(`Invalid identifier: "${e}"`);return`"${e}"`}mapType(e){switch(e){case"string":return"TEXT";case"string[]":return"TEXT";case"number":return"REAL";case"boolean":return"INTEGER";case"json":return"TEXT";case"date":return"TEXT";default:return"TEXT"}}parseRow(e,t){let r={};for(let[i,n]of Object.entries(e!=null?e:{})){let s=t[i],a=n;if(n!=null&&s){if(s.type==="boolean")a=!!n;else if(s.type==="date"&&typeof n=="string"){let l=new Date(n);Number.isNaN(l.getTime())||(a=l)}else if((s.type==="json"||s.type==="string[]")&&typeof n=="string")try{a=JSON.parse(n)}catch(l){}}r[i]=a}return r}buildFilter(e,t="t0"){return m.buildFilter(e,t)}buildGroupBy(e,t="t0"){return m.buildGroupBy(e,t)}buildSort(e,t="t0"){return m.buildSort(e,t)}buildSelect(e,t){return m.buildSelect(e,t)}buildInsert(e,t){return m.buildInsert(e,t)}buildUpdate(e,t,r){return m.buildUpdate(e,t,r)}buildDelete(e,t){return m.buildDelete(e,t)}};var A=class{constructor(e){this.savepointDepth=0;this.schemaMap=new Map;var t;this.executor=new T(e.dbPath),this.executor.initMetaTable(),this.tableNamePrefix=(t=e.tableNamePrefix)!=null?t:"",this.tableNameResolver=e.tableNameMapper}setTableNameResolver(e){this.tableNameResolver=e}resolveTableName(e){return this.tableNameResolver?String(this.tableNameResolver(e)||"").trim()||e:!this.tableNamePrefix||e.startsWith(this.tableNamePrefix)?e:`${this.tableNamePrefix}${e}`}async getSchemaVersion(){let e=this.executor.get("SELECT version FROM schema_version LIMIT 1");return e?e.version:(this.executor.run("INSERT INTO schema_version (version) VALUES (?)",[0]),0)}async setSchemaVersion(e){if(!this.executor.get("SELECT 1 FROM schema_version LIMIT 1")){this.executor.run("INSERT INTO schema_version (version) VALUES (?)",[e]);return}this.executor.run("UPDATE schema_version SET version = ?",[e])}async addTable(e){let t=this.resolveTableName(e.name),r=e.columns.map(i=>{let n=`${this.executor.escapeIdentifier(i.name)} ${this.executor.mapType(i.type)}`;return i.isOptional||(n+=" NOT NULL"),i.name==="id"&&(n+=" PRIMARY KEY"),n}).join(", ");this.executor.run(`CREATE TABLE IF NOT EXISTS ${this.executor.escapeIdentifier(t)} (${r})`);for(let i of e.columns){if(!i.isIndexed)continue;let n=`idx_${t}_${i.name}`;this.executor.run(`CREATE INDEX IF NOT EXISTS ${this.executor.escapeIdentifier(n)} ON ${this.executor.escapeIdentifier(t)}(${this.executor.escapeIdentifier(i.name)})`)}this.schemaMap.set(e.name,e)}async addColumn(e,t){let r=this.resolveTableName(e);if(this.executor.all(`PRAGMA table_info(${this.executor.escapeIdentifier(r)})`).some(a=>a.name===t.name))return;let n=`ALTER TABLE ${this.executor.escapeIdentifier(r)} ADD COLUMN ${this.executor.escapeIdentifier(t.name)} ${this.executor.mapType(t.type)}`;if(!t.isOptional){let a=t.type==="boolean"?"0":t.type==="number"?"0.0":"''";n+=` DEFAULT ${a} NOT NULL`}if(this.executor.run(n),t.isIndexed){let a=`idx_${r}_${t.name}`;this.executor.run(`CREATE INDEX IF NOT EXISTS ${this.executor.escapeIdentifier(a)} ON ${this.executor.escapeIdentifier(r)}(${this.executor.escapeIdentifier(t.name)})`)}let s=this.schemaMap.get(e);s&&!s.columns.find(a=>a.name===t.name)&&(s.columns.push(t),this.schemaMap.set(e,s))}async get(e,t){var s;let r,i;return typeof t=="string"?i={id:t}:(r=t,i=r.filters),(s=(await this.query(e,{...r,filters:i,limit:1}))[0])!=null?s:null}async query(e,t){var o,p,f;let r=this.resolveTableName(e),i=(o=t==null?void 0:t.joins)!=null&&o.length?{...t,joins:t.joins.map(h=>({...h,table:this.resolveTableName(h.table)}))}:t,{sql:n,params:s,projectionMap:a}=this.executor.buildSelect(r,i),l=this.executor.all(n,s);if((p=t==null?void 0:t.aggregates)!=null&&p.length)return l;if(t!=null&&t.fields)return((f=t==null?void 0:t.resultShape)!=null?f:"flat")==="nested"&&(a!=null&&a.length)?l.map(y=>{let g={};for(let E of a)g[E.alias]||(g[E.alias]={}),g[E.alias][E.field]=y[E.key];return g}):l;let u=this.schemaMap.get(e);if(!u)return l;let d=Object.fromEntries(u.columns.map(h=>[h.name,h]));return l.map(h=>this.executor.parseRow(h,d))}async create(e,t){var o,p;let r=this.resolveTableName(e),{sql:i,params:n}=this.executor.buildInsert(r,t),s=this.executor.run(i,n),a=(p=t==null?void 0:t.id)!=null?p:(o=s.lastInsertRowid)==null?void 0:o.toString(),l=a?{...t,id:a}:{...t},u=this.schemaMap.get(e);if(!u)return l;let d=Object.fromEntries(u.columns.map(f=>[f.name,f]));return this.executor.parseRow(l,d)}async update(e,t,r){if(!Object.keys(r).length){let l=await this.get(e,t);if(!l)throw new Error(`Record not found: ${e}#${t}`);return l}let i=this.resolveTableName(e),{sql:n,params:s}=this.executor.buildUpdate(i,t,r);this.executor.run(n,s);let a=await this.get(e,t);if(!a)throw new Error(`Record not found after update: ${e}#${t}`);return a}async delete(e,t){let r=this.resolveTableName(e),{sql:i,params:n}=this.executor.buildDelete(r,t);this.executor.run(i,n)}async bulkCreate(e,t){return t.length?this.transaction(async r=>{let i=[];for(let n of t)i.push(await r.create(e,n));return i}):[]}async bulkUpdate(e,t){return t.length?this.transaction(async r=>{let i=[];for(let n of t)Object.keys(n.updates).length&&i.push(await r.update(e,n.id,n.updates));return i}):[]}async transaction(e){let t=this.savepointDepth===0,r=t?"BEGIN IMMEDIATE":`SAVEPOINT sp${this.savepointDepth}`;this.executor.run(r),this.savepointDepth+=1;try{let i=await e(this),n=t?"COMMIT":`RELEASE SAVEPOINT sp${this.savepointDepth-1}`;return this.executor.run(n),i}catch(i){let n=t?"ROLLBACK":`ROLLBACK TO SAVEPOINT sp${this.savepointDepth-1}`;try{this.executor.run(n)}catch(s){}throw i}finally{this.savepointDepth-=1}}};var P=require("node:crypto"),I=class{getEnvVar(e){return process.env[e]}isOnline(){return typeof navigator!="undefined"&&typeof navigator.onLine!="undefined"?navigator.onLine:!0}async hashPin(e){return(0,P.createHash)("sha256").update(e).digest("hex")}async verifyPin(e,t){return await this.hashPin(e)===t}};var x=class{constructor(e){this.options=e}configure(e){}createChannel(e){}localNotification(e){this.options.notify(e)}};var L=b(require("node:fs/promises")),C=b(require("node:path")),$=class{constructor(e){this.options=e}getDocumentPath(e){return C.default.join(this.options.documentsPath,e)}async writeFile(e,t){await L.default.writeFile(e,t,"utf8")}async share(e){var t,r;await((r=(t=this.options).revealFile)==null?void 0:r.call(t,e))}};function _(c,e){if(!e||Object.keys(e).length===0)return c;let t=new URLSearchParams;for(let[i,n]of Object.entries(e))n!=null&&t.set(i,String(n));let r=t.toString();return r?c.includes("?")?`${c}&${r}`:`${c}?${r}`:c}var O=class{constructor(e={}){let t=e.fetch;if(t)this.fetchImpl=t;else{let r=globalThis.fetch;if(typeof r!="function")throw new Error("ElectronHttpAdapter: globalThis.fetch is not available. Pass a fetch implementation via options.fetch, or ensure the app is running on Electron \u2265 20 / Node.js \u2265 18.");this.fetchImpl=r}}async request(e){var n,s;let t=_(e.url,e.query),r=typeof AbortController!="undefined"?new AbortController:null,i=r&&e.timeoutMs?setTimeout(()=>r.abort(),e.timeoutMs):null;try{let a=e.body!==void 0&&e.body!==null,l={...(n=e.headers)!=null?n:{}};a&&!l["content-type"]&&!l["Content-Type"]&&(l["content-type"]="application/json");let u=await this.fetchImpl(t,{method:e.method,headers:l,body:a?JSON.stringify(e.body):void 0,signal:r==null?void 0:r.signal}),d={};u.headers.forEach((f,h)=>{d[h.toLowerCase()]=f});let p=((s=d["content-type"])!=null?s:"").includes("application/json")?await u.json():await u.text();return{status:u.status,headers:d,data:p}}finally{i!==null&&clearTimeout(i)}}};var U=!0;function Q(c){let e=c.query;if(!e||Object.keys(e).length===0)return c.url;let r=new URLSearchParams(e).toString();return c.url.includes("?")?`${c.url}&${r}`:`${c.url}?${r}`}var w=class{constructor(e={}){this.ws=null;this.connectionOptions=null;this.listeners=new Map;this.reconnectAttempts=0;this.reconnectTimeout=null;this.intentionalClose=!1;var r,i,n,s,a;this.reconnect=(r=e.reconnect)!=null?r:!0,this.maxReconnectAttempts=Math.max(0,(i=e.maxReconnectAttempts)!=null?i:5),this.reconnectDelayMs=Math.max(0,(n=e.reconnectDelayMs)!=null?n:500),this.maxReconnectDelayMs=Math.max(this.reconnectDelayMs,(s=e.maxReconnectDelayMs)!=null?s:3e4);let t=(a=e.webSocket)!=null?a:globalThis.WebSocket;if(typeof t!="function")throw new Error("ElectronSocketAdapter: globalThis.WebSocket is not available. Pass a WebSocket constructor via options.webSocket. In the Electron main process you can use the `ws` package.");this.WebSocketCtor=t}connect(e){return this.connectionOptions=e,this.intentionalClose=!1,this.reconnectAttempts=0,this.openConnection(e)}async disconnect(){this.intentionalClose=!0,this.clearReconnectTimeout(),this.ws&&(this.ws.close(1e3,"client disconnect"),this.ws=null)}subscribe(e,t){return this.listeners.has(e)||this.listeners.set(e,new Set),this.listeners.get(e).add(t),()=>{let r=this.listeners.get(e);r&&(r.delete(t),r.size===0&&this.listeners.delete(e))}}async publish(e,t){var i,n;if(!this.ws||this.ws.readyState!==this.ws.OPEN)throw new Error(`ElectronSocketAdapter: cannot publish "${e}" \u2014 not connected (readyState=${(n=(i=this.ws)==null?void 0:i.readyState)!=null?n:"null"}).`);let r={event:e,payload:t};this.ws.send(JSON.stringify(r))}isConnected(){return this.ws!==null&&this.ws.readyState===this.ws.OPEN}openConnection(e){return new Promise((t,r)=>{let i=Q(e),n;try{n=new this.WebSocketCtor(i)}catch(s){r(s instanceof Error?s:new Error(String(s)));return}n.onopen=()=>{this.ws=n,this.reconnectAttempts=0,t()},n.onerror=()=>{this.ws||r(new Error("ElectronSocketAdapter: connection failed"))},n.onclose=()=>{this.ws===n&&(this.ws=null),!this.intentionalClose&&this.reconnect&&this.connectionOptions&&this.reconnectAttempts<this.maxReconnectAttempts&&this.scheduleReconnect()},n.onmessage=s=>{this.handleMessage(s.data)}})}handleMessage(e){if(typeof e!="string")return;let t;try{t=JSON.parse(e)}catch{return}if(typeof t!="object"||t===null||typeof t.event!="string")return;let{event:r,payload:i}=t,n=this.listeners.get(r);if(n)for(let s of n)try{s(i)}catch{}}scheduleReconnect(){this.clearReconnectTimeout();let e=++this.reconnectAttempts,t=Math.min(this.reconnectDelayMs*Math.pow(2,e-1),this.maxReconnectDelayMs);this.reconnectTimeout=setTimeout(()=>{!this.intentionalClose&&this.connectionOptions&&this.openConnection(this.connectionOptions).catch(()=>{})},t)}clearReconnectTimeout(){this.reconnectTimeout!==null&&(clearTimeout(this.reconnectTimeout),this.reconnectTimeout=null)}};var H=!0;var S=b(require("node:fs")),M=b(require("node:path")),R=class{constructor(e){var r;let t=(r=e.fileName)!=null?r:"storage.json";S.default.mkdirSync(e.storageDir,{recursive:!0}),this.filePath=M.default.join(e.storageDir,t);try{this.data=JSON.parse(S.default.readFileSync(this.filePath,"utf-8"))}catch{this.data={}}}async getItem(e){let t=this.data[e];return t!==void 0?t:null}async setItem(e,t){this.data[e]=t,await S.default.promises.writeFile(this.filePath,JSON.stringify(this.data,null,2),"utf-8")}async removeItem(e){delete this.data[e],await S.default.promises.writeFile(this.filePath,JSON.stringify(this.data,null,2),"utf-8")}};var z={platform:"electron",ready:!0,notes:"All adapter domains implemented: SQLiteAdapter (db), ElectronHttpAdapter (http), ElectronSocketAdapter (socket), ElectronStorageAdapter (storage), ElectronPlatformAdapter (platform), ElectronExportAdapter + ElectronNotificationAdapter (desktop)."};0&&(module.exports={ElectronExportAdapter,ElectronHttpAdapter,ElectronNotificationAdapter,ElectronPlatformAdapter,ElectronSocketAdapter,ElectronStorageAdapter,OFPLATFORM_ELECTRON_HTTP_ADAPTERS_READY,OFPLATFORM_ELECTRON_SOCKET_ADAPTERS_READY,OFPLATFORM_ELECTRON_STATUS,SQLiteAdapter,SQLiteExecutor,SQLiteQueryBuilder});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ofplatform-electron",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Electron platform adapters for of* host apps.",
|
|
6
6
|
"author": {
|
|
@@ -24,19 +24,20 @@
|
|
|
24
24
|
"clean": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\"",
|
|
25
25
|
"build": "npm run clean && tsc -p tsconfig.build.json && node esbuild.config.js",
|
|
26
26
|
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
27
|
-
"
|
|
27
|
+
"test": "npm run build && node --test ./tests/*.test.js",
|
|
28
|
+
"ci:check": "npm run typecheck && npm run test",
|
|
28
29
|
"prepublishOnly": "npm run ci:check",
|
|
29
30
|
"prepack": "npm run build",
|
|
30
31
|
"bundle": "node esbuild.config.js"
|
|
31
32
|
},
|
|
32
33
|
"dependencies": {
|
|
33
34
|
"better-sqlite3": "^11.8.1",
|
|
34
|
-
"ofcore": "0.
|
|
35
|
+
"ofcore": "0.2.0-alpha.0"
|
|
35
36
|
},
|
|
36
37
|
"devDependencies": {
|
|
37
38
|
"@types/better-sqlite3": "^7.6.12",
|
|
38
|
-
"
|
|
39
|
-
"
|
|
39
|
+
"esbuild": "^0.25.11",
|
|
40
|
+
"typescript": "^5.9.3"
|
|
40
41
|
},
|
|
41
42
|
"publishConfig": {
|
|
42
43
|
"access": "public"
|