@walkeros/server-destination-sqlite 4.0.0 → 4.1.0-next-1778155282668
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +90 -34
- package/dist/dev.d.mts +23 -4
- package/dist/dev.d.ts +23 -4
- package/dist/dev.js +1 -1
- package/dist/dev.js.map +1 -1
- package/dist/dev.mjs +1 -1
- package/dist/dev.mjs.map +1 -1
- package/dist/examples/index.d.mts +23 -4
- package/dist/examples/index.d.ts +23 -4
- package/dist/examples/index.js +2 -0
- package/dist/examples/index.mjs +2 -0
- package/dist/index.d.mts +75 -8
- package/dist/index.d.ts +75 -8
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/dist/walkerOS.json +2 -2
- package/package.json +4 -4
package/dist/index.d.mts
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
|
-
import { Destination as Destination$1, Mapping as Mapping$1, Flow, WalkerOS } from '@walkeros/core';
|
|
1
|
+
import { Destination as Destination$1, Mapping as Mapping$1, SetupFn as SetupFn$1, Flow, WalkerOS, LifecycleContext } from '@walkeros/core';
|
|
2
2
|
import { DestinationServer } from '@walkeros/server-core';
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* @deprecated Use `config.setup` instead. Kept for one minor cycle.
|
|
6
|
+
* `'auto'` maps to `setup: true`, `'manual'` maps to `setup: false`.
|
|
7
|
+
* Removed in the next major.
|
|
8
|
+
*/
|
|
4
9
|
type SchemaMode = 'auto' | 'manual';
|
|
5
10
|
/**
|
|
6
11
|
* Thin cross-driver connection interface. Both drivers are adapted to this shape.
|
|
@@ -14,6 +19,8 @@ interface SqliteClient {
|
|
|
14
19
|
* Prepare a statement for repeated execution. Returned function binds args and runs.
|
|
15
20
|
*/
|
|
16
21
|
prepare: (sql: string) => (args: ReadonlyArray<unknown>) => Promise<void>;
|
|
22
|
+
/** Run a query that returns rows. Used by setup() for sqlite_master and PRAGMA table_info. */
|
|
23
|
+
query: (sql: string, args?: ReadonlyArray<unknown>) => Promise<ReadonlyArray<Record<string, unknown>>>;
|
|
17
24
|
/** Close the connection. */
|
|
18
25
|
close: () => Promise<void>;
|
|
19
26
|
}
|
|
@@ -34,14 +41,26 @@ interface SqliteSettings {
|
|
|
34
41
|
/** Target table name. Defaults to `events`. */
|
|
35
42
|
table?: string;
|
|
36
43
|
/**
|
|
37
|
-
*
|
|
38
|
-
* `
|
|
39
|
-
*
|
|
44
|
+
* @deprecated Use `config.setup` instead. Kept for one minor cycle.
|
|
45
|
+
* `'auto'` maps to `setup: true` (init runs CREATE TABLE for the legacy schema).
|
|
46
|
+
* `'manual'` maps to `setup: false`. Removed in the next major.
|
|
40
47
|
*/
|
|
41
48
|
schema?: SchemaMode;
|
|
42
49
|
_client?: SqliteClient;
|
|
43
50
|
_runInsert?: (args: ReadonlyArray<unknown>) => Promise<void>;
|
|
44
51
|
_ownedClient?: boolean;
|
|
52
|
+
/**
|
|
53
|
+
* Internal flag set by the migration shim. When true, init() runs the legacy
|
|
54
|
+
* 13-column CREATE TABLE path for backward compatibility. Otherwise init()
|
|
55
|
+
* assumes the table already exists (created via `walkeros setup destination.<id>`).
|
|
56
|
+
*/
|
|
57
|
+
_legacyAutoCreate?: boolean;
|
|
58
|
+
/**
|
|
59
|
+
* Internal flag set by the migration shim. When true (legacy `schema: 'manual'`),
|
|
60
|
+
* init() skips the modern table-existence probe so the user can bring their own
|
|
61
|
+
* table and column shape without hitting the new "table not found" hard-fail.
|
|
62
|
+
*/
|
|
63
|
+
_legacySkipProbe?: boolean;
|
|
45
64
|
}
|
|
46
65
|
interface Settings {
|
|
47
66
|
sqlite: SqliteSettings;
|
|
@@ -52,7 +71,35 @@ interface Mapping {
|
|
|
52
71
|
table?: string;
|
|
53
72
|
}
|
|
54
73
|
/**
|
|
55
|
-
*
|
|
74
|
+
* Provisioning options for `walkeros setup destination.<name>`.
|
|
75
|
+
* Triggered only by the explicit CLI command. Idempotent, never auto-run.
|
|
76
|
+
*
|
|
77
|
+
* Connection URL and target table are read from `settings.sqlite.url` and
|
|
78
|
+
* `settings.sqlite.table` (single source of truth, not duplicated here).
|
|
79
|
+
*/
|
|
80
|
+
interface Setup {
|
|
81
|
+
/** Pragmas to apply at setup time. Defaults: journal_mode=WAL, synchronous=NORMAL, foreign_keys=ON, temp_store=MEMORY. */
|
|
82
|
+
pragmas?: Record<string, string | number>;
|
|
83
|
+
/** Schema columns. Default: 15-column walkerOS Event v4 canonical (only `name` REQUIRED). */
|
|
84
|
+
schema?: SetupColumn[];
|
|
85
|
+
/** Indexes to create after the table. Optional. */
|
|
86
|
+
indexes?: SetupIndex[];
|
|
87
|
+
}
|
|
88
|
+
/** Single column in the SQLite schema. */
|
|
89
|
+
interface SetupColumn {
|
|
90
|
+
name: string;
|
|
91
|
+
type: 'TEXT' | 'INTEGER' | 'REAL' | 'BLOB' | 'NUMERIC';
|
|
92
|
+
notNull?: boolean;
|
|
93
|
+
primaryKey?: boolean;
|
|
94
|
+
}
|
|
95
|
+
/** SQLite index definition. */
|
|
96
|
+
interface SetupIndex {
|
|
97
|
+
name: string;
|
|
98
|
+
columns: string[];
|
|
99
|
+
unique?: boolean;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Env, optional driver override. Production leaves this undefined and the
|
|
56
103
|
* destination loads better-sqlite3 or @libsql/client dynamically. Tests
|
|
57
104
|
* provide a factory via `SqliteDriver` or a pre-built client via `client`.
|
|
58
105
|
*/
|
|
@@ -60,7 +107,7 @@ interface Env extends DestinationServer.Env {
|
|
|
60
107
|
SqliteDriver?: SqliteClientFactory;
|
|
61
108
|
client?: SqliteClient;
|
|
62
109
|
}
|
|
63
|
-
type Types = Destination$1.Types<Settings, Mapping, Env, InitSettings>;
|
|
110
|
+
type Types = Destination$1.Types<Settings, Mapping, Env, InitSettings, Setup>;
|
|
64
111
|
interface Destination extends DestinationServer.Destination<Types> {
|
|
65
112
|
init: DestinationServer.InitFn<Types>;
|
|
66
113
|
}
|
|
@@ -69,6 +116,7 @@ type Config = {
|
|
|
69
116
|
} & DestinationServer.Config<Types>;
|
|
70
117
|
type InitFn = DestinationServer.InitFn<Types>;
|
|
71
118
|
type PushFn = DestinationServer.PushFn<Types>;
|
|
119
|
+
type SetupFn = SetupFn$1<Config, Env>;
|
|
72
120
|
type PartialConfig = DestinationServer.PartialConfig<Types>;
|
|
73
121
|
type PushEvents = DestinationServer.PushEvents<Mapping>;
|
|
74
122
|
type Rule = Mapping$1.Rule<Mapping>;
|
|
@@ -87,12 +135,16 @@ type index$1_Rule = Rule;
|
|
|
87
135
|
type index$1_Rules = Rules;
|
|
88
136
|
type index$1_SchemaMode = SchemaMode;
|
|
89
137
|
type index$1_Settings = Settings;
|
|
138
|
+
type index$1_Setup = Setup;
|
|
139
|
+
type index$1_SetupColumn = SetupColumn;
|
|
140
|
+
type index$1_SetupFn = SetupFn;
|
|
141
|
+
type index$1_SetupIndex = SetupIndex;
|
|
90
142
|
type index$1_SqliteClient = SqliteClient;
|
|
91
143
|
type index$1_SqliteClientFactory = SqliteClientFactory;
|
|
92
144
|
type index$1_SqliteSettings = SqliteSettings;
|
|
93
145
|
type index$1_Types = Types;
|
|
94
146
|
declare namespace index$1 {
|
|
95
|
-
export type { index$1_Config as Config, index$1_Destination as Destination, index$1_Env as Env, index$1_InitFn as InitFn, index$1_InitSettings as InitSettings, index$1_Mapping as Mapping, index$1_PartialConfig as PartialConfig, index$1_PushEvents as PushEvents, index$1_PushFn as PushFn, index$1_Rule as Rule, index$1_Rules as Rules, index$1_SchemaMode as SchemaMode, index$1_Settings as Settings, index$1_SqliteClient as SqliteClient, index$1_SqliteClientFactory as SqliteClientFactory, index$1_SqliteSettings as SqliteSettings, index$1_Types as Types };
|
|
147
|
+
export type { index$1_Config as Config, index$1_Destination as Destination, index$1_Env as Env, index$1_InitFn as InitFn, index$1_InitSettings as InitSettings, index$1_Mapping as Mapping, index$1_PartialConfig as PartialConfig, index$1_PushEvents as PushEvents, index$1_PushFn as PushFn, index$1_Rule as Rule, index$1_Rules as Rules, index$1_SchemaMode as SchemaMode, index$1_Settings as Settings, index$1_Setup as Setup, index$1_SetupColumn as SetupColumn, index$1_SetupFn as SetupFn, index$1_SetupIndex as SetupIndex, index$1_SqliteClient as SqliteClient, index$1_SqliteClientFactory as SqliteClientFactory, index$1_SqliteSettings as SqliteSettings, index$1_Types as Types };
|
|
96
148
|
}
|
|
97
149
|
|
|
98
150
|
declare const push: Env;
|
|
@@ -167,6 +219,21 @@ declare function eventToRow(event: WalkerOS.Event): unknown[];
|
|
|
167
219
|
|
|
168
220
|
declare function isLibsqlUrl(url: string): boolean;
|
|
169
221
|
|
|
222
|
+
type WideConfig = DestinationServer.Config<Types>;
|
|
223
|
+
/**
|
|
224
|
+
* Default 15-column walkerOS Event v4 canonical schema.
|
|
225
|
+
* Mirrors BigQuery (Plan 2). Only `name` is REQUIRED.
|
|
226
|
+
*/
|
|
227
|
+
declare const DEFAULT_SCHEMA: SetupColumn[];
|
|
228
|
+
declare const DEFAULT_PRAGMAS: Record<string, string>;
|
|
229
|
+
declare const DEFAULT_SETUP: Required<Setup>;
|
|
230
|
+
interface SetupResult {
|
|
231
|
+
tableCreated: boolean;
|
|
232
|
+
pragmasApplied: string[];
|
|
233
|
+
indexesCreated: string[];
|
|
234
|
+
}
|
|
235
|
+
declare const setup: (ctx: LifecycleContext<WideConfig, Env>) => Promise<SetupResult | undefined>;
|
|
236
|
+
|
|
170
237
|
declare const destinationSQLite: Destination;
|
|
171
238
|
|
|
172
|
-
export { CANONICAL_COLUMNS, index$1 as DestinationSQLite, buildCreateTableSql, buildInsertSql, destinationSQLite as default, destinationSQLite, eventToRow, index as examples, isLibsqlUrl };
|
|
239
|
+
export { CANONICAL_COLUMNS, DEFAULT_PRAGMAS, DEFAULT_SCHEMA, DEFAULT_SETUP, index$1 as DestinationSQLite, buildCreateTableSql, buildInsertSql, destinationSQLite as default, destinationSQLite, eventToRow, index as examples, isLibsqlUrl, setup };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
|
-
import { Destination as Destination$1, Mapping as Mapping$1, Flow, WalkerOS } from '@walkeros/core';
|
|
1
|
+
import { Destination as Destination$1, Mapping as Mapping$1, SetupFn as SetupFn$1, Flow, WalkerOS, LifecycleContext } from '@walkeros/core';
|
|
2
2
|
import { DestinationServer } from '@walkeros/server-core';
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* @deprecated Use `config.setup` instead. Kept for one minor cycle.
|
|
6
|
+
* `'auto'` maps to `setup: true`, `'manual'` maps to `setup: false`.
|
|
7
|
+
* Removed in the next major.
|
|
8
|
+
*/
|
|
4
9
|
type SchemaMode = 'auto' | 'manual';
|
|
5
10
|
/**
|
|
6
11
|
* Thin cross-driver connection interface. Both drivers are adapted to this shape.
|
|
@@ -14,6 +19,8 @@ interface SqliteClient {
|
|
|
14
19
|
* Prepare a statement for repeated execution. Returned function binds args and runs.
|
|
15
20
|
*/
|
|
16
21
|
prepare: (sql: string) => (args: ReadonlyArray<unknown>) => Promise<void>;
|
|
22
|
+
/** Run a query that returns rows. Used by setup() for sqlite_master and PRAGMA table_info. */
|
|
23
|
+
query: (sql: string, args?: ReadonlyArray<unknown>) => Promise<ReadonlyArray<Record<string, unknown>>>;
|
|
17
24
|
/** Close the connection. */
|
|
18
25
|
close: () => Promise<void>;
|
|
19
26
|
}
|
|
@@ -34,14 +41,26 @@ interface SqliteSettings {
|
|
|
34
41
|
/** Target table name. Defaults to `events`. */
|
|
35
42
|
table?: string;
|
|
36
43
|
/**
|
|
37
|
-
*
|
|
38
|
-
* `
|
|
39
|
-
*
|
|
44
|
+
* @deprecated Use `config.setup` instead. Kept for one minor cycle.
|
|
45
|
+
* `'auto'` maps to `setup: true` (init runs CREATE TABLE for the legacy schema).
|
|
46
|
+
* `'manual'` maps to `setup: false`. Removed in the next major.
|
|
40
47
|
*/
|
|
41
48
|
schema?: SchemaMode;
|
|
42
49
|
_client?: SqliteClient;
|
|
43
50
|
_runInsert?: (args: ReadonlyArray<unknown>) => Promise<void>;
|
|
44
51
|
_ownedClient?: boolean;
|
|
52
|
+
/**
|
|
53
|
+
* Internal flag set by the migration shim. When true, init() runs the legacy
|
|
54
|
+
* 13-column CREATE TABLE path for backward compatibility. Otherwise init()
|
|
55
|
+
* assumes the table already exists (created via `walkeros setup destination.<id>`).
|
|
56
|
+
*/
|
|
57
|
+
_legacyAutoCreate?: boolean;
|
|
58
|
+
/**
|
|
59
|
+
* Internal flag set by the migration shim. When true (legacy `schema: 'manual'`),
|
|
60
|
+
* init() skips the modern table-existence probe so the user can bring their own
|
|
61
|
+
* table and column shape without hitting the new "table not found" hard-fail.
|
|
62
|
+
*/
|
|
63
|
+
_legacySkipProbe?: boolean;
|
|
45
64
|
}
|
|
46
65
|
interface Settings {
|
|
47
66
|
sqlite: SqliteSettings;
|
|
@@ -52,7 +71,35 @@ interface Mapping {
|
|
|
52
71
|
table?: string;
|
|
53
72
|
}
|
|
54
73
|
/**
|
|
55
|
-
*
|
|
74
|
+
* Provisioning options for `walkeros setup destination.<name>`.
|
|
75
|
+
* Triggered only by the explicit CLI command. Idempotent, never auto-run.
|
|
76
|
+
*
|
|
77
|
+
* Connection URL and target table are read from `settings.sqlite.url` and
|
|
78
|
+
* `settings.sqlite.table` (single source of truth, not duplicated here).
|
|
79
|
+
*/
|
|
80
|
+
interface Setup {
|
|
81
|
+
/** Pragmas to apply at setup time. Defaults: journal_mode=WAL, synchronous=NORMAL, foreign_keys=ON, temp_store=MEMORY. */
|
|
82
|
+
pragmas?: Record<string, string | number>;
|
|
83
|
+
/** Schema columns. Default: 15-column walkerOS Event v4 canonical (only `name` REQUIRED). */
|
|
84
|
+
schema?: SetupColumn[];
|
|
85
|
+
/** Indexes to create after the table. Optional. */
|
|
86
|
+
indexes?: SetupIndex[];
|
|
87
|
+
}
|
|
88
|
+
/** Single column in the SQLite schema. */
|
|
89
|
+
interface SetupColumn {
|
|
90
|
+
name: string;
|
|
91
|
+
type: 'TEXT' | 'INTEGER' | 'REAL' | 'BLOB' | 'NUMERIC';
|
|
92
|
+
notNull?: boolean;
|
|
93
|
+
primaryKey?: boolean;
|
|
94
|
+
}
|
|
95
|
+
/** SQLite index definition. */
|
|
96
|
+
interface SetupIndex {
|
|
97
|
+
name: string;
|
|
98
|
+
columns: string[];
|
|
99
|
+
unique?: boolean;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Env, optional driver override. Production leaves this undefined and the
|
|
56
103
|
* destination loads better-sqlite3 or @libsql/client dynamically. Tests
|
|
57
104
|
* provide a factory via `SqliteDriver` or a pre-built client via `client`.
|
|
58
105
|
*/
|
|
@@ -60,7 +107,7 @@ interface Env extends DestinationServer.Env {
|
|
|
60
107
|
SqliteDriver?: SqliteClientFactory;
|
|
61
108
|
client?: SqliteClient;
|
|
62
109
|
}
|
|
63
|
-
type Types = Destination$1.Types<Settings, Mapping, Env, InitSettings>;
|
|
110
|
+
type Types = Destination$1.Types<Settings, Mapping, Env, InitSettings, Setup>;
|
|
64
111
|
interface Destination extends DestinationServer.Destination<Types> {
|
|
65
112
|
init: DestinationServer.InitFn<Types>;
|
|
66
113
|
}
|
|
@@ -69,6 +116,7 @@ type Config = {
|
|
|
69
116
|
} & DestinationServer.Config<Types>;
|
|
70
117
|
type InitFn = DestinationServer.InitFn<Types>;
|
|
71
118
|
type PushFn = DestinationServer.PushFn<Types>;
|
|
119
|
+
type SetupFn = SetupFn$1<Config, Env>;
|
|
72
120
|
type PartialConfig = DestinationServer.PartialConfig<Types>;
|
|
73
121
|
type PushEvents = DestinationServer.PushEvents<Mapping>;
|
|
74
122
|
type Rule = Mapping$1.Rule<Mapping>;
|
|
@@ -87,12 +135,16 @@ type index$1_Rule = Rule;
|
|
|
87
135
|
type index$1_Rules = Rules;
|
|
88
136
|
type index$1_SchemaMode = SchemaMode;
|
|
89
137
|
type index$1_Settings = Settings;
|
|
138
|
+
type index$1_Setup = Setup;
|
|
139
|
+
type index$1_SetupColumn = SetupColumn;
|
|
140
|
+
type index$1_SetupFn = SetupFn;
|
|
141
|
+
type index$1_SetupIndex = SetupIndex;
|
|
90
142
|
type index$1_SqliteClient = SqliteClient;
|
|
91
143
|
type index$1_SqliteClientFactory = SqliteClientFactory;
|
|
92
144
|
type index$1_SqliteSettings = SqliteSettings;
|
|
93
145
|
type index$1_Types = Types;
|
|
94
146
|
declare namespace index$1 {
|
|
95
|
-
export type { index$1_Config as Config, index$1_Destination as Destination, index$1_Env as Env, index$1_InitFn as InitFn, index$1_InitSettings as InitSettings, index$1_Mapping as Mapping, index$1_PartialConfig as PartialConfig, index$1_PushEvents as PushEvents, index$1_PushFn as PushFn, index$1_Rule as Rule, index$1_Rules as Rules, index$1_SchemaMode as SchemaMode, index$1_Settings as Settings, index$1_SqliteClient as SqliteClient, index$1_SqliteClientFactory as SqliteClientFactory, index$1_SqliteSettings as SqliteSettings, index$1_Types as Types };
|
|
147
|
+
export type { index$1_Config as Config, index$1_Destination as Destination, index$1_Env as Env, index$1_InitFn as InitFn, index$1_InitSettings as InitSettings, index$1_Mapping as Mapping, index$1_PartialConfig as PartialConfig, index$1_PushEvents as PushEvents, index$1_PushFn as PushFn, index$1_Rule as Rule, index$1_Rules as Rules, index$1_SchemaMode as SchemaMode, index$1_Settings as Settings, index$1_Setup as Setup, index$1_SetupColumn as SetupColumn, index$1_SetupFn as SetupFn, index$1_SetupIndex as SetupIndex, index$1_SqliteClient as SqliteClient, index$1_SqliteClientFactory as SqliteClientFactory, index$1_SqliteSettings as SqliteSettings, index$1_Types as Types };
|
|
96
148
|
}
|
|
97
149
|
|
|
98
150
|
declare const push: Env;
|
|
@@ -167,6 +219,21 @@ declare function eventToRow(event: WalkerOS.Event): unknown[];
|
|
|
167
219
|
|
|
168
220
|
declare function isLibsqlUrl(url: string): boolean;
|
|
169
221
|
|
|
222
|
+
type WideConfig = DestinationServer.Config<Types>;
|
|
223
|
+
/**
|
|
224
|
+
* Default 15-column walkerOS Event v4 canonical schema.
|
|
225
|
+
* Mirrors BigQuery (Plan 2). Only `name` is REQUIRED.
|
|
226
|
+
*/
|
|
227
|
+
declare const DEFAULT_SCHEMA: SetupColumn[];
|
|
228
|
+
declare const DEFAULT_PRAGMAS: Record<string, string>;
|
|
229
|
+
declare const DEFAULT_SETUP: Required<Setup>;
|
|
230
|
+
interface SetupResult {
|
|
231
|
+
tableCreated: boolean;
|
|
232
|
+
pragmasApplied: string[];
|
|
233
|
+
indexesCreated: string[];
|
|
234
|
+
}
|
|
235
|
+
declare const setup: (ctx: LifecycleContext<WideConfig, Env>) => Promise<SetupResult | undefined>;
|
|
236
|
+
|
|
170
237
|
declare const destinationSQLite: Destination;
|
|
171
238
|
|
|
172
|
-
export { CANONICAL_COLUMNS, index$1 as DestinationSQLite, buildCreateTableSql, buildInsertSql, destinationSQLite as default, destinationSQLite, eventToRow, index as examples, isLibsqlUrl };
|
|
239
|
+
export { CANONICAL_COLUMNS, DEFAULT_PRAGMAS, DEFAULT_SCHEMA, DEFAULT_SETUP, index$1 as DestinationSQLite, buildCreateTableSql, buildInsertSql, destinationSQLite as default, destinationSQLite, eventToRow, index as examples, isLibsqlUrl, setup };
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var mod,__defProp=Object.defineProperty,__getOwnPropDesc=Object.getOwnPropertyDescriptor,__getOwnPropNames=Object.getOwnPropertyNames,__hasOwnProp=Object.prototype.hasOwnProperty,__export=(target,all)=>{for(var name in all)__defProp(target,name,{get:all[name],enumerable:!0})},index_exports={};__export(index_exports,{CANONICAL_COLUMNS:()=>CANONICAL_COLUMNS,DestinationSQLite:()=>types_exports,buildCreateTableSql:()=>buildCreateTableSql,buildInsertSql:()=>buildInsertSql,default:()=>index_default,destinationSQLite:()=>destinationSQLite,eventToRow:()=>eventToRow,examples:()=>examples_exports,isLibsqlUrl:()=>isLibsqlUrl}),module.exports=(mod=index_exports,((to,from,except,desc)=>{if(from&&"object"==typeof from||"function"==typeof from)for(let key of __getOwnPropNames(from))__hasOwnProp.call(to,key)||key===except||__defProp(to,key,{get:()=>from[key],enumerable:!(desc=__getOwnPropDesc(from,key))||desc.enumerable});return to})(__defProp({},"__esModule",{value:!0}),mod));var import_core=require("@walkeros/core");function isSqliteEnv(env){if(!(0,import_core.isObject)(env))return!1;const maybe=env;return"function"==typeof maybe.SqliteDriver||(0,import_core.isObject)(maybe.client??null)}var LIBSQL_URL_PREFIXES=["libsql://","http://","https://","ws://","wss://"];function isLibsqlUrl(url){return LIBSQL_URL_PREFIXES.some(p=>url.startsWith(p))}var defaultFactory=async(url,authToken)=>isLibsqlUrl(url)?async function(url,authToken){let createClient;try{const loaded=require("@libsql/client"),fn=loaded.createClient??loaded.default?.createClient;if("function"!=typeof fn)throw new Error("createClient export not found on @libsql/client");createClient=fn}catch(err){throw new Error(`@walkeros/server-destination-sqlite: @libsql/client is not installed. Install it with \`npm install @libsql/client\`, or use a local file URL. Original error: ${String(err)}`)}const client=createClient({url:url,authToken:authToken});return{async execute(sql,args=[]){await client.execute({sql:sql,args:args})},prepare:sql=>async args=>{await client.execute({sql:sql,args:args})},async close(){client.close()}}}(url,authToken):async function(filePath){let Database;try{const loaded=require("better-sqlite3");Database="default"in loaded&&"function"==typeof loaded.default?loaded.default:loaded}catch(err){throw new Error(`@walkeros/server-destination-sqlite: better-sqlite3 is not installed. Install it with \`npm install better-sqlite3\`, or switch settings.sqlite.url to a libSQL URL. Original error: ${String(err)}`)}const db=new Database(filePath);return{async execute(sql,args=[]){db.prepare(sql).run(...args)},prepare(sql){const stmt=db.prepare(sql);return async args=>{stmt.run(...args)}},async close(){db.close()}}}(url);var import_core2=require("@walkeros/core"),CANONICAL_COLUMNS=["timestamp","event_id","name","entity","action","session_id","user_id","page_url","page_title","referrer_url","data","globals","consent"];function buildCreateTableSql(table){return`CREATE TABLE IF NOT EXISTS ${table} (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,\n timestamp INTEGER,\n event_id TEXT,\n name TEXT,\n entity TEXT,\n action TEXT,\n session_id TEXT,\n user_id TEXT,\n page_url TEXT,\n page_title TEXT,\n referrer_url TEXT,\n data TEXT,\n globals TEXT,\n consent TEXT\n)`}function buildInsertSql(table){return`INSERT INTO ${table} (${CANONICAL_COLUMNS.join(", ")}) VALUES (${CANONICAL_COLUMNS.map(()=>"?").join(", ")})`}function eventToRow(event){const data=(0,import_core2.isObject)(event.data)?event.data:{},title=(0,import_core2.isString)(data.title)?data.title:"";return["number"==typeof event.timestamp?event.timestamp:Date.now(),event.id??"",event.name??"",event.entity??"",event.action??"",event.user?.session??"",event.user?.id??"",event.source?.url??"",title,event.source?.referrer??"",JSON.stringify(data),JSON.stringify(event.globals??{}),JSON.stringify(event.consent??{})]}var import_core3=require("@walkeros/core"),types_exports={},examples_exports={};__export(examples_exports,{env:()=>env_exports,step:()=>step_exports});var env_exports={};__export(env_exports,{push:()=>push2,simulation:()=>simulation});var mockClient={execute:()=>Promise.resolve(),prepare:()=>()=>Promise.resolve(),close:()=>Promise.resolve()},push2={SqliteDriver:()=>Promise.resolve(mockClient)},simulation=["call:client.prepare","call:client.execute"],step_exports={};__export(step_exports,{customTable:()=>customTable,defaultInsert:()=>defaultInsert,ignoredEvent:()=>ignoredEvent,orderComplete:()=>orderComplete,tableOverride:()=>tableOverride});var import_core4=require("@walkeros/core"),defaultInsert={title:"Default insert",description:"A walker event is inserted into the default events table with canonical columns and JSON-encoded sections.",in:(0,import_core4.getEvent)("page view",{timestamp:1700000100,id:"evt-1",user:{session:"sess-1",id:"user-42"},data:{title:"Home"},source:{type:"browser",platform:"web",url:"https://example.com/",referrer:"https://example.com/prev"},globals:{env:"prod"},consent:{analytics:!0}}),out:[["client.runInsert",[1700000100,"evt-1","page view","page","view","sess-1","user-42","https://example.com/","Home","https://example.com/prev",JSON.stringify({title:"Home"}),JSON.stringify({env:"prod"}),JSON.stringify({analytics:!0})]]]},customTable={title:"Custom table",description:"A destination-level table setting inserts events into a custom SQLite table with the same column layout.",in:(0,import_core4.getEvent)("form submit",{timestamp:1700000101,id:"evt-2",user:{session:"sess-99",id:""},data:{type:"contact"},source:{type:"browser",platform:"web",url:"https://example.com/contact"},globals:{},consent:{}}),settings:{sqlite:{url:":memory:",table:"siteEvents"}},out:[["client.runInsert",[1700000101,"evt-2","form submit","form","submit","sess-99","","https://example.com/contact","","",JSON.stringify({type:"contact"}),JSON.stringify({}),JSON.stringify({})]]]},orderComplete={title:"Order insert",description:"An order complete is inserted with numeric data serialized as JSON in the data column.",in:(0,import_core4.getEvent)("order complete",{timestamp:1700000102,id:"evt-3",user:{session:"",id:""},data:{id:"ORD-1",total:99},source:{type:"collector",schema:"4"},globals:{},consent:{}}),out:[["client.runInsert",[1700000102,"evt-3","order complete","order","complete","","","","","",JSON.stringify({id:"ORD-1",total:99}),JSON.stringify({}),JSON.stringify({})]]]},tableOverride={title:"Table override",description:"A mapping rule overrides the target table so specific events are inserted into a dedicated SQLite table.",in:(0,import_core4.getEvent)("order complete",{timestamp:1700000103,id:"evt-4",user:{session:"",id:""},data:{id:"ORD-2",total:42},source:{type:"collector",schema:"4"},globals:{},consent:{}}),mapping:{settings:{table:"orders"}},out:[["client.runInsert",[1700000103,"evt-4","order complete","order","complete","","","","","",JSON.stringify({id:"ORD-2",total:42}),JSON.stringify({}),JSON.stringify({})]]]},ignoredEvent={public:!1,in:(0,import_core4.getEvent)("debug noise",{timestamp:1700000104,id:"evt-5",source:{type:"collector",schema:"4"}}),mapping:{ignore:!0},out:[]},destinationSQLite={type:"sqlite",config:{},async init({config:partialConfig,logger:logger,env:env}){const config=function(partialConfig={},logger){const sqlite=(partialConfig.settings??{}).sqlite??{};sqlite.url||logger.throw("Config settings sqlite.url missing");const sqliteSettings={...sqlite,url:sqlite.url,table:sqlite.table??"events",schema:sqlite.schema??"auto"};"manual"!==sqliteSettings.schema||partialConfig.mapping||logger.throw('Config settings sqlite.schema="manual" requires a mapping (no default column mapping will be used).');const settings={sqlite:sqliteSettings};return{...partialConfig,settings:settings}}(partialConfig,logger),sqlite=config.settings.sqlite;if(sqlite._client)return config;let client;if(isSqliteEnv(env)){const envTyped=env;envTyped.client?client=envTyped.client:envTyped.SqliteDriver&&(client=await envTyped.SqliteDriver(sqlite.url,sqlite.authToken))}if(!client)try{client=await async function(url,authToken){return defaultFactory(url,authToken)}(sqlite.url,sqlite.authToken)}catch(err){return logger.throw(`@walkeros/server-destination-sqlite: driver load failed: ${String(err)}`),config}if("auto"===sqlite.schema)try{await client.execute(buildCreateTableSql(sqlite.table??"events"))}catch(err){return logger.throw(`@walkeros/server-destination-sqlite: CREATE TABLE failed: ${String(err)}`),config}return sqlite._client=client,sqlite._runInsert=client.prepare(buildInsertSql(sqlite.table??"events")),sqlite._ownedClient=!(isSqliteEnv(env)&&env.client),config},push:async(event,context)=>await async function(event,{config:config,rule:rule,logger:logger}){const settings=config.settings,sqlite=settings?.sqlite;if(!sqlite)return void logger.warn("SQLite settings missing");const client=sqlite._client;if(!client)return void logger.warn("SQLite client not initialized");const ruleSettings=rule?.settings??{},ruleTable=(0,import_core3.isString)(ruleSettings.table)?ruleSettings.table:"",effectiveTable=ruleTable||sqlite.table||"events",runInsert=ruleTable&&ruleTable!==sqlite.table?client.prepare(buildInsertSql(effectiveTable)):sqlite._runInsert;if(!runInsert)return void logger.warn("SQLite insert statement not prepared");const row=eventToRow(event);logger.debug("SQLite INSERT",{table:effectiveTable,eventName:event.name});try{await runInsert(row),logger.debug("SQLite INSERT complete",{table:effectiveTable})}catch(error){logger.error("SQLite INSERT failed",{table:effectiveTable,error:error instanceof Error?error.message:String(error)})}}(event,context),async destroy({config:config}){const settings=config?.settings,sqlite=settings?.sqlite;if(!sqlite)return;const client=sqlite._client;if(client&&sqlite._ownedClient)try{await client.close()}finally{sqlite._client=void 0,sqlite._runInsert=void 0,sqlite._ownedClient=void 0}}},index_default=destinationSQLite;//# sourceMappingURL=index.js.map
|
|
1
|
+
"use strict";var mod,__defProp=Object.defineProperty,__getOwnPropDesc=Object.getOwnPropertyDescriptor,__getOwnPropNames=Object.getOwnPropertyNames,__hasOwnProp=Object.prototype.hasOwnProperty,__export=(target,all)=>{for(var name in all)__defProp(target,name,{get:all[name],enumerable:!0})},index_exports={};__export(index_exports,{CANONICAL_COLUMNS:()=>CANONICAL_COLUMNS,DEFAULT_PRAGMAS:()=>DEFAULT_PRAGMAS,DEFAULT_SCHEMA:()=>DEFAULT_SCHEMA,DEFAULT_SETUP:()=>DEFAULT_SETUP,DestinationSQLite:()=>types_exports,buildCreateTableSql:()=>buildCreateTableSql,buildInsertSql:()=>buildInsertSql,default:()=>index_default,destinationSQLite:()=>destinationSQLite,eventToRow:()=>eventToRow,examples:()=>examples_exports,isLibsqlUrl:()=>isLibsqlUrl,setup:()=>setup}),module.exports=(mod=index_exports,((to,from,except,desc)=>{if(from&&"object"==typeof from||"function"==typeof from)for(let key of __getOwnPropNames(from))__hasOwnProp.call(to,key)||key===except||__defProp(to,key,{get:()=>from[key],enumerable:!(desc=__getOwnPropDesc(from,key))||desc.enumerable});return to})(__defProp({},"__esModule",{value:!0}),mod));var import_core=require("@walkeros/core");function isSqliteEnv(env){if(!(0,import_core.isObject)(env))return!1;const maybe=env;return"function"==typeof maybe.SqliteDriver||(0,import_core.isObject)(maybe.client??null)}var LIBSQL_URL_PREFIXES=["libsql://","http://","https://","ws://","wss://"];function isLibsqlUrl(url){return LIBSQL_URL_PREFIXES.some(p=>url.startsWith(p))}var defaultFactory=async(url,authToken)=>isLibsqlUrl(url)?async function(url,authToken){let createClient;try{const loaded=require("@libsql/client"),fn=loaded.createClient??loaded.default?.createClient;if("function"!=typeof fn)throw new Error("createClient export not found on @libsql/client");createClient=fn}catch(err){throw new Error(`@walkeros/server-destination-sqlite: @libsql/client is not installed. Install it with \`npm install @libsql/client\`, or use a local file URL. Original error: ${String(err)}`)}const client=createClient({url:url,authToken:authToken});return{async execute(sql,args=[]){await client.execute({sql:sql,args:args})},prepare:sql=>async args=>{await client.execute({sql:sql,args:args})},async query(sql,args=[]){const result=await client.execute({sql:sql,args:args});return result?.rows??[]},async close(){client.close()}}}(url,authToken):async function(filePath){let Database;try{const loaded=require("better-sqlite3");Database="default"in loaded&&"function"==typeof loaded.default?loaded.default:loaded}catch(err){throw new Error(`@walkeros/server-destination-sqlite: better-sqlite3 is not installed. Install it with \`npm install better-sqlite3\`, or switch settings.sqlite.url to a libSQL URL. Original error: ${String(err)}`)}const db=new Database(filePath);return{async execute(sql,args=[]){db.prepare(sql).run(...args)},prepare(sql){const stmt=db.prepare(sql);return async args=>{stmt.run(...args)}},query:async(sql,args=[])=>db.prepare(sql).all(...args),async close(){db.close()}}}(url);async function createClientFromSettings(url,authToken){return defaultFactory(url,authToken)}var import_core2=require("@walkeros/core"),CANONICAL_COLUMNS=["timestamp","event_id","name","entity","action","session_id","user_id","page_url","page_title","referrer_url","data","globals","consent"];function buildCreateTableSql(table){return`CREATE TABLE IF NOT EXISTS ${table} (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,\n timestamp INTEGER,\n event_id TEXT,\n name TEXT,\n entity TEXT,\n action TEXT,\n session_id TEXT,\n user_id TEXT,\n page_url TEXT,\n page_title TEXT,\n referrer_url TEXT,\n data TEXT,\n globals TEXT,\n consent TEXT\n)`}function buildInsertSql(table){return`INSERT INTO ${table} (${CANONICAL_COLUMNS.join(", ")}) VALUES (${CANONICAL_COLUMNS.map(()=>"?").join(", ")})`}function eventToRow(event){const data=(0,import_core2.isObject)(event.data)?event.data:{},title=(0,import_core2.isString)(data.title)?data.title:"";return["number"==typeof event.timestamp?event.timestamp:Date.now(),event.id??"",event.name??"",event.entity??"",event.action??"",event.user?.session??"",event.user?.id??"",event.source?.url??"",title,event.source?.referrer??"",JSON.stringify(data),JSON.stringify(event.globals??{}),JSON.stringify(event.consent??{})]}var import_core3=require("@walkeros/core"),import_core4=require("@walkeros/core"),DEFAULT_SCHEMA=[{name:"name",type:"TEXT",notNull:!0},{name:"data",type:"TEXT"},{name:"context",type:"TEXT"},{name:"globals",type:"TEXT"},{name:"custom",type:"TEXT"},{name:"user",type:"TEXT"},{name:"nested",type:"TEXT"},{name:"consent",type:"TEXT"},{name:"id",type:"TEXT"},{name:"trigger",type:"TEXT"},{name:"entity",type:"TEXT"},{name:"action",type:"TEXT"},{name:"timestamp",type:"TEXT"},{name:"timing",type:"INTEGER"},{name:"source",type:"TEXT"}],DEFAULT_PRAGMAS={journal_mode:"WAL",synchronous:"NORMAL",foreign_keys:"ON",temp_store:"MEMORY"},DEFAULT_SETUP={pragmas:DEFAULT_PRAGMAS,schema:DEFAULT_SCHEMA,indexes:[]};function isString3(value){return"string"==typeof value}function isPragmaTableInfoRow(value){if("object"!=typeof value||null===value)return!1;const obj={...value};return isString3(obj.name)&&isString3(obj.type)}function isSqliteMasterRow(value){if("object"!=typeof value||null===value)return!1;return isString3({...value}.name)}async function tableExists(client,table){const rows=await client.query("SELECT name FROM sqlite_master WHERE type='table' AND name=?",[table]);for(const row of rows)if(isSqliteMasterRow(row)&&row.name===table)return!0;return!1}var setup=async ctx=>{const{config:config,env:env,logger:logger}=ctx,merged=(0,import_core4.resolveSetup)(config.setup,DEFAULT_SETUP);if(!merged)return void logger.debug("setup: skipped (config.setup is false or unset)");const options={pragmas:{...DEFAULT_PRAGMAS,...merged.pragmas??{}},schema:merged.schema??DEFAULT_SCHEMA,indexes:merged.indexes??[]},sqlite=config.settings?.sqlite;if(!sqlite||!sqlite.url)return void logger.throw("setup: settings.sqlite.url is missing");const table=sqlite.table??"events";let client,owned=!0;isSqliteEnv(env)&&env.client?(client=env.client,owned=!1):client=isSqliteEnv(env)&&env.SqliteDriver?await env.SqliteDriver(sqlite.url,sqlite.authToken):await createClientFromSettings(sqlite.url,sqlite.authToken);try{const pragmasApplied=[];for(const[key,value]of Object.entries(options.pragmas))await client.execute(`PRAGMA ${key} = ${value}`),pragmasApplied.push(key);const tableExisted=await tableExists(client,table);await client.execute(function(table,columns){return`CREATE TABLE IF NOT EXISTS ${table} (\n ${columns.map(c=>{const parts=[c.name,c.type];return c.primaryKey&&parts.push("PRIMARY KEY"),c.notNull&&parts.push("NOT NULL"),parts.join(" ")}).join(",\n ")}\n)`}(table,options.schema)),tableExisted&&await async function(client,table,declared,logger){const rows=await client.query(`PRAGMA table_info(${table})`),actualByName=new Map;for(const row of rows)isPragmaTableInfoRow(row)&&actualByName.set(row.name,row.type.toUpperCase());for(const declaredCol of declared){const actualType=actualByName.get(declaredCol.name);void 0!==actualType?actualType!==declaredCol.type.toUpperCase()&&logger.warn("setup.drift",{field:declaredCol.name,declared:declaredCol.type,actual:actualType}):logger.warn("setup.drift",{field:declaredCol.name,declared:declaredCol.type,actual:"missing"})}}(client,table,options.schema,logger);const indexesCreated=[];for(const idx of options.indexes){const unique=idx.unique?"UNIQUE ":"",cols=idx.columns.join(", ");await client.execute(`CREATE ${unique}INDEX IF NOT EXISTS ${idx.name} ON ${table}(${cols})`),indexesCreated.push(idx.name)}return{tableCreated:!tableExisted,pragmasApplied:pragmasApplied,indexesCreated:indexesCreated}}finally{if(owned)try{await client.close()}catch{}}},types_exports={},examples_exports={};__export(examples_exports,{env:()=>env_exports,step:()=>step_exports});var env_exports={};__export(env_exports,{push:()=>push2,simulation:()=>simulation});var mockClient={execute:()=>Promise.resolve(),prepare:()=>()=>Promise.resolve(),query:()=>Promise.resolve([]),close:()=>Promise.resolve()},push2={SqliteDriver:()=>Promise.resolve(mockClient)},simulation=["call:client.prepare","call:client.execute"],step_exports={};__export(step_exports,{customTable:()=>customTable,defaultInsert:()=>defaultInsert,ignoredEvent:()=>ignoredEvent,orderComplete:()=>orderComplete,tableOverride:()=>tableOverride});var import_core5=require("@walkeros/core"),defaultInsert={title:"Default insert",description:"A walker event is inserted into the default events table with canonical columns and JSON-encoded sections.",in:(0,import_core5.getEvent)("page view",{timestamp:1700000100,id:"evt-1",user:{session:"sess-1",id:"user-42"},data:{title:"Home"},source:{type:"browser",platform:"web",url:"https://example.com/",referrer:"https://example.com/prev"},globals:{env:"prod"},consent:{analytics:!0}}),out:[["client.runInsert",[1700000100,"evt-1","page view","page","view","sess-1","user-42","https://example.com/","Home","https://example.com/prev",JSON.stringify({title:"Home"}),JSON.stringify({env:"prod"}),JSON.stringify({analytics:!0})]]]},customTable={title:"Custom table",description:"A destination-level table setting inserts events into a custom SQLite table with the same column layout.",in:(0,import_core5.getEvent)("form submit",{timestamp:1700000101,id:"evt-2",user:{session:"sess-99",id:""},data:{type:"contact"},source:{type:"browser",platform:"web",url:"https://example.com/contact"},globals:{},consent:{}}),settings:{sqlite:{url:":memory:",table:"siteEvents"}},out:[["client.runInsert",[1700000101,"evt-2","form submit","form","submit","sess-99","","https://example.com/contact","","",JSON.stringify({type:"contact"}),JSON.stringify({}),JSON.stringify({})]]]},orderComplete={title:"Order insert",description:"An order complete is inserted with numeric data serialized as JSON in the data column.",in:(0,import_core5.getEvent)("order complete",{timestamp:1700000102,id:"evt-3",user:{session:"",id:""},data:{id:"ORD-1",total:99},source:{type:"collector",schema:"4"},globals:{},consent:{}}),out:[["client.runInsert",[1700000102,"evt-3","order complete","order","complete","","","","","",JSON.stringify({id:"ORD-1",total:99}),JSON.stringify({}),JSON.stringify({})]]]},tableOverride={title:"Table override",description:"A mapping rule overrides the target table so specific events are inserted into a dedicated SQLite table.",in:(0,import_core5.getEvent)("order complete",{timestamp:1700000103,id:"evt-4",user:{session:"",id:""},data:{id:"ORD-2",total:42},source:{type:"collector",schema:"4"},globals:{},consent:{}}),mapping:{settings:{table:"orders"}},out:[["client.runInsert",[1700000103,"evt-4","order complete","order","complete","","","","","",JSON.stringify({id:"ORD-2",total:42}),JSON.stringify({}),JSON.stringify({})]]]},ignoredEvent={public:!1,in:(0,import_core5.getEvent)("debug noise",{timestamp:1700000104,id:"evt-5",source:{type:"collector",schema:"4"}}),mapping:{ignore:!0},out:[]},destinationSQLite={type:"sqlite",config:{},setup:setup,async init({config:partialConfig,logger:logger,env:env,id:id}){const config=function(partialConfig={},logger){const sqlite=(partialConfig.settings??{}).sqlite??{};sqlite.url||logger.throw("Config settings sqlite.url missing");const sqliteSettings={...sqlite,url:sqlite.url,table:sqlite.table??"events"};void 0!==sqlite.schema?(logger.warn('config.settings.sqlite.schema is deprecated; use config.setup instead. "schema: auto" maps to "setup: true" (run "walkeros setup destination.<id>"); "schema: manual" maps to "setup: false". This field is removed in the next major.'),"manual"!==sqlite.schema||partialConfig.mapping||logger.throw('Config settings sqlite.schema="manual" requires a mapping (no default column mapping will be used).'),sqliteSettings._legacyAutoCreate="auto"===sqlite.schema,sqliteSettings._legacySkipProbe="manual"===sqlite.schema):(sqliteSettings._legacyAutoCreate=!1,sqliteSettings._legacySkipProbe=!1),delete sqliteSettings.schema;const settings={sqlite:sqliteSettings};return{...partialConfig,settings:settings}}(partialConfig,logger),sqlite=config.settings.sqlite;if(sqlite._client)return config;let client;if(isSqliteEnv(env)){const envTyped=env;envTyped.client?client=envTyped.client:envTyped.SqliteDriver&&(client=await envTyped.SqliteDriver(sqlite.url,sqlite.authToken))}if(!client)try{client=await createClientFromSettings(sqlite.url,sqlite.authToken)}catch(err){return logger.throw(`@walkeros/server-destination-sqlite: driver load failed: ${String(err)}`),config}if(sqlite._legacyAutoCreate)try{await client.execute(buildCreateTableSql(sqlite.table??"events"))}catch(err){return logger.throw(`@walkeros/server-destination-sqlite: CREATE TABLE failed: ${String(err)}`),config}else if(!sqlite._legacySkipProbe){let exists=!1;try{exists=await tableExists(client,sqlite.table??"events")}catch(err){return logger.throw(`@walkeros/server-destination-sqlite: table probe failed: ${String(err)}`),config}if(!exists)return logger.throw(`SQLite table "${sqlite.table??"events"}" not found in ${sqlite.url}. Run "walkeros setup destination.${id}" to create it.`),config}return sqlite._client=client,sqlite._runInsert=client.prepare(buildInsertSql(sqlite.table??"events")),sqlite._ownedClient=!(isSqliteEnv(env)&&env.client),config},push:async(event,context)=>await async function(event,{config:config,rule:rule,logger:logger}){const settings=config.settings,sqlite=settings?.sqlite;if(!sqlite)return void logger.warn("SQLite settings missing");const client=sqlite._client;if(!client)return void logger.warn("SQLite client not initialized");const ruleSettings=rule?.settings??{},ruleTable=(0,import_core3.isString)(ruleSettings.table)?ruleSettings.table:"",effectiveTable=ruleTable||sqlite.table||"events",runInsert=ruleTable&&ruleTable!==sqlite.table?client.prepare(buildInsertSql(effectiveTable)):sqlite._runInsert;if(!runInsert)return void logger.warn("SQLite insert statement not prepared");const row=eventToRow(event);logger.debug("SQLite INSERT",{table:effectiveTable,eventName:event.name});try{await runInsert(row),logger.debug("SQLite INSERT complete",{table:effectiveTable})}catch(error){logger.error("SQLite INSERT failed",{table:effectiveTable,error:error instanceof Error?error.message:String(error)})}}(event,context),async destroy({config:config}){const settings=config?.settings,sqlite=settings?.sqlite;if(!sqlite)return;const client=sqlite._client;if(client&&sqlite._ownedClient)try{await client.close()}finally{sqlite._client=void 0,sqlite._runInsert=void 0,sqlite._ownedClient=void 0}}},index_default=destinationSQLite;//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/config.ts","../src/drivers/betterSqlite3.ts","../src/drivers/libsql.ts","../src/drivers/index.ts","../src/serialize.ts","../src/push.ts","../src/types/index.ts","../src/examples/index.ts","../src/examples/env.ts","../src/examples/step.ts"],"sourcesContent":["import type { Destination, Env, Settings, SqliteClient } from './types';\nimport { getConfig, isSqliteEnv } from './config';\nimport { createClientFromSettings } from './drivers';\nimport { buildCreateTableSql, buildInsertSql } from './serialize';\nimport { push } from './push';\n\n// Types re-export\nexport * as DestinationSQLite from './types';\n\n// Examples\nexport * as examples from './examples';\n\n// Serialization helpers (exported for tests and advanced consumers)\nexport {\n CANONICAL_COLUMNS,\n buildCreateTableSql,\n buildInsertSql,\n eventToRow,\n} from './serialize';\n\n// Driver URL detection (exported for tests and advanced consumers)\nexport { isLibsqlUrl } from './drivers';\n\nexport const destinationSQLite: Destination = {\n type: 'sqlite',\n\n config: {},\n\n async init({ config: partialConfig, logger, env }) {\n const config = getConfig(partialConfig, logger);\n const settings = config.settings as Settings;\n const sqlite = settings.sqlite;\n\n // Skip creation if a client has already been wired in (testing).\n if (sqlite._client) return config;\n\n let client: SqliteClient | undefined;\n\n // Prefer env-injected client / factory (tests, dependency injection).\n if (isSqliteEnv(env)) {\n const envTyped = env as Env;\n if (envTyped.client) {\n client = envTyped.client;\n } else if (envTyped.SqliteDriver) {\n client = await envTyped.SqliteDriver(sqlite.url, sqlite.authToken);\n }\n }\n\n // Production path: load real driver based on the URL prefix.\n if (!client) {\n try {\n client = await createClientFromSettings(sqlite.url, sqlite.authToken);\n } catch (err) {\n logger.throw(\n `@walkeros/server-destination-sqlite: driver load failed: ${String(err)}`,\n );\n return config;\n }\n }\n\n // Create the canonical events table unless the user opted out.\n if (sqlite.schema === 'auto') {\n try {\n await client.execute(buildCreateTableSql(sqlite.table ?? 'events'));\n } catch (err) {\n logger.throw(\n `@walkeros/server-destination-sqlite: CREATE TABLE failed: ${String(err)}`,\n );\n return config;\n }\n }\n\n // Cache the prepared insert for per-event calls.\n sqlite._client = client;\n sqlite._runInsert = client.prepare(\n buildInsertSql(sqlite.table ?? 'events'),\n );\n sqlite._ownedClient = !(isSqliteEnv(env) && (env as Env).client);\n\n return config;\n },\n\n async push(event, context) {\n return await push(event, context);\n },\n\n async destroy({ config }) {\n const settings = config?.settings as Settings | undefined;\n const sqlite = settings?.sqlite;\n if (!sqlite) return;\n\n const client = sqlite._client;\n // Only close clients the destination created (not user-provided).\n if (client && sqlite._ownedClient) {\n try {\n await client.close();\n } finally {\n sqlite._client = undefined;\n sqlite._runInsert = undefined;\n sqlite._ownedClient = undefined;\n }\n }\n },\n};\n\nexport default destinationSQLite;\n","import type {\n Config,\n Env,\n PartialConfig,\n Settings,\n SqliteSettings,\n} from './types';\nimport type { Logger } from '@walkeros/core';\nimport { isObject } from '@walkeros/core';\n\nexport function getConfig(\n partialConfig: PartialConfig = {},\n logger: Logger.Instance,\n): Config {\n const raw = (partialConfig.settings ?? {}) as Partial<Settings>;\n const sqlite: Partial<SqliteSettings> =\n raw.sqlite ?? ({} as Partial<SqliteSettings>);\n\n if (!sqlite.url) {\n logger.throw('Config settings sqlite.url missing');\n }\n\n const sqliteSettings: SqliteSettings = {\n ...sqlite,\n url: sqlite.url as string,\n table: sqlite.table ?? 'events',\n schema: sqlite.schema ?? 'auto',\n };\n\n if (sqliteSettings.schema === 'manual' && !partialConfig.mapping) {\n logger.throw(\n 'Config settings sqlite.schema=\"manual\" requires a mapping (no default column mapping will be used).',\n );\n }\n\n const settings: Settings = { sqlite: sqliteSettings };\n\n return { ...partialConfig, settings };\n}\n\nexport function isSqliteEnv(env: unknown): env is Env {\n if (!isObject(env)) return false;\n const maybe = env as { SqliteDriver?: unknown; client?: unknown };\n return (\n typeof maybe.SqliteDriver === 'function' || isObject(maybe.client ?? null)\n );\n}\n","import type { SqliteClient } from '../types';\n\n/**\n * better-sqlite3 driver -- synchronous native SQLite for local files and ':memory:'.\n * Wrapped in Promise.resolve so the cross-driver interface is always async.\n *\n * The library is loaded via dynamic require to allow tests to mock via\n * jest.mock('better-sqlite3'), and to keep it as an optional peer dependency.\n */\ninterface BetterSqliteStatement {\n run: (...args: unknown[]) => unknown;\n}\n\ninterface BetterSqliteDatabase {\n prepare: (sql: string) => BetterSqliteStatement;\n close: () => void;\n}\n\ninterface BetterSqliteConstructor {\n new (filePath: string): BetterSqliteDatabase;\n}\n\nexport async function createBetterSqliteClient(\n filePath: string,\n): Promise<SqliteClient> {\n let Database: BetterSqliteConstructor;\n try {\n // Dynamic require so the module stays an optional peer dep and tests can mock.\n const loaded = require('better-sqlite3') as\n | BetterSqliteConstructor\n | { default: BetterSqliteConstructor };\n Database =\n 'default' in loaded && typeof loaded.default === 'function'\n ? loaded.default\n : (loaded as BetterSqliteConstructor);\n } catch (err) {\n throw new Error(\n '@walkeros/server-destination-sqlite: better-sqlite3 is not installed. ' +\n 'Install it with `npm install better-sqlite3`, or switch settings.sqlite.url to a libSQL URL. ' +\n `Original error: ${String(err)}`,\n );\n }\n\n const db = new Database(filePath);\n\n return {\n async execute(sql, args = []) {\n db.prepare(sql).run(...(args as unknown[]));\n },\n prepare(sql) {\n const stmt = db.prepare(sql);\n return async (args) => {\n stmt.run(...(args as unknown[]));\n };\n },\n async close() {\n db.close();\n },\n };\n}\n","import type { SqliteClient } from '../types';\n\n/**\n * libSQL / Turso driver -- async HTTP(S)/WSS/local file driver.\n *\n * Loaded via dynamic require to stay an optional peer dep and let tests mock\n * via jest.mock('@libsql/client').\n */\ninterface LibsqlExecuteArgs {\n sql: string;\n args?: ReadonlyArray<unknown>;\n}\n\ninterface LibsqlClient {\n execute: (input: LibsqlExecuteArgs) => Promise<unknown>;\n close: () => void;\n}\n\ninterface LibsqlCreateClientConfig {\n url: string;\n authToken?: string;\n}\n\ntype CreateClientFn = (config: LibsqlCreateClientConfig) => LibsqlClient;\n\nexport async function createLibsqlClient(\n url: string,\n authToken?: string,\n): Promise<SqliteClient> {\n let createClient: CreateClientFn;\n try {\n const loaded = require('@libsql/client') as {\n createClient?: CreateClientFn;\n default?: { createClient?: CreateClientFn };\n };\n const fn = loaded.createClient ?? loaded.default?.createClient;\n if (typeof fn !== 'function') {\n throw new Error('createClient export not found on @libsql/client');\n }\n createClient = fn;\n } catch (err) {\n throw new Error(\n '@walkeros/server-destination-sqlite: @libsql/client is not installed. ' +\n 'Install it with `npm install @libsql/client`, or use a local file URL. ' +\n `Original error: ${String(err)}`,\n );\n }\n\n const client = createClient({ url, authToken });\n\n return {\n async execute(sql, args = []) {\n await client.execute({ sql, args });\n },\n prepare(sql) {\n // libSQL has no server-side prepared-statement cache for HTTP; we close over\n // the sql string and call execute() per run. Cost is negligible vs network RTT.\n return async (args) => {\n await client.execute({ sql, args });\n };\n },\n async close() {\n client.close();\n },\n };\n}\n","import type { SqliteClient, SqliteClientFactory } from '../types';\nimport { createBetterSqliteClient } from './betterSqlite3';\nimport { createLibsqlClient } from './libsql';\n\nconst LIBSQL_URL_PREFIXES = [\n 'libsql://',\n 'http://',\n 'https://',\n 'ws://',\n 'wss://',\n];\n\nexport function isLibsqlUrl(url: string): boolean {\n return LIBSQL_URL_PREFIXES.some((p) => url.startsWith(p));\n}\n\n/**\n * Default client factory -- picks better-sqlite3 for local file paths and\n * libSQL for remote URLs. Tests can override via env.SqliteDriver.\n */\nexport const defaultFactory: SqliteClientFactory = async (url, authToken) => {\n if (isLibsqlUrl(url)) return createLibsqlClient(url, authToken);\n return createBetterSqliteClient(url);\n};\n\nexport async function createClientFromSettings(\n url: string,\n authToken: string | undefined,\n): Promise<SqliteClient> {\n return defaultFactory(url, authToken);\n}\n\nexport { createBetterSqliteClient, createLibsqlClient };\n","import type { WalkerOS } from '@walkeros/core';\nimport { isObject, isString } from '@walkeros/core';\n\n/**\n * Canonical columns for the auto-created events table. Order matters -- used\n * to build both CREATE TABLE and the prepared INSERT.\n */\nexport const CANONICAL_COLUMNS = [\n 'timestamp',\n 'event_id',\n 'name',\n 'entity',\n 'action',\n 'session_id',\n 'user_id',\n 'page_url',\n 'page_title',\n 'referrer_url',\n 'data',\n 'globals',\n 'consent',\n] as const;\n\nexport function buildCreateTableSql(table: string): string {\n return `CREATE TABLE IF NOT EXISTS ${table} (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,\n timestamp INTEGER,\n event_id TEXT,\n name TEXT,\n entity TEXT,\n action TEXT,\n session_id TEXT,\n user_id TEXT,\n page_url TEXT,\n page_title TEXT,\n referrer_url TEXT,\n data TEXT,\n globals TEXT,\n consent TEXT\n)`;\n}\n\nexport function buildInsertSql(table: string): string {\n const cols = CANONICAL_COLUMNS.join(', ');\n const placeholders = CANONICAL_COLUMNS.map(() => '?').join(', ');\n return `INSERT INTO ${table} (${cols}) VALUES (${placeholders})`;\n}\n\n/**\n * Map a walkerOS event onto the canonical column order. JSON blobs are\n * stringified. Missing fields become empty strings / zeros.\n */\nexport function eventToRow(event: WalkerOS.Event): unknown[] {\n const data = isObject(event.data) ? event.data : {};\n const title = isString(data.title) ? data.title : '';\n\n return [\n typeof event.timestamp === 'number' ? event.timestamp : Date.now(),\n event.id ?? '',\n event.name ?? '',\n event.entity ?? '',\n event.action ?? '',\n event.user?.session ?? '',\n event.user?.id ?? '',\n event.source?.url ?? '',\n title,\n event.source?.referrer ?? '',\n JSON.stringify(data),\n JSON.stringify(event.globals ?? {}),\n JSON.stringify(event.consent ?? {}),\n ];\n}\n","import type { PushFn, SqliteSettings } from './types';\nimport { isString } from '@walkeros/core';\nimport { buildInsertSql, eventToRow } from './serialize';\n\nexport const push: PushFn = async function (event, { config, rule, logger }) {\n const settings = config.settings as { sqlite?: SqliteSettings } | undefined;\n const sqlite: SqliteSettings | undefined = settings?.sqlite;\n\n if (!sqlite) {\n logger.warn('SQLite settings missing');\n return;\n }\n\n const client = sqlite._client;\n if (!client) {\n logger.warn('SQLite client not initialized');\n return;\n }\n\n const ruleSettings = rule?.settings ?? {};\n const ruleTable = isString(ruleSettings.table) ? ruleSettings.table : '';\n\n // If the rule overrides the table, we can't reuse the cached prepared statement\n // (which was bound to the default table). Build an ad-hoc prepared run.\n const effectiveTable = ruleTable || sqlite.table || 'events';\n const runInsert =\n ruleTable && ruleTable !== sqlite.table\n ? client.prepare(buildInsertSql(effectiveTable))\n : sqlite._runInsert;\n\n if (!runInsert) {\n logger.warn('SQLite insert statement not prepared');\n return;\n }\n\n const row = eventToRow(event);\n\n logger.debug('SQLite INSERT', {\n table: effectiveTable,\n eventName: event.name,\n });\n\n try {\n await runInsert(row);\n logger.debug('SQLite INSERT complete', { table: effectiveTable });\n } catch (error) {\n logger.error('SQLite INSERT failed', {\n table: effectiveTable,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n};\n","import type {\n Mapping as WalkerOSMapping,\n Destination as CoreDestination,\n} from '@walkeros/core';\nimport type { DestinationServer } from '@walkeros/server-core';\n\nexport type SchemaMode = 'auto' | 'manual';\n\n/**\n * Thin cross-driver connection interface. Both drivers are adapted to this shape.\n * Production code uses the adapters in src/drivers/*; tests inject a mock client\n * via env.client to capture sql/args without touching a real database.\n */\nexport interface SqliteClient {\n /** Execute a SQL statement. Used for CREATE TABLE and ad-hoc commands. */\n execute: (sql: string, args?: ReadonlyArray<unknown>) => Promise<void>;\n /**\n * Prepare a statement for repeated execution. Returned function binds args and runs.\n */\n prepare: (sql: string) => (args: ReadonlyArray<unknown>) => Promise<void>;\n /** Close the connection. */\n close: () => Promise<void>;\n}\n\n/**\n * Factory that constructs an SqliteClient from the user's connection settings.\n * Used by env.SqliteDriver so tests can inject a spy without mocking node_modules.\n */\nexport type SqliteClientFactory = (\n url: string,\n authToken?: string,\n) => Promise<SqliteClient>;\n\nexport interface SqliteSettings {\n /**\n * Connection URL. Starts with `libsql://`, `http://`, `https://`, `wss://`, `ws://`\n * → libSQL driver. Anything else → better-sqlite3 (treated as a file path).\n * Special value `:memory:` → in-memory (better-sqlite3).\n */\n url: string;\n /** libSQL / Turso auth token. Ignored for better-sqlite3. */\n authToken?: string;\n /** Target table name. Defaults to `events`. */\n table?: string;\n /**\n * `auto` runs `CREATE TABLE IF NOT EXISTS` with the canonical schema on init.\n * `manual` skips CREATE TABLE. The user brings their own schema and mapping.\n * Defaults to `auto`.\n */\n schema?: SchemaMode;\n\n // Runtime -- set during init, not user-facing.\n _client?: SqliteClient;\n _runInsert?: (args: ReadonlyArray<unknown>) => Promise<void>;\n _ownedClient?: boolean;\n}\n\nexport interface Settings {\n sqlite: SqliteSettings;\n}\n\nexport type InitSettings = Partial<Settings>;\n\nexport interface Mapping {\n /** Override target table for this rule. */\n table?: string;\n}\n\n/**\n * Env -- optional driver override. Production leaves this undefined and the\n * destination loads better-sqlite3 or @libsql/client dynamically. Tests\n * provide a factory via `SqliteDriver` or a pre-built client via `client`.\n */\nexport interface Env extends DestinationServer.Env {\n SqliteDriver?: SqliteClientFactory;\n client?: SqliteClient;\n}\n\nexport type Types = CoreDestination.Types<Settings, Mapping, Env, InitSettings>;\n\nexport interface Destination extends DestinationServer.Destination<Types> {\n init: DestinationServer.InitFn<Types>;\n}\n\nexport type Config = {\n settings: Settings;\n} & DestinationServer.Config<Types>;\n\nexport type InitFn = DestinationServer.InitFn<Types>;\nexport type PushFn = DestinationServer.PushFn<Types>;\nexport type PartialConfig = DestinationServer.PartialConfig<Types>;\nexport type PushEvents = DestinationServer.PushEvents<Mapping>;\n\nexport type Rule = WalkerOSMapping.Rule<Mapping>;\nexport type Rules = WalkerOSMapping.Rules<Rule>;\n","export * as env from './env';\nexport * as step from './step';\n","import type { Env, SqliteClient, SqliteClientFactory } from '../types';\n\n// Narrow helper type aliases so mock functions are typed without `any`.\ntype ExecuteFn = (sql: string, args?: ReadonlyArray<unknown>) => Promise<void>;\ntype PrepareFn = (\n sql: string,\n) => (args: ReadonlyArray<unknown>) => Promise<void>;\ntype CloseFn = () => Promise<void>;\n\nconst asyncExecute: ExecuteFn = () => Promise.resolve();\nconst asyncClose: CloseFn = () => Promise.resolve();\nconst asyncPrepare: PrepareFn = () => () => Promise.resolve();\n\nconst mockClient: SqliteClient = {\n execute: asyncExecute,\n prepare: asyncPrepare,\n close: asyncClose,\n};\n\nconst mockFactory: SqliteClientFactory = () => Promise.resolve(mockClient);\n\nexport const push: Env = {\n SqliteDriver: mockFactory,\n};\n\n/**\n * Simulation tracking paths. Specifies which function calls to record when\n * running step examples through the collector.\n */\nexport const simulation = ['call:client.prepare', 'call:client.execute'];\n","import type { Flow } from '@walkeros/core';\nimport { getEvent } from '@walkeros/core';\nimport type { Settings } from '../types';\n\n/**\n * Extended step example that may carry destination-level settings overrides.\n */\nexport type SqliteStepExample = Flow.StepExample & {\n settings?: Partial<Settings>;\n};\n\n/**\n * Canonical insert into the default `events` table. `out` records the\n * column args the prepared INSERT is bound with.\n */\nexport const defaultInsert: SqliteStepExample = {\n title: 'Default insert',\n description:\n 'A walker event is inserted into the default events table with canonical columns and JSON-encoded sections.',\n in: getEvent('page view', {\n timestamp: 1700000100,\n id: 'evt-1',\n user: { session: 'sess-1', id: 'user-42' },\n data: { title: 'Home' },\n source: {\n type: 'browser',\n platform: 'web',\n url: 'https://example.com/',\n referrer: 'https://example.com/prev',\n },\n globals: { env: 'prod' },\n consent: { analytics: true },\n }),\n out: [\n [\n 'client.runInsert',\n [\n 1700000100,\n 'evt-1',\n 'page view',\n 'page',\n 'view',\n 'sess-1',\n 'user-42',\n 'https://example.com/',\n 'Home',\n 'https://example.com/prev',\n JSON.stringify({ title: 'Home' }),\n JSON.stringify({ env: 'prod' }),\n JSON.stringify({ analytics: true }),\n ],\n ],\n ],\n};\n\n/**\n * Custom table name. Verifies table overrides while using the canonical column set.\n */\nexport const customTable: SqliteStepExample = {\n title: 'Custom table',\n description:\n 'A destination-level table setting inserts events into a custom SQLite table with the same column layout.',\n in: getEvent('form submit', {\n timestamp: 1700000101,\n id: 'evt-2',\n user: { session: 'sess-99', id: '' },\n data: { type: 'contact' },\n source: {\n type: 'browser',\n platform: 'web',\n url: 'https://example.com/contact',\n },\n globals: {},\n consent: {},\n }),\n settings: {\n sqlite: {\n url: ':memory:',\n table: 'siteEvents',\n },\n },\n out: [\n [\n 'client.runInsert',\n [\n 1700000101,\n 'evt-2',\n 'form submit',\n 'form',\n 'submit',\n 'sess-99',\n '',\n 'https://example.com/contact',\n '',\n '',\n JSON.stringify({ type: 'contact' }),\n JSON.stringify({}),\n JSON.stringify({}),\n ],\n ],\n ],\n};\n\n/**\n * Order event with numeric data. Confirms JSON serialization of nested values.\n */\nexport const orderComplete: SqliteStepExample = {\n title: 'Order insert',\n description:\n 'An order complete is inserted with numeric data serialized as JSON in the data column.',\n in: getEvent('order complete', {\n timestamp: 1700000102,\n id: 'evt-3',\n user: { session: '', id: '' },\n data: { id: 'ORD-1', total: 99 },\n source: { type: 'collector', schema: '4' },\n globals: {},\n consent: {},\n }),\n out: [\n [\n 'client.runInsert',\n [\n 1700000102,\n 'evt-3',\n 'order complete',\n 'order',\n 'complete',\n '',\n '',\n '',\n '',\n '',\n JSON.stringify({ id: 'ORD-1', total: 99 }),\n JSON.stringify({}),\n JSON.stringify({}),\n ],\n ],\n ],\n};\n\n/**\n * Table override per rule -- routes this event to a dedicated table.\n */\nexport const tableOverride: SqliteStepExample = {\n title: 'Table override',\n description:\n 'A mapping rule overrides the target table so specific events are inserted into a dedicated SQLite table.',\n in: getEvent('order complete', {\n timestamp: 1700000103,\n id: 'evt-4',\n user: { session: '', id: '' },\n data: { id: 'ORD-2', total: 42 },\n source: { type: 'collector', schema: '4' },\n globals: {},\n consent: {},\n }),\n mapping: {\n settings: {\n table: 'orders',\n },\n },\n out: [\n [\n 'client.runInsert',\n [\n 1700000103,\n 'evt-4',\n 'order complete',\n 'order',\n 'complete',\n '',\n '',\n '',\n '',\n '',\n JSON.stringify({ id: 'ORD-2', total: 42 }),\n JSON.stringify({}),\n JSON.stringify({}),\n ],\n ],\n ],\n};\n\n/**\n * Ignored event -- mapping.ignore: true produces no insert call.\n */\nexport const ignoredEvent: SqliteStepExample = {\n public: false,\n in: getEvent('debug noise', {\n timestamp: 1700000104,\n id: 'evt-5',\n source: { type: 'collector', schema: '4' },\n }),\n mapping: { ignore: true },\n out: [],\n};\n"],"mappings":"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","names":["import_core","import_core","push","import_core"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/config.ts","../src/drivers/betterSqlite3.ts","../src/drivers/libsql.ts","../src/drivers/index.ts","../src/serialize.ts","../src/push.ts","../src/setup.ts","../src/types/index.ts","../src/examples/index.ts","../src/examples/env.ts","../src/examples/step.ts"],"sourcesContent":["import type { Destination, Env, Settings, SqliteClient } from './types';\nimport { getConfig, isSqliteEnv } from './config';\nimport { createClientFromSettings } from './drivers';\nimport { buildCreateTableSql, buildInsertSql } from './serialize';\nimport { push } from './push';\nimport { setup, tableExists } from './setup';\n\n// Types re-export\nexport * as DestinationSQLite from './types';\n\n// Examples\nexport * as examples from './examples';\n\n// Serialization helpers (exported for tests and advanced consumers)\nexport {\n CANONICAL_COLUMNS,\n buildCreateTableSql,\n buildInsertSql,\n eventToRow,\n} from './serialize';\n\n// Driver URL detection (exported for tests and advanced consumers)\nexport { isLibsqlUrl } from './drivers';\n\n// Setup helpers (exported for tests and advanced consumers)\nexport { setup, DEFAULT_SCHEMA, DEFAULT_PRAGMAS, DEFAULT_SETUP } from './setup';\n\nexport const destinationSQLite: Destination = {\n type: 'sqlite',\n\n config: {},\n\n setup,\n\n async init({ config: partialConfig, logger, env, id }) {\n const config = getConfig(partialConfig, logger);\n const settings = config.settings as Settings;\n const sqlite = settings.sqlite;\n\n // Skip creation if a client has already been wired in (testing).\n if (sqlite._client) return config;\n\n let client: SqliteClient | undefined;\n\n // Prefer env-injected client / factory (tests, dependency injection).\n if (isSqliteEnv(env)) {\n const envTyped = env as Env;\n if (envTyped.client) {\n client = envTyped.client;\n } else if (envTyped.SqliteDriver) {\n client = await envTyped.SqliteDriver(sqlite.url, sqlite.authToken);\n }\n }\n\n // Production path: load real driver based on the URL prefix.\n if (!client) {\n try {\n client = await createClientFromSettings(sqlite.url, sqlite.authToken);\n } catch (err) {\n logger.throw(\n `@walkeros/server-destination-sqlite: driver load failed: ${String(err)}`,\n );\n return config;\n }\n }\n\n // Legacy auto-create path. Only runs when the user opted in via the\n // deprecated `settings.sqlite.schema: 'auto'` field. New users run\n // `walkeros setup destination.<id>` (see setup.ts) or set `config.setup`.\n if (sqlite._legacyAutoCreate) {\n try {\n await client.execute(buildCreateTableSql(sqlite.table ?? 'events'));\n } catch (err) {\n logger.throw(\n `@walkeros/server-destination-sqlite: CREATE TABLE failed: ${String(err)}`,\n );\n return config;\n }\n } else if (!sqlite._legacySkipProbe) {\n // Modern path: assume the table exists. Probe once and hard-fail with\n // an actionable message if it does not. Legacy `schema: 'manual'` skips\n // this probe (user supplies their own table shape).\n let exists = false;\n try {\n exists = await tableExists(client, sqlite.table ?? 'events');\n } catch (err) {\n logger.throw(\n `@walkeros/server-destination-sqlite: table probe failed: ${String(err)}`,\n );\n return config;\n }\n if (!exists) {\n logger.throw(\n `SQLite table \"${sqlite.table ?? 'events'}\" not found in ${sqlite.url}. ` +\n `Run \"walkeros setup destination.${id}\" to create it.`,\n );\n return config;\n }\n }\n\n // Cache the prepared insert for per-event calls.\n sqlite._client = client;\n sqlite._runInsert = client.prepare(\n buildInsertSql(sqlite.table ?? 'events'),\n );\n sqlite._ownedClient = !(isSqliteEnv(env) && (env as Env).client);\n\n return config;\n },\n\n async push(event, context) {\n return await push(event, context);\n },\n\n async destroy({ config }) {\n const settings = config?.settings as Settings | undefined;\n const sqlite = settings?.sqlite;\n if (!sqlite) return;\n\n const client = sqlite._client;\n // Only close clients the destination created (not user-provided).\n if (client && sqlite._ownedClient) {\n try {\n await client.close();\n } finally {\n sqlite._client = undefined;\n sqlite._runInsert = undefined;\n sqlite._ownedClient = undefined;\n }\n }\n },\n};\n\nexport default destinationSQLite;\n","import type {\n Config,\n Env,\n PartialConfig,\n Settings,\n SqliteSettings,\n} from './types';\nimport type { Logger } from '@walkeros/core';\nimport { isObject } from '@walkeros/core';\n\nexport function getConfig(\n partialConfig: PartialConfig = {},\n logger: Logger.Instance,\n): Config {\n const raw = (partialConfig.settings ?? {}) as Partial<Settings>;\n const sqlite: Partial<SqliteSettings> =\n raw.sqlite ?? ({} as Partial<SqliteSettings>);\n\n if (!sqlite.url) {\n logger.throw('Config settings sqlite.url missing');\n }\n\n const sqliteSettings: SqliteSettings = {\n ...sqlite,\n url: sqlite.url as string,\n table: sqlite.table ?? 'events',\n };\n\n // Migration shim: settings.sqlite.schema is the predecessor of config.setup.\n // Accept BOTH for one minor cycle, emit a deprecation WARN if `schema` is\n // used. Removed in the next major.\n if (sqlite.schema !== undefined) {\n logger.warn(\n 'config.settings.sqlite.schema is deprecated; use config.setup instead. ' +\n '\"schema: auto\" maps to \"setup: true\" (run \"walkeros setup destination.<id>\"); ' +\n '\"schema: manual\" maps to \"setup: false\". This field is removed in the next major.',\n );\n if (sqlite.schema === 'manual' && !partialConfig.mapping) {\n // Preserve the existing throw for the legacy \"manual without mapping\" case.\n logger.throw(\n 'Config settings sqlite.schema=\"manual\" requires a mapping (no default column mapping will be used).',\n );\n }\n sqliteSettings._legacyAutoCreate = sqlite.schema === 'auto';\n // Legacy `schema: 'manual'` opted out of the auto-create AND opted out of\n // the table-existence probe (user brings their own table). Honor that.\n sqliteSettings._legacySkipProbe = sqlite.schema === 'manual';\n } else {\n // No legacy schema flag. Default behavior: do NOT auto-create in init().\n // The user must run `walkeros setup destination.<id>` or set `config.setup: true`.\n sqliteSettings._legacyAutoCreate = false;\n sqliteSettings._legacySkipProbe = false;\n }\n\n // Strip the deprecated key from the live settings object so downstream code\n // never reads it. The flag is preserved on `_legacyAutoCreate`.\n delete sqliteSettings.schema;\n\n const settings: Settings = { sqlite: sqliteSettings };\n\n return { ...partialConfig, settings };\n}\n\nexport function isSqliteEnv(env: unknown): env is Env {\n if (!isObject(env)) return false;\n const maybe = env as { SqliteDriver?: unknown; client?: unknown };\n return (\n typeof maybe.SqliteDriver === 'function' || isObject(maybe.client ?? null)\n );\n}\n","import type { SqliteClient } from '../types';\n\n/**\n * better-sqlite3 driver -- synchronous native SQLite for local files and ':memory:'.\n * Wrapped in Promise.resolve so the cross-driver interface is always async.\n *\n * The library is loaded via dynamic require to allow tests to mock via\n * jest.mock('better-sqlite3'), and to keep it as an optional peer dependency.\n */\ninterface BetterSqliteStatement {\n run: (...args: unknown[]) => unknown;\n all: (...args: unknown[]) => ReadonlyArray<Record<string, unknown>>;\n}\n\ninterface BetterSqliteDatabase {\n prepare: (sql: string) => BetterSqliteStatement;\n close: () => void;\n}\n\ninterface BetterSqliteConstructor {\n new (filePath: string): BetterSqliteDatabase;\n}\n\nexport async function createBetterSqliteClient(\n filePath: string,\n): Promise<SqliteClient> {\n let Database: BetterSqliteConstructor;\n try {\n // Dynamic require so the module stays an optional peer dep and tests can mock.\n const loaded = require('better-sqlite3') as\n | BetterSqliteConstructor\n | { default: BetterSqliteConstructor };\n Database =\n 'default' in loaded && typeof loaded.default === 'function'\n ? loaded.default\n : (loaded as BetterSqliteConstructor);\n } catch (err) {\n throw new Error(\n '@walkeros/server-destination-sqlite: better-sqlite3 is not installed. ' +\n 'Install it with `npm install better-sqlite3`, or switch settings.sqlite.url to a libSQL URL. ' +\n `Original error: ${String(err)}`,\n );\n }\n\n const db = new Database(filePath);\n\n return {\n async execute(sql, args = []) {\n db.prepare(sql).run(...(args as unknown[]));\n },\n prepare(sql) {\n const stmt = db.prepare(sql);\n return async (args) => {\n stmt.run(...(args as unknown[]));\n };\n },\n async query(sql, args = []) {\n return db.prepare(sql).all(...(args as unknown[]));\n },\n async close() {\n db.close();\n },\n };\n}\n","import type { SqliteClient } from '../types';\n\n/**\n * libSQL / Turso driver -- async HTTP(S)/WSS/local file driver.\n *\n * Loaded via dynamic require to stay an optional peer dep and let tests mock\n * via jest.mock('@libsql/client').\n */\ninterface LibsqlExecuteArgs {\n sql: string;\n args?: ReadonlyArray<unknown>;\n}\n\ninterface LibsqlResultSet {\n rows?: ReadonlyArray<Record<string, unknown>>;\n}\n\ninterface LibsqlClient {\n execute: (input: LibsqlExecuteArgs) => Promise<LibsqlResultSet>;\n close: () => void;\n}\n\ninterface LibsqlCreateClientConfig {\n url: string;\n authToken?: string;\n}\n\ntype CreateClientFn = (config: LibsqlCreateClientConfig) => LibsqlClient;\n\nexport async function createLibsqlClient(\n url: string,\n authToken?: string,\n): Promise<SqliteClient> {\n let createClient: CreateClientFn;\n try {\n const loaded = require('@libsql/client') as {\n createClient?: CreateClientFn;\n default?: { createClient?: CreateClientFn };\n };\n const fn = loaded.createClient ?? loaded.default?.createClient;\n if (typeof fn !== 'function') {\n throw new Error('createClient export not found on @libsql/client');\n }\n createClient = fn;\n } catch (err) {\n throw new Error(\n '@walkeros/server-destination-sqlite: @libsql/client is not installed. ' +\n 'Install it with `npm install @libsql/client`, or use a local file URL. ' +\n `Original error: ${String(err)}`,\n );\n }\n\n const client = createClient({ url, authToken });\n\n return {\n async execute(sql, args = []) {\n await client.execute({ sql, args });\n },\n prepare(sql) {\n // libSQL has no server-side prepared-statement cache for HTTP; we close over\n // the sql string and call execute() per run. Cost is negligible vs network RTT.\n return async (args) => {\n await client.execute({ sql, args });\n };\n },\n async query(sql, args = []) {\n const result = await client.execute({ sql, args });\n return result?.rows ?? [];\n },\n async close() {\n client.close();\n },\n };\n}\n","import type { SqliteClient, SqliteClientFactory } from '../types';\nimport { createBetterSqliteClient } from './betterSqlite3';\nimport { createLibsqlClient } from './libsql';\n\nconst LIBSQL_URL_PREFIXES = [\n 'libsql://',\n 'http://',\n 'https://',\n 'ws://',\n 'wss://',\n];\n\nexport function isLibsqlUrl(url: string): boolean {\n return LIBSQL_URL_PREFIXES.some((p) => url.startsWith(p));\n}\n\n/**\n * Default client factory -- picks better-sqlite3 for local file paths and\n * libSQL for remote URLs. Tests can override via env.SqliteDriver.\n */\nexport const defaultFactory: SqliteClientFactory = async (url, authToken) => {\n if (isLibsqlUrl(url)) return createLibsqlClient(url, authToken);\n return createBetterSqliteClient(url);\n};\n\nexport async function createClientFromSettings(\n url: string,\n authToken: string | undefined,\n): Promise<SqliteClient> {\n return defaultFactory(url, authToken);\n}\n\nexport { createBetterSqliteClient, createLibsqlClient };\n","import type { WalkerOS } from '@walkeros/core';\nimport { isObject, isString } from '@walkeros/core';\n\n/**\n * Canonical columns for the auto-created events table. Order matters -- used\n * to build both CREATE TABLE and the prepared INSERT.\n */\nexport const CANONICAL_COLUMNS = [\n 'timestamp',\n 'event_id',\n 'name',\n 'entity',\n 'action',\n 'session_id',\n 'user_id',\n 'page_url',\n 'page_title',\n 'referrer_url',\n 'data',\n 'globals',\n 'consent',\n] as const;\n\nexport function buildCreateTableSql(table: string): string {\n return `CREATE TABLE IF NOT EXISTS ${table} (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,\n timestamp INTEGER,\n event_id TEXT,\n name TEXT,\n entity TEXT,\n action TEXT,\n session_id TEXT,\n user_id TEXT,\n page_url TEXT,\n page_title TEXT,\n referrer_url TEXT,\n data TEXT,\n globals TEXT,\n consent TEXT\n)`;\n}\n\nexport function buildInsertSql(table: string): string {\n const cols = CANONICAL_COLUMNS.join(', ');\n const placeholders = CANONICAL_COLUMNS.map(() => '?').join(', ');\n return `INSERT INTO ${table} (${cols}) VALUES (${placeholders})`;\n}\n\n/**\n * Map a walkerOS event onto the canonical column order. JSON blobs are\n * stringified. Missing fields become empty strings / zeros.\n */\nexport function eventToRow(event: WalkerOS.Event): unknown[] {\n const data = isObject(event.data) ? event.data : {};\n const title = isString(data.title) ? data.title : '';\n\n return [\n typeof event.timestamp === 'number' ? event.timestamp : Date.now(),\n event.id ?? '',\n event.name ?? '',\n event.entity ?? '',\n event.action ?? '',\n event.user?.session ?? '',\n event.user?.id ?? '',\n event.source?.url ?? '',\n title,\n event.source?.referrer ?? '',\n JSON.stringify(data),\n JSON.stringify(event.globals ?? {}),\n JSON.stringify(event.consent ?? {}),\n ];\n}\n","import type { PushFn, SqliteSettings } from './types';\nimport { isString } from '@walkeros/core';\nimport { buildInsertSql, eventToRow } from './serialize';\n\nexport const push: PushFn = async function (event, { config, rule, logger }) {\n const settings = config.settings as { sqlite?: SqliteSettings } | undefined;\n const sqlite: SqliteSettings | undefined = settings?.sqlite;\n\n if (!sqlite) {\n logger.warn('SQLite settings missing');\n return;\n }\n\n const client = sqlite._client;\n if (!client) {\n logger.warn('SQLite client not initialized');\n return;\n }\n\n const ruleSettings = rule?.settings ?? {};\n const ruleTable = isString(ruleSettings.table) ? ruleSettings.table : '';\n\n // If the rule overrides the table, we can't reuse the cached prepared statement\n // (which was bound to the default table). Build an ad-hoc prepared run.\n const effectiveTable = ruleTable || sqlite.table || 'events';\n const runInsert =\n ruleTable && ruleTable !== sqlite.table\n ? client.prepare(buildInsertSql(effectiveTable))\n : sqlite._runInsert;\n\n if (!runInsert) {\n logger.warn('SQLite insert statement not prepared');\n return;\n }\n\n const row = eventToRow(event);\n\n logger.debug('SQLite INSERT', {\n table: effectiveTable,\n eventName: event.name,\n });\n\n try {\n await runInsert(row);\n logger.debug('SQLite INSERT complete', { table: effectiveTable });\n } catch (error) {\n logger.error('SQLite INSERT failed', {\n table: effectiveTable,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n};\n","import type { LifecycleContext, Logger } from '@walkeros/core';\nimport { resolveSetup } from '@walkeros/core';\nimport type { DestinationServer } from '@walkeros/server-core';\nimport type { Env, Setup, SetupColumn, SqliteClient, Types } from './types';\nimport { isSqliteEnv } from './config';\nimport { createClientFromSettings } from './drivers';\n\n// Setup is wired to the destination's `setup` slot which uses the broader\n// `DestinationServer.Config<Types>` (settings is optional). We runtime-narrow\n// instead of using the local Config alias so the assignment in index.ts\n// type-checks without contravariance issues.\ntype WideConfig = DestinationServer.Config<Types>;\n\n/**\n * Default 15-column walkerOS Event v4 canonical schema.\n * Mirrors BigQuery (Plan 2). Only `name` is REQUIRED.\n */\nexport const DEFAULT_SCHEMA: SetupColumn[] = [\n { name: 'name', type: 'TEXT', notNull: true },\n { name: 'data', type: 'TEXT' },\n { name: 'context', type: 'TEXT' },\n { name: 'globals', type: 'TEXT' },\n { name: 'custom', type: 'TEXT' },\n { name: 'user', type: 'TEXT' },\n { name: 'nested', type: 'TEXT' },\n { name: 'consent', type: 'TEXT' },\n { name: 'id', type: 'TEXT' },\n { name: 'trigger', type: 'TEXT' },\n { name: 'entity', type: 'TEXT' },\n { name: 'action', type: 'TEXT' },\n { name: 'timestamp', type: 'TEXT' },\n { name: 'timing', type: 'INTEGER' },\n { name: 'source', type: 'TEXT' },\n];\n\nexport const DEFAULT_PRAGMAS: Record<string, string> = {\n journal_mode: 'WAL',\n synchronous: 'NORMAL',\n foreign_keys: 'ON',\n temp_store: 'MEMORY',\n};\n\nexport const DEFAULT_SETUP: Required<Setup> = {\n pragmas: DEFAULT_PRAGMAS,\n schema: DEFAULT_SCHEMA,\n indexes: [],\n};\n\nexport interface SetupResult {\n tableCreated: boolean;\n pragmasApplied: string[];\n indexesCreated: string[];\n}\n\ninterface PragmaTableInfoRow {\n name: string;\n type: string;\n}\n\ninterface SqliteMasterRow {\n name: string;\n}\n\nfunction isString(value: unknown): value is string {\n return typeof value === 'string';\n}\n\nfunction isPragmaTableInfoRow(value: unknown): value is PragmaTableInfoRow {\n if (typeof value !== 'object' || value === null) return false;\n const obj: Record<string, unknown> = { ...value };\n return isString(obj.name) && isString(obj.type);\n}\n\nfunction isSqliteMasterRow(value: unknown): value is SqliteMasterRow {\n if (typeof value !== 'object' || value === null) return false;\n const obj: Record<string, unknown> = { ...value };\n return isString(obj.name);\n}\n\nfunction buildCreateTableSql(table: string, columns: SetupColumn[]): string {\n const lines = columns.map((c) => {\n const parts: string[] = [c.name, c.type];\n if (c.primaryKey) parts.push('PRIMARY KEY');\n if (c.notNull) parts.push('NOT NULL');\n return parts.join(' ');\n });\n return `CREATE TABLE IF NOT EXISTS ${table} (\\n ${lines.join(',\\n ')}\\n)`;\n}\n\nasync function tableExists(\n client: SqliteClient,\n table: string,\n): Promise<boolean> {\n const rows = await client.query(\n \"SELECT name FROM sqlite_master WHERE type='table' AND name=?\",\n [table],\n );\n for (const row of rows) {\n if (isSqliteMasterRow(row) && row.name === table) return true;\n }\n return false;\n}\n\nasync function detectDrift(\n client: SqliteClient,\n table: string,\n declared: SetupColumn[],\n logger: Logger.Instance,\n): Promise<void> {\n const rows = await client.query(`PRAGMA table_info(${table})`);\n const actualByName = new Map<string, string>();\n for (const row of rows) {\n if (isPragmaTableInfoRow(row)) {\n actualByName.set(row.name, row.type.toUpperCase());\n }\n }\n\n for (const declaredCol of declared) {\n const actualType = actualByName.get(declaredCol.name);\n if (actualType === undefined) {\n logger.warn('setup.drift', {\n field: declaredCol.name,\n declared: declaredCol.type,\n actual: 'missing',\n });\n continue;\n }\n if (actualType !== declaredCol.type.toUpperCase()) {\n logger.warn('setup.drift', {\n field: declaredCol.name,\n declared: declaredCol.type,\n actual: actualType,\n });\n }\n }\n}\n\nexport const setup = async (\n ctx: LifecycleContext<WideConfig, Env>,\n): Promise<SetupResult | undefined> => {\n const { config, env, logger } = ctx;\n const merged = resolveSetup(config.setup, DEFAULT_SETUP);\n if (!merged) {\n logger.debug('setup: skipped (config.setup is false or unset)');\n return;\n }\n const options: Required<Setup> = {\n pragmas: { ...DEFAULT_PRAGMAS, ...(merged.pragmas ?? {}) },\n schema: merged.schema ?? DEFAULT_SCHEMA,\n indexes: merged.indexes ?? [],\n };\n\n const sqlite = config.settings?.sqlite;\n if (!sqlite || !sqlite.url) {\n logger.throw('setup: settings.sqlite.url is missing');\n return;\n }\n const table = sqlite.table ?? 'events';\n\n // Open transient client (or reuse env-injected one). We do NOT touch\n // sqlite._client / sqlite._runInsert here, setup is a separate lifecycle.\n let client: SqliteClient;\n let owned = true;\n if (isSqliteEnv(env) && env.client) {\n client = env.client;\n owned = false;\n } else if (isSqliteEnv(env) && env.SqliteDriver) {\n client = await env.SqliteDriver(sqlite.url, sqlite.authToken);\n } else {\n client = await createClientFromSettings(sqlite.url, sqlite.authToken);\n }\n\n try {\n // 1. Pragmas first (some, like journal_mode, must apply before any write).\n const pragmasApplied: string[] = [];\n for (const [key, value] of Object.entries(options.pragmas)) {\n await client.execute(`PRAGMA ${key} = ${value}`);\n pragmasApplied.push(key);\n }\n\n // 2. Probe whether the table already exists, so tableCreated is reported correctly.\n const tableExisted = await tableExists(client, table);\n\n // 3. CREATE TABLE IF NOT EXISTS with the declared schema.\n await client.execute(buildCreateTableSql(table, options.schema));\n\n // 4. Drift detection. Only when the table existed before; on fresh create\n // the schema matches by definition. Setup never auto-mutates: drift is\n // surfaced via WARN logs, never via ALTER TABLE.\n if (tableExisted) {\n await detectDrift(client, table, options.schema, logger);\n }\n\n // 5. Indexes (CREATE INDEX IF NOT EXISTS).\n const indexesCreated: string[] = [];\n for (const idx of options.indexes) {\n const unique = idx.unique ? 'UNIQUE ' : '';\n const cols = idx.columns.join(', ');\n await client.execute(\n `CREATE ${unique}INDEX IF NOT EXISTS ${idx.name} ON ${table}(${cols})`,\n );\n indexesCreated.push(idx.name);\n }\n\n return {\n tableCreated: !tableExisted,\n pragmasApplied,\n indexesCreated,\n };\n } finally {\n if (owned) {\n try {\n await client.close();\n } catch {\n /* swallow close errors during setup */\n }\n }\n }\n};\n\nexport { tableExists };\n","import type {\n Mapping as WalkerOSMapping,\n Destination as CoreDestination,\n SetupFn as CoreSetupFn,\n} from '@walkeros/core';\nimport type { DestinationServer } from '@walkeros/server-core';\n\n/**\n * @deprecated Use `config.setup` instead. Kept for one minor cycle.\n * `'auto'` maps to `setup: true`, `'manual'` maps to `setup: false`.\n * Removed in the next major.\n */\nexport type SchemaMode = 'auto' | 'manual';\n\n/**\n * Thin cross-driver connection interface. Both drivers are adapted to this shape.\n * Production code uses the adapters in src/drivers/*; tests inject a mock client\n * via env.client to capture sql/args without touching a real database.\n */\nexport interface SqliteClient {\n /** Execute a SQL statement. Used for CREATE TABLE and ad-hoc commands. */\n execute: (sql: string, args?: ReadonlyArray<unknown>) => Promise<void>;\n /**\n * Prepare a statement for repeated execution. Returned function binds args and runs.\n */\n prepare: (sql: string) => (args: ReadonlyArray<unknown>) => Promise<void>;\n /** Run a query that returns rows. Used by setup() for sqlite_master and PRAGMA table_info. */\n query: (\n sql: string,\n args?: ReadonlyArray<unknown>,\n ) => Promise<ReadonlyArray<Record<string, unknown>>>;\n /** Close the connection. */\n close: () => Promise<void>;\n}\n\n/**\n * Factory that constructs an SqliteClient from the user's connection settings.\n * Used by env.SqliteDriver so tests can inject a spy without mocking node_modules.\n */\nexport type SqliteClientFactory = (\n url: string,\n authToken?: string,\n) => Promise<SqliteClient>;\n\nexport interface SqliteSettings {\n /**\n * Connection URL. Starts with `libsql://`, `http://`, `https://`, `wss://`, `ws://`\n * → libSQL driver. Anything else → better-sqlite3 (treated as a file path).\n * Special value `:memory:` → in-memory (better-sqlite3).\n */\n url: string;\n /** libSQL / Turso auth token. Ignored for better-sqlite3. */\n authToken?: string;\n /** Target table name. Defaults to `events`. */\n table?: string;\n /**\n * @deprecated Use `config.setup` instead. Kept for one minor cycle.\n * `'auto'` maps to `setup: true` (init runs CREATE TABLE for the legacy schema).\n * `'manual'` maps to `setup: false`. Removed in the next major.\n */\n schema?: SchemaMode;\n\n // Runtime, set during init/setup, not user-facing.\n _client?: SqliteClient;\n _runInsert?: (args: ReadonlyArray<unknown>) => Promise<void>;\n _ownedClient?: boolean;\n /**\n * Internal flag set by the migration shim. When true, init() runs the legacy\n * 13-column CREATE TABLE path for backward compatibility. Otherwise init()\n * assumes the table already exists (created via `walkeros setup destination.<id>`).\n */\n _legacyAutoCreate?: boolean;\n /**\n * Internal flag set by the migration shim. When true (legacy `schema: 'manual'`),\n * init() skips the modern table-existence probe so the user can bring their own\n * table and column shape without hitting the new \"table not found\" hard-fail.\n */\n _legacySkipProbe?: boolean;\n}\n\nexport interface Settings {\n sqlite: SqliteSettings;\n}\n\nexport type InitSettings = Partial<Settings>;\n\nexport interface Mapping {\n /** Override target table for this rule. */\n table?: string;\n}\n\n/**\n * Provisioning options for `walkeros setup destination.<name>`.\n * Triggered only by the explicit CLI command. Idempotent, never auto-run.\n *\n * Connection URL and target table are read from `settings.sqlite.url` and\n * `settings.sqlite.table` (single source of truth, not duplicated here).\n */\nexport interface Setup {\n /** Pragmas to apply at setup time. Defaults: journal_mode=WAL, synchronous=NORMAL, foreign_keys=ON, temp_store=MEMORY. */\n pragmas?: Record<string, string | number>;\n /** Schema columns. Default: 15-column walkerOS Event v4 canonical (only `name` REQUIRED). */\n schema?: SetupColumn[];\n /** Indexes to create after the table. Optional. */\n indexes?: SetupIndex[];\n}\n\n/** Single column in the SQLite schema. */\nexport interface SetupColumn {\n name: string;\n type: 'TEXT' | 'INTEGER' | 'REAL' | 'BLOB' | 'NUMERIC';\n notNull?: boolean;\n primaryKey?: boolean;\n}\n\n/** SQLite index definition. */\nexport interface SetupIndex {\n name: string;\n columns: string[];\n unique?: boolean;\n}\n\n/**\n * Env, optional driver override. Production leaves this undefined and the\n * destination loads better-sqlite3 or @libsql/client dynamically. Tests\n * provide a factory via `SqliteDriver` or a pre-built client via `client`.\n */\nexport interface Env extends DestinationServer.Env {\n SqliteDriver?: SqliteClientFactory;\n client?: SqliteClient;\n}\n\nexport type Types = CoreDestination.Types<\n Settings,\n Mapping,\n Env,\n InitSettings,\n Setup\n>;\n\nexport interface Destination extends DestinationServer.Destination<Types> {\n init: DestinationServer.InitFn<Types>;\n}\n\nexport type Config = {\n settings: Settings;\n} & DestinationServer.Config<Types>;\n\nexport type InitFn = DestinationServer.InitFn<Types>;\nexport type PushFn = DestinationServer.PushFn<Types>;\nexport type SetupFn = CoreSetupFn<Config, Env>;\nexport type PartialConfig = DestinationServer.PartialConfig<Types>;\nexport type PushEvents = DestinationServer.PushEvents<Mapping>;\n\nexport type Rule = WalkerOSMapping.Rule<Mapping>;\nexport type Rules = WalkerOSMapping.Rules<Rule>;\n","export * as env from './env';\nexport * as step from './step';\n","import type { Env, SqliteClient, SqliteClientFactory } from '../types';\n\n// Narrow helper type aliases so mock functions are typed without `any`.\ntype ExecuteFn = (sql: string, args?: ReadonlyArray<unknown>) => Promise<void>;\ntype PrepareFn = (\n sql: string,\n) => (args: ReadonlyArray<unknown>) => Promise<void>;\ntype QueryFn = (\n sql: string,\n args?: ReadonlyArray<unknown>,\n) => Promise<ReadonlyArray<Record<string, unknown>>>;\ntype CloseFn = () => Promise<void>;\n\nconst asyncExecute: ExecuteFn = () => Promise.resolve();\nconst asyncClose: CloseFn = () => Promise.resolve();\nconst asyncPrepare: PrepareFn = () => () => Promise.resolve();\nconst asyncQuery: QueryFn = () => Promise.resolve([]);\n\nconst mockClient: SqliteClient = {\n execute: asyncExecute,\n prepare: asyncPrepare,\n query: asyncQuery,\n close: asyncClose,\n};\n\nconst mockFactory: SqliteClientFactory = () => Promise.resolve(mockClient);\n\nexport const push: Env = {\n SqliteDriver: mockFactory,\n};\n\n/**\n * Simulation tracking paths. Specifies which function calls to record when\n * running step examples through the collector.\n */\nexport const simulation = ['call:client.prepare', 'call:client.execute'];\n","import type { Flow } from '@walkeros/core';\nimport { getEvent } from '@walkeros/core';\nimport type { Settings } from '../types';\n\n/**\n * Extended step example that may carry destination-level settings overrides.\n */\nexport type SqliteStepExample = Flow.StepExample & {\n settings?: Partial<Settings>;\n};\n\n/**\n * Canonical insert into the default `events` table. `out` records the\n * column args the prepared INSERT is bound with.\n */\nexport const defaultInsert: SqliteStepExample = {\n title: 'Default insert',\n description:\n 'A walker event is inserted into the default events table with canonical columns and JSON-encoded sections.',\n in: getEvent('page view', {\n timestamp: 1700000100,\n id: 'evt-1',\n user: { session: 'sess-1', id: 'user-42' },\n data: { title: 'Home' },\n source: {\n type: 'browser',\n platform: 'web',\n url: 'https://example.com/',\n referrer: 'https://example.com/prev',\n },\n globals: { env: 'prod' },\n consent: { analytics: true },\n }),\n out: [\n [\n 'client.runInsert',\n [\n 1700000100,\n 'evt-1',\n 'page view',\n 'page',\n 'view',\n 'sess-1',\n 'user-42',\n 'https://example.com/',\n 'Home',\n 'https://example.com/prev',\n JSON.stringify({ title: 'Home' }),\n JSON.stringify({ env: 'prod' }),\n JSON.stringify({ analytics: true }),\n ],\n ],\n ],\n};\n\n/**\n * Custom table name. Verifies table overrides while using the canonical column set.\n */\nexport const customTable: SqliteStepExample = {\n title: 'Custom table',\n description:\n 'A destination-level table setting inserts events into a custom SQLite table with the same column layout.',\n in: getEvent('form submit', {\n timestamp: 1700000101,\n id: 'evt-2',\n user: { session: 'sess-99', id: '' },\n data: { type: 'contact' },\n source: {\n type: 'browser',\n platform: 'web',\n url: 'https://example.com/contact',\n },\n globals: {},\n consent: {},\n }),\n settings: {\n sqlite: {\n url: ':memory:',\n table: 'siteEvents',\n },\n },\n out: [\n [\n 'client.runInsert',\n [\n 1700000101,\n 'evt-2',\n 'form submit',\n 'form',\n 'submit',\n 'sess-99',\n '',\n 'https://example.com/contact',\n '',\n '',\n JSON.stringify({ type: 'contact' }),\n JSON.stringify({}),\n JSON.stringify({}),\n ],\n ],\n ],\n};\n\n/**\n * Order event with numeric data. Confirms JSON serialization of nested values.\n */\nexport const orderComplete: SqliteStepExample = {\n title: 'Order insert',\n description:\n 'An order complete is inserted with numeric data serialized as JSON in the data column.',\n in: getEvent('order complete', {\n timestamp: 1700000102,\n id: 'evt-3',\n user: { session: '', id: '' },\n data: { id: 'ORD-1', total: 99 },\n source: { type: 'collector', schema: '4' },\n globals: {},\n consent: {},\n }),\n out: [\n [\n 'client.runInsert',\n [\n 1700000102,\n 'evt-3',\n 'order complete',\n 'order',\n 'complete',\n '',\n '',\n '',\n '',\n '',\n JSON.stringify({ id: 'ORD-1', total: 99 }),\n JSON.stringify({}),\n JSON.stringify({}),\n ],\n ],\n ],\n};\n\n/**\n * Table override per rule -- routes this event to a dedicated table.\n */\nexport const tableOverride: SqliteStepExample = {\n title: 'Table override',\n description:\n 'A mapping rule overrides the target table so specific events are inserted into a dedicated SQLite table.',\n in: getEvent('order complete', {\n timestamp: 1700000103,\n id: 'evt-4',\n user: { session: '', id: '' },\n data: { id: 'ORD-2', total: 42 },\n source: { type: 'collector', schema: '4' },\n globals: {},\n consent: {},\n }),\n mapping: {\n settings: {\n table: 'orders',\n },\n },\n out: [\n [\n 'client.runInsert',\n [\n 1700000103,\n 'evt-4',\n 'order complete',\n 'order',\n 'complete',\n '',\n '',\n '',\n '',\n '',\n JSON.stringify({ id: 'ORD-2', total: 42 }),\n JSON.stringify({}),\n JSON.stringify({}),\n ],\n ],\n ],\n};\n\n/**\n * Ignored event -- mapping.ignore: true produces no insert call.\n */\nexport const ignoredEvent: SqliteStepExample = {\n public: false,\n in: getEvent('debug noise', {\n timestamp: 1700000104,\n id: 'evt-5',\n source: { type: 'collector', schema: '4' },\n }),\n mapping: { ignore: true },\n out: [],\n};\n"],"mappings":"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","names":["import_core","import_core","import_core","isString","buildCreateTableSql","push","import_core"]}
|