@walkeros/server-destination-sqlite 3.4.0-next-1776749829492
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 +132 -0
- package/dist/dev.d.mts +158 -0
- package/dist/dev.d.ts +158 -0
- package/dist/dev.js +1 -0
- package/dist/dev.js.map +1 -0
- package/dist/dev.mjs +1 -0
- package/dist/dev.mjs.map +1 -0
- package/dist/examples/index.d.mts +110 -0
- package/dist/examples/index.d.ts +110 -0
- package/dist/examples/index.js +214 -0
- package/dist/examples/index.mjs +192 -0
- package/dist/index.d.mts +172 -0
- package/dist/index.d.ts +172 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +1 -0
- package/dist/index.mjs.map +1 -0
- package/dist/walkerOS.json +535 -0
- package/package.json +92 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { Destination as Destination$1, Mapping as Mapping$1, Flow, WalkerOS } from '@walkeros/core';
|
|
2
|
+
import { DestinationServer } from '@walkeros/server-core';
|
|
3
|
+
|
|
4
|
+
type SchemaMode = 'auto' | 'manual';
|
|
5
|
+
/**
|
|
6
|
+
* Thin cross-driver connection interface. Both drivers are adapted to this shape.
|
|
7
|
+
* Production code uses the adapters in src/drivers/*; tests inject a mock client
|
|
8
|
+
* via env.client to capture sql/args without touching a real database.
|
|
9
|
+
*/
|
|
10
|
+
interface SqliteClient {
|
|
11
|
+
/** Execute a SQL statement. Used for CREATE TABLE and ad-hoc commands. */
|
|
12
|
+
execute: (sql: string, args?: ReadonlyArray<unknown>) => Promise<void>;
|
|
13
|
+
/**
|
|
14
|
+
* Prepare a statement for repeated execution. Returned function binds args and runs.
|
|
15
|
+
*/
|
|
16
|
+
prepare: (sql: string) => (args: ReadonlyArray<unknown>) => Promise<void>;
|
|
17
|
+
/** Close the connection. */
|
|
18
|
+
close: () => Promise<void>;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Factory that constructs an SqliteClient from the user's connection settings.
|
|
22
|
+
* Used by env.SqliteDriver so tests can inject a spy without mocking node_modules.
|
|
23
|
+
*/
|
|
24
|
+
type SqliteClientFactory = (url: string, authToken?: string) => Promise<SqliteClient>;
|
|
25
|
+
interface SqliteSettings {
|
|
26
|
+
/**
|
|
27
|
+
* Connection URL. Starts with `libsql://`, `http://`, `https://`, `wss://`, `ws://`
|
|
28
|
+
* → libSQL driver. Anything else → better-sqlite3 (treated as a file path).
|
|
29
|
+
* Special value `:memory:` → in-memory (better-sqlite3).
|
|
30
|
+
*/
|
|
31
|
+
url: string;
|
|
32
|
+
/** libSQL / Turso auth token. Ignored for better-sqlite3. */
|
|
33
|
+
authToken?: string;
|
|
34
|
+
/** Target table name. Defaults to `events`. */
|
|
35
|
+
table?: string;
|
|
36
|
+
/**
|
|
37
|
+
* `auto` runs `CREATE TABLE IF NOT EXISTS` with the canonical schema on init.
|
|
38
|
+
* `manual` skips CREATE TABLE. The user brings their own schema and mapping.
|
|
39
|
+
* Defaults to `auto`.
|
|
40
|
+
*/
|
|
41
|
+
schema?: SchemaMode;
|
|
42
|
+
_client?: SqliteClient;
|
|
43
|
+
_runInsert?: (args: ReadonlyArray<unknown>) => Promise<void>;
|
|
44
|
+
_ownedClient?: boolean;
|
|
45
|
+
}
|
|
46
|
+
interface Settings {
|
|
47
|
+
sqlite: SqliteSettings;
|
|
48
|
+
}
|
|
49
|
+
type InitSettings = Partial<Settings>;
|
|
50
|
+
interface Mapping {
|
|
51
|
+
/** Override target table for this rule. */
|
|
52
|
+
table?: string;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Env -- optional driver override. Production leaves this undefined and the
|
|
56
|
+
* destination loads better-sqlite3 or @libsql/client dynamically. Tests
|
|
57
|
+
* provide a factory via `SqliteDriver` or a pre-built client via `client`.
|
|
58
|
+
*/
|
|
59
|
+
interface Env extends DestinationServer.Env {
|
|
60
|
+
SqliteDriver?: SqliteClientFactory;
|
|
61
|
+
client?: SqliteClient;
|
|
62
|
+
}
|
|
63
|
+
type Types = Destination$1.Types<Settings, Mapping, Env, InitSettings>;
|
|
64
|
+
interface Destination extends DestinationServer.Destination<Types> {
|
|
65
|
+
init: DestinationServer.InitFn<Types>;
|
|
66
|
+
}
|
|
67
|
+
type Config = {
|
|
68
|
+
settings: Settings;
|
|
69
|
+
} & DestinationServer.Config<Types>;
|
|
70
|
+
type InitFn = DestinationServer.InitFn<Types>;
|
|
71
|
+
type PushFn = DestinationServer.PushFn<Types>;
|
|
72
|
+
type PartialConfig = DestinationServer.PartialConfig<Types>;
|
|
73
|
+
type PushEvents = DestinationServer.PushEvents<Mapping>;
|
|
74
|
+
type Rule = Mapping$1.Rule<Mapping>;
|
|
75
|
+
type Rules = Mapping$1.Rules<Rule>;
|
|
76
|
+
|
|
77
|
+
type index$1_Config = Config;
|
|
78
|
+
type index$1_Destination = Destination;
|
|
79
|
+
type index$1_Env = Env;
|
|
80
|
+
type index$1_InitFn = InitFn;
|
|
81
|
+
type index$1_InitSettings = InitSettings;
|
|
82
|
+
type index$1_Mapping = Mapping;
|
|
83
|
+
type index$1_PartialConfig = PartialConfig;
|
|
84
|
+
type index$1_PushEvents = PushEvents;
|
|
85
|
+
type index$1_PushFn = PushFn;
|
|
86
|
+
type index$1_Rule = Rule;
|
|
87
|
+
type index$1_Rules = Rules;
|
|
88
|
+
type index$1_SchemaMode = SchemaMode;
|
|
89
|
+
type index$1_Settings = Settings;
|
|
90
|
+
type index$1_SqliteClient = SqliteClient;
|
|
91
|
+
type index$1_SqliteClientFactory = SqliteClientFactory;
|
|
92
|
+
type index$1_SqliteSettings = SqliteSettings;
|
|
93
|
+
type index$1_Types = Types;
|
|
94
|
+
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 };
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
declare const push: Env;
|
|
99
|
+
/**
|
|
100
|
+
* Simulation tracking paths. Specifies which function calls to record when
|
|
101
|
+
* running step examples through the collector.
|
|
102
|
+
*/
|
|
103
|
+
declare const simulation: string[];
|
|
104
|
+
|
|
105
|
+
declare const env_push: typeof push;
|
|
106
|
+
declare const env_simulation: typeof simulation;
|
|
107
|
+
declare namespace env {
|
|
108
|
+
export { env_push as push, env_simulation as simulation };
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Extended step example that may carry destination-level settings overrides.
|
|
113
|
+
*/
|
|
114
|
+
type SqliteStepExample = Flow.StepExample & {
|
|
115
|
+
settings?: Partial<Settings>;
|
|
116
|
+
};
|
|
117
|
+
/**
|
|
118
|
+
* Canonical insert into the default `events` table. `out` records the
|
|
119
|
+
* column args the prepared INSERT is bound with.
|
|
120
|
+
*/
|
|
121
|
+
declare const defaultInsert: SqliteStepExample;
|
|
122
|
+
/**
|
|
123
|
+
* Custom table name. Verifies table overrides while using the canonical column set.
|
|
124
|
+
*/
|
|
125
|
+
declare const customTable: SqliteStepExample;
|
|
126
|
+
/**
|
|
127
|
+
* Order event with numeric data. Confirms JSON serialization of nested values.
|
|
128
|
+
*/
|
|
129
|
+
declare const orderComplete: SqliteStepExample;
|
|
130
|
+
/**
|
|
131
|
+
* Table override per rule -- routes this event to a dedicated table.
|
|
132
|
+
*/
|
|
133
|
+
declare const tableOverride: SqliteStepExample;
|
|
134
|
+
/**
|
|
135
|
+
* Ignored event -- mapping.ignore: true produces no insert call.
|
|
136
|
+
*/
|
|
137
|
+
declare const ignoredEvent: SqliteStepExample;
|
|
138
|
+
|
|
139
|
+
type step_SqliteStepExample = SqliteStepExample;
|
|
140
|
+
declare const step_customTable: typeof customTable;
|
|
141
|
+
declare const step_defaultInsert: typeof defaultInsert;
|
|
142
|
+
declare const step_ignoredEvent: typeof ignoredEvent;
|
|
143
|
+
declare const step_orderComplete: typeof orderComplete;
|
|
144
|
+
declare const step_tableOverride: typeof tableOverride;
|
|
145
|
+
declare namespace step {
|
|
146
|
+
export { type step_SqliteStepExample as SqliteStepExample, step_customTable as customTable, step_defaultInsert as defaultInsert, step_ignoredEvent as ignoredEvent, step_orderComplete as orderComplete, step_tableOverride as tableOverride };
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
declare const index_env: typeof env;
|
|
150
|
+
declare const index_step: typeof step;
|
|
151
|
+
declare namespace index {
|
|
152
|
+
export { index_env as env, index_step as step };
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Canonical columns for the auto-created events table. Order matters -- used
|
|
157
|
+
* to build both CREATE TABLE and the prepared INSERT.
|
|
158
|
+
*/
|
|
159
|
+
declare const CANONICAL_COLUMNS: readonly ["timestamp", "event_id", "name", "entity", "action", "session_id", "user_id", "page_url", "page_title", "referrer_url", "data", "globals", "consent"];
|
|
160
|
+
declare function buildCreateTableSql(table: string): string;
|
|
161
|
+
declare function buildInsertSql(table: string): string;
|
|
162
|
+
/**
|
|
163
|
+
* Map a walkerOS event onto the canonical column order. JSON blobs are
|
|
164
|
+
* stringified. Missing fields become empty strings / zeros.
|
|
165
|
+
*/
|
|
166
|
+
declare function eventToRow(event: WalkerOS.Event): unknown[];
|
|
167
|
+
|
|
168
|
+
declare function isLibsqlUrl(url: string): boolean;
|
|
169
|
+
|
|
170
|
+
declare const destinationSQLite: Destination;
|
|
171
|
+
|
|
172
|
+
export { CANONICAL_COLUMNS, index$1 as DestinationSQLite, buildCreateTableSql, buildInsertSql, destinationSQLite as default, destinationSQLite, eventToRow, index as examples, isLibsqlUrl };
|
package/dist/index.js
ADDED
|
@@ -0,0 +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){var _a;if(!(0,import_core.isObject)(env))return!1;const maybe=env;return"function"==typeof maybe.SqliteDriver||(0,import_core.isObject)(null!=(_a=maybe.client)?_a: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){var _a,_b;let createClient;try{const loaded=require("@libsql/client"),fn=null!=(_b=loaded.createClient)?_b:null==(_a=loaded.default)?void 0:_a.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){var _a,_b,_c,_d,_e,_f,_g,_h,_i,_j,_k,_l,_m,_n;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(),null!=(_a=event.id)?_a:"",null!=(_b=event.name)?_b:"",null!=(_c=event.entity)?_c:"",null!=(_d=event.action)?_d:"",null!=(_f=null==(_e=event.user)?void 0:_e.session)?_f:"",null!=(_h=null==(_g=event.user)?void 0:_g.id)?_h:"",null!=(_j=null==(_i=event.source)?void 0:_i.id)?_j:"",title,null!=(_l=null==(_k=event.source)?void 0:_k.previous_id)?_l:"",JSON.stringify(data),JSON.stringify(null!=(_m=event.globals)?_m:{}),JSON.stringify(null!=(_n=event.consent)?_n:{})]}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={in:(0,import_core4.getEvent)("page view",{timestamp:1700000100,id:"evt-1",user:{session:"sess-1",id:"user-42"},data:{title:"Home"},source:{type:"server",id:"https://example.com/",previous_id:"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={in:(0,import_core4.getEvent)("form submit",{timestamp:1700000101,id:"evt-2",user:{session:"sess-99",id:""},data:{type:"contact"},source:{type:"server",id:"https://example.com/contact",previous_id:""},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={in:(0,import_core4.getEvent)("order complete",{timestamp:1700000102,id:"evt-3",user:{session:"",id:""},data:{id:"ORD-1",total:99},source:{type:"server",id:"",previous_id:""},globals:{},consent:{}}),out:[["client.runInsert",[1700000102,"evt-3","order complete","order","complete","","","","","",JSON.stringify({id:"ORD-1",total:99}),JSON.stringify({}),JSON.stringify({})]]]},tableOverride={in:(0,import_core4.getEvent)("order complete",{timestamp:1700000103,id:"evt-4",user:{session:"",id:""},data:{id:"ORD-2",total:42},source:{type:"server",id:"",previous_id:""},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={in:(0,import_core4.getEvent)("debug noise",{timestamp:1700000104,id:"evt-5",source:{type:"server",id:"",previous_id:""}}),mapping:{ignore:!0},out:[]},destinationSQLite={type:"sqlite",config:{},async init({config:partialConfig,logger:logger,env:env}){var _a,_b;const config=function(partialConfig={},logger){var _a,_b,_c,_d;const sqlite=null!=(_b=(null!=(_a=partialConfig.settings)?_a:{}).sqlite)?_b:{};sqlite.url||logger.throw("Config settings sqlite.url missing");const sqliteSettings={...sqlite,url:sqlite.url,table:null!=(_c=sqlite.table)?_c:"events",schema:null!=(_d=sqlite.schema)?_d:"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(null!=(_a=sqlite.table)?_a:"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(null!=(_b=sqlite.table)?_b:"events")),sqlite._ownedClient=!(isSqliteEnv(env)&&env.client),config},push:async(event,context)=>await async function(event,{config:config,rule:rule,logger:logger}){var _a;const settings=config.settings,sqlite=null==settings?void 0: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=null!=(_a=null==rule?void 0:rule.settings)?_a:{},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=null==config?void 0:config.settings,sqlite=null==settings?void 0: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
|
|
@@ -0,0 +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?.id ?? '',\n title,\n event.source?.previous_id ?? '',\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 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: 'server',\n id: 'https://example.com/',\n previous_id: '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 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: 'server',\n id: 'https://example.com/contact',\n previous_id: '',\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 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: 'server', id: '', previous_id: '' },\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 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: 'server', id: '', previous_id: '' },\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 in: getEvent('debug noise', {\n timestamp: 1700000104,\n id: 'evt-5',\n source: { type: 'server', id: '', previous_id: '' },\n }),\n mapping: { ignore: true },\n out: [],\n};\n"],"mappings":"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","names":["import_core","import_core","push","import_core"]}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var __defProp=Object.defineProperty,__require=(x=>"undefined"!=typeof require?require:"undefined"!=typeof Proxy?new Proxy(x,{get:(a,b)=>("undefined"!=typeof require?require:a)[b]}):x)(function(x){if("undefined"!=typeof require)return require.apply(this,arguments);throw Error('Dynamic require of "'+x+'" is not supported')}),__export=(target,all)=>{for(var name in all)__defProp(target,name,{get:all[name],enumerable:!0})};import{isObject}from"@walkeros/core";function isSqliteEnv(env){var _a;if(!isObject(env))return!1;const maybe=env;return"function"==typeof maybe.SqliteDriver||isObject(null!=(_a=maybe.client)?_a: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){var _a,_b;let createClient;try{const loaded=__require("@libsql/client"),fn=null!=(_b=loaded.createClient)?_b:null==(_a=loaded.default)?void 0:_a.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);import{isObject as isObject2,isString}from"@walkeros/core";var 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){var _a,_b,_c,_d,_e,_f,_g,_h,_i,_j,_k,_l,_m,_n;const data=isObject2(event.data)?event.data:{},title=isString(data.title)?data.title:"";return["number"==typeof event.timestamp?event.timestamp:Date.now(),null!=(_a=event.id)?_a:"",null!=(_b=event.name)?_b:"",null!=(_c=event.entity)?_c:"",null!=(_d=event.action)?_d:"",null!=(_f=null==(_e=event.user)?void 0:_e.session)?_f:"",null!=(_h=null==(_g=event.user)?void 0:_g.id)?_h:"",null!=(_j=null==(_i=event.source)?void 0:_i.id)?_j:"",title,null!=(_l=null==(_k=event.source)?void 0:_k.previous_id)?_l:"",JSON.stringify(data),JSON.stringify(null!=(_m=event.globals)?_m:{}),JSON.stringify(null!=(_n=event.consent)?_n:{})]}import{isString as isString2}from"@walkeros/core";var 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});import{getEvent}from"@walkeros/core";var defaultInsert={in:getEvent("page view",{timestamp:1700000100,id:"evt-1",user:{session:"sess-1",id:"user-42"},data:{title:"Home"},source:{type:"server",id:"https://example.com/",previous_id:"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={in:getEvent("form submit",{timestamp:1700000101,id:"evt-2",user:{session:"sess-99",id:""},data:{type:"contact"},source:{type:"server",id:"https://example.com/contact",previous_id:""},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={in:getEvent("order complete",{timestamp:1700000102,id:"evt-3",user:{session:"",id:""},data:{id:"ORD-1",total:99},source:{type:"server",id:"",previous_id:""},globals:{},consent:{}}),out:[["client.runInsert",[1700000102,"evt-3","order complete","order","complete","","","","","",JSON.stringify({id:"ORD-1",total:99}),JSON.stringify({}),JSON.stringify({})]]]},tableOverride={in:getEvent("order complete",{timestamp:1700000103,id:"evt-4",user:{session:"",id:""},data:{id:"ORD-2",total:42},source:{type:"server",id:"",previous_id:""},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={in:getEvent("debug noise",{timestamp:1700000104,id:"evt-5",source:{type:"server",id:"",previous_id:""}}),mapping:{ignore:!0},out:[]},destinationSQLite={type:"sqlite",config:{},async init({config:partialConfig,logger:logger,env:env}){var _a,_b;const config=function(partialConfig={},logger){var _a,_b,_c,_d;const sqlite=null!=(_b=(null!=(_a=partialConfig.settings)?_a:{}).sqlite)?_b:{};sqlite.url||logger.throw("Config settings sqlite.url missing");const sqliteSettings={...sqlite,url:sqlite.url,table:null!=(_c=sqlite.table)?_c:"events",schema:null!=(_d=sqlite.schema)?_d:"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(null!=(_a=sqlite.table)?_a:"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(null!=(_b=sqlite.table)?_b:"events")),sqlite._ownedClient=!(isSqliteEnv(env)&&env.client),config},push:async(event,context)=>await async function(event,{config:config,rule:rule,logger:logger}){var _a;const settings=config.settings,sqlite=null==settings?void 0: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=null!=(_a=null==rule?void 0:rule.settings)?_a:{},ruleTable=isString2(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=null==config?void 0:config.settings,sqlite=null==settings?void 0: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;export{CANONICAL_COLUMNS,types_exports as DestinationSQLite,buildCreateTableSql,buildInsertSql,index_default as default,destinationSQLite,eventToRow,examples_exports as examples,isLibsqlUrl};//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../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","../src/index.ts"],"sourcesContent":["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?.id ?? '',\n title,\n event.source?.previous_id ?? '',\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 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: 'server',\n id: 'https://example.com/',\n previous_id: '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 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: 'server',\n id: 'https://example.com/contact',\n previous_id: '',\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 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: 'server', id: '', previous_id: '' },\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 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: 'server', id: '', previous_id: '' },\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 in: getEvent('debug noise', {\n timestamp: 1700000104,\n id: 'evt-5',\n source: { type: 'server', id: '', previous_id: '' },\n }),\n mapping: { ignore: true },\n out: [],\n};\n","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"],"mappings":"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","names":["isObject","isString","isString","push"]}
|