@walkeros/server-destination-sqlite 3.4.2 → 4.0.0-next-1777463920154
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 +2 -2
- 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.js +10 -9
- package/dist/examples/index.mjs +10 -9
- 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 +14 -67
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -95,8 +95,8 @@ CREATE TABLE IF NOT EXISTS events (
|
|
|
95
95
|
```
|
|
96
96
|
|
|
97
97
|
Nested JSON fields (`data`, `globals`, `consent`) are stored as JSON strings.
|
|
98
|
-
`page_url` comes from `source.
|
|
99
|
-
`referrer_url` from `source.
|
|
98
|
+
`page_url` comes from `source.url`; `page_title` from `data.title`;
|
|
99
|
+
`referrer_url` from `source.referrer`.
|
|
100
100
|
|
|
101
101
|
## Drivers
|
|
102
102
|
|
package/dist/dev.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var e,t=Object.defineProperty,
|
|
1
|
+
"use strict";var e,t=Object.defineProperty,r=Object.getOwnPropertyDescriptor,i=Object.getOwnPropertyNames,s=Object.prototype.hasOwnProperty,o=(e,r)=>{for(var i in r)t(e,i,{get:r[i],enumerable:!0})},n={};o(n,{examples:()=>v,schemas:()=>a}),module.exports=(e=n,((e,o,n,a)=>{if(o&&"object"==typeof o||"function"==typeof o)for(let l of i(o))s.call(e,l)||l===n||t(e,l,{get:()=>o[l],enumerable:!(a=r(o,l))||a.enumerable});return e})(t({},"__esModule",{value:!0}),e));var a={};o(a,{MappingSchema:()=>d,SettingsSchema:()=>p,SqliteSettingsSchema:()=>m,mapping:()=>g,settings:()=>b});var l=require("@walkeros/core/dev"),c=require("@walkeros/core/dev"),m=c.z.object({url:c.z.string().min(1).describe("SQLite connection URL. libsql://, http(s)://, ws(s):// route to libSQL/Turso. Anything else is treated as a local file path via better-sqlite3. Use ':memory:' for an ephemeral in-memory database."),authToken:c.z.string().describe("libSQL / Turso auth token. Ignored for better-sqlite3 (local) connections.").optional(),table:c.z.string().describe('Target table name. Defaults to "events".').optional(),schema:c.z.enum(["auto","manual"]).describe('"auto" creates the canonical events table with CREATE TABLE IF NOT EXISTS on init. "manual" skips table creation. The user brings their own schema and mapping.').optional()}),p=c.z.object({sqlite:m.describe("SQLite / libSQL configuration (like { url: './events.db' } or { url: 'libsql://my-db.turso.io', authToken: '...' })")}),u=require("@walkeros/core/dev"),d=u.z.object({table:u.z.string().describe("Override target table name for this rule. Takes precedence over settings.sqlite.table.").optional()}),b=(0,l.zodToSchema)(p),g=(0,l.zodToSchema)(d),v={};o(v,{env:()=>h,step:()=>O});var h={};o(h,{push:()=>y,simulation:()=>S});var f={execute:()=>Promise.resolve(),prepare:()=>()=>Promise.resolve(),close:()=>Promise.resolve()},y={SqliteDriver:()=>Promise.resolve(f)},S=["call:client.prepare","call:client.execute"],O={};o(O,{customTable:()=>T,defaultInsert:()=>N,ignoredEvent:()=>k,orderComplete:()=>J,tableOverride:()=>q});var w=require("@walkeros/core"),N={title:"Default insert",description:"A walker event is inserted into the default events table with canonical columns and JSON-encoded sections.",in:(0,w.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})]]]},T={title:"Custom table",description:"A destination-level table setting inserts events into a custom SQLite table with the same column layout.",in:(0,w.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({})]]]},J={title:"Order insert",description:"An order complete is inserted with numeric data serialized as JSON in the data column.",in:(0,w.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({})]]]},q={title:"Table override",description:"A mapping rule overrides the target table so specific events are inserted into a dedicated SQLite table.",in:(0,w.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({})]]]},k={public:!1,in:(0,w.getEvent)("debug noise",{timestamp:1700000104,id:"evt-5",source:{type:"collector",schema:"4"}}),mapping:{ignore:!0},out:[]};//# sourceMappingURL=dev.js.map
|
package/dist/dev.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/dev.ts","../src/schemas/index.ts","../src/schemas/settings.ts","../src/schemas/mapping.ts","../src/examples/index.ts","../src/examples/env.ts","../src/examples/step.ts"],"sourcesContent":["export * as schemas from './schemas';\nexport * as examples from './examples';\n","import { zodToSchema } from '@walkeros/core/dev';\nimport { SettingsSchema } from './settings';\nimport { MappingSchema } from './mapping';\n\nexport {\n SettingsSchema,\n SqliteSettingsSchema,\n type Settings,\n} from './settings';\nexport { MappingSchema, type Mapping } from './mapping';\n\n// JSON Schema\nexport const settings = zodToSchema(SettingsSchema);\nexport const mapping = zodToSchema(MappingSchema);\n","import { z } from '@walkeros/core/dev';\n\nexport const SqliteSettingsSchema = z.object({\n url: z\n .string()\n .min(1)\n .describe(\n \"SQLite connection URL. libsql://, http(s)://, ws(s):// route to libSQL/Turso. Anything else is treated as a local file path via better-sqlite3. Use ':memory:' for an ephemeral in-memory database.\",\n ),\n authToken: z\n .string()\n .describe(\n 'libSQL / Turso auth token. Ignored for better-sqlite3 (local) connections.',\n )\n .optional(),\n table: z\n .string()\n .describe('Target table name. Defaults to \"events\".')\n .optional(),\n schema: z\n .enum(['auto', 'manual'])\n .describe(\n '\"auto\" creates the canonical events table with CREATE TABLE IF NOT EXISTS on init. \"manual\" skips table creation. The user brings their own schema and mapping.',\n )\n .optional(),\n});\n\nexport const SettingsSchema = z.object({\n sqlite: SqliteSettingsSchema.describe(\n \"SQLite / libSQL configuration (like { url: './events.db' } or { url: 'libsql://my-db.turso.io', authToken: '...' })\",\n ),\n});\n\nexport type Settings = z.infer<typeof SettingsSchema>;\n","import { z } from '@walkeros/core/dev';\n\nexport const MappingSchema = z.object({\n table: z\n .string()\n .describe(\n 'Override target table name for this rule. Takes precedence over settings.sqlite.table.',\n )\n .optional(),\n});\n\nexport type Mapping = z.infer<typeof MappingSchema>;\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: '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 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: '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 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: '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 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: '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 public: false,\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_dev","import_dev"]}
|
|
1
|
+
{"version":3,"sources":["../src/dev.ts","../src/schemas/index.ts","../src/schemas/settings.ts","../src/schemas/mapping.ts","../src/examples/index.ts","../src/examples/env.ts","../src/examples/step.ts"],"sourcesContent":["export * as schemas from './schemas';\nexport * as examples from './examples';\n","import { zodToSchema } from '@walkeros/core/dev';\nimport { SettingsSchema } from './settings';\nimport { MappingSchema } from './mapping';\n\nexport {\n SettingsSchema,\n SqliteSettingsSchema,\n type Settings,\n} from './settings';\nexport { MappingSchema, type Mapping } from './mapping';\n\n// JSON Schema\nexport const settings = zodToSchema(SettingsSchema);\nexport const mapping = zodToSchema(MappingSchema);\n","import { z } from '@walkeros/core/dev';\n\nexport const SqliteSettingsSchema = z.object({\n url: z\n .string()\n .min(1)\n .describe(\n \"SQLite connection URL. libsql://, http(s)://, ws(s):// route to libSQL/Turso. Anything else is treated as a local file path via better-sqlite3. Use ':memory:' for an ephemeral in-memory database.\",\n ),\n authToken: z\n .string()\n .describe(\n 'libSQL / Turso auth token. Ignored for better-sqlite3 (local) connections.',\n )\n .optional(),\n table: z\n .string()\n .describe('Target table name. Defaults to \"events\".')\n .optional(),\n schema: z\n .enum(['auto', 'manual'])\n .describe(\n '\"auto\" creates the canonical events table with CREATE TABLE IF NOT EXISTS on init. \"manual\" skips table creation. The user brings their own schema and mapping.',\n )\n .optional(),\n});\n\nexport const SettingsSchema = z.object({\n sqlite: SqliteSettingsSchema.describe(\n \"SQLite / libSQL configuration (like { url: './events.db' } or { url: 'libsql://my-db.turso.io', authToken: '...' })\",\n ),\n});\n\nexport type Settings = z.infer<typeof SettingsSchema>;\n","import { z } from '@walkeros/core/dev';\n\nexport const MappingSchema = z.object({\n table: z\n .string()\n .describe(\n 'Override target table name for this rule. Takes precedence over settings.sqlite.table.',\n )\n .optional(),\n});\n\nexport type Mapping = z.infer<typeof MappingSchema>;\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":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAAAA,cAA4B;;;ACA5B,iBAAkB;AAEX,IAAM,uBAAuB,aAAE,OAAO;AAAA,EAC3C,KAAK,aACF,OAAO,EACP,IAAI,CAAC,EACL;AAAA,IACC;AAAA,EACF;AAAA,EACF,WAAW,aACR,OAAO,EACP;AAAA,IACC;AAAA,EACF,EACC,SAAS;AAAA,EACZ,OAAO,aACJ,OAAO,EACP,SAAS,0CAA0C,EACnD,SAAS;AAAA,EACZ,QAAQ,aACL,KAAK,CAAC,QAAQ,QAAQ,CAAC,EACvB;AAAA,IACC;AAAA,EACF,EACC,SAAS;AACd,CAAC;AAEM,IAAM,iBAAiB,aAAE,OAAO;AAAA,EACrC,QAAQ,qBAAqB;AAAA,IAC3B;AAAA,EACF;AACF,CAAC;;;AC/BD,IAAAC,cAAkB;AAEX,IAAM,gBAAgB,cAAE,OAAO;AAAA,EACpC,OAAO,cACJ,OAAO,EACP;AAAA,IACC;AAAA,EACF,EACC,SAAS;AACd,CAAC;;;AFGM,IAAM,eAAW,yBAAY,cAAc;AAC3C,IAAM,cAAU,yBAAY,aAAa;;;AGbhD;AAAA;AAAA;AAAA;AAAA;;;ACAA;AAAA;AAAA;AAAA;AAAA;AASA,IAAM,eAA0B,MAAM,QAAQ,QAAQ;AACtD,IAAM,aAAsB,MAAM,QAAQ,QAAQ;AAClD,IAAM,eAA0B,MAAM,MAAM,QAAQ,QAAQ;AAE5D,IAAM,aAA2B;AAAA,EAC/B,SAAS;AAAA,EACT,SAAS;AAAA,EACT,OAAO;AACT;AAEA,IAAM,cAAmC,MAAM,QAAQ,QAAQ,UAAU;AAElE,IAAM,OAAY;AAAA,EACvB,cAAc;AAChB;AAMO,IAAM,aAAa,CAAC,uBAAuB,qBAAqB;;;AC7BvE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,kBAAyB;AAclB,IAAM,gBAAmC;AAAA,EAC9C,OAAO;AAAA,EACP,aACE;AAAA,EACF,QAAI,sBAAS,aAAa;AAAA,IACxB,WAAW;AAAA,IACX,IAAI;AAAA,IACJ,MAAM,EAAE,SAAS,UAAU,IAAI,UAAU;AAAA,IACzC,MAAM,EAAE,OAAO,OAAO;AAAA,IACtB,QAAQ;AAAA,MACN,MAAM;AAAA,MACN,UAAU;AAAA,MACV,KAAK;AAAA,MACL,UAAU;AAAA,IACZ;AAAA,IACA,SAAS,EAAE,KAAK,OAAO;AAAA,IACvB,SAAS,EAAE,WAAW,KAAK;AAAA,EAC7B,CAAC;AAAA,EACD,KAAK;AAAA,IACH;AAAA,MACE;AAAA,MACA;AAAA,QACE;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,KAAK,UAAU,EAAE,OAAO,OAAO,CAAC;AAAA,QAChC,KAAK,UAAU,EAAE,KAAK,OAAO,CAAC;AAAA,QAC9B,KAAK,UAAU,EAAE,WAAW,KAAK,CAAC;AAAA,MACpC;AAAA,IACF;AAAA,EACF;AACF;AAKO,IAAM,cAAiC;AAAA,EAC5C,OAAO;AAAA,EACP,aACE;AAAA,EACF,QAAI,sBAAS,eAAe;AAAA,IAC1B,WAAW;AAAA,IACX,IAAI;AAAA,IACJ,MAAM,EAAE,SAAS,WAAW,IAAI,GAAG;AAAA,IACnC,MAAM,EAAE,MAAM,UAAU;AAAA,IACxB,QAAQ;AAAA,MACN,MAAM;AAAA,MACN,UAAU;AAAA,MACV,KAAK;AAAA,IACP;AAAA,IACA,SAAS,CAAC;AAAA,IACV,SAAS,CAAC;AAAA,EACZ,CAAC;AAAA,EACD,UAAU;AAAA,IACR,QAAQ;AAAA,MACN,KAAK;AAAA,MACL,OAAO;AAAA,IACT;AAAA,EACF;AAAA,EACA,KAAK;AAAA,IACH;AAAA,MACE;AAAA,MACA;AAAA,QACE;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,KAAK,UAAU,EAAE,MAAM,UAAU,CAAC;AAAA,QAClC,KAAK,UAAU,CAAC,CAAC;AAAA,QACjB,KAAK,UAAU,CAAC,CAAC;AAAA,MACnB;AAAA,IACF;AAAA,EACF;AACF;AAKO,IAAM,gBAAmC;AAAA,EAC9C,OAAO;AAAA,EACP,aACE;AAAA,EACF,QAAI,sBAAS,kBAAkB;AAAA,IAC7B,WAAW;AAAA,IACX,IAAI;AAAA,IACJ,MAAM,EAAE,SAAS,IAAI,IAAI,GAAG;AAAA,IAC5B,MAAM,EAAE,IAAI,SAAS,OAAO,GAAG;AAAA,IAC/B,QAAQ,EAAE,MAAM,aAAa,QAAQ,IAAI;AAAA,IACzC,SAAS,CAAC;AAAA,IACV,SAAS,CAAC;AAAA,EACZ,CAAC;AAAA,EACD,KAAK;AAAA,IACH;AAAA,MACE;AAAA,MACA;AAAA,QACE;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,KAAK,UAAU,EAAE,IAAI,SAAS,OAAO,GAAG,CAAC;AAAA,QACzC,KAAK,UAAU,CAAC,CAAC;AAAA,QACjB,KAAK,UAAU,CAAC,CAAC;AAAA,MACnB;AAAA,IACF;AAAA,EACF;AACF;AAKO,IAAM,gBAAmC;AAAA,EAC9C,OAAO;AAAA,EACP,aACE;AAAA,EACF,QAAI,sBAAS,kBAAkB;AAAA,IAC7B,WAAW;AAAA,IACX,IAAI;AAAA,IACJ,MAAM,EAAE,SAAS,IAAI,IAAI,GAAG;AAAA,IAC5B,MAAM,EAAE,IAAI,SAAS,OAAO,GAAG;AAAA,IAC/B,QAAQ,EAAE,MAAM,aAAa,QAAQ,IAAI;AAAA,IACzC,SAAS,CAAC;AAAA,IACV,SAAS,CAAC;AAAA,EACZ,CAAC;AAAA,EACD,SAAS;AAAA,IACP,UAAU;AAAA,MACR,OAAO;AAAA,IACT;AAAA,EACF;AAAA,EACA,KAAK;AAAA,IACH;AAAA,MACE;AAAA,MACA;AAAA,QACE;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,KAAK,UAAU,EAAE,IAAI,SAAS,OAAO,GAAG,CAAC;AAAA,QACzC,KAAK,UAAU,CAAC,CAAC;AAAA,QACjB,KAAK,UAAU,CAAC,CAAC;AAAA,MACnB;AAAA,IACF;AAAA,EACF;AACF;AAKO,IAAM,eAAkC;AAAA,EAC7C,QAAQ;AAAA,EACR,QAAI,sBAAS,eAAe;AAAA,IAC1B,WAAW;AAAA,IACX,IAAI;AAAA,IACJ,QAAQ,EAAE,MAAM,aAAa,QAAQ,IAAI;AAAA,EAC3C,CAAC;AAAA,EACD,SAAS,EAAE,QAAQ,KAAK;AAAA,EACxB,KAAK,CAAC;AACR;","names":["import_dev","import_dev"]}
|
package/dist/dev.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var e=Object.defineProperty,t=(t,i)=>{for(var s in i)e(t,s,{get:i[s],enumerable:!0})},i={};t(i,{MappingSchema:()=>l,SettingsSchema:()=>a,SqliteSettingsSchema:()=>o,mapping:()=>m,settings:()=>c});import{zodToSchema as s}from"@walkeros/core/dev";import{z as r}from"@walkeros/core/dev";var o=r.object({url:r.string().min(1).describe("SQLite connection URL. libsql://, http(s)://, ws(s):// route to libSQL/Turso. Anything else is treated as a local file path via better-sqlite3. Use ':memory:' for an ephemeral in-memory database."),authToken:r.string().describe("libSQL / Turso auth token. Ignored for better-sqlite3 (local) connections.").optional(),table:r.string().describe('Target table name. Defaults to "events".').optional(),schema:r.enum(["auto","manual"]).describe('"auto" creates the canonical events table with CREATE TABLE IF NOT EXISTS on init. "manual" skips table creation. The user brings their own schema and mapping.').optional()}),a=r.object({sqlite:o.describe("SQLite / libSQL configuration (like { url: './events.db' } or { url: 'libsql://my-db.turso.io', authToken: '...' })")});import{z as n}from"@walkeros/core/dev";var l=n.object({table:n.string().describe("Override target table name for this rule. Takes precedence over settings.sqlite.table.").optional()}),c=s(a),m=s(l),p={};t(p,{env:()=>d,step:()=>g});var d={};t(d,{push:()=>
|
|
1
|
+
var e=Object.defineProperty,t=(t,i)=>{for(var s in i)e(t,s,{get:i[s],enumerable:!0})},i={};t(i,{MappingSchema:()=>l,SettingsSchema:()=>a,SqliteSettingsSchema:()=>o,mapping:()=>m,settings:()=>c});import{zodToSchema as s}from"@walkeros/core/dev";import{z as r}from"@walkeros/core/dev";var o=r.object({url:r.string().min(1).describe("SQLite connection URL. libsql://, http(s)://, ws(s):// route to libSQL/Turso. Anything else is treated as a local file path via better-sqlite3. Use ':memory:' for an ephemeral in-memory database."),authToken:r.string().describe("libSQL / Turso auth token. Ignored for better-sqlite3 (local) connections.").optional(),table:r.string().describe('Target table name. Defaults to "events".').optional(),schema:r.enum(["auto","manual"]).describe('"auto" creates the canonical events table with CREATE TABLE IF NOT EXISTS on init. "manual" skips table creation. The user brings their own schema and mapping.').optional()}),a=r.object({sqlite:o.describe("SQLite / libSQL configuration (like { url: './events.db' } or { url: 'libsql://my-db.turso.io', authToken: '...' })")});import{z as n}from"@walkeros/core/dev";var l=n.object({table:n.string().describe("Override target table name for this rule. Takes precedence over settings.sqlite.table.").optional()}),c=s(a),m=s(l),p={};t(p,{env:()=>d,step:()=>g});var d={};t(d,{push:()=>b,simulation:()=>v});var u={execute:()=>Promise.resolve(),prepare:()=>()=>Promise.resolve(),close:()=>Promise.resolve()},b={SqliteDriver:()=>Promise.resolve(u)},v=["call:client.prepare","call:client.execute"],g={};t(g,{customTable:()=>S,defaultInsert:()=>f,ignoredEvent:()=>w,orderComplete:()=>y,tableOverride:()=>O});import{getEvent as h}from"@walkeros/core";var f={title:"Default insert",description:"A walker event is inserted into the default events table with canonical columns and JSON-encoded sections.",in:h("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})]]]},S={title:"Custom table",description:"A destination-level table setting inserts events into a custom SQLite table with the same column layout.",in:h("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({})]]]},y={title:"Order insert",description:"An order complete is inserted with numeric data serialized as JSON in the data column.",in:h("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({})]]]},O={title:"Table override",description:"A mapping rule overrides the target table so specific events are inserted into a dedicated SQLite table.",in:h("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({})]]]},w={public:!1,in:h("debug noise",{timestamp:1700000104,id:"evt-5",source:{type:"collector",schema:"4"}}),mapping:{ignore:!0},out:[]};export{p as examples,i as schemas};//# sourceMappingURL=dev.mjs.map
|
package/dist/dev.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/schemas/index.ts","../src/schemas/settings.ts","../src/schemas/mapping.ts","../src/examples/index.ts","../src/examples/env.ts","../src/examples/step.ts"],"sourcesContent":["import { zodToSchema } from '@walkeros/core/dev';\nimport { SettingsSchema } from './settings';\nimport { MappingSchema } from './mapping';\n\nexport {\n SettingsSchema,\n SqliteSettingsSchema,\n type Settings,\n} from './settings';\nexport { MappingSchema, type Mapping } from './mapping';\n\n// JSON Schema\nexport const settings = zodToSchema(SettingsSchema);\nexport const mapping = zodToSchema(MappingSchema);\n","import { z } from '@walkeros/core/dev';\n\nexport const SqliteSettingsSchema = z.object({\n url: z\n .string()\n .min(1)\n .describe(\n \"SQLite connection URL. libsql://, http(s)://, ws(s):// route to libSQL/Turso. Anything else is treated as a local file path via better-sqlite3. Use ':memory:' for an ephemeral in-memory database.\",\n ),\n authToken: z\n .string()\n .describe(\n 'libSQL / Turso auth token. Ignored for better-sqlite3 (local) connections.',\n )\n .optional(),\n table: z\n .string()\n .describe('Target table name. Defaults to \"events\".')\n .optional(),\n schema: z\n .enum(['auto', 'manual'])\n .describe(\n '\"auto\" creates the canonical events table with CREATE TABLE IF NOT EXISTS on init. \"manual\" skips table creation. The user brings their own schema and mapping.',\n )\n .optional(),\n});\n\nexport const SettingsSchema = z.object({\n sqlite: SqliteSettingsSchema.describe(\n \"SQLite / libSQL configuration (like { url: './events.db' } or { url: 'libsql://my-db.turso.io', authToken: '...' })\",\n ),\n});\n\nexport type Settings = z.infer<typeof SettingsSchema>;\n","import { z } from '@walkeros/core/dev';\n\nexport const MappingSchema = z.object({\n table: z\n .string()\n .describe(\n 'Override target table name for this rule. Takes precedence over settings.sqlite.table.',\n )\n .optional(),\n});\n\nexport type Mapping = z.infer<typeof MappingSchema>;\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: '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 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: '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 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: '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 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: '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 public: false,\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":["z"]}
|
|
1
|
+
{"version":3,"sources":["../src/schemas/index.ts","../src/schemas/settings.ts","../src/schemas/mapping.ts","../src/examples/index.ts","../src/examples/env.ts","../src/examples/step.ts"],"sourcesContent":["import { zodToSchema } from '@walkeros/core/dev';\nimport { SettingsSchema } from './settings';\nimport { MappingSchema } from './mapping';\n\nexport {\n SettingsSchema,\n SqliteSettingsSchema,\n type Settings,\n} from './settings';\nexport { MappingSchema, type Mapping } from './mapping';\n\n// JSON Schema\nexport const settings = zodToSchema(SettingsSchema);\nexport const mapping = zodToSchema(MappingSchema);\n","import { z } from '@walkeros/core/dev';\n\nexport const SqliteSettingsSchema = z.object({\n url: z\n .string()\n .min(1)\n .describe(\n \"SQLite connection URL. libsql://, http(s)://, ws(s):// route to libSQL/Turso. Anything else is treated as a local file path via better-sqlite3. Use ':memory:' for an ephemeral in-memory database.\",\n ),\n authToken: z\n .string()\n .describe(\n 'libSQL / Turso auth token. Ignored for better-sqlite3 (local) connections.',\n )\n .optional(),\n table: z\n .string()\n .describe('Target table name. Defaults to \"events\".')\n .optional(),\n schema: z\n .enum(['auto', 'manual'])\n .describe(\n '\"auto\" creates the canonical events table with CREATE TABLE IF NOT EXISTS on init. \"manual\" skips table creation. The user brings their own schema and mapping.',\n )\n .optional(),\n});\n\nexport const SettingsSchema = z.object({\n sqlite: SqliteSettingsSchema.describe(\n \"SQLite / libSQL configuration (like { url: './events.db' } or { url: 'libsql://my-db.turso.io', authToken: '...' })\",\n ),\n});\n\nexport type Settings = z.infer<typeof SettingsSchema>;\n","import { z } from '@walkeros/core/dev';\n\nexport const MappingSchema = z.object({\n table: z\n .string()\n .describe(\n 'Override target table name for this rule. Takes precedence over settings.sqlite.table.',\n )\n .optional(),\n});\n\nexport type Mapping = z.infer<typeof MappingSchema>;\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":["z"]}
|
package/dist/examples/index.js
CHANGED
|
@@ -64,9 +64,10 @@ var defaultInsert = {
|
|
|
64
64
|
user: { session: "sess-1", id: "user-42" },
|
|
65
65
|
data: { title: "Home" },
|
|
66
66
|
source: {
|
|
67
|
-
type: "
|
|
68
|
-
|
|
69
|
-
|
|
67
|
+
type: "browser",
|
|
68
|
+
platform: "web",
|
|
69
|
+
url: "https://example.com/",
|
|
70
|
+
referrer: "https://example.com/prev"
|
|
70
71
|
},
|
|
71
72
|
globals: { env: "prod" },
|
|
72
73
|
consent: { analytics: true }
|
|
@@ -101,9 +102,9 @@ var customTable = {
|
|
|
101
102
|
user: { session: "sess-99", id: "" },
|
|
102
103
|
data: { type: "contact" },
|
|
103
104
|
source: {
|
|
104
|
-
type: "
|
|
105
|
-
|
|
106
|
-
|
|
105
|
+
type: "browser",
|
|
106
|
+
platform: "web",
|
|
107
|
+
url: "https://example.com/contact"
|
|
107
108
|
},
|
|
108
109
|
globals: {},
|
|
109
110
|
consent: {}
|
|
@@ -143,7 +144,7 @@ var orderComplete = {
|
|
|
143
144
|
id: "evt-3",
|
|
144
145
|
user: { session: "", id: "" },
|
|
145
146
|
data: { id: "ORD-1", total: 99 },
|
|
146
|
-
source: { type: "
|
|
147
|
+
source: { type: "collector", schema: "4" },
|
|
147
148
|
globals: {},
|
|
148
149
|
consent: {}
|
|
149
150
|
}),
|
|
@@ -176,7 +177,7 @@ var tableOverride = {
|
|
|
176
177
|
id: "evt-4",
|
|
177
178
|
user: { session: "", id: "" },
|
|
178
179
|
data: { id: "ORD-2", total: 42 },
|
|
179
|
-
source: { type: "
|
|
180
|
+
source: { type: "collector", schema: "4" },
|
|
180
181
|
globals: {},
|
|
181
182
|
consent: {}
|
|
182
183
|
}),
|
|
@@ -211,7 +212,7 @@ var ignoredEvent = {
|
|
|
211
212
|
in: (0, import_core.getEvent)("debug noise", {
|
|
212
213
|
timestamp: 1700000104,
|
|
213
214
|
id: "evt-5",
|
|
214
|
-
source: { type: "
|
|
215
|
+
source: { type: "collector", schema: "4" }
|
|
215
216
|
}),
|
|
216
217
|
mapping: { ignore: true },
|
|
217
218
|
out: []
|
package/dist/examples/index.mjs
CHANGED
|
@@ -43,9 +43,10 @@ var defaultInsert = {
|
|
|
43
43
|
user: { session: "sess-1", id: "user-42" },
|
|
44
44
|
data: { title: "Home" },
|
|
45
45
|
source: {
|
|
46
|
-
type: "
|
|
47
|
-
|
|
48
|
-
|
|
46
|
+
type: "browser",
|
|
47
|
+
platform: "web",
|
|
48
|
+
url: "https://example.com/",
|
|
49
|
+
referrer: "https://example.com/prev"
|
|
49
50
|
},
|
|
50
51
|
globals: { env: "prod" },
|
|
51
52
|
consent: { analytics: true }
|
|
@@ -80,9 +81,9 @@ var customTable = {
|
|
|
80
81
|
user: { session: "sess-99", id: "" },
|
|
81
82
|
data: { type: "contact" },
|
|
82
83
|
source: {
|
|
83
|
-
type: "
|
|
84
|
-
|
|
85
|
-
|
|
84
|
+
type: "browser",
|
|
85
|
+
platform: "web",
|
|
86
|
+
url: "https://example.com/contact"
|
|
86
87
|
},
|
|
87
88
|
globals: {},
|
|
88
89
|
consent: {}
|
|
@@ -122,7 +123,7 @@ var orderComplete = {
|
|
|
122
123
|
id: "evt-3",
|
|
123
124
|
user: { session: "", id: "" },
|
|
124
125
|
data: { id: "ORD-1", total: 99 },
|
|
125
|
-
source: { type: "
|
|
126
|
+
source: { type: "collector", schema: "4" },
|
|
126
127
|
globals: {},
|
|
127
128
|
consent: {}
|
|
128
129
|
}),
|
|
@@ -155,7 +156,7 @@ var tableOverride = {
|
|
|
155
156
|
id: "evt-4",
|
|
156
157
|
user: { session: "", id: "" },
|
|
157
158
|
data: { id: "ORD-2", total: 42 },
|
|
158
|
-
source: { type: "
|
|
159
|
+
source: { type: "collector", schema: "4" },
|
|
159
160
|
globals: {},
|
|
160
161
|
consent: {}
|
|
161
162
|
}),
|
|
@@ -190,7 +191,7 @@ var ignoredEvent = {
|
|
|
190
191
|
in: getEvent("debug noise", {
|
|
191
192
|
timestamp: 1700000104,
|
|
192
193
|
id: "evt-5",
|
|
193
|
-
source: { type: "
|
|
194
|
+
source: { type: "collector", schema: "4" }
|
|
194
195
|
}),
|
|
195
196
|
mapping: { ignore: true },
|
|
196
197
|
out: []
|
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){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={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:"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={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:"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={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:"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={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:"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={public:!1,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
|
|
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
|
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?.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 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: '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 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: '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 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: '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 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: '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 public: false,\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":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACQA,kBAAyB;AAElB,SAAS,UACd,gBAA+B,CAAC,GAChC,QACQ;AAbV;AAcE,QAAM,OAAO,mBAAc,aAAd,YAA0B,CAAC;AACxC,QAAM,UACJ,SAAI,WAAJ,YAAe,CAAC;AAElB,MAAI,CAAC,OAAO,KAAK;AACf,WAAO,MAAM,oCAAoC;AAAA,EACnD;AAEA,QAAM,iBAAiC;AAAA,IACrC,GAAG;AAAA,IACH,KAAK,OAAO;AAAA,IACZ,QAAO,YAAO,UAAP,YAAgB;AAAA,IACvB,SAAQ,YAAO,WAAP,YAAiB;AAAA,EAC3B;AAEA,MAAI,eAAe,WAAW,YAAY,CAAC,cAAc,SAAS;AAChE,WAAO;AAAA,MACL;AAAA,IACF;AAAA,EACF;AAEA,QAAM,WAAqB,EAAE,QAAQ,eAAe;AAEpD,SAAO,EAAE,GAAG,eAAe,SAAS;AACtC;AAEO,SAAS,YAAY,KAA0B;AAxCtD;AAyCE,MAAI,KAAC,sBAAS,GAAG,EAAG,QAAO;AAC3B,QAAM,QAAQ;AACd,SACE,OAAO,MAAM,iBAAiB,kBAAc,uBAAS,WAAM,WAAN,YAAgB,IAAI;AAE7E;;;ACxBA,eAAsB,yBACpB,UACuB;AACvB,MAAI;AACJ,MAAI;AAEF,UAAM,SAAS,QAAQ,gBAAgB;AAGvC,eACE,aAAa,UAAU,OAAO,OAAO,YAAY,aAC7C,OAAO,UACN;AAAA,EACT,SAAS,KAAK;AACZ,UAAM,IAAI;AAAA,MACR,wLAEqB,OAAO,GAAG,CAAC;AAAA,IAClC;AAAA,EACF;AAEA,QAAM,KAAK,IAAI,SAAS,QAAQ;AAEhC,SAAO;AAAA,IACL,MAAM,QAAQ,KAAK,OAAO,CAAC,GAAG;AAC5B,SAAG,QAAQ,GAAG,EAAE,IAAI,GAAI,IAAkB;AAAA,IAC5C;AAAA,IACA,QAAQ,KAAK;AACX,YAAM,OAAO,GAAG,QAAQ,GAAG;AAC3B,aAAO,OAAO,SAAS;AACrB,aAAK,IAAI,GAAI,IAAkB;AAAA,MACjC;AAAA,IACF;AAAA,IACA,MAAM,QAAQ;AACZ,SAAG,MAAM;AAAA,IACX;AAAA,EACF;AACF;;;AClCA,eAAsB,mBACpB,KACA,WACuB;AA5BzB;AA6BE,MAAI;AACJ,MAAI;AACF,UAAM,SAAS,QAAQ,gBAAgB;AAIvC,UAAM,MAAK,YAAO,iBAAP,aAAuB,YAAO,YAAP,mBAAgB;AAClD,QAAI,OAAO,OAAO,YAAY;AAC5B,YAAM,IAAI,MAAM,iDAAiD;AAAA,IACnE;AACA,mBAAe;AAAA,EACjB,SAAS,KAAK;AACZ,UAAM,IAAI;AAAA,MACR,kKAEqB,OAAO,GAAG,CAAC;AAAA,IAClC;AAAA,EACF;AAEA,QAAM,SAAS,aAAa,EAAE,KAAK,UAAU,CAAC;AAE9C,SAAO;AAAA,IACL,MAAM,QAAQ,KAAK,OAAO,CAAC,GAAG;AAC5B,YAAM,OAAO,QAAQ,EAAE,KAAK,KAAK,CAAC;AAAA,IACpC;AAAA,IACA,QAAQ,KAAK;AAGX,aAAO,OAAO,SAAS;AACrB,cAAM,OAAO,QAAQ,EAAE,KAAK,KAAK,CAAC;AAAA,MACpC;AAAA,IACF;AAAA,IACA,MAAM,QAAQ;AACZ,aAAO,MAAM;AAAA,IACf;AAAA,EACF;AACF;;;AC7DA,IAAM,sBAAsB;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEO,SAAS,YAAY,KAAsB;AAChD,SAAO,oBAAoB,KAAK,CAAC,MAAM,IAAI,WAAW,CAAC,CAAC;AAC1D;AAMO,IAAM,iBAAsC,OAAO,KAAK,cAAc;AAC3E,MAAI,YAAY,GAAG,EAAG,QAAO,mBAAmB,KAAK,SAAS;AAC9D,SAAO,yBAAyB,GAAG;AACrC;AAEA,eAAsB,yBACpB,KACA,WACuB;AACvB,SAAO,eAAe,KAAK,SAAS;AACtC;;;AC7BA,IAAAA,eAAmC;AAM5B,IAAM,oBAAoB;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEO,SAAS,oBAAoB,OAAuB;AACzD,SAAO,8BAA8B,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAiB5C;AAEO,SAAS,eAAe,OAAuB;AACpD,QAAM,OAAO,kBAAkB,KAAK,IAAI;AACxC,QAAM,eAAe,kBAAkB,IAAI,MAAM,GAAG,EAAE,KAAK,IAAI;AAC/D,SAAO,eAAe,KAAK,KAAK,IAAI,aAAa,YAAY;AAC/D;AAMO,SAAS,WAAW,OAAkC;AArD7D;AAsDE,QAAM,WAAO,uBAAS,MAAM,IAAI,IAAI,MAAM,OAAO,CAAC;AAClD,QAAM,YAAQ,uBAAS,KAAK,KAAK,IAAI,KAAK,QAAQ;AAElD,SAAO;AAAA,IACL,OAAO,MAAM,cAAc,WAAW,MAAM,YAAY,KAAK,IAAI;AAAA,KACjE,WAAM,OAAN,YAAY;AAAA,KACZ,WAAM,SAAN,YAAc;AAAA,KACd,WAAM,WAAN,YAAgB;AAAA,KAChB,WAAM,WAAN,YAAgB;AAAA,KAChB,iBAAM,SAAN,mBAAY,YAAZ,YAAuB;AAAA,KACvB,iBAAM,SAAN,mBAAY,OAAZ,YAAkB;AAAA,KAClB,iBAAM,WAAN,mBAAc,OAAd,YAAoB;AAAA,IACpB;AAAA,KACA,iBAAM,WAAN,mBAAc,gBAAd,YAA6B;AAAA,IAC7B,KAAK,UAAU,IAAI;AAAA,IACnB,KAAK,WAAU,WAAM,YAAN,YAAiB,CAAC,CAAC;AAAA,IAClC,KAAK,WAAU,WAAM,YAAN,YAAiB,CAAC,CAAC;AAAA,EACpC;AACF;;;ACvEA,IAAAC,eAAyB;AAGlB,IAAM,OAAe,eAAgB,OAAO,EAAE,QAAQ,MAAM,OAAO,GAAG;AAJ7E;AAKE,QAAM,WAAW,OAAO;AACxB,QAAM,SAAqC,qCAAU;AAErD,MAAI,CAAC,QAAQ;AACX,WAAO,KAAK,yBAAyB;AACrC;AAAA,EACF;AAEA,QAAM,SAAS,OAAO;AACtB,MAAI,CAAC,QAAQ;AACX,WAAO,KAAK,+BAA+B;AAC3C;AAAA,EACF;AAEA,QAAM,gBAAe,kCAAM,aAAN,YAAkB,CAAC;AACxC,QAAM,gBAAY,uBAAS,aAAa,KAAK,IAAI,aAAa,QAAQ;AAItE,QAAM,iBAAiB,aAAa,OAAO,SAAS;AACpD,QAAM,YACJ,aAAa,cAAc,OAAO,QAC9B,OAAO,QAAQ,eAAe,cAAc,CAAC,IAC7C,OAAO;AAEb,MAAI,CAAC,WAAW;AACd,WAAO,KAAK,sCAAsC;AAClD;AAAA,EACF;AAEA,QAAM,MAAM,WAAW,KAAK;AAE5B,SAAO,MAAM,iBAAiB;AAAA,IAC5B,OAAO;AAAA,IACP,WAAW,MAAM;AAAA,EACnB,CAAC;AAED,MAAI;AACF,UAAM,UAAU,GAAG;AACnB,WAAO,MAAM,0BAA0B,EAAE,OAAO,eAAe,CAAC;AAAA,EAClE,SAAS,OAAO;AACd,WAAO,MAAM,wBAAwB;AAAA,MACnC,OAAO;AAAA,MACP,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,IAC9D,CAAC;AAAA,EACH;AACF;;;ACnDA;;;ACAA;AAAA;AAAA;AAAA;AAAA;;;ACAA;AAAA;AAAA,cAAAC;AAAA,EAAA;AAAA;AASA,IAAM,eAA0B,MAAM,QAAQ,QAAQ;AACtD,IAAM,aAAsB,MAAM,QAAQ,QAAQ;AAClD,IAAM,eAA0B,MAAM,MAAM,QAAQ,QAAQ;AAE5D,IAAM,aAA2B;AAAA,EAC/B,SAAS;AAAA,EACT,SAAS;AAAA,EACT,OAAO;AACT;AAEA,IAAM,cAAmC,MAAM,QAAQ,QAAQ,UAAU;AAElE,IAAMA,QAAY;AAAA,EACvB,cAAc;AAChB;AAMO,IAAM,aAAa,CAAC,uBAAuB,qBAAqB;;;AC7BvE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,IAAAC,eAAyB;AAclB,IAAM,gBAAmC;AAAA,EAC9C,OAAO;AAAA,EACP,aACE;AAAA,EACF,QAAI,uBAAS,aAAa;AAAA,IACxB,WAAW;AAAA,IACX,IAAI;AAAA,IACJ,MAAM,EAAE,SAAS,UAAU,IAAI,UAAU;AAAA,IACzC,MAAM,EAAE,OAAO,OAAO;AAAA,IACtB,QAAQ;AAAA,MACN,MAAM;AAAA,MACN,IAAI;AAAA,MACJ,aAAa;AAAA,IACf;AAAA,IACA,SAAS,EAAE,KAAK,OAAO;AAAA,IACvB,SAAS,EAAE,WAAW,KAAK;AAAA,EAC7B,CAAC;AAAA,EACD,KAAK;AAAA,IACH;AAAA,MACE;AAAA,MACA;AAAA,QACE;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,KAAK,UAAU,EAAE,OAAO,OAAO,CAAC;AAAA,QAChC,KAAK,UAAU,EAAE,KAAK,OAAO,CAAC;AAAA,QAC9B,KAAK,UAAU,EAAE,WAAW,KAAK,CAAC;AAAA,MACpC;AAAA,IACF;AAAA,EACF;AACF;AAKO,IAAM,cAAiC;AAAA,EAC5C,OAAO;AAAA,EACP,aACE;AAAA,EACF,QAAI,uBAAS,eAAe;AAAA,IAC1B,WAAW;AAAA,IACX,IAAI;AAAA,IACJ,MAAM,EAAE,SAAS,WAAW,IAAI,GAAG;AAAA,IACnC,MAAM,EAAE,MAAM,UAAU;AAAA,IACxB,QAAQ;AAAA,MACN,MAAM;AAAA,MACN,IAAI;AAAA,MACJ,aAAa;AAAA,IACf;AAAA,IACA,SAAS,CAAC;AAAA,IACV,SAAS,CAAC;AAAA,EACZ,CAAC;AAAA,EACD,UAAU;AAAA,IACR,QAAQ;AAAA,MACN,KAAK;AAAA,MACL,OAAO;AAAA,IACT;AAAA,EACF;AAAA,EACA,KAAK;AAAA,IACH;AAAA,MACE;AAAA,MACA;AAAA,QACE;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,KAAK,UAAU,EAAE,MAAM,UAAU,CAAC;AAAA,QAClC,KAAK,UAAU,CAAC,CAAC;AAAA,QACjB,KAAK,UAAU,CAAC,CAAC;AAAA,MACnB;AAAA,IACF;AAAA,EACF;AACF;AAKO,IAAM,gBAAmC;AAAA,EAC9C,OAAO;AAAA,EACP,aACE;AAAA,EACF,QAAI,uBAAS,kBAAkB;AAAA,IAC7B,WAAW;AAAA,IACX,IAAI;AAAA,IACJ,MAAM,EAAE,SAAS,IAAI,IAAI,GAAG;AAAA,IAC5B,MAAM,EAAE,IAAI,SAAS,OAAO,GAAG;AAAA,IAC/B,QAAQ,EAAE,MAAM,UAAU,IAAI,IAAI,aAAa,GAAG;AAAA,IAClD,SAAS,CAAC;AAAA,IACV,SAAS,CAAC;AAAA,EACZ,CAAC;AAAA,EACD,KAAK;AAAA,IACH;AAAA,MACE;AAAA,MACA;AAAA,QACE;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,KAAK,UAAU,EAAE,IAAI,SAAS,OAAO,GAAG,CAAC;AAAA,QACzC,KAAK,UAAU,CAAC,CAAC;AAAA,QACjB,KAAK,UAAU,CAAC,CAAC;AAAA,MACnB;AAAA,IACF;AAAA,EACF;AACF;AAKO,IAAM,gBAAmC;AAAA,EAC9C,OAAO;AAAA,EACP,aACE;AAAA,EACF,QAAI,uBAAS,kBAAkB;AAAA,IAC7B,WAAW;AAAA,IACX,IAAI;AAAA,IACJ,MAAM,EAAE,SAAS,IAAI,IAAI,GAAG;AAAA,IAC5B,MAAM,EAAE,IAAI,SAAS,OAAO,GAAG;AAAA,IAC/B,QAAQ,EAAE,MAAM,UAAU,IAAI,IAAI,aAAa,GAAG;AAAA,IAClD,SAAS,CAAC;AAAA,IACV,SAAS,CAAC;AAAA,EACZ,CAAC;AAAA,EACD,SAAS;AAAA,IACP,UAAU;AAAA,MACR,OAAO;AAAA,IACT;AAAA,EACF;AAAA,EACA,KAAK;AAAA,IACH;AAAA,MACE;AAAA,MACA;AAAA,QACE;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,KAAK,UAAU,EAAE,IAAI,SAAS,OAAO,GAAG,CAAC;AAAA,QACzC,KAAK,UAAU,CAAC,CAAC;AAAA,QACjB,KAAK,UAAU,CAAC,CAAC;AAAA,MACnB;AAAA,IACF;AAAA,EACF;AACF;AAKO,IAAM,eAAkC;AAAA,EAC7C,QAAQ;AAAA,EACR,QAAI,uBAAS,eAAe;AAAA,IAC1B,WAAW;AAAA,IACX,IAAI;AAAA,IACJ,QAAQ,EAAE,MAAM,UAAU,IAAI,IAAI,aAAa,GAAG;AAAA,EACpD,CAAC;AAAA,EACD,SAAS,EAAE,QAAQ,KAAK;AAAA,EACxB,KAAK,CAAC;AACR;;;AV5KO,IAAM,oBAAiC;AAAA,EAC5C,MAAM;AAAA,EAEN,QAAQ,CAAC;AAAA,EAET,MAAM,KAAK,EAAE,QAAQ,eAAe,QAAQ,IAAI,GAAG;AA5BrD;AA6BI,UAAM,SAAS,UAAU,eAAe,MAAM;AAC9C,UAAM,WAAW,OAAO;AACxB,UAAM,SAAS,SAAS;AAGxB,QAAI,OAAO,QAAS,QAAO;AAE3B,QAAI;AAGJ,QAAI,YAAY,GAAG,GAAG;AACpB,YAAM,WAAW;AACjB,UAAI,SAAS,QAAQ;AACnB,iBAAS,SAAS;AAAA,MACpB,WAAW,SAAS,cAAc;AAChC,iBAAS,MAAM,SAAS,aAAa,OAAO,KAAK,OAAO,SAAS;AAAA,MACnE;AAAA,IACF;AAGA,QAAI,CAAC,QAAQ;AACX,UAAI;AACF,iBAAS,MAAM,yBAAyB,OAAO,KAAK,OAAO,SAAS;AAAA,MACtE,SAAS,KAAK;AACZ,eAAO;AAAA,UACL,4DAA4D,OAAO,GAAG,CAAC;AAAA,QACzE;AACA,eAAO;AAAA,MACT;AAAA,IACF;AAGA,QAAI,OAAO,WAAW,QAAQ;AAC5B,UAAI;AACF,cAAM,OAAO,QAAQ,qBAAoB,YAAO,UAAP,YAAgB,QAAQ,CAAC;AAAA,MACpE,SAAS,KAAK;AACZ,eAAO;AAAA,UACL,6DAA6D,OAAO,GAAG,CAAC;AAAA,QAC1E;AACA,eAAO;AAAA,MACT;AAAA,IACF;AAGA,WAAO,UAAU;AACjB,WAAO,aAAa,OAAO;AAAA,MACzB,gBAAe,YAAO,UAAP,YAAgB,QAAQ;AAAA,IACzC;AACA,WAAO,eAAe,EAAE,YAAY,GAAG,KAAM,IAAY;AAEzD,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,KAAK,OAAO,SAAS;AACzB,WAAO,MAAM,KAAK,OAAO,OAAO;AAAA,EAClC;AAAA,EAEA,MAAM,QAAQ,EAAE,OAAO,GAAG;AACxB,UAAM,WAAW,iCAAQ;AACzB,UAAM,SAAS,qCAAU;AACzB,QAAI,CAAC,OAAQ;AAEb,UAAM,SAAS,OAAO;AAEtB,QAAI,UAAU,OAAO,cAAc;AACjC,UAAI;AACF,cAAM,OAAO,MAAM;AAAA,MACrB,UAAE;AACA,eAAO,UAAU;AACjB,eAAO,aAAa;AACpB,eAAO,eAAe;AAAA,MACxB;AAAA,IACF;AAAA,EACF;AACF;AAEA,IAAO,gBAAQ;","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/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"]}
|
package/dist/index.mjs
CHANGED
|
@@ -1 +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={title:"Default insert",description:"A walker event is inserted into the default events table with canonical columns and JSON-encoded sections.",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={title:"Custom table",description:"A destination-level table setting inserts events into a custom SQLite table with the same column layout.",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={title:"Order insert",description:"An order complete is inserted with numeric data serialized as JSON in the data column.",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={title:"Table override",description:"A mapping rule overrides the target table so specific events are inserted into a dedicated SQLite table.",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={public:!1,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
|
|
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){if(!isObject(env))return!1;const maybe=env;return"function"==typeof maybe.SqliteDriver||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);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){const data=isObject2(event.data)?event.data:{},title=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??{})]}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={title:"Default insert",description:"A walker event is inserted into the default events table with canonical columns and JSON-encoded sections.",in: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: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: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: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: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=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=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;export{CANONICAL_COLUMNS,types_exports as DestinationSQLite,buildCreateTableSql,buildInsertSql,index_default as default,destinationSQLite,eventToRow,examples_exports as examples,isLibsqlUrl};//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +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 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: '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 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: '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 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: '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 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: '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 public: false,\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"]}
|
|
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?.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","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"]}
|
package/dist/walkerOS.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$meta": {
|
|
3
3
|
"package": "@walkeros/server-destination-sqlite",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "4.0.0-next-1777463920154",
|
|
5
5
|
"type": "destination",
|
|
6
6
|
"platform": [
|
|
7
7
|
"server"
|
|
@@ -103,13 +103,6 @@
|
|
|
103
103
|
"entity": "child",
|
|
104
104
|
"data": {
|
|
105
105
|
"is": "subordinated"
|
|
106
|
-
},
|
|
107
|
-
"nested": [],
|
|
108
|
-
"context": {
|
|
109
|
-
"element": [
|
|
110
|
-
"child",
|
|
111
|
-
0
|
|
112
|
-
]
|
|
113
106
|
}
|
|
114
107
|
}
|
|
115
108
|
],
|
|
@@ -120,16 +113,10 @@
|
|
|
120
113
|
"action": "submit",
|
|
121
114
|
"timestamp": 1700000101,
|
|
122
115
|
"timing": 3.14,
|
|
123
|
-
"group": "gr0up",
|
|
124
|
-
"count": 1,
|
|
125
|
-
"version": {
|
|
126
|
-
"source": "3.4.2",
|
|
127
|
-
"tagging": 1
|
|
128
|
-
},
|
|
129
116
|
"source": {
|
|
130
|
-
"type": "
|
|
131
|
-
"
|
|
132
|
-
"
|
|
117
|
+
"type": "browser",
|
|
118
|
+
"platform": "web",
|
|
119
|
+
"url": "https://example.com/contact"
|
|
133
120
|
}
|
|
134
121
|
},
|
|
135
122
|
"settings": {
|
|
@@ -188,13 +175,6 @@
|
|
|
188
175
|
"entity": "child",
|
|
189
176
|
"data": {
|
|
190
177
|
"is": "subordinated"
|
|
191
|
-
},
|
|
192
|
-
"nested": [],
|
|
193
|
-
"context": {
|
|
194
|
-
"element": [
|
|
195
|
-
"child",
|
|
196
|
-
0
|
|
197
|
-
]
|
|
198
178
|
}
|
|
199
179
|
}
|
|
200
180
|
],
|
|
@@ -207,16 +187,11 @@
|
|
|
207
187
|
"action": "view",
|
|
208
188
|
"timestamp": 1700000100,
|
|
209
189
|
"timing": 3.14,
|
|
210
|
-
"group": "gr0up",
|
|
211
|
-
"count": 1,
|
|
212
|
-
"version": {
|
|
213
|
-
"source": "3.4.2",
|
|
214
|
-
"tagging": 1
|
|
215
|
-
},
|
|
216
190
|
"source": {
|
|
217
|
-
"type": "
|
|
218
|
-
"
|
|
219
|
-
"
|
|
191
|
+
"type": "browser",
|
|
192
|
+
"platform": "web",
|
|
193
|
+
"url": "https://example.com/",
|
|
194
|
+
"referrer": "https://example.com/prev"
|
|
220
195
|
}
|
|
221
196
|
},
|
|
222
197
|
"out": [
|
|
@@ -276,13 +251,6 @@
|
|
|
276
251
|
"entity": "child",
|
|
277
252
|
"data": {
|
|
278
253
|
"is": "subordinated"
|
|
279
|
-
},
|
|
280
|
-
"nested": [],
|
|
281
|
-
"context": {
|
|
282
|
-
"element": [
|
|
283
|
-
"child",
|
|
284
|
-
0
|
|
285
|
-
]
|
|
286
254
|
}
|
|
287
255
|
}
|
|
288
256
|
],
|
|
@@ -295,16 +263,9 @@
|
|
|
295
263
|
"action": "noise",
|
|
296
264
|
"timestamp": 1700000104,
|
|
297
265
|
"timing": 3.14,
|
|
298
|
-
"group": "gr0up",
|
|
299
|
-
"count": 1,
|
|
300
|
-
"version": {
|
|
301
|
-
"source": "3.4.2",
|
|
302
|
-
"tagging": 1
|
|
303
|
-
},
|
|
304
266
|
"source": {
|
|
305
|
-
"type": "
|
|
306
|
-
"
|
|
307
|
-
"previous_id": ""
|
|
267
|
+
"type": "collector",
|
|
268
|
+
"schema": "4"
|
|
308
269
|
}
|
|
309
270
|
},
|
|
310
271
|
"mapping": {
|
|
@@ -390,16 +351,9 @@
|
|
|
390
351
|
"action": "complete",
|
|
391
352
|
"timestamp": 1700000102,
|
|
392
353
|
"timing": 3.14,
|
|
393
|
-
"group": "gr0up",
|
|
394
|
-
"count": 1,
|
|
395
|
-
"version": {
|
|
396
|
-
"source": "3.4.2",
|
|
397
|
-
"tagging": 1
|
|
398
|
-
},
|
|
399
354
|
"source": {
|
|
400
|
-
"type": "
|
|
401
|
-
"
|
|
402
|
-
"previous_id": ""
|
|
355
|
+
"type": "collector",
|
|
356
|
+
"schema": "4"
|
|
403
357
|
}
|
|
404
358
|
},
|
|
405
359
|
"out": [
|
|
@@ -501,16 +455,9 @@
|
|
|
501
455
|
"action": "complete",
|
|
502
456
|
"timestamp": 1700000103,
|
|
503
457
|
"timing": 3.14,
|
|
504
|
-
"group": "gr0up",
|
|
505
|
-
"count": 1,
|
|
506
|
-
"version": {
|
|
507
|
-
"source": "3.4.2",
|
|
508
|
-
"tagging": 1
|
|
509
|
-
},
|
|
510
458
|
"source": {
|
|
511
|
-
"type": "
|
|
512
|
-
"
|
|
513
|
-
"previous_id": ""
|
|
459
|
+
"type": "collector",
|
|
460
|
+
"schema": "4"
|
|
514
461
|
}
|
|
515
462
|
},
|
|
516
463
|
"mapping": {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@walkeros/server-destination-sqlite",
|
|
3
3
|
"description": "SQLite server destination for walkerOS (local via better-sqlite3, remote via libSQL/Turso)",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "4.0.0-next-1777463920154",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "./dist/index.js",
|
|
7
7
|
"module": "./dist/index.mjs",
|
|
@@ -37,8 +37,8 @@
|
|
|
37
37
|
"update": "npx npm-check-updates -u && npm update"
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@walkeros/core": "
|
|
41
|
-
"@walkeros/server-core": "
|
|
40
|
+
"@walkeros/core": "4.0.0-next-1777463920154",
|
|
41
|
+
"@walkeros/server-core": "4.0.0-next-1777463920154"
|
|
42
42
|
},
|
|
43
43
|
"peerDependencies": {
|
|
44
44
|
"better-sqlite3": "^11.0.0",
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
}
|
|
54
54
|
},
|
|
55
55
|
"devDependencies": {
|
|
56
|
-
"@walkeros/collector": "
|
|
56
|
+
"@walkeros/collector": "4.0.0-next-1777463920154",
|
|
57
57
|
"better-sqlite3": "^11.0.0",
|
|
58
58
|
"@libsql/client": "^0.14.0",
|
|
59
59
|
"@types/better-sqlite3": "^7.6.11"
|