@walkeros/server-transformer-fingerprint 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/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/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 +20 -56
- package/package.json +5 -5
package/dist/dev.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var e,t=Object.defineProperty,i=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,s=Object.prototype.hasOwnProperty,n=(e,i)=>{for(var r in i)t(e,r,{get:i[r],enumerable:!0})},a={};n(a,{examples:()=>c,hints:()=>
|
|
1
|
+
"use strict";var e,t=Object.defineProperty,i=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,s=Object.prototype.hasOwnProperty,n=(e,i)=>{for(var r in i)t(e,r,{get:i[r],enumerable:!0})},a={};n(a,{examples:()=>c,hints:()=>v,schemas:()=>o}),module.exports=(e=a,((e,n,a,o)=>{if(n&&"object"==typeof n||"function"==typeof n)for(let p of r(n))s.call(e,p)||p===a||t(e,p,{get:()=>n[p],enumerable:!(o=i(n,p))||o.enumerable});return e})(t({},"__esModule",{value:!0}),e));var o={};n(o,{SettingsSchema:()=>d,settings:()=>l});var p=require("@walkeros/core/dev"),g=require("@walkeros/core/dev"),d=g.z.object({fields:g.z.array(g.z.union([g.z.string().describe('Dot-notation path: "ingest.ip", "event.data.userId"'),g.z.object({key:g.z.string().optional().describe("Source property path"),value:g.z.unknown().optional().describe("Static value or fallback"),fn:g.z.string().optional().describe("$code: function for value transformation")}).describe("Mapping value config for computed fields")])).describe("Fields to include in hash (order matters). Each resolved via getMappingValue with source { event, ingest }."),output:g.z.string().optional().describe('Dot-notation path where hash is stored on the event. Default: "user.hash"'),length:g.z.number().int().positive().optional().describe("Truncate hash to this length. Default: full 64-char SHA-256 hash")}).describe("Fingerprint transformer: generates deterministic user hashes from event fields"),l=(0,p.zodToSchema)(d),c={};n(c,{step:()=>u});var u={};n(u,{ipAnonymization:()=>h,missingFields:()=>f,serverFingerprint:()=>m});var m={title:"Server fingerprint",description:"Standard server fingerprint using ingest.ip and ingest.userAgent. Requires source config.ingest.",in:{name:"page view",data:{domain:"www.example.com",title:"Getting Started",id:"/docs/getting-started"},id:"ev-1700000600",trigger:"load",entity:"page",action:"view",timestamp:1700000600,source:{type:"express",platform:"server"}},out:[["return",{event:{name:"page view",data:{domain:"www.example.com",title:"Getting Started",id:"/docs/getting-started"},user:{hash:"158f99cc06e33fd6"},id:"ev-1700000600",trigger:"load",entity:"page",action:"view",timestamp:1700000600,source:{type:"express",platform:"server"}}}]]},f={public:!1,description:"Graceful handling when ingest is missing - fields resolve to empty strings, hash is still generated.",in:{name:"session start",data:{id:"s3ss10n"},id:"ev-1700000601",trigger:"load",entity:"session",action:"start",timestamp:1700000601,source:{type:"express",platform:"server"}},out:[["return",{event:{name:"session start",data:{id:"s3ss10n"},user:{hash:"e183220b699c10a8"},id:"ev-1700000601",trigger:"load",entity:"session",action:"start",timestamp:1700000601,source:{type:"express",platform:"server"}}}]]},h={title:"IP anonymization",description:'Privacy-preserving fingerprint using key+fn pattern: fn truncates IP to /24 subnet before hashing, so 10.0.42.* users share a hash. Config: fields: [{ key: "ingest.ip", fn: ip => ip.replace(/\\.\\d+$/, ".0") }, "ingest.userAgent"]',in:{name:"page view",data:{domain:"www.example.com",title:"Privacy Policy",id:"/privacy"},id:"ev-1700000602",trigger:"load",entity:"page",action:"view",timestamp:1700000602,source:{type:"express",platform:"server"}},out:[["return",{event:{name:"page view",data:{domain:"www.example.com",title:"Privacy Policy",id:"/privacy"},user:{hash:"44d9154b9a9b3792"},id:"ev-1700000602",trigger:"load",entity:"page",action:"view",timestamp:1700000602,source:{type:"express",platform:"server"}}}]]},v={"ingest-prerequisite":{text:"Fields starting with ingest.* require the server source to have config.ingest configured. Without it, ingest is undefined and all ingest.* fields resolve to empty strings — the hash is still generated but not unique. Always pair this transformer with a source that extracts request metadata.",code:[{lang:"json",code:JSON.stringify({sources:{express:{package:"@walkeros/server-source-express",config:{settings:{port:8080},ingest:{ip:"req.ip",userAgent:"req.headers.user-agent",origin:"req.headers.origin"}}}},transformers:{fingerprint:{package:"@walkeros/server-transformer-fingerprint",config:{settings:{fields:["ingest.ip","ingest.userAgent"],output:"user.hash",length:16}}}}},null,2)}]},"fields-overview":{text:"Fields resolve from { event, ingest } via walkerOS mapping. Common patterns: ingest.ip (client IP), ingest.userAgent (browser UA), event.data.* (any event property). For time-based rotation use fn fields: daily rotation with toISOString().slice(0,10), monthly with getDate(). Order matters — same fields in different order produce different hashes. Use { key, fn } objects to transform before hashing (e.g., IP anonymization via the ipAnonymization step example)."}};//# 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/examples/index.ts","../src/examples/step.ts","../src/hints.ts"],"sourcesContent":["export * as schemas from './schemas';\nexport * as examples from './examples';\nexport { hints } from './hints';\n","import { zodToSchema } from '@walkeros/core/dev';\nimport { SettingsSchema } from './settings';\n\nexport { SettingsSchema, type Settings } from './settings';\nexport const settings = zodToSchema(SettingsSchema);\n","import { z } from '@walkeros/core/dev';\n\n/**\n * Fingerprint transformer settings schema.\n *\n * Mirrors: types.ts FingerprintSettings\n */\nexport const SettingsSchema = z\n .object({\n fields: z\n .array(\n z.union([\n z\n .string()\n .describe('Dot-notation path: \"ingest.ip\", \"event.data.userId\"'),\n z\n .object({\n key: z.string().optional().describe('Source property path'),\n value: z\n .unknown()\n .optional()\n .describe('Static value or fallback'),\n fn: z\n .string()\n .optional()\n .describe('$code: function for value transformation'),\n })\n .describe('Mapping value config for computed fields'),\n ]),\n )\n .describe(\n 'Fields to include in hash (order matters). Each resolved via getMappingValue with source { event, ingest }.',\n ),\n output: z\n .string()\n .optional()\n .describe(\n 'Dot-notation path where hash is stored on the event. Default: \"user.hash\"',\n ),\n length: z\n .number()\n .int()\n .positive()\n .optional()\n .describe(\n 'Truncate hash to this length. Default: full 64-char SHA-256 hash',\n ),\n })\n .describe(\n 'Fingerprint transformer: generates deterministic user hashes from event fields',\n );\n\nexport type Settings = z.infer<typeof SettingsSchema>;\n","export * as step from './step';\n","import type { Flow } from '@walkeros/core';\n\nexport const serverFingerprint: Flow.StepExample = {\n title: 'Server fingerprint',\n description:\n 'Standard server fingerprint using ingest.ip and ingest.userAgent. Requires source config.ingest.',\n in: {\n name: 'page view',\n data: {\n domain: 'www.example.com',\n title: 'Getting Started',\n id: '/docs/getting-started',\n },\n id: '1700000600-gr0up-1',\n trigger: 'load',\n entity: 'page',\n action: 'view',\n timestamp: 1700000600,\n group: 'gr0up',\n count: 1,\n version: { tagging: 1 },\n source: { type: 'server', id: '', previous_id: '' },\n },\n out: [\n [\n 'return',\n {\n event: {\n name: 'page view',\n data: {\n domain: 'www.example.com',\n title: 'Getting Started',\n id: '/docs/getting-started',\n },\n user: { hash: '158f99cc06e33fd6' },\n id: '1700000600-gr0up-1',\n trigger: 'load',\n entity: 'page',\n action: 'view',\n timestamp: 1700000600,\n group: 'gr0up',\n count: 1,\n version: { tagging: 1 },\n source: { type: 'server', id: '', previous_id: '' },\n },\n },\n ],\n ],\n};\n\nexport const missingFields: Flow.StepExample = {\n public: false,\n description:\n 'Graceful handling when ingest is missing — fields resolve to empty strings, hash is still generated.',\n in: {\n name: 'session start',\n data: { id: 's3ss10n' },\n id: '1700000601-gr0up-2',\n trigger: 'load',\n entity: 'session',\n action: 'start',\n timestamp: 1700000601,\n group: 'gr0up',\n count: 2,\n version: { tagging: 1 },\n source: { type: 'server', id: '', previous_id: '' },\n },\n out: [\n [\n 'return',\n {\n event: {\n name: 'session start',\n data: { id: 's3ss10n' },\n user: { hash: 'e183220b699c10a8' },\n id: '1700000601-gr0up-2',\n trigger: 'load',\n entity: 'session',\n action: 'start',\n timestamp: 1700000601,\n group: 'gr0up',\n count: 2,\n version: { tagging: 1 },\n source: { type: 'server', id: '', previous_id: '' },\n },\n },\n ],\n ],\n};\n\nexport const ipAnonymization: Flow.StepExample = {\n title: 'IP anonymization',\n description:\n 'Privacy-preserving fingerprint using key+fn pattern: ' +\n 'fn truncates IP to /24 subnet before hashing, so 10.0.42.* users share a hash. ' +\n 'Config: fields: [{ key: \"ingest.ip\", fn: ip => ip.replace(/\\\\.\\\\d+$/, \".0\") }, \"ingest.userAgent\"]',\n in: {\n name: 'page view',\n data: {\n domain: 'www.example.com',\n title: 'Privacy Policy',\n id: '/privacy',\n },\n id: '1700000602-gr0up-3',\n trigger: 'load',\n entity: 'page',\n action: 'view',\n timestamp: 1700000602,\n group: 'gr0up',\n count: 3,\n version: { tagging: 1 },\n source: { type: 'server', id: '', previous_id: '' },\n },\n out: [\n [\n 'return',\n {\n event: {\n name: 'page view',\n data: {\n domain: 'www.example.com',\n title: 'Privacy Policy',\n id: '/privacy',\n },\n user: { hash: '44d9154b9a9b3792' },\n id: '1700000602-gr0up-3',\n trigger: 'load',\n entity: 'page',\n action: 'view',\n timestamp: 1700000602,\n group: 'gr0up',\n count: 3,\n version: { tagging: 1 },\n source: { type: 'server', id: '', previous_id: '' },\n },\n },\n ],\n ],\n};\n","import type { Hint } from '@walkeros/core';\n\nexport const hints: Hint.Hints = {\n 'ingest-prerequisite': {\n text: 'Fields starting with ingest.* require the server source to have config.ingest configured. Without it, ingest is undefined and all ingest.* fields resolve to empty strings — the hash is still generated but not unique. Always pair this transformer with a source that extracts request metadata.',\n code: [\n {\n lang: 'json',\n code: JSON.stringify(\n {\n sources: {\n express: {\n package: '@walkeros/server-source-express',\n config: {\n settings: { port: 8080 },\n ingest: {\n ip: 'req.ip',\n userAgent: 'req.headers.user-agent',\n origin: 'req.headers.origin',\n },\n },\n },\n },\n transformers: {\n fingerprint: {\n package: '@walkeros/server-transformer-fingerprint',\n config: {\n settings: {\n fields: ['ingest.ip', 'ingest.userAgent'],\n output: 'user.hash',\n length: 16,\n },\n },\n },\n },\n },\n null,\n 2,\n ),\n },\n ],\n },\n 'fields-overview': {\n text: 'Fields resolve from { event, ingest } via walkerOS mapping. Common patterns: ingest.ip (client IP), ingest.userAgent (browser UA), event.data.* (any event property). For time-based rotation use fn fields: daily rotation with toISOString().slice(0,10), monthly with getDate(). Order matters — same fields in different order produce different hashes. Use { key, fn } objects to transform before hashing (e.g., IP anonymization via the ipAnonymization step example).',\n },\n};\n"],"mappings":"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","names":["import_dev"]}
|
|
1
|
+
{"version":3,"sources":["../src/dev.ts","../src/schemas/index.ts","../src/schemas/settings.ts","../src/examples/index.ts","../src/examples/step.ts","../src/hints.ts"],"sourcesContent":["export * as schemas from './schemas';\nexport * as examples from './examples';\nexport { hints } from './hints';\n","import { zodToSchema } from '@walkeros/core/dev';\nimport { SettingsSchema } from './settings';\n\nexport { SettingsSchema, type Settings } from './settings';\nexport const settings = zodToSchema(SettingsSchema);\n","import { z } from '@walkeros/core/dev';\n\n/**\n * Fingerprint transformer settings schema.\n *\n * Mirrors: types.ts FingerprintSettings\n */\nexport const SettingsSchema = z\n .object({\n fields: z\n .array(\n z.union([\n z\n .string()\n .describe('Dot-notation path: \"ingest.ip\", \"event.data.userId\"'),\n z\n .object({\n key: z.string().optional().describe('Source property path'),\n value: z\n .unknown()\n .optional()\n .describe('Static value or fallback'),\n fn: z\n .string()\n .optional()\n .describe('$code: function for value transformation'),\n })\n .describe('Mapping value config for computed fields'),\n ]),\n )\n .describe(\n 'Fields to include in hash (order matters). Each resolved via getMappingValue with source { event, ingest }.',\n ),\n output: z\n .string()\n .optional()\n .describe(\n 'Dot-notation path where hash is stored on the event. Default: \"user.hash\"',\n ),\n length: z\n .number()\n .int()\n .positive()\n .optional()\n .describe(\n 'Truncate hash to this length. Default: full 64-char SHA-256 hash',\n ),\n })\n .describe(\n 'Fingerprint transformer: generates deterministic user hashes from event fields',\n );\n\nexport type Settings = z.infer<typeof SettingsSchema>;\n","export * as step from './step';\n","import type { Flow } from '@walkeros/core';\n\nexport const serverFingerprint: Flow.StepExample = {\n title: 'Server fingerprint',\n description:\n 'Standard server fingerprint using ingest.ip and ingest.userAgent. Requires source config.ingest.',\n in: {\n name: 'page view',\n data: {\n domain: 'www.example.com',\n title: 'Getting Started',\n id: '/docs/getting-started',\n },\n id: 'ev-1700000600',\n trigger: 'load',\n entity: 'page',\n action: 'view',\n timestamp: 1700000600,\n source: { type: 'express', platform: 'server' },\n },\n out: [\n [\n 'return',\n {\n event: {\n name: 'page view',\n data: {\n domain: 'www.example.com',\n title: 'Getting Started',\n id: '/docs/getting-started',\n },\n user: { hash: '158f99cc06e33fd6' },\n id: 'ev-1700000600',\n trigger: 'load',\n entity: 'page',\n action: 'view',\n timestamp: 1700000600,\n source: { type: 'express', platform: 'server' },\n },\n },\n ],\n ],\n};\n\nexport const missingFields: Flow.StepExample = {\n public: false,\n description:\n 'Graceful handling when ingest is missing - fields resolve to empty strings, hash is still generated.',\n in: {\n name: 'session start',\n data: { id: 's3ss10n' },\n id: 'ev-1700000601',\n trigger: 'load',\n entity: 'session',\n action: 'start',\n timestamp: 1700000601,\n source: { type: 'express', platform: 'server' },\n },\n out: [\n [\n 'return',\n {\n event: {\n name: 'session start',\n data: { id: 's3ss10n' },\n user: { hash: 'e183220b699c10a8' },\n id: 'ev-1700000601',\n trigger: 'load',\n entity: 'session',\n action: 'start',\n timestamp: 1700000601,\n source: { type: 'express', platform: 'server' },\n },\n },\n ],\n ],\n};\n\nexport const ipAnonymization: Flow.StepExample = {\n title: 'IP anonymization',\n description:\n 'Privacy-preserving fingerprint using key+fn pattern: ' +\n 'fn truncates IP to /24 subnet before hashing, so 10.0.42.* users share a hash. ' +\n 'Config: fields: [{ key: \"ingest.ip\", fn: ip => ip.replace(/\\\\.\\\\d+$/, \".0\") }, \"ingest.userAgent\"]',\n in: {\n name: 'page view',\n data: {\n domain: 'www.example.com',\n title: 'Privacy Policy',\n id: '/privacy',\n },\n id: 'ev-1700000602',\n trigger: 'load',\n entity: 'page',\n action: 'view',\n timestamp: 1700000602,\n source: { type: 'express', platform: 'server' },\n },\n out: [\n [\n 'return',\n {\n event: {\n name: 'page view',\n data: {\n domain: 'www.example.com',\n title: 'Privacy Policy',\n id: '/privacy',\n },\n user: { hash: '44d9154b9a9b3792' },\n id: 'ev-1700000602',\n trigger: 'load',\n entity: 'page',\n action: 'view',\n timestamp: 1700000602,\n source: { type: 'express', platform: 'server' },\n },\n },\n ],\n ],\n};\n","import type { Hint } from '@walkeros/core';\n\nexport const hints: Hint.Hints = {\n 'ingest-prerequisite': {\n text: 'Fields starting with ingest.* require the server source to have config.ingest configured. Without it, ingest is undefined and all ingest.* fields resolve to empty strings — the hash is still generated but not unique. Always pair this transformer with a source that extracts request metadata.',\n code: [\n {\n lang: 'json',\n code: JSON.stringify(\n {\n sources: {\n express: {\n package: '@walkeros/server-source-express',\n config: {\n settings: { port: 8080 },\n ingest: {\n ip: 'req.ip',\n userAgent: 'req.headers.user-agent',\n origin: 'req.headers.origin',\n },\n },\n },\n },\n transformers: {\n fingerprint: {\n package: '@walkeros/server-transformer-fingerprint',\n config: {\n settings: {\n fields: ['ingest.ip', 'ingest.userAgent'],\n output: 'user.hash',\n length: 16,\n },\n },\n },\n },\n },\n null,\n 2,\n ),\n },\n ],\n },\n 'fields-overview': {\n text: 'Fields resolve from { event, ingest } via walkerOS mapping. Common patterns: ingest.ip (client IP), ingest.userAgent (browser UA), event.data.* (any event property). For time-based rotation use fn fields: daily rotation with toISOString().slice(0,10), monthly with getDate(). Order matters — same fields in different order produce different hashes. Use { key, fn } objects to transform before hashing (e.g., IP anonymization via the ipAnonymization step example).',\n },\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAAAA,cAA4B;;;ACA5B,iBAAkB;AAOX,IAAM,iBAAiB,aAC3B,OAAO;AAAA,EACN,QAAQ,aACL;AAAA,IACC,aAAE,MAAM;AAAA,MACN,aACG,OAAO,EACP,SAAS,qDAAqD;AAAA,MACjE,aACG,OAAO;AAAA,QACN,KAAK,aAAE,OAAO,EAAE,SAAS,EAAE,SAAS,sBAAsB;AAAA,QAC1D,OAAO,aACJ,QAAQ,EACR,SAAS,EACT,SAAS,0BAA0B;AAAA,QACtC,IAAI,aACD,OAAO,EACP,SAAS,EACT,SAAS,0CAA0C;AAAA,MACxD,CAAC,EACA,SAAS,0CAA0C;AAAA,IACxD,CAAC;AAAA,EACH,EACC;AAAA,IACC;AAAA,EACF;AAAA,EACF,QAAQ,aACL,OAAO,EACP,SAAS,EACT;AAAA,IACC;AAAA,EACF;AAAA,EACF,QAAQ,aACL,OAAO,EACP,IAAI,EACJ,SAAS,EACT,SAAS,EACT;AAAA,IACC;AAAA,EACF;AACJ,CAAC,EACA;AAAA,EACC;AACF;;;AD9CK,IAAM,eAAW,yBAAY,cAAc;;;AEJlD;AAAA;AAAA;AAAA;;;ACAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEO,IAAM,oBAAsC;AAAA,EACjD,OAAO;AAAA,EACP,aACE;AAAA,EACF,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,QAAQ;AAAA,MACR,OAAO;AAAA,MACP,IAAI;AAAA,IACN;AAAA,IACA,IAAI;AAAA,IACJ,SAAS;AAAA,IACT,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,WAAW;AAAA,IACX,QAAQ,EAAE,MAAM,WAAW,UAAU,SAAS;AAAA,EAChD;AAAA,EACA,KAAK;AAAA,IACH;AAAA,MACE;AAAA,MACA;AAAA,QACE,OAAO;AAAA,UACL,MAAM;AAAA,UACN,MAAM;AAAA,YACJ,QAAQ;AAAA,YACR,OAAO;AAAA,YACP,IAAI;AAAA,UACN;AAAA,UACA,MAAM,EAAE,MAAM,mBAAmB;AAAA,UACjC,IAAI;AAAA,UACJ,SAAS;AAAA,UACT,QAAQ;AAAA,UACR,QAAQ;AAAA,UACR,WAAW;AAAA,UACX,QAAQ,EAAE,MAAM,WAAW,UAAU,SAAS;AAAA,QAChD;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAEO,IAAM,gBAAkC;AAAA,EAC7C,QAAQ;AAAA,EACR,aACE;AAAA,EACF,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM,EAAE,IAAI,UAAU;AAAA,IACtB,IAAI;AAAA,IACJ,SAAS;AAAA,IACT,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,WAAW;AAAA,IACX,QAAQ,EAAE,MAAM,WAAW,UAAU,SAAS;AAAA,EAChD;AAAA,EACA,KAAK;AAAA,IACH;AAAA,MACE;AAAA,MACA;AAAA,QACE,OAAO;AAAA,UACL,MAAM;AAAA,UACN,MAAM,EAAE,IAAI,UAAU;AAAA,UACtB,MAAM,EAAE,MAAM,mBAAmB;AAAA,UACjC,IAAI;AAAA,UACJ,SAAS;AAAA,UACT,QAAQ;AAAA,UACR,QAAQ;AAAA,UACR,WAAW;AAAA,UACX,QAAQ,EAAE,MAAM,WAAW,UAAU,SAAS;AAAA,QAChD;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAEO,IAAM,kBAAoC;AAAA,EAC/C,OAAO;AAAA,EACP,aACE;AAAA,EAGF,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,QAAQ;AAAA,MACR,OAAO;AAAA,MACP,IAAI;AAAA,IACN;AAAA,IACA,IAAI;AAAA,IACJ,SAAS;AAAA,IACT,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,WAAW;AAAA,IACX,QAAQ,EAAE,MAAM,WAAW,UAAU,SAAS;AAAA,EAChD;AAAA,EACA,KAAK;AAAA,IACH;AAAA,MACE;AAAA,MACA;AAAA,QACE,OAAO;AAAA,UACL,MAAM;AAAA,UACN,MAAM;AAAA,YACJ,QAAQ;AAAA,YACR,OAAO;AAAA,YACP,IAAI;AAAA,UACN;AAAA,UACA,MAAM,EAAE,MAAM,mBAAmB;AAAA,UACjC,IAAI;AAAA,UACJ,SAAS;AAAA,UACT,QAAQ;AAAA,UACR,QAAQ;AAAA,UACR,WAAW;AAAA,UACX,QAAQ,EAAE,MAAM,WAAW,UAAU,SAAS;AAAA,QAChD;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;;;ACtHO,IAAM,QAAoB;AAAA,EAC/B,uBAAuB;AAAA,IACrB,MAAM;AAAA,IACN,MAAM;AAAA,MACJ;AAAA,QACE,MAAM;AAAA,QACN,MAAM,KAAK;AAAA,UACT;AAAA,YACE,SAAS;AAAA,cACP,SAAS;AAAA,gBACP,SAAS;AAAA,gBACT,QAAQ;AAAA,kBACN,UAAU,EAAE,MAAM,KAAK;AAAA,kBACvB,QAAQ;AAAA,oBACN,IAAI;AAAA,oBACJ,WAAW;AAAA,oBACX,QAAQ;AAAA,kBACV;AAAA,gBACF;AAAA,cACF;AAAA,YACF;AAAA,YACA,cAAc;AAAA,cACZ,aAAa;AAAA,gBACX,SAAS;AAAA,gBACT,QAAQ;AAAA,kBACN,UAAU;AAAA,oBACR,QAAQ,CAAC,aAAa,kBAAkB;AAAA,oBACxC,QAAQ;AAAA,oBACR,QAAQ;AAAA,kBACV;AAAA,gBACF;AAAA,cACF;AAAA,YACF;AAAA,UACF;AAAA,UACA;AAAA,UACA;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EACA,mBAAmB;AAAA,IACjB,MAAM;AAAA,EACR;AACF;","names":["import_dev"]}
|
package/dist/dev.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var e=Object.defineProperty,t=(t,i)=>{for(var r in i)e(t,r,{get:i[r],enumerable:!0})},i={};t(i,{SettingsSchema:()=>n,settings:()=>a});import{zodToSchema as r}from"@walkeros/core/dev";import{z as s}from"@walkeros/core/dev";var n=s.object({fields:s.array(s.union([s.string().describe('Dot-notation path: "ingest.ip", "event.data.userId"'),s.object({key:s.string().optional().describe("Source property path"),value:s.unknown().optional().describe("Static value or fallback"),fn:s.string().optional().describe("$code: function for value transformation")}).describe("Mapping value config for computed fields")])).describe("Fields to include in hash (order matters). Each resolved via getMappingValue with source { event, ingest }."),output:s.string().optional().describe('Dot-notation path where hash is stored on the event. Default: "user.hash"'),length:s.number().int().positive().optional().describe("Truncate hash to this length. Default: full 64-char SHA-256 hash")}).describe("Fingerprint transformer: generates deterministic user hashes from event fields"),a=r(n),o={};t(o,{step:()=>g});var g={};t(g,{ipAnonymization:()=>
|
|
1
|
+
var e=Object.defineProperty,t=(t,i)=>{for(var r in i)e(t,r,{get:i[r],enumerable:!0})},i={};t(i,{SettingsSchema:()=>n,settings:()=>a});import{zodToSchema as r}from"@walkeros/core/dev";import{z as s}from"@walkeros/core/dev";var n=s.object({fields:s.array(s.union([s.string().describe('Dot-notation path: "ingest.ip", "event.data.userId"'),s.object({key:s.string().optional().describe("Source property path"),value:s.unknown().optional().describe("Static value or fallback"),fn:s.string().optional().describe("$code: function for value transformation")}).describe("Mapping value config for computed fields")])).describe("Fields to include in hash (order matters). Each resolved via getMappingValue with source { event, ingest }."),output:s.string().optional().describe('Dot-notation path where hash is stored on the event. Default: "user.hash"'),length:s.number().int().positive().optional().describe("Truncate hash to this length. Default: full 64-char SHA-256 hash")}).describe("Fingerprint transformer: generates deterministic user hashes from event fields"),a=r(n),o={};t(o,{step:()=>g});var g={};t(g,{ipAnonymization:()=>l,missingFields:()=>d,serverFingerprint:()=>p});var p={title:"Server fingerprint",description:"Standard server fingerprint using ingest.ip and ingest.userAgent. Requires source config.ingest.",in:{name:"page view",data:{domain:"www.example.com",title:"Getting Started",id:"/docs/getting-started"},id:"ev-1700000600",trigger:"load",entity:"page",action:"view",timestamp:1700000600,source:{type:"express",platform:"server"}},out:[["return",{event:{name:"page view",data:{domain:"www.example.com",title:"Getting Started",id:"/docs/getting-started"},user:{hash:"158f99cc06e33fd6"},id:"ev-1700000600",trigger:"load",entity:"page",action:"view",timestamp:1700000600,source:{type:"express",platform:"server"}}}]]},d={public:!1,description:"Graceful handling when ingest is missing - fields resolve to empty strings, hash is still generated.",in:{name:"session start",data:{id:"s3ss10n"},id:"ev-1700000601",trigger:"load",entity:"session",action:"start",timestamp:1700000601,source:{type:"express",platform:"server"}},out:[["return",{event:{name:"session start",data:{id:"s3ss10n"},user:{hash:"e183220b699c10a8"},id:"ev-1700000601",trigger:"load",entity:"session",action:"start",timestamp:1700000601,source:{type:"express",platform:"server"}}}]]},l={title:"IP anonymization",description:'Privacy-preserving fingerprint using key+fn pattern: fn truncates IP to /24 subnet before hashing, so 10.0.42.* users share a hash. Config: fields: [{ key: "ingest.ip", fn: ip => ip.replace(/\\.\\d+$/, ".0") }, "ingest.userAgent"]',in:{name:"page view",data:{domain:"www.example.com",title:"Privacy Policy",id:"/privacy"},id:"ev-1700000602",trigger:"load",entity:"page",action:"view",timestamp:1700000602,source:{type:"express",platform:"server"}},out:[["return",{event:{name:"page view",data:{domain:"www.example.com",title:"Privacy Policy",id:"/privacy"},user:{hash:"44d9154b9a9b3792"},id:"ev-1700000602",trigger:"load",entity:"page",action:"view",timestamp:1700000602,source:{type:"express",platform:"server"}}}]]},c={"ingest-prerequisite":{text:"Fields starting with ingest.* require the server source to have config.ingest configured. Without it, ingest is undefined and all ingest.* fields resolve to empty strings — the hash is still generated but not unique. Always pair this transformer with a source that extracts request metadata.",code:[{lang:"json",code:JSON.stringify({sources:{express:{package:"@walkeros/server-source-express",config:{settings:{port:8080},ingest:{ip:"req.ip",userAgent:"req.headers.user-agent",origin:"req.headers.origin"}}}},transformers:{fingerprint:{package:"@walkeros/server-transformer-fingerprint",config:{settings:{fields:["ingest.ip","ingest.userAgent"],output:"user.hash",length:16}}}}},null,2)}]},"fields-overview":{text:"Fields resolve from { event, ingest } via walkerOS mapping. Common patterns: ingest.ip (client IP), ingest.userAgent (browser UA), event.data.* (any event property). For time-based rotation use fn fields: daily rotation with toISOString().slice(0,10), monthly with getDate(). Order matters — same fields in different order produce different hashes. Use { key, fn } objects to transform before hashing (e.g., IP anonymization via the ipAnonymization step example)."}};export{o as examples,c as hints,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/examples/index.ts","../src/examples/step.ts","../src/hints.ts"],"sourcesContent":["import { zodToSchema } from '@walkeros/core/dev';\nimport { SettingsSchema } from './settings';\n\nexport { SettingsSchema, type Settings } from './settings';\nexport const settings = zodToSchema(SettingsSchema);\n","import { z } from '@walkeros/core/dev';\n\n/**\n * Fingerprint transformer settings schema.\n *\n * Mirrors: types.ts FingerprintSettings\n */\nexport const SettingsSchema = z\n .object({\n fields: z\n .array(\n z.union([\n z\n .string()\n .describe('Dot-notation path: \"ingest.ip\", \"event.data.userId\"'),\n z\n .object({\n key: z.string().optional().describe('Source property path'),\n value: z\n .unknown()\n .optional()\n .describe('Static value or fallback'),\n fn: z\n .string()\n .optional()\n .describe('$code: function for value transformation'),\n })\n .describe('Mapping value config for computed fields'),\n ]),\n )\n .describe(\n 'Fields to include in hash (order matters). Each resolved via getMappingValue with source { event, ingest }.',\n ),\n output: z\n .string()\n .optional()\n .describe(\n 'Dot-notation path where hash is stored on the event. Default: \"user.hash\"',\n ),\n length: z\n .number()\n .int()\n .positive()\n .optional()\n .describe(\n 'Truncate hash to this length. Default: full 64-char SHA-256 hash',\n ),\n })\n .describe(\n 'Fingerprint transformer: generates deterministic user hashes from event fields',\n );\n\nexport type Settings = z.infer<typeof SettingsSchema>;\n","export * as step from './step';\n","import type { Flow } from '@walkeros/core';\n\nexport const serverFingerprint: Flow.StepExample = {\n title: 'Server fingerprint',\n description:\n 'Standard server fingerprint using ingest.ip and ingest.userAgent. Requires source config.ingest.',\n in: {\n name: 'page view',\n data: {\n domain: 'www.example.com',\n title: 'Getting Started',\n id: '/docs/getting-started',\n },\n id: '1700000600-gr0up-1',\n trigger: 'load',\n entity: 'page',\n action: 'view',\n timestamp: 1700000600,\n group: 'gr0up',\n count: 1,\n version: { tagging: 1 },\n source: { type: 'server', id: '', previous_id: '' },\n },\n out: [\n [\n 'return',\n {\n event: {\n name: 'page view',\n data: {\n domain: 'www.example.com',\n title: 'Getting Started',\n id: '/docs/getting-started',\n },\n user: { hash: '158f99cc06e33fd6' },\n id: '1700000600-gr0up-1',\n trigger: 'load',\n entity: 'page',\n action: 'view',\n timestamp: 1700000600,\n group: 'gr0up',\n count: 1,\n version: { tagging: 1 },\n source: { type: 'server', id: '', previous_id: '' },\n },\n },\n ],\n ],\n};\n\nexport const missingFields: Flow.StepExample = {\n public: false,\n description:\n 'Graceful handling when ingest is missing — fields resolve to empty strings, hash is still generated.',\n in: {\n name: 'session start',\n data: { id: 's3ss10n' },\n id: '1700000601-gr0up-2',\n trigger: 'load',\n entity: 'session',\n action: 'start',\n timestamp: 1700000601,\n group: 'gr0up',\n count: 2,\n version: { tagging: 1 },\n source: { type: 'server', id: '', previous_id: '' },\n },\n out: [\n [\n 'return',\n {\n event: {\n name: 'session start',\n data: { id: 's3ss10n' },\n user: { hash: 'e183220b699c10a8' },\n id: '1700000601-gr0up-2',\n trigger: 'load',\n entity: 'session',\n action: 'start',\n timestamp: 1700000601,\n group: 'gr0up',\n count: 2,\n version: { tagging: 1 },\n source: { type: 'server', id: '', previous_id: '' },\n },\n },\n ],\n ],\n};\n\nexport const ipAnonymization: Flow.StepExample = {\n title: 'IP anonymization',\n description:\n 'Privacy-preserving fingerprint using key+fn pattern: ' +\n 'fn truncates IP to /24 subnet before hashing, so 10.0.42.* users share a hash. ' +\n 'Config: fields: [{ key: \"ingest.ip\", fn: ip => ip.replace(/\\\\.\\\\d+$/, \".0\") }, \"ingest.userAgent\"]',\n in: {\n name: 'page view',\n data: {\n domain: 'www.example.com',\n title: 'Privacy Policy',\n id: '/privacy',\n },\n id: '1700000602-gr0up-3',\n trigger: 'load',\n entity: 'page',\n action: 'view',\n timestamp: 1700000602,\n group: 'gr0up',\n count: 3,\n version: { tagging: 1 },\n source: { type: 'server', id: '', previous_id: '' },\n },\n out: [\n [\n 'return',\n {\n event: {\n name: 'page view',\n data: {\n domain: 'www.example.com',\n title: 'Privacy Policy',\n id: '/privacy',\n },\n user: { hash: '44d9154b9a9b3792' },\n id: '1700000602-gr0up-3',\n trigger: 'load',\n entity: 'page',\n action: 'view',\n timestamp: 1700000602,\n group: 'gr0up',\n count: 3,\n version: { tagging: 1 },\n source: { type: 'server', id: '', previous_id: '' },\n },\n },\n ],\n ],\n};\n","import type { Hint } from '@walkeros/core';\n\nexport const hints: Hint.Hints = {\n 'ingest-prerequisite': {\n text: 'Fields starting with ingest.* require the server source to have config.ingest configured. Without it, ingest is undefined and all ingest.* fields resolve to empty strings — the hash is still generated but not unique. Always pair this transformer with a source that extracts request metadata.',\n code: [\n {\n lang: 'json',\n code: JSON.stringify(\n {\n sources: {\n express: {\n package: '@walkeros/server-source-express',\n config: {\n settings: { port: 8080 },\n ingest: {\n ip: 'req.ip',\n userAgent: 'req.headers.user-agent',\n origin: 'req.headers.origin',\n },\n },\n },\n },\n transformers: {\n fingerprint: {\n package: '@walkeros/server-transformer-fingerprint',\n config: {\n settings: {\n fields: ['ingest.ip', 'ingest.userAgent'],\n output: 'user.hash',\n length: 16,\n },\n },\n },\n },\n },\n null,\n 2,\n ),\n },\n ],\n },\n 'fields-overview': {\n text: 'Fields resolve from { event, ingest } via walkerOS mapping. Common patterns: ingest.ip (client IP), ingest.userAgent (browser UA), event.data.* (any event property). For time-based rotation use fn fields: daily rotation with toISOString().slice(0,10), monthly with getDate(). Order matters — same fields in different order produce different hashes. Use { key, fn } objects to transform before hashing (e.g., IP anonymization via the ipAnonymization step example).',\n },\n};\n"],"mappings":";;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,SAAS,mBAAmB;;;ACA5B,SAAS,SAAS;AAOX,IAAM,iBAAiB,EAC3B,OAAO;AAAA,EACN,QAAQ,EACL;AAAA,IACC,EAAE,MAAM;AAAA,MACN,EACG,OAAO,EACP,SAAS,qDAAqD;AAAA,MACjE,EACG,OAAO;AAAA,QACN,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,sBAAsB;AAAA,QAC1D,OAAO,EACJ,QAAQ,EACR,SAAS,EACT,SAAS,0BAA0B;AAAA,QACtC,IAAI,EACD,OAAO,EACP,SAAS,EACT,SAAS,0CAA0C;AAAA,MACxD,CAAC,EACA,SAAS,0CAA0C;AAAA,IACxD,CAAC;AAAA,EACH,EACC;AAAA,IACC;AAAA,EACF;AAAA,EACF,QAAQ,EACL,OAAO,EACP,SAAS,EACT;AAAA,IACC;AAAA,EACF;AAAA,EACF,QAAQ,EACL,OAAO,EACP,IAAI,EACJ,SAAS,EACT,SAAS,EACT;AAAA,IACC;AAAA,EACF;AACJ,CAAC,EACA;AAAA,EACC;AACF;;;AD9CK,IAAM,WAAW,YAAY,cAAc;;;AEJlD;AAAA;AAAA;AAAA;;;ACAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEO,IAAM,oBAAsC;AAAA,EACjD,OAAO;AAAA,EACP,aACE;AAAA,EACF,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,QAAQ;AAAA,MACR,OAAO;AAAA,MACP,IAAI;AAAA,IACN;AAAA,IACA,IAAI;AAAA,IACJ,SAAS;AAAA,IACT,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,WAAW;AAAA,IACX,OAAO;AAAA,IACP,OAAO;AAAA,IACP,SAAS,EAAE,SAAS,EAAE;AAAA,IACtB,QAAQ,EAAE,MAAM,UAAU,IAAI,IAAI,aAAa,GAAG;AAAA,EACpD;AAAA,EACA,KAAK;AAAA,IACH;AAAA,MACE;AAAA,MACA;AAAA,QACE,OAAO;AAAA,UACL,MAAM;AAAA,UACN,MAAM;AAAA,YACJ,QAAQ;AAAA,YACR,OAAO;AAAA,YACP,IAAI;AAAA,UACN;AAAA,UACA,MAAM,EAAE,MAAM,mBAAmB;AAAA,UACjC,IAAI;AAAA,UACJ,SAAS;AAAA,UACT,QAAQ;AAAA,UACR,QAAQ;AAAA,UACR,WAAW;AAAA,UACX,OAAO;AAAA,UACP,OAAO;AAAA,UACP,SAAS,EAAE,SAAS,EAAE;AAAA,UACtB,QAAQ,EAAE,MAAM,UAAU,IAAI,IAAI,aAAa,GAAG;AAAA,QACpD;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAEO,IAAM,gBAAkC;AAAA,EAC7C,QAAQ;AAAA,EACR,aACE;AAAA,EACF,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM,EAAE,IAAI,UAAU;AAAA,IACtB,IAAI;AAAA,IACJ,SAAS;AAAA,IACT,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,WAAW;AAAA,IACX,OAAO;AAAA,IACP,OAAO;AAAA,IACP,SAAS,EAAE,SAAS,EAAE;AAAA,IACtB,QAAQ,EAAE,MAAM,UAAU,IAAI,IAAI,aAAa,GAAG;AAAA,EACpD;AAAA,EACA,KAAK;AAAA,IACH;AAAA,MACE;AAAA,MACA;AAAA,QACE,OAAO;AAAA,UACL,MAAM;AAAA,UACN,MAAM,EAAE,IAAI,UAAU;AAAA,UACtB,MAAM,EAAE,MAAM,mBAAmB;AAAA,UACjC,IAAI;AAAA,UACJ,SAAS;AAAA,UACT,QAAQ;AAAA,UACR,QAAQ;AAAA,UACR,WAAW;AAAA,UACX,OAAO;AAAA,UACP,OAAO;AAAA,UACP,SAAS,EAAE,SAAS,EAAE;AAAA,UACtB,QAAQ,EAAE,MAAM,UAAU,IAAI,IAAI,aAAa,GAAG;AAAA,QACpD;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAEO,IAAM,kBAAoC;AAAA,EAC/C,OAAO;AAAA,EACP,aACE;AAAA,EAGF,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,QAAQ;AAAA,MACR,OAAO;AAAA,MACP,IAAI;AAAA,IACN;AAAA,IACA,IAAI;AAAA,IACJ,SAAS;AAAA,IACT,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,WAAW;AAAA,IACX,OAAO;AAAA,IACP,OAAO;AAAA,IACP,SAAS,EAAE,SAAS,EAAE;AAAA,IACtB,QAAQ,EAAE,MAAM,UAAU,IAAI,IAAI,aAAa,GAAG;AAAA,EACpD;AAAA,EACA,KAAK;AAAA,IACH;AAAA,MACE;AAAA,MACA;AAAA,QACE,OAAO;AAAA,UACL,MAAM;AAAA,UACN,MAAM;AAAA,YACJ,QAAQ;AAAA,YACR,OAAO;AAAA,YACP,IAAI;AAAA,UACN;AAAA,UACA,MAAM,EAAE,MAAM,mBAAmB;AAAA,UACjC,IAAI;AAAA,UACJ,SAAS;AAAA,UACT,QAAQ;AAAA,UACR,QAAQ;AAAA,UACR,WAAW;AAAA,UACX,OAAO;AAAA,UACP,OAAO;AAAA,UACP,SAAS,EAAE,SAAS,EAAE;AAAA,UACtB,QAAQ,EAAE,MAAM,UAAU,IAAI,IAAI,aAAa,GAAG;AAAA,QACpD;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;;;ACxIO,IAAM,QAAoB;AAAA,EAC/B,uBAAuB;AAAA,IACrB,MAAM;AAAA,IACN,MAAM;AAAA,MACJ;AAAA,QACE,MAAM;AAAA,QACN,MAAM,KAAK;AAAA,UACT;AAAA,YACE,SAAS;AAAA,cACP,SAAS;AAAA,gBACP,SAAS;AAAA,gBACT,QAAQ;AAAA,kBACN,UAAU,EAAE,MAAM,KAAK;AAAA,kBACvB,QAAQ;AAAA,oBACN,IAAI;AAAA,oBACJ,WAAW;AAAA,oBACX,QAAQ;AAAA,kBACV;AAAA,gBACF;AAAA,cACF;AAAA,YACF;AAAA,YACA,cAAc;AAAA,cACZ,aAAa;AAAA,gBACX,SAAS;AAAA,gBACT,QAAQ;AAAA,kBACN,UAAU;AAAA,oBACR,QAAQ,CAAC,aAAa,kBAAkB;AAAA,oBACxC,QAAQ;AAAA,oBACR,QAAQ;AAAA,kBACV;AAAA,gBACF;AAAA,cACF;AAAA,YACF;AAAA,UACF;AAAA,UACA;AAAA,UACA;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EACA,mBAAmB;AAAA,IACjB,MAAM;AAAA,EACR;AACF;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/schemas/index.ts","../src/schemas/settings.ts","../src/examples/index.ts","../src/examples/step.ts","../src/hints.ts"],"sourcesContent":["import { zodToSchema } from '@walkeros/core/dev';\nimport { SettingsSchema } from './settings';\n\nexport { SettingsSchema, type Settings } from './settings';\nexport const settings = zodToSchema(SettingsSchema);\n","import { z } from '@walkeros/core/dev';\n\n/**\n * Fingerprint transformer settings schema.\n *\n * Mirrors: types.ts FingerprintSettings\n */\nexport const SettingsSchema = z\n .object({\n fields: z\n .array(\n z.union([\n z\n .string()\n .describe('Dot-notation path: \"ingest.ip\", \"event.data.userId\"'),\n z\n .object({\n key: z.string().optional().describe('Source property path'),\n value: z\n .unknown()\n .optional()\n .describe('Static value or fallback'),\n fn: z\n .string()\n .optional()\n .describe('$code: function for value transformation'),\n })\n .describe('Mapping value config for computed fields'),\n ]),\n )\n .describe(\n 'Fields to include in hash (order matters). Each resolved via getMappingValue with source { event, ingest }.',\n ),\n output: z\n .string()\n .optional()\n .describe(\n 'Dot-notation path where hash is stored on the event. Default: \"user.hash\"',\n ),\n length: z\n .number()\n .int()\n .positive()\n .optional()\n .describe(\n 'Truncate hash to this length. Default: full 64-char SHA-256 hash',\n ),\n })\n .describe(\n 'Fingerprint transformer: generates deterministic user hashes from event fields',\n );\n\nexport type Settings = z.infer<typeof SettingsSchema>;\n","export * as step from './step';\n","import type { Flow } from '@walkeros/core';\n\nexport const serverFingerprint: Flow.StepExample = {\n title: 'Server fingerprint',\n description:\n 'Standard server fingerprint using ingest.ip and ingest.userAgent. Requires source config.ingest.',\n in: {\n name: 'page view',\n data: {\n domain: 'www.example.com',\n title: 'Getting Started',\n id: '/docs/getting-started',\n },\n id: 'ev-1700000600',\n trigger: 'load',\n entity: 'page',\n action: 'view',\n timestamp: 1700000600,\n source: { type: 'express', platform: 'server' },\n },\n out: [\n [\n 'return',\n {\n event: {\n name: 'page view',\n data: {\n domain: 'www.example.com',\n title: 'Getting Started',\n id: '/docs/getting-started',\n },\n user: { hash: '158f99cc06e33fd6' },\n id: 'ev-1700000600',\n trigger: 'load',\n entity: 'page',\n action: 'view',\n timestamp: 1700000600,\n source: { type: 'express', platform: 'server' },\n },\n },\n ],\n ],\n};\n\nexport const missingFields: Flow.StepExample = {\n public: false,\n description:\n 'Graceful handling when ingest is missing - fields resolve to empty strings, hash is still generated.',\n in: {\n name: 'session start',\n data: { id: 's3ss10n' },\n id: 'ev-1700000601',\n trigger: 'load',\n entity: 'session',\n action: 'start',\n timestamp: 1700000601,\n source: { type: 'express', platform: 'server' },\n },\n out: [\n [\n 'return',\n {\n event: {\n name: 'session start',\n data: { id: 's3ss10n' },\n user: { hash: 'e183220b699c10a8' },\n id: 'ev-1700000601',\n trigger: 'load',\n entity: 'session',\n action: 'start',\n timestamp: 1700000601,\n source: { type: 'express', platform: 'server' },\n },\n },\n ],\n ],\n};\n\nexport const ipAnonymization: Flow.StepExample = {\n title: 'IP anonymization',\n description:\n 'Privacy-preserving fingerprint using key+fn pattern: ' +\n 'fn truncates IP to /24 subnet before hashing, so 10.0.42.* users share a hash. ' +\n 'Config: fields: [{ key: \"ingest.ip\", fn: ip => ip.replace(/\\\\.\\\\d+$/, \".0\") }, \"ingest.userAgent\"]',\n in: {\n name: 'page view',\n data: {\n domain: 'www.example.com',\n title: 'Privacy Policy',\n id: '/privacy',\n },\n id: 'ev-1700000602',\n trigger: 'load',\n entity: 'page',\n action: 'view',\n timestamp: 1700000602,\n source: { type: 'express', platform: 'server' },\n },\n out: [\n [\n 'return',\n {\n event: {\n name: 'page view',\n data: {\n domain: 'www.example.com',\n title: 'Privacy Policy',\n id: '/privacy',\n },\n user: { hash: '44d9154b9a9b3792' },\n id: 'ev-1700000602',\n trigger: 'load',\n entity: 'page',\n action: 'view',\n timestamp: 1700000602,\n source: { type: 'express', platform: 'server' },\n },\n },\n ],\n ],\n};\n","import type { Hint } from '@walkeros/core';\n\nexport const hints: Hint.Hints = {\n 'ingest-prerequisite': {\n text: 'Fields starting with ingest.* require the server source to have config.ingest configured. Without it, ingest is undefined and all ingest.* fields resolve to empty strings — the hash is still generated but not unique. Always pair this transformer with a source that extracts request metadata.',\n code: [\n {\n lang: 'json',\n code: JSON.stringify(\n {\n sources: {\n express: {\n package: '@walkeros/server-source-express',\n config: {\n settings: { port: 8080 },\n ingest: {\n ip: 'req.ip',\n userAgent: 'req.headers.user-agent',\n origin: 'req.headers.origin',\n },\n },\n },\n },\n transformers: {\n fingerprint: {\n package: '@walkeros/server-transformer-fingerprint',\n config: {\n settings: {\n fields: ['ingest.ip', 'ingest.userAgent'],\n output: 'user.hash',\n length: 16,\n },\n },\n },\n },\n },\n null,\n 2,\n ),\n },\n ],\n },\n 'fields-overview': {\n text: 'Fields resolve from { event, ingest } via walkerOS mapping. Common patterns: ingest.ip (client IP), ingest.userAgent (browser UA), event.data.* (any event property). For time-based rotation use fn fields: daily rotation with toISOString().slice(0,10), monthly with getDate(). Order matters — same fields in different order produce different hashes. Use { key, fn } objects to transform before hashing (e.g., IP anonymization via the ipAnonymization step example).',\n },\n};\n"],"mappings":";;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,SAAS,mBAAmB;;;ACA5B,SAAS,SAAS;AAOX,IAAM,iBAAiB,EAC3B,OAAO;AAAA,EACN,QAAQ,EACL;AAAA,IACC,EAAE,MAAM;AAAA,MACN,EACG,OAAO,EACP,SAAS,qDAAqD;AAAA,MACjE,EACG,OAAO;AAAA,QACN,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,sBAAsB;AAAA,QAC1D,OAAO,EACJ,QAAQ,EACR,SAAS,EACT,SAAS,0BAA0B;AAAA,QACtC,IAAI,EACD,OAAO,EACP,SAAS,EACT,SAAS,0CAA0C;AAAA,MACxD,CAAC,EACA,SAAS,0CAA0C;AAAA,IACxD,CAAC;AAAA,EACH,EACC;AAAA,IACC;AAAA,EACF;AAAA,EACF,QAAQ,EACL,OAAO,EACP,SAAS,EACT;AAAA,IACC;AAAA,EACF;AAAA,EACF,QAAQ,EACL,OAAO,EACP,IAAI,EACJ,SAAS,EACT,SAAS,EACT;AAAA,IACC;AAAA,EACF;AACJ,CAAC,EACA;AAAA,EACC;AACF;;;AD9CK,IAAM,WAAW,YAAY,cAAc;;;AEJlD;AAAA;AAAA;AAAA;;;ACAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEO,IAAM,oBAAsC;AAAA,EACjD,OAAO;AAAA,EACP,aACE;AAAA,EACF,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,QAAQ;AAAA,MACR,OAAO;AAAA,MACP,IAAI;AAAA,IACN;AAAA,IACA,IAAI;AAAA,IACJ,SAAS;AAAA,IACT,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,WAAW;AAAA,IACX,QAAQ,EAAE,MAAM,WAAW,UAAU,SAAS;AAAA,EAChD;AAAA,EACA,KAAK;AAAA,IACH;AAAA,MACE;AAAA,MACA;AAAA,QACE,OAAO;AAAA,UACL,MAAM;AAAA,UACN,MAAM;AAAA,YACJ,QAAQ;AAAA,YACR,OAAO;AAAA,YACP,IAAI;AAAA,UACN;AAAA,UACA,MAAM,EAAE,MAAM,mBAAmB;AAAA,UACjC,IAAI;AAAA,UACJ,SAAS;AAAA,UACT,QAAQ;AAAA,UACR,QAAQ;AAAA,UACR,WAAW;AAAA,UACX,QAAQ,EAAE,MAAM,WAAW,UAAU,SAAS;AAAA,QAChD;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAEO,IAAM,gBAAkC;AAAA,EAC7C,QAAQ;AAAA,EACR,aACE;AAAA,EACF,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM,EAAE,IAAI,UAAU;AAAA,IACtB,IAAI;AAAA,IACJ,SAAS;AAAA,IACT,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,WAAW;AAAA,IACX,QAAQ,EAAE,MAAM,WAAW,UAAU,SAAS;AAAA,EAChD;AAAA,EACA,KAAK;AAAA,IACH;AAAA,MACE;AAAA,MACA;AAAA,QACE,OAAO;AAAA,UACL,MAAM;AAAA,UACN,MAAM,EAAE,IAAI,UAAU;AAAA,UACtB,MAAM,EAAE,MAAM,mBAAmB;AAAA,UACjC,IAAI;AAAA,UACJ,SAAS;AAAA,UACT,QAAQ;AAAA,UACR,QAAQ;AAAA,UACR,WAAW;AAAA,UACX,QAAQ,EAAE,MAAM,WAAW,UAAU,SAAS;AAAA,QAChD;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAEO,IAAM,kBAAoC;AAAA,EAC/C,OAAO;AAAA,EACP,aACE;AAAA,EAGF,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,QAAQ;AAAA,MACR,OAAO;AAAA,MACP,IAAI;AAAA,IACN;AAAA,IACA,IAAI;AAAA,IACJ,SAAS;AAAA,IACT,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,WAAW;AAAA,IACX,QAAQ,EAAE,MAAM,WAAW,UAAU,SAAS;AAAA,EAChD;AAAA,EACA,KAAK;AAAA,IACH;AAAA,MACE;AAAA,MACA;AAAA,QACE,OAAO;AAAA,UACL,MAAM;AAAA,UACN,MAAM;AAAA,YACJ,QAAQ;AAAA,YACR,OAAO;AAAA,YACP,IAAI;AAAA,UACN;AAAA,UACA,MAAM,EAAE,MAAM,mBAAmB;AAAA,UACjC,IAAI;AAAA,UACJ,SAAS;AAAA,UACT,QAAQ;AAAA,UACR,QAAQ;AAAA,UACR,WAAW;AAAA,UACX,QAAQ,EAAE,MAAM,WAAW,UAAU,SAAS;AAAA,QAChD;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;;;ACtHO,IAAM,QAAoB;AAAA,EAC/B,uBAAuB;AAAA,IACrB,MAAM;AAAA,IACN,MAAM;AAAA,MACJ;AAAA,QACE,MAAM;AAAA,QACN,MAAM,KAAK;AAAA,UACT;AAAA,YACE,SAAS;AAAA,cACP,SAAS;AAAA,gBACP,SAAS;AAAA,gBACT,QAAQ;AAAA,kBACN,UAAU,EAAE,MAAM,KAAK;AAAA,kBACvB,QAAQ;AAAA,oBACN,IAAI;AAAA,oBACJ,WAAW;AAAA,oBACX,QAAQ;AAAA,kBACV;AAAA,gBACF;AAAA,cACF;AAAA,YACF;AAAA,YACA,cAAc;AAAA,cACZ,aAAa;AAAA,gBACX,SAAS;AAAA,gBACT,QAAQ;AAAA,kBACN,UAAU;AAAA,oBACR,QAAQ,CAAC,aAAa,kBAAkB;AAAA,oBACxC,QAAQ;AAAA,oBACR,QAAQ;AAAA,kBACV;AAAA,gBACF;AAAA,cACF;AAAA,YACF;AAAA,UACF;AAAA,UACA;AAAA,UACA;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EACA,mBAAmB;AAAA,IACjB,MAAM;AAAA,EACR;AACF;","names":[]}
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var e,r=Object.defineProperty,t=Object.getOwnPropertyDescriptor,
|
|
1
|
+
"use strict";var e,r=Object.defineProperty,t=Object.getOwnPropertyDescriptor,o=Object.getOwnPropertyNames,n=Object.prototype.hasOwnProperty,a={};((e,t)=>{for(var o in t)r(e,o,{get:t[o],enumerable:!0})})(a,{default:()=>l,transformerFingerprint:()=>l}),module.exports=(e=a,((e,a,s,i)=>{if(a&&"object"==typeof a||"function"==typeof a)for(let l of o(a))n.call(e,l)||l===s||r(e,l,{get:()=>a[l],enumerable:!(i=t(a,l))||i.enumerable});return e})(r({},"__esModule",{value:!0}),e));var s=require("@walkeros/core"),i=require("@walkeros/server-core"),l=e=>{const{config:r}=e,t=r.settings||{},o=t.fields||[],n=t.output||"user.hash",a=t.length;return{type:"fingerprint",config:r,async push(e,r){const{ingest:t,collector:l}=r,c={event:e,ingest:t},p=""+(await Promise.all(o.map(e=>(0,s.getMappingValue)(c,e,{collector:l})))).map(e=>String(e??"")).join(""),u=await(0,i.getHashServer)(p,a);return{event:(0,s.setByPath)(e,n,u)}}}};//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/transformer.ts"],"sourcesContent":["export { transformerFingerprint } from './transformer';\nexport type { FingerprintSettings } from './types';\n\nexport { transformerFingerprint as default } from './transformer';\n","import type { Mapping, Transformer } from '@walkeros/core';\nimport { getMappingValue, setByPath } from '@walkeros/core';\nimport { getHashServer } from '@walkeros/server-core';\nimport type { FingerprintSettings } from './types';\n\n/**\n * Fingerprint transformer - hash configurable fields for session continuity.\n *\n * Resolves fields from { event, ingest } source object using getMappingValue,\n * concatenates values in order, hashes with SHA-256, and stores at output path.\n *\n * @example\n * transformerFingerprint({\n * config: {\n * settings: {\n * fields: [\n * 'ingest.ip',\n * 'ingest.userAgent',\n * { fn: () => new Date().getDate() },\n * ],\n * output: 'user.hash',\n * length: 16,\n * },\n * },\n * })\n */\nexport const transformerFingerprint: Transformer.Init<\n Transformer.Types<FingerprintSettings>\n> = (context) => {\n const { config } = context;\n const settings = (config.settings || {}) as Partial<FingerprintSettings>;\n const fields: Mapping.Value[] = settings.fields || [];\n const output: string = settings.output || 'user.hash';\n const length: number | undefined = settings.length;\n\n return {\n type: 'fingerprint',\n config: config as Transformer.Config<\n Transformer.Types<FingerprintSettings>\n >,\n\n async push(event, context) {\n const { ingest, collector } = context;\n\n // Build source object for field resolution\n const source = { event, ingest };\n\n // Resolve each field via mapping (maintains order)\n const values = await Promise.all(\n fields.map((field: Mapping.Value) =>\n getMappingValue(source, field, { collector }),\n ),\n );\n\n // Safe string concatenation: '' prefix + String() cast for each value\n // '' prefix ensures we always have a string even if fields is empty\n // String(v ?? '') handles undefined/null gracefully\n const input = '' + values.map((v: unknown) => String(v ?? '')).join('');\n\n // Hash and store at output path\n const hash = await getHashServer(input, length);\n return { event: setByPath(event, output, hash) };\n },\n };\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACCA,kBAA2C;AAC3C,yBAA8B;AAwBvB,IAAM,yBAET,CAAC,YAAY;AACf,QAAM,EAAE,OAAO,IAAI;AACnB,QAAM,WAAY,OAAO,YAAY,CAAC;AACtC,QAAM,SAA0B,SAAS,UAAU,CAAC;AACpD,QAAM,SAAiB,SAAS,UAAU;AAC1C,QAAM,SAA6B,SAAS;AAE5C,SAAO;AAAA,IACL,MAAM;AAAA,IACN;AAAA,IAIA,MAAM,KAAK,OAAOA,UAAS;AACzB,YAAM,EAAE,QAAQ,UAAU,IAAIA;AAG9B,YAAM,SAAS,EAAE,OAAO,OAAO;AAG/B,YAAM,SAAS,MAAM,QAAQ;AAAA,QAC3B,OAAO;AAAA,UAAI,CAAC,cACV,6BAAgB,QAAQ,OAAO,EAAE,UAAU,CAAC;AAAA,QAC9C;AAAA,MACF;AAKA,YAAM,QAAQ,KAAK,OAAO,IAAI,CAAC,MAAe,OAAO,
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/transformer.ts"],"sourcesContent":["export { transformerFingerprint } from './transformer';\nexport type { FingerprintSettings } from './types';\n\nexport { transformerFingerprint as default } from './transformer';\n","import type { Mapping, Transformer } from '@walkeros/core';\nimport { getMappingValue, setByPath } from '@walkeros/core';\nimport { getHashServer } from '@walkeros/server-core';\nimport type { FingerprintSettings } from './types';\n\n/**\n * Fingerprint transformer - hash configurable fields for session continuity.\n *\n * Resolves fields from { event, ingest } source object using getMappingValue,\n * concatenates values in order, hashes with SHA-256, and stores at output path.\n *\n * @example\n * transformerFingerprint({\n * config: {\n * settings: {\n * fields: [\n * 'ingest.ip',\n * 'ingest.userAgent',\n * { fn: () => new Date().getDate() },\n * ],\n * output: 'user.hash',\n * length: 16,\n * },\n * },\n * })\n */\nexport const transformerFingerprint: Transformer.Init<\n Transformer.Types<FingerprintSettings>\n> = (context) => {\n const { config } = context;\n const settings = (config.settings || {}) as Partial<FingerprintSettings>;\n const fields: Mapping.Value[] = settings.fields || [];\n const output: string = settings.output || 'user.hash';\n const length: number | undefined = settings.length;\n\n return {\n type: 'fingerprint',\n config: config as Transformer.Config<\n Transformer.Types<FingerprintSettings>\n >,\n\n async push(event, context) {\n const { ingest, collector } = context;\n\n // Build source object for field resolution\n const source = { event, ingest };\n\n // Resolve each field via mapping (maintains order)\n const values = await Promise.all(\n fields.map((field: Mapping.Value) =>\n getMappingValue(source, field, { collector }),\n ),\n );\n\n // Safe string concatenation: '' prefix + String() cast for each value\n // '' prefix ensures we always have a string even if fields is empty\n // String(v ?? '') handles undefined/null gracefully\n const input = '' + values.map((v: unknown) => String(v ?? '')).join('');\n\n // Hash and store at output path\n const hash = await getHashServer(input, length);\n return { event: setByPath(event, output, hash) };\n },\n };\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACCA,kBAA2C;AAC3C,yBAA8B;AAwBvB,IAAM,yBAET,CAAC,YAAY;AACf,QAAM,EAAE,OAAO,IAAI;AACnB,QAAM,WAAY,OAAO,YAAY,CAAC;AACtC,QAAM,SAA0B,SAAS,UAAU,CAAC;AACpD,QAAM,SAAiB,SAAS,UAAU;AAC1C,QAAM,SAA6B,SAAS;AAE5C,SAAO;AAAA,IACL,MAAM;AAAA,IACN;AAAA,IAIA,MAAM,KAAK,OAAOA,UAAS;AACzB,YAAM,EAAE,QAAQ,UAAU,IAAIA;AAG9B,YAAM,SAAS,EAAE,OAAO,OAAO;AAG/B,YAAM,SAAS,MAAM,QAAQ;AAAA,QAC3B,OAAO;AAAA,UAAI,CAAC,cACV,6BAAgB,QAAQ,OAAO,EAAE,UAAU,CAAC;AAAA,QAC9C;AAAA,MACF;AAKA,YAAM,QAAQ,KAAK,OAAO,IAAI,CAAC,MAAe,OAAO,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE;AAGtE,YAAM,OAAO,UAAM,kCAAc,OAAO,MAAM;AAC9C,aAAO,EAAE,WAAO,uBAAU,OAAO,QAAQ,IAAI,EAAE;AAAA,IACjD;AAAA,EACF;AACF;","names":["context"]}
|
package/dist/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{getMappingValue as e,setByPath as t}from"@walkeros/core";import{getHashServer as r}from"@walkeros/server-core";var o=o=>{const{config:n}=o,s=n.settings||{},i=s.fields||[],a=s.output||"user.hash",
|
|
1
|
+
import{getMappingValue as e,setByPath as t}from"@walkeros/core";import{getHashServer as r}from"@walkeros/server-core";var o=o=>{const{config:n}=o,s=n.settings||{},i=s.fields||[],a=s.output||"user.hash",c=s.length;return{type:"fingerprint",config:n,async push(o,n){const{ingest:s,collector:l}=n,p={event:o,ingest:s},g=""+(await Promise.all(i.map(t=>e(p,t,{collector:l})))).map(e=>String(e??"")).join(""),f=await r(g,c);return{event:t(o,a,f)}}}};export{o as default,o as transformerFingerprint};//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/transformer.ts"],"sourcesContent":["import type { Mapping, Transformer } from '@walkeros/core';\nimport { getMappingValue, setByPath } from '@walkeros/core';\nimport { getHashServer } from '@walkeros/server-core';\nimport type { FingerprintSettings } from './types';\n\n/**\n * Fingerprint transformer - hash configurable fields for session continuity.\n *\n * Resolves fields from { event, ingest } source object using getMappingValue,\n * concatenates values in order, hashes with SHA-256, and stores at output path.\n *\n * @example\n * transformerFingerprint({\n * config: {\n * settings: {\n * fields: [\n * 'ingest.ip',\n * 'ingest.userAgent',\n * { fn: () => new Date().getDate() },\n * ],\n * output: 'user.hash',\n * length: 16,\n * },\n * },\n * })\n */\nexport const transformerFingerprint: Transformer.Init<\n Transformer.Types<FingerprintSettings>\n> = (context) => {\n const { config } = context;\n const settings = (config.settings || {}) as Partial<FingerprintSettings>;\n const fields: Mapping.Value[] = settings.fields || [];\n const output: string = settings.output || 'user.hash';\n const length: number | undefined = settings.length;\n\n return {\n type: 'fingerprint',\n config: config as Transformer.Config<\n Transformer.Types<FingerprintSettings>\n >,\n\n async push(event, context) {\n const { ingest, collector } = context;\n\n // Build source object for field resolution\n const source = { event, ingest };\n\n // Resolve each field via mapping (maintains order)\n const values = await Promise.all(\n fields.map((field: Mapping.Value) =>\n getMappingValue(source, field, { collector }),\n ),\n );\n\n // Safe string concatenation: '' prefix + String() cast for each value\n // '' prefix ensures we always have a string even if fields is empty\n // String(v ?? '') handles undefined/null gracefully\n const input = '' + values.map((v: unknown) => String(v ?? '')).join('');\n\n // Hash and store at output path\n const hash = await getHashServer(input, length);\n return { event: setByPath(event, output, hash) };\n },\n };\n};\n"],"mappings":";AACA,SAAS,iBAAiB,iBAAiB;AAC3C,SAAS,qBAAqB;AAwBvB,IAAM,yBAET,CAAC,YAAY;AACf,QAAM,EAAE,OAAO,IAAI;AACnB,QAAM,WAAY,OAAO,YAAY,CAAC;AACtC,QAAM,SAA0B,SAAS,UAAU,CAAC;AACpD,QAAM,SAAiB,SAAS,UAAU;AAC1C,QAAM,SAA6B,SAAS;AAE5C,SAAO;AAAA,IACL,MAAM;AAAA,IACN;AAAA,IAIA,MAAM,KAAK,OAAOA,UAAS;AACzB,YAAM,EAAE,QAAQ,UAAU,IAAIA;AAG9B,YAAM,SAAS,EAAE,OAAO,OAAO;AAG/B,YAAM,SAAS,MAAM,QAAQ;AAAA,QAC3B,OAAO;AAAA,UAAI,CAAC,UACV,gBAAgB,QAAQ,OAAO,EAAE,UAAU,CAAC;AAAA,QAC9C;AAAA,MACF;AAKA,YAAM,QAAQ,KAAK,OAAO,IAAI,CAAC,MAAe,OAAO,
|
|
1
|
+
{"version":3,"sources":["../src/transformer.ts"],"sourcesContent":["import type { Mapping, Transformer } from '@walkeros/core';\nimport { getMappingValue, setByPath } from '@walkeros/core';\nimport { getHashServer } from '@walkeros/server-core';\nimport type { FingerprintSettings } from './types';\n\n/**\n * Fingerprint transformer - hash configurable fields for session continuity.\n *\n * Resolves fields from { event, ingest } source object using getMappingValue,\n * concatenates values in order, hashes with SHA-256, and stores at output path.\n *\n * @example\n * transformerFingerprint({\n * config: {\n * settings: {\n * fields: [\n * 'ingest.ip',\n * 'ingest.userAgent',\n * { fn: () => new Date().getDate() },\n * ],\n * output: 'user.hash',\n * length: 16,\n * },\n * },\n * })\n */\nexport const transformerFingerprint: Transformer.Init<\n Transformer.Types<FingerprintSettings>\n> = (context) => {\n const { config } = context;\n const settings = (config.settings || {}) as Partial<FingerprintSettings>;\n const fields: Mapping.Value[] = settings.fields || [];\n const output: string = settings.output || 'user.hash';\n const length: number | undefined = settings.length;\n\n return {\n type: 'fingerprint',\n config: config as Transformer.Config<\n Transformer.Types<FingerprintSettings>\n >,\n\n async push(event, context) {\n const { ingest, collector } = context;\n\n // Build source object for field resolution\n const source = { event, ingest };\n\n // Resolve each field via mapping (maintains order)\n const values = await Promise.all(\n fields.map((field: Mapping.Value) =>\n getMappingValue(source, field, { collector }),\n ),\n );\n\n // Safe string concatenation: '' prefix + String() cast for each value\n // '' prefix ensures we always have a string even if fields is empty\n // String(v ?? '') handles undefined/null gracefully\n const input = '' + values.map((v: unknown) => String(v ?? '')).join('');\n\n // Hash and store at output path\n const hash = await getHashServer(input, length);\n return { event: setByPath(event, output, hash) };\n },\n };\n};\n"],"mappings":";AACA,SAAS,iBAAiB,iBAAiB;AAC3C,SAAS,qBAAqB;AAwBvB,IAAM,yBAET,CAAC,YAAY;AACf,QAAM,EAAE,OAAO,IAAI;AACnB,QAAM,WAAY,OAAO,YAAY,CAAC;AACtC,QAAM,SAA0B,SAAS,UAAU,CAAC;AACpD,QAAM,SAAiB,SAAS,UAAU;AAC1C,QAAM,SAA6B,SAAS;AAE5C,SAAO;AAAA,IACL,MAAM;AAAA,IACN;AAAA,IAIA,MAAM,KAAK,OAAOA,UAAS;AACzB,YAAM,EAAE,QAAQ,UAAU,IAAIA;AAG9B,YAAM,SAAS,EAAE,OAAO,OAAO;AAG/B,YAAM,SAAS,MAAM,QAAQ;AAAA,QAC3B,OAAO;AAAA,UAAI,CAAC,UACV,gBAAgB,QAAQ,OAAO,EAAE,UAAU,CAAC;AAAA,QAC9C;AAAA,MACF;AAKA,YAAM,QAAQ,KAAK,OAAO,IAAI,CAAC,MAAe,OAAO,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE;AAGtE,YAAM,OAAO,MAAM,cAAc,OAAO,MAAM;AAC9C,aAAO,EAAE,OAAO,UAAU,OAAO,QAAQ,IAAI,EAAE;AAAA,IACjD;AAAA,EACF;AACF;","names":["context"]}
|
package/dist/walkerOS.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$meta": {
|
|
3
3
|
"package": "@walkeros/server-transformer-fingerprint",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "4.0.0-next-1777463920154",
|
|
5
5
|
"type": "transformer",
|
|
6
6
|
"platform": [
|
|
7
7
|
"server"
|
|
@@ -74,20 +74,14 @@
|
|
|
74
74
|
"title": "Privacy Policy",
|
|
75
75
|
"id": "/privacy"
|
|
76
76
|
},
|
|
77
|
-
"id": "1700000602
|
|
77
|
+
"id": "ev-1700000602",
|
|
78
78
|
"trigger": "load",
|
|
79
79
|
"entity": "page",
|
|
80
80
|
"action": "view",
|
|
81
81
|
"timestamp": 1700000602,
|
|
82
|
-
"group": "gr0up",
|
|
83
|
-
"count": 3,
|
|
84
|
-
"version": {
|
|
85
|
-
"tagging": 1
|
|
86
|
-
},
|
|
87
82
|
"source": {
|
|
88
|
-
"type": "
|
|
89
|
-
"
|
|
90
|
-
"previous_id": ""
|
|
83
|
+
"type": "express",
|
|
84
|
+
"platform": "server"
|
|
91
85
|
}
|
|
92
86
|
},
|
|
93
87
|
"out": [
|
|
@@ -104,20 +98,14 @@
|
|
|
104
98
|
"user": {
|
|
105
99
|
"hash": "44d9154b9a9b3792"
|
|
106
100
|
},
|
|
107
|
-
"id": "1700000602
|
|
101
|
+
"id": "ev-1700000602",
|
|
108
102
|
"trigger": "load",
|
|
109
103
|
"entity": "page",
|
|
110
104
|
"action": "view",
|
|
111
105
|
"timestamp": 1700000602,
|
|
112
|
-
"group": "gr0up",
|
|
113
|
-
"count": 3,
|
|
114
|
-
"version": {
|
|
115
|
-
"tagging": 1
|
|
116
|
-
},
|
|
117
106
|
"source": {
|
|
118
|
-
"type": "
|
|
119
|
-
"
|
|
120
|
-
"previous_id": ""
|
|
107
|
+
"type": "express",
|
|
108
|
+
"platform": "server"
|
|
121
109
|
}
|
|
122
110
|
}
|
|
123
111
|
}
|
|
@@ -126,26 +114,20 @@
|
|
|
126
114
|
},
|
|
127
115
|
"missingFields": {
|
|
128
116
|
"public": false,
|
|
129
|
-
"description": "Graceful handling when ingest is missing
|
|
117
|
+
"description": "Graceful handling when ingest is missing - fields resolve to empty strings, hash is still generated.",
|
|
130
118
|
"in": {
|
|
131
119
|
"name": "session start",
|
|
132
120
|
"data": {
|
|
133
121
|
"id": "s3ss10n"
|
|
134
122
|
},
|
|
135
|
-
"id": "1700000601
|
|
123
|
+
"id": "ev-1700000601",
|
|
136
124
|
"trigger": "load",
|
|
137
125
|
"entity": "session",
|
|
138
126
|
"action": "start",
|
|
139
127
|
"timestamp": 1700000601,
|
|
140
|
-
"group": "gr0up",
|
|
141
|
-
"count": 2,
|
|
142
|
-
"version": {
|
|
143
|
-
"tagging": 1
|
|
144
|
-
},
|
|
145
128
|
"source": {
|
|
146
|
-
"type": "
|
|
147
|
-
"
|
|
148
|
-
"previous_id": ""
|
|
129
|
+
"type": "express",
|
|
130
|
+
"platform": "server"
|
|
149
131
|
}
|
|
150
132
|
},
|
|
151
133
|
"out": [
|
|
@@ -160,20 +142,14 @@
|
|
|
160
142
|
"user": {
|
|
161
143
|
"hash": "e183220b699c10a8"
|
|
162
144
|
},
|
|
163
|
-
"id": "1700000601
|
|
145
|
+
"id": "ev-1700000601",
|
|
164
146
|
"trigger": "load",
|
|
165
147
|
"entity": "session",
|
|
166
148
|
"action": "start",
|
|
167
149
|
"timestamp": 1700000601,
|
|
168
|
-
"group": "gr0up",
|
|
169
|
-
"count": 2,
|
|
170
|
-
"version": {
|
|
171
|
-
"tagging": 1
|
|
172
|
-
},
|
|
173
150
|
"source": {
|
|
174
|
-
"type": "
|
|
175
|
-
"
|
|
176
|
-
"previous_id": ""
|
|
151
|
+
"type": "express",
|
|
152
|
+
"platform": "server"
|
|
177
153
|
}
|
|
178
154
|
}
|
|
179
155
|
}
|
|
@@ -190,20 +166,14 @@
|
|
|
190
166
|
"title": "Getting Started",
|
|
191
167
|
"id": "/docs/getting-started"
|
|
192
168
|
},
|
|
193
|
-
"id": "1700000600
|
|
169
|
+
"id": "ev-1700000600",
|
|
194
170
|
"trigger": "load",
|
|
195
171
|
"entity": "page",
|
|
196
172
|
"action": "view",
|
|
197
173
|
"timestamp": 1700000600,
|
|
198
|
-
"group": "gr0up",
|
|
199
|
-
"count": 1,
|
|
200
|
-
"version": {
|
|
201
|
-
"tagging": 1
|
|
202
|
-
},
|
|
203
174
|
"source": {
|
|
204
|
-
"type": "
|
|
205
|
-
"
|
|
206
|
-
"previous_id": ""
|
|
175
|
+
"type": "express",
|
|
176
|
+
"platform": "server"
|
|
207
177
|
}
|
|
208
178
|
},
|
|
209
179
|
"out": [
|
|
@@ -220,20 +190,14 @@
|
|
|
220
190
|
"user": {
|
|
221
191
|
"hash": "158f99cc06e33fd6"
|
|
222
192
|
},
|
|
223
|
-
"id": "1700000600
|
|
193
|
+
"id": "ev-1700000600",
|
|
224
194
|
"trigger": "load",
|
|
225
195
|
"entity": "page",
|
|
226
196
|
"action": "view",
|
|
227
197
|
"timestamp": 1700000600,
|
|
228
|
-
"group": "gr0up",
|
|
229
|
-
"count": 1,
|
|
230
|
-
"version": {
|
|
231
|
-
"tagging": 1
|
|
232
|
-
},
|
|
233
198
|
"source": {
|
|
234
|
-
"type": "
|
|
235
|
-
"
|
|
236
|
-
"previous_id": ""
|
|
199
|
+
"type": "express",
|
|
200
|
+
"platform": "server"
|
|
237
201
|
}
|
|
238
202
|
}
|
|
239
203
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@walkeros/server-transformer-fingerprint",
|
|
3
3
|
"description": "Fingerprint transformer for walkerOS server - hash configurable fields for session continuity",
|
|
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",
|
|
@@ -27,8 +27,8 @@
|
|
|
27
27
|
"update": "npx npm-check-updates -u && npm update"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
|
-
"@walkeros/core": "
|
|
31
|
-
"@walkeros/server-core": "
|
|
30
|
+
"@walkeros/core": "4.0.0-next-1777463920154",
|
|
31
|
+
"@walkeros/server-core": "4.0.0-next-1777463920154"
|
|
32
32
|
},
|
|
33
33
|
"repository": {
|
|
34
34
|
"url": "git+https://github.com/elbwalker/walkerOS.git",
|
|
@@ -60,7 +60,7 @@
|
|
|
60
60
|
}
|
|
61
61
|
],
|
|
62
62
|
"dependencies": {
|
|
63
|
-
"@walkeros/core": "
|
|
64
|
-
"@walkeros/server-core": "
|
|
63
|
+
"@walkeros/core": "4.0.0-next-1777463920154",
|
|
64
|
+
"@walkeros/server-core": "4.0.0-next-1777463920154"
|
|
65
65
|
}
|
|
66
66
|
}
|