@walkeros/server-destination-datamanager 0.4.2 → 0.5.0
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 +11 -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/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/schemas.js +1 -1
- package/dist/schemas.js.map +1 -1
- package/dist/schemas.mjs +1 -1
- package/dist/schemas.mjs.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -791,12 +791,21 @@ authentication**
|
|
|
791
791
|
| `eventName` | string | 40 | Event name (required for GA4) |
|
|
792
792
|
| `eventSource` | string | | WEB, APP, IN_STORE, PHONE, OTHER |
|
|
793
793
|
|
|
794
|
+
## Type Definitions
|
|
795
|
+
|
|
796
|
+
See [src/types/](./src/types/) for TypeScript interfaces.
|
|
797
|
+
|
|
798
|
+
## Related
|
|
799
|
+
|
|
800
|
+
- [Website Documentation](https://www.walkeros.io/docs/destinations/server/datamanager/)
|
|
801
|
+
- [Destination Interface](../../../core/src/types/destination.ts)
|
|
802
|
+
|
|
794
803
|
## Resources
|
|
795
804
|
|
|
796
805
|
- [Google Data Manager API Documentation](https://developers.google.com/data-manager/api)
|
|
797
806
|
- [Data Formatting Guidelines](https://developers.google.com/data-manager/api/devguides/concepts/formatting)
|
|
798
807
|
- [DMA Compliance](https://developers.google.com/data-manager/api/devguides/concepts/dma)
|
|
799
|
-
- [walkerOS Documentation](https://www.
|
|
808
|
+
- [walkerOS Documentation](https://www.walkeros.io/docs/)
|
|
800
809
|
|
|
801
810
|
## License
|
|
802
811
|
|
|
@@ -807,5 +816,5 @@ MIT
|
|
|
807
816
|
For issues and questions:
|
|
808
817
|
|
|
809
818
|
- [GitHub Issues](https://github.com/elbwalker/walkerOS/issues)
|
|
810
|
-
- [walkerOS Documentation](https://www.
|
|
819
|
+
- [walkerOS Documentation](https://www.walkeros.io/docs/)
|
|
811
820
|
- [Google Data Manager Support](https://developers.google.com/data-manager/api/support/contact)
|
package/dist/dev.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var e,t=Object.defineProperty,a=Object.getOwnPropertyDescriptor,n=Object.getOwnPropertyNames,o=Object.prototype.hasOwnProperty,i=(e,a)=>{for(var n in a)t(e,n,{get:a[n],enumerable:!0})},c={};i(c,{examples:()=>
|
|
1
|
+
"use strict";var e,t=Object.defineProperty,a=Object.getOwnPropertyDescriptor,n=Object.getOwnPropertyNames,o=Object.prototype.hasOwnProperty,i=(e,a)=>{for(var n in a)t(e,n,{get:a[n],enumerable:!0})},c={};i(c,{examples:()=>D,schemas:()=>r}),module.exports=(e=c,((e,i,c,r)=>{if(i&&"object"==typeof i||"function"==typeof i)for(let s of n(i))o.call(e,s)||s===c||t(e,s,{get:()=>i[s],enumerable:!(r=a(i,s))||r.enumerable});return e})(t({},"__esModule",{value:!0}),e));var r={};i(r,{mapping:()=>N,settings:()=>A});var s=require("@walkeros/core/dev"),d=s.z.enum(["GOOGLE_ADS","DISPLAY_VIDEO_ADVERTISER","DISPLAY_VIDEO_PARTNER","GOOGLE_ANALYTICS_PROPERTY"]),l=s.z.enum(["WEB","APP","IN_STORE","PHONE","OTHER"]),u=s.z.enum(["CONSENT_GRANTED","CONSENT_DENIED"]),p=s.z.object({adUserData:u.describe("Consent for data collection and use").optional(),adPersonalization:u.describe("Consent for ad personalization").optional()}),m=s.z.object({accountId:s.z.string().min(1).describe('Account ID (e.g., "123-456-7890" for Google Ads)'),accountType:d.describe("Type of account")}),g=s.z.object({operatingAccount:m.describe("Operating account details"),productDestinationId:s.z.string().min(1).describe("Product-specific destination ID (conversion action or user list)")}),v=require("@walkeros/core/dev"),O=v.z.object({client_email:v.z.string().email().describe("Service account email"),private_key:v.z.string().min(1).describe("Service account private key (PEM format)")}),E=v.z.object({credentials:O.optional().describe("Service account credentials (client_email + private_key). Recommended for serverless environments."),keyFilename:v.z.string().optional().describe("Path to service account JSON file. For local development or environments with filesystem access."),scopes:v.z.array(v.z.string()).optional().describe("OAuth scopes for Data Manager API. Defaults to datamanager scope."),destinations:v.z.array(g).min(1).max(10).describe("Array of destination accounts and conversion actions/user lists (max 10)"),eventSource:l.optional().default("WEB").describe("Event source for all events. Defaults to WEB. Values: WEB, APP, IN_STORE, PHONE, OTHER"),batchSize:v.z.number().int().min(1).max(2e3).describe("Maximum number of events to batch before sending (max 2000, like 100)").optional(),batchInterval:v.z.number().int().min(0).describe("Time in milliseconds to wait before auto-flushing batch (like 5000)").optional(),validateOnly:v.z.boolean().describe("If true, validate request without ingestion (testing mode)").optional(),url:v.z.string().url().describe("Override API endpoint for testing (like https://datamanager.googleapis.com/v1)").optional(),consent:p.describe("Request-level consent for all events").optional(),testEventCode:v.z.string().describe("Test event code for debugging (like TEST12345)").optional(),logLevel:v.z.enum(["debug","info","warn","error","none"]).describe("Log level for debugging (debug shows all API calls)").optional(),userData:v.z.record(v.z.string(),v.z.unknown()).describe("Guided helper: User data mapping for all events (like { email: 'user.id', phone: 'data.phone' })").optional(),userId:v.z.any().describe("Guided helper: First-party user ID for all events (like 'user.id')").optional(),clientId:v.z.any().describe("Guided helper: GA4 client ID for all events (like 'user.device')").optional(),sessionAttributes:v.z.any().describe("Guided helper: Privacy-safe attribution for all events (like 'context.sessionAttributes')").optional(),consentAdUserData:v.z.union([v.z.string(),v.z.boolean()]).describe("Consent mapping: Field name from event.consent (like 'marketing') or static boolean value").optional(),consentAdPersonalization:v.z.union([v.z.string(),v.z.boolean()]).describe("Consent mapping: Field name from event.consent (like 'targeting') or static boolean value").optional()}),b=require("@walkeros/core/dev").z.object({}),I=require("@walkeros/core/dev"),A=(0,I.zodToSchema)(E),N=(0,I.zodToSchema)(b),D={};i(D,{auth:()=>_,basic:()=>S,mapping:()=>L});var _={};i(_,{awsLambda:()=>y,customScopes:()=>z,dockerKubernetes:()=>f,gcpCloudFunctions:()=>G,localDevelopment:()=>T});var y={settings:{credentials:{client_email:process.env.GOOGLE_CLIENT_EMAIL||"",private_key:(process.env.GOOGLE_PRIVATE_KEY||"").replace(/\\n/g,"\n")},destinations:[{operatingAccount:{accountId:"123-456-7890",accountType:"GOOGLE_ADS"},productDestinationId:"AW-CONVERSION-123"}]}},G={settings:{destinations:[{operatingAccount:{accountId:"123-456-7890",accountType:"GOOGLE_ADS"},productDestinationId:"AW-CONVERSION-123"}]}},T={settings:{keyFilename:"./service-account.json",destinations:[{operatingAccount:{accountId:"123-456-7890",accountType:"GOOGLE_ADS"},productDestinationId:"AW-CONVERSION-123"}]}},f={settings:{destinations:[{operatingAccount:{accountId:"123-456-7890",accountType:"GOOGLE_ADS"},productDestinationId:"AW-CONVERSION-123"}]}},z={settings:{credentials:{client_email:process.env.GOOGLE_CLIENT_EMAIL||"",private_key:(process.env.GOOGLE_PRIVATE_KEY||"").replace(/\\n/g,"\n")},scopes:["https://www.googleapis.com/auth/datamanager"],destinations:[{operatingAccount:{accountId:"123-456-7890",accountType:"GOOGLE_ADS"},productDestinationId:"AW-CONVERSION-123"}]}},S={};i(S,{complete:()=>h,debug:()=>k,ga4:()=>R,minimal:()=>P});var P={settings:{credentials:{client_email:"service-account@project.iam.gserviceaccount.com",private_key:"-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n"},destinations:[{operatingAccount:{accountId:"123-456-7890",accountType:"GOOGLE_ADS"},productDestinationId:"AW-CONVERSION-123"}]}},h={settings:{credentials:{client_email:"service-account@project.iam.gserviceaccount.com",private_key:"-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n"},destinations:[{operatingAccount:{accountId:"123-456-7890",accountType:"GOOGLE_ADS"},productDestinationId:"AW-CONVERSION-123"},{operatingAccount:{accountId:"987654321",accountType:"GOOGLE_ANALYTICS_PROPERTY"},productDestinationId:"G-XXXXXXXXXX"}],batchSize:100,batchInterval:5e3,validateOnly:!1,consent:{adUserData:"CONSENT_GRANTED",adPersonalization:"CONSENT_GRANTED"},userData:{email:"user.id",phone:"data.phone",firstName:"data.firstName",lastName:"data.lastName"},userId:"user.id",clientId:"user.device",sessionAttributes:"context.sessionAttributes"}},R={settings:{destinations:[{operatingAccount:{accountId:"123456789",accountType:"GOOGLE_ANALYTICS_PROPERTY"},productDestinationId:"G-XXXXXXXXXX"}]}},k={settings:{keyFilename:"./service-account.json",destinations:[{operatingAccount:{accountId:"123-456-7890",accountType:"GOOGLE_ADS"},productDestinationId:"AW-CONVERSION-123"}]}},L={};i(L,{Lead:()=>V,PageView:()=>X,Purchase:()=>w,mapping:()=>j,userDataMapping:()=>Y});var C=require("@walkeros/core"),w={name:"purchase",data:{map:{transactionId:"data.id",conversionValue:"data.total",currency:{key:"data.currency",value:"USD"},eventName:{value:"purchase"},userId:"user.id",email:"user.id",gclid:"context.gclid",gbraid:"context.gbraid",wbraid:"context.wbraid",cartData:{map:{items:{loop:["nested",{condition:e=>(0,C.isObject)(e)&&"product"===e.entity,map:{merchantProductId:"data.id",price:"data.price",quantity:{key:"data.quantity",value:1}}}]}}}}}},V={name:"generate_lead",data:{map:{eventName:{value:"generate_lead"},conversionValue:{value:10},currency:{value:"USD"}}}},X={name:"page_view",data:{map:{eventName:{value:"page_view"}}}},j={order:{complete:w},lead:{submit:V},page:{view:X}},Y={settings:{keyFilename:"./service-account.json",destinations:[{operatingAccount:{accountId:"123-456-7890",accountType:"GOOGLE_ADS"},productDestinationId:"AW-CONVERSION-123"}]},data:{map:{email:"user.id",phone:"data.phone",firstName:"data.firstName",lastName:"data.lastName",regionCode:"data.country",postalCode:"data.zip"}},mapping:j};//# sourceMappingURL=dev.js.map
|
package/dist/dev.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/dev.ts","../src/schemas.ts","../src/schemas/primitives.ts","../src/schemas/settings.ts","../src/schemas/mapping.ts","../src/schemas/index.ts","../src/examples/index.ts","../src/examples/auth.ts","../src/examples/basic.ts","../src/examples/mapping.ts"],"sourcesContent":["export * as schemas from './schemas';\nexport * as examples from './examples';\n","// Browser-safe schema-only exports\n// This file exports ONLY schemas without any Node.js dependencies\nexport { settings, mapping } from './schemas/index';\n","import { z } from '@walkeros/core/dev';\n\nexport const AccountTypeSchema = z.enum([\n 'GOOGLE_ADS',\n 'DISPLAY_VIDEO_ADVERTISER',\n 'DISPLAY_VIDEO_PARTNER',\n 'GOOGLE_ANALYTICS_PROPERTY',\n]);\n\nexport const EventSourceSchema = z.enum([\n 'WEB',\n 'APP',\n 'IN_STORE',\n 'PHONE',\n 'OTHER',\n]);\n\nexport const ConsentStatusSchema = z.enum([\n 'CONSENT_GRANTED',\n 'CONSENT_DENIED',\n]);\n\nexport const ConsentSchema = z.object({\n adUserData: ConsentStatusSchema.describe(\n 'Consent for data collection and use',\n ).optional(),\n adPersonalization: ConsentStatusSchema.describe(\n 'Consent for ad personalization',\n ).optional(),\n});\n\nexport const OperatingAccountSchema = z.object({\n accountId: z\n .string()\n .min(1)\n .describe('Account ID (e.g., \"123-456-7890\" for Google Ads)'),\n accountType: AccountTypeSchema.describe('Type of account'),\n});\n\nexport const DestinationSchema = z.object({\n operatingAccount: OperatingAccountSchema.describe(\n 'Operating account details',\n ),\n productDestinationId: z\n .string()\n .min(1)\n .describe(\n 'Product-specific destination ID (conversion action or user list)',\n ),\n});\n","import { z } from '@walkeros/core/dev';\nimport {\n DestinationSchema,\n EventSourceSchema,\n ConsentSchema,\n} from './primitives';\n\nexport const SettingsSchema = z.object({\n accessToken: z\n .string()\n .min(1)\n .describe(\n 'OAuth 2.0 access token with datamanager scope (like ya29.c.xxx)',\n ),\n destinations: z\n .array(DestinationSchema)\n .min(1)\n .max(10)\n .describe(\n 'Array of destination accounts and conversion actions/user lists (max 10)',\n ),\n eventSource: EventSourceSchema.optional()\n .default('WEB')\n .describe(\n 'Event source for all events. Defaults to WEB. Values: WEB, APP, IN_STORE, PHONE, OTHER',\n ),\n batchSize: z\n .number()\n .int()\n .min(1)\n .max(2000)\n .describe(\n 'Maximum number of events to batch before sending (max 2000, like 100)',\n )\n .optional(),\n batchInterval: z\n .number()\n .int()\n .min(0)\n .describe(\n 'Time in milliseconds to wait before auto-flushing batch (like 5000)',\n )\n .optional(),\n validateOnly: z\n .boolean()\n .describe('If true, validate request without ingestion (testing mode)')\n .optional(),\n url: z\n .string()\n .url()\n .describe(\n 'Override API endpoint for testing (like https://datamanager.googleapis.com/v1)',\n )\n .optional(),\n consent: ConsentSchema.describe(\n 'Request-level consent for all events',\n ).optional(),\n testEventCode: z\n .string()\n .describe('Test event code for debugging (like TEST12345)')\n .optional(),\n logLevel: z\n .enum(['debug', 'info', 'warn', 'error', 'none'])\n .describe('Log level for debugging (debug shows all API calls)')\n .optional(),\n userData: z\n .record(z.string(), z.unknown())\n .describe(\n \"Guided helper: User data mapping for all events (like { email: 'user.id', phone: 'data.phone' })\",\n )\n .optional(),\n userId: z\n .any()\n .describe(\n \"Guided helper: First-party user ID for all events (like 'user.id')\",\n )\n .optional(),\n clientId: z\n .any()\n .describe(\n \"Guided helper: GA4 client ID for all events (like 'user.device')\",\n )\n .optional(),\n sessionAttributes: z\n .any()\n .describe(\n \"Guided helper: Privacy-safe attribution for all events (like 'context.sessionAttributes')\",\n )\n .optional(),\n consentAdUserData: z\n .union([z.string(), z.boolean()])\n .describe(\n \"Consent mapping: Field name from event.consent (like 'marketing') or static boolean value\",\n )\n .optional(),\n consentAdPersonalization: z\n .union([z.string(), z.boolean()])\n .describe(\n \"Consent mapping: Field name from event.consent (like 'targeting') or static boolean value\",\n )\n .optional(),\n});\n\nexport type Settings = z.infer<typeof SettingsSchema>;\n","import { z } from '@walkeros/core/dev';\n\n// Data Manager uses flexible mapping via walkerOS mapping system\n// No event-specific mapping schema needed (similar to Meta CAPI pattern)\nexport const MappingSchema = z.object({});\n\nexport type Mapping = z.infer<typeof MappingSchema>;\n","export * from './primitives';\nexport * from './settings';\nexport * from './mapping';\n\nimport { zodToSchema } from '@walkeros/core/dev';\nimport { SettingsSchema } from './settings';\nimport { MappingSchema } from './mapping';\n\nexport const settings = zodToSchema(SettingsSchema);\nexport const mapping = zodToSchema(MappingSchema);\n","export * as auth from './auth';\nexport * as basic from './basic';\nexport * as mapping from './mapping';\n","import type { DestinationDataManager } from '..';\n\n/**\n * AWS Lambda / Serverless Configuration\n * Uses inline credentials from environment variables\n * Best for: AWS Lambda, Docker, Kubernetes, any serverless environment\n */\nexport const awsLambda: DestinationDataManager.Config = {\n settings: {\n credentials: {\n client_email: process.env.GOOGLE_CLIENT_EMAIL || '',\n private_key: (process.env.GOOGLE_PRIVATE_KEY || '').replace(/\\\\n/g, '\\n'),\n },\n destinations: [\n {\n operatingAccount: {\n accountId: '123-456-7890',\n accountType: 'GOOGLE_ADS',\n },\n productDestinationId: 'AW-CONVERSION-123',\n },\n ],\n },\n};\n\n/**\n * GCP Cloud Functions / Cloud Run Configuration\n * Uses Application Default Credentials (ADC) - no explicit auth config needed\n * Best for: Google Cloud Functions, Cloud Run, GCE, GKE\n */\nexport const gcpCloudFunctions: DestinationDataManager.Config = {\n settings: {\n // No auth config needed - ADC works automatically on GCP!\n destinations: [\n {\n operatingAccount: {\n accountId: '123-456-7890',\n accountType: 'GOOGLE_ADS',\n },\n productDestinationId: 'AW-CONVERSION-123',\n },\n ],\n },\n};\n\n/**\n * Local Development Configuration\n * Uses service account JSON file\n * Best for: Local development, testing\n */\nexport const localDevelopment: DestinationDataManager.Config = {\n settings: {\n keyFilename: './service-account.json',\n destinations: [\n {\n operatingAccount: {\n accountId: '123-456-7890',\n accountType: 'GOOGLE_ADS',\n },\n productDestinationId: 'AW-CONVERSION-123',\n },\n ],\n },\n};\n\n/**\n * Docker / Kubernetes Configuration\n * Uses ADC via GOOGLE_APPLICATION_CREDENTIALS environment variable\n * Best for: Docker containers, Kubernetes pods\n *\n * Setup:\n * 1. Mount service account JSON as secret/configmap\n * 2. Set GOOGLE_APPLICATION_CREDENTIALS=/path/to/service-account.json\n * 3. ADC will automatically use it\n */\nexport const dockerKubernetes: DestinationDataManager.Config = {\n settings: {\n // No explicit config - ADC uses GOOGLE_APPLICATION_CREDENTIALS env var\n destinations: [\n {\n operatingAccount: {\n accountId: '123-456-7890',\n accountType: 'GOOGLE_ADS',\n },\n productDestinationId: 'AW-CONVERSION-123',\n },\n ],\n },\n};\n\n/**\n * Custom Scopes Configuration\n * For specific use cases requiring different OAuth scopes\n */\nexport const customScopes: DestinationDataManager.Config = {\n settings: {\n credentials: {\n client_email: process.env.GOOGLE_CLIENT_EMAIL || '',\n private_key: (process.env.GOOGLE_PRIVATE_KEY || '').replace(/\\\\n/g, '\\n'),\n },\n scopes: ['https://www.googleapis.com/auth/datamanager'],\n destinations: [\n {\n operatingAccount: {\n accountId: '123-456-7890',\n accountType: 'GOOGLE_ADS',\n },\n productDestinationId: 'AW-CONVERSION-123',\n },\n ],\n },\n};\n","import type { DestinationDataManager } from '..';\n\n/**\n * Minimal configuration for Google Data Manager with inline credentials\n */\nexport const minimal: DestinationDataManager.Config = {\n settings: {\n credentials: {\n client_email: 'service-account@project.iam.gserviceaccount.com',\n private_key:\n '-----BEGIN PRIVATE KEY-----\\n...\\n-----END PRIVATE KEY-----\\n',\n },\n destinations: [\n {\n operatingAccount: {\n accountId: '123-456-7890',\n accountType: 'GOOGLE_ADS',\n },\n productDestinationId: 'AW-CONVERSION-123',\n },\n ],\n },\n};\n\n/**\n * Complete configuration with all options\n */\nexport const complete: DestinationDataManager.Config = {\n settings: {\n credentials: {\n client_email: 'service-account@project.iam.gserviceaccount.com',\n private_key:\n '-----BEGIN PRIVATE KEY-----\\n...\\n-----END PRIVATE KEY-----\\n',\n },\n destinations: [\n {\n operatingAccount: {\n accountId: '123-456-7890',\n accountType: 'GOOGLE_ADS',\n },\n productDestinationId: 'AW-CONVERSION-123',\n },\n {\n operatingAccount: {\n accountId: '987654321',\n accountType: 'GOOGLE_ANALYTICS_PROPERTY',\n },\n productDestinationId: 'G-XXXXXXXXXX',\n },\n ],\n batchSize: 100,\n batchInterval: 5000,\n validateOnly: false,\n consent: {\n adUserData: 'CONSENT_GRANTED',\n adPersonalization: 'CONSENT_GRANTED',\n },\n\n // Guided helpers (apply to all events)\n userData: {\n email: 'user.id',\n phone: 'data.phone',\n firstName: 'data.firstName',\n lastName: 'data.lastName',\n },\n userId: 'user.id',\n clientId: 'user.device',\n sessionAttributes: 'context.sessionAttributes',\n },\n};\n\n/**\n * GA4-specific configuration using Application Default Credentials\n */\nexport const ga4: DestinationDataManager.Config = {\n settings: {\n destinations: [\n {\n operatingAccount: {\n accountId: '123456789',\n accountType: 'GOOGLE_ANALYTICS_PROPERTY',\n },\n productDestinationId: 'G-XXXXXXXXXX',\n },\n ],\n },\n};\n\n/**\n * Debug configuration with logging enabled using keyFilename\n */\nexport const debug: DestinationDataManager.Config = {\n settings: {\n keyFilename: './service-account.json',\n destinations: [\n {\n operatingAccount: {\n accountId: '123-456-7890',\n accountType: 'GOOGLE_ADS',\n },\n productDestinationId: 'AW-CONVERSION-123',\n },\n ],\n },\n};\n","import type { DestinationDataManager } from '..';\nimport { isObject } from '@walkeros/core';\n\n/**\n * Purchase event mapping for Google Ads conversion\n */\nexport const Purchase: DestinationDataManager.Rule = {\n name: 'purchase',\n data: {\n map: {\n // Required fields\n transactionId: 'data.id',\n conversionValue: 'data.total',\n currency: { key: 'data.currency', value: 'USD' },\n eventName: { value: 'purchase' },\n\n // User identification\n userId: 'user.id',\n email: 'user.id', // Will be hashed automatically\n\n // Attribution identifiers (captured by browser source from URL)\n gclid: 'context.gclid', // Google Click ID\n gbraid: 'context.gbraid', // iOS attribution\n wbraid: 'context.wbraid', // Web-to-app\n\n // Shopping cart data\n cartData: {\n map: {\n items: {\n loop: [\n 'nested',\n {\n condition: (entity) =>\n isObject(entity) && entity.entity === 'product',\n map: {\n merchantProductId: 'data.id',\n price: 'data.price',\n quantity: { key: 'data.quantity', value: 1 },\n },\n },\n ],\n },\n },\n },\n },\n },\n};\n\n/**\n * Lead event mapping\n */\nexport const Lead: DestinationDataManager.Rule = {\n name: 'generate_lead',\n data: {\n map: {\n eventName: { value: 'generate_lead' },\n conversionValue: { value: 10 },\n currency: { value: 'USD' },\n },\n },\n};\n\n/**\n * Page view mapping for GA4\n */\nexport const PageView: DestinationDataManager.Rule = {\n name: 'page_view',\n data: {\n map: {\n eventName: { value: 'page_view' },\n },\n },\n};\n\n/**\n * Complete mapping configuration\n */\nexport const mapping = {\n order: {\n complete: Purchase,\n },\n lead: {\n submit: Lead,\n },\n page: {\n view: PageView,\n },\n} satisfies DestinationDataManager.Rules;\n\n/**\n * User data mapping configuration\n * Maps walkerOS user properties to Data Manager user identifiers\n */\nexport const userDataMapping: DestinationDataManager.Config = {\n settings: {\n keyFilename: './service-account.json',\n destinations: [\n {\n operatingAccount: {\n accountId: '123-456-7890',\n accountType: 'GOOGLE_ADS',\n },\n productDestinationId: 'AW-CONVERSION-123',\n },\n ],\n },\n data: {\n map: {\n email: 'user.id',\n phone: 'data.phone',\n firstName: 'data.firstName',\n lastName: 'data.lastName',\n regionCode: 'data.country',\n postalCode: 'data.zip',\n },\n },\n mapping,\n};\n"],"mappings":"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","names":["import_dev","import_dev","import_dev","mapping"]}
|
|
1
|
+
{"version":3,"sources":["../src/dev.ts","../src/schemas.ts","../src/schemas/primitives.ts","../src/schemas/settings.ts","../src/schemas/mapping.ts","../src/schemas/index.ts","../src/examples/index.ts","../src/examples/auth.ts","../src/examples/basic.ts","../src/examples/mapping.ts"],"sourcesContent":["export * as schemas from './schemas';\nexport * as examples from './examples';\n","// Browser-safe schema-only exports\n// This file exports ONLY schemas without any Node.js dependencies\nexport { settings, mapping } from './schemas/index';\n","import { z } from '@walkeros/core/dev';\n\nexport const AccountTypeSchema = z.enum([\n 'GOOGLE_ADS',\n 'DISPLAY_VIDEO_ADVERTISER',\n 'DISPLAY_VIDEO_PARTNER',\n 'GOOGLE_ANALYTICS_PROPERTY',\n]);\n\nexport const EventSourceSchema = z.enum([\n 'WEB',\n 'APP',\n 'IN_STORE',\n 'PHONE',\n 'OTHER',\n]);\n\nexport const ConsentStatusSchema = z.enum([\n 'CONSENT_GRANTED',\n 'CONSENT_DENIED',\n]);\n\nexport const ConsentSchema = z.object({\n adUserData: ConsentStatusSchema.describe(\n 'Consent for data collection and use',\n ).optional(),\n adPersonalization: ConsentStatusSchema.describe(\n 'Consent for ad personalization',\n ).optional(),\n});\n\nexport const OperatingAccountSchema = z.object({\n accountId: z\n .string()\n .min(1)\n .describe('Account ID (e.g., \"123-456-7890\" for Google Ads)'),\n accountType: AccountTypeSchema.describe('Type of account'),\n});\n\nexport const DestinationSchema = z.object({\n operatingAccount: OperatingAccountSchema.describe(\n 'Operating account details',\n ),\n productDestinationId: z\n .string()\n .min(1)\n .describe(\n 'Product-specific destination ID (conversion action or user list)',\n ),\n});\n","import { z } from '@walkeros/core/dev';\nimport {\n DestinationSchema,\n EventSourceSchema,\n ConsentSchema,\n} from './primitives';\n\n/**\n * Service account credentials schema\n */\nconst CredentialsSchema = z.object({\n client_email: z.string().email().describe('Service account email'),\n private_key: z\n .string()\n .min(1)\n .describe('Service account private key (PEM format)'),\n});\n\nexport const SettingsSchema = z.object({\n credentials: CredentialsSchema.optional().describe(\n 'Service account credentials (client_email + private_key). Recommended for serverless environments.',\n ),\n keyFilename: z\n .string()\n .optional()\n .describe(\n 'Path to service account JSON file. For local development or environments with filesystem access.',\n ),\n scopes: z\n .array(z.string())\n .optional()\n .describe(\n 'OAuth scopes for Data Manager API. Defaults to datamanager scope.',\n ),\n destinations: z\n .array(DestinationSchema)\n .min(1)\n .max(10)\n .describe(\n 'Array of destination accounts and conversion actions/user lists (max 10)',\n ),\n eventSource: EventSourceSchema.optional()\n .default('WEB')\n .describe(\n 'Event source for all events. Defaults to WEB. Values: WEB, APP, IN_STORE, PHONE, OTHER',\n ),\n batchSize: z\n .number()\n .int()\n .min(1)\n .max(2000)\n .describe(\n 'Maximum number of events to batch before sending (max 2000, like 100)',\n )\n .optional(),\n batchInterval: z\n .number()\n .int()\n .min(0)\n .describe(\n 'Time in milliseconds to wait before auto-flushing batch (like 5000)',\n )\n .optional(),\n validateOnly: z\n .boolean()\n .describe('If true, validate request without ingestion (testing mode)')\n .optional(),\n url: z\n .string()\n .url()\n .describe(\n 'Override API endpoint for testing (like https://datamanager.googleapis.com/v1)',\n )\n .optional(),\n consent: ConsentSchema.describe(\n 'Request-level consent for all events',\n ).optional(),\n testEventCode: z\n .string()\n .describe('Test event code for debugging (like TEST12345)')\n .optional(),\n logLevel: z\n .enum(['debug', 'info', 'warn', 'error', 'none'])\n .describe('Log level for debugging (debug shows all API calls)')\n .optional(),\n userData: z\n .record(z.string(), z.unknown())\n .describe(\n \"Guided helper: User data mapping for all events (like { email: 'user.id', phone: 'data.phone' })\",\n )\n .optional(),\n userId: z\n .any()\n .describe(\n \"Guided helper: First-party user ID for all events (like 'user.id')\",\n )\n .optional(),\n clientId: z\n .any()\n .describe(\n \"Guided helper: GA4 client ID for all events (like 'user.device')\",\n )\n .optional(),\n sessionAttributes: z\n .any()\n .describe(\n \"Guided helper: Privacy-safe attribution for all events (like 'context.sessionAttributes')\",\n )\n .optional(),\n consentAdUserData: z\n .union([z.string(), z.boolean()])\n .describe(\n \"Consent mapping: Field name from event.consent (like 'marketing') or static boolean value\",\n )\n .optional(),\n consentAdPersonalization: z\n .union([z.string(), z.boolean()])\n .describe(\n \"Consent mapping: Field name from event.consent (like 'targeting') or static boolean value\",\n )\n .optional(),\n});\n\nexport type Settings = z.infer<typeof SettingsSchema>;\n","import { z } from '@walkeros/core/dev';\n\n// Data Manager uses flexible mapping via walkerOS mapping system\n// No event-specific mapping schema needed (similar to Meta CAPI pattern)\nexport const MappingSchema = z.object({});\n\nexport type Mapping = z.infer<typeof MappingSchema>;\n","export * from './primitives';\nexport * from './settings';\nexport * from './mapping';\n\nimport { zodToSchema } from '@walkeros/core/dev';\nimport { SettingsSchema } from './settings';\nimport { MappingSchema } from './mapping';\n\nexport const settings = zodToSchema(SettingsSchema);\nexport const mapping = zodToSchema(MappingSchema);\n","export * as auth from './auth';\nexport * as basic from './basic';\nexport * as mapping from './mapping';\n","import type { DestinationDataManager } from '..';\n\n/**\n * AWS Lambda / Serverless Configuration\n * Uses inline credentials from environment variables\n * Best for: AWS Lambda, Docker, Kubernetes, any serverless environment\n */\nexport const awsLambda: DestinationDataManager.Config = {\n settings: {\n credentials: {\n client_email: process.env.GOOGLE_CLIENT_EMAIL || '',\n private_key: (process.env.GOOGLE_PRIVATE_KEY || '').replace(/\\\\n/g, '\\n'),\n },\n destinations: [\n {\n operatingAccount: {\n accountId: '123-456-7890',\n accountType: 'GOOGLE_ADS',\n },\n productDestinationId: 'AW-CONVERSION-123',\n },\n ],\n },\n};\n\n/**\n * GCP Cloud Functions / Cloud Run Configuration\n * Uses Application Default Credentials (ADC) - no explicit auth config needed\n * Best for: Google Cloud Functions, Cloud Run, GCE, GKE\n */\nexport const gcpCloudFunctions: DestinationDataManager.Config = {\n settings: {\n // No auth config needed - ADC works automatically on GCP!\n destinations: [\n {\n operatingAccount: {\n accountId: '123-456-7890',\n accountType: 'GOOGLE_ADS',\n },\n productDestinationId: 'AW-CONVERSION-123',\n },\n ],\n },\n};\n\n/**\n * Local Development Configuration\n * Uses service account JSON file\n * Best for: Local development, testing\n */\nexport const localDevelopment: DestinationDataManager.Config = {\n settings: {\n keyFilename: './service-account.json',\n destinations: [\n {\n operatingAccount: {\n accountId: '123-456-7890',\n accountType: 'GOOGLE_ADS',\n },\n productDestinationId: 'AW-CONVERSION-123',\n },\n ],\n },\n};\n\n/**\n * Docker / Kubernetes Configuration\n * Uses ADC via GOOGLE_APPLICATION_CREDENTIALS environment variable\n * Best for: Docker containers, Kubernetes pods\n *\n * Setup:\n * 1. Mount service account JSON as secret/configmap\n * 2. Set GOOGLE_APPLICATION_CREDENTIALS=/path/to/service-account.json\n * 3. ADC will automatically use it\n */\nexport const dockerKubernetes: DestinationDataManager.Config = {\n settings: {\n // No explicit config - ADC uses GOOGLE_APPLICATION_CREDENTIALS env var\n destinations: [\n {\n operatingAccount: {\n accountId: '123-456-7890',\n accountType: 'GOOGLE_ADS',\n },\n productDestinationId: 'AW-CONVERSION-123',\n },\n ],\n },\n};\n\n/**\n * Custom Scopes Configuration\n * For specific use cases requiring different OAuth scopes\n */\nexport const customScopes: DestinationDataManager.Config = {\n settings: {\n credentials: {\n client_email: process.env.GOOGLE_CLIENT_EMAIL || '',\n private_key: (process.env.GOOGLE_PRIVATE_KEY || '').replace(/\\\\n/g, '\\n'),\n },\n scopes: ['https://www.googleapis.com/auth/datamanager'],\n destinations: [\n {\n operatingAccount: {\n accountId: '123-456-7890',\n accountType: 'GOOGLE_ADS',\n },\n productDestinationId: 'AW-CONVERSION-123',\n },\n ],\n },\n};\n","import type { DestinationDataManager } from '..';\n\n/**\n * Minimal configuration for Google Data Manager with inline credentials\n */\nexport const minimal: DestinationDataManager.Config = {\n settings: {\n credentials: {\n client_email: 'service-account@project.iam.gserviceaccount.com',\n private_key:\n '-----BEGIN PRIVATE KEY-----\\n...\\n-----END PRIVATE KEY-----\\n',\n },\n destinations: [\n {\n operatingAccount: {\n accountId: '123-456-7890',\n accountType: 'GOOGLE_ADS',\n },\n productDestinationId: 'AW-CONVERSION-123',\n },\n ],\n },\n};\n\n/**\n * Complete configuration with all options\n */\nexport const complete: DestinationDataManager.Config = {\n settings: {\n credentials: {\n client_email: 'service-account@project.iam.gserviceaccount.com',\n private_key:\n '-----BEGIN PRIVATE KEY-----\\n...\\n-----END PRIVATE KEY-----\\n',\n },\n destinations: [\n {\n operatingAccount: {\n accountId: '123-456-7890',\n accountType: 'GOOGLE_ADS',\n },\n productDestinationId: 'AW-CONVERSION-123',\n },\n {\n operatingAccount: {\n accountId: '987654321',\n accountType: 'GOOGLE_ANALYTICS_PROPERTY',\n },\n productDestinationId: 'G-XXXXXXXXXX',\n },\n ],\n batchSize: 100,\n batchInterval: 5000,\n validateOnly: false,\n consent: {\n adUserData: 'CONSENT_GRANTED',\n adPersonalization: 'CONSENT_GRANTED',\n },\n\n // Guided helpers (apply to all events)\n userData: {\n email: 'user.id',\n phone: 'data.phone',\n firstName: 'data.firstName',\n lastName: 'data.lastName',\n },\n userId: 'user.id',\n clientId: 'user.device',\n sessionAttributes: 'context.sessionAttributes',\n },\n};\n\n/**\n * GA4-specific configuration using Application Default Credentials\n */\nexport const ga4: DestinationDataManager.Config = {\n settings: {\n destinations: [\n {\n operatingAccount: {\n accountId: '123456789',\n accountType: 'GOOGLE_ANALYTICS_PROPERTY',\n },\n productDestinationId: 'G-XXXXXXXXXX',\n },\n ],\n },\n};\n\n/**\n * Debug configuration with logging enabled using keyFilename\n */\nexport const debug: DestinationDataManager.Config = {\n settings: {\n keyFilename: './service-account.json',\n destinations: [\n {\n operatingAccount: {\n accountId: '123-456-7890',\n accountType: 'GOOGLE_ADS',\n },\n productDestinationId: 'AW-CONVERSION-123',\n },\n ],\n },\n};\n","import type { DestinationDataManager } from '..';\nimport { isObject } from '@walkeros/core';\n\n/**\n * Purchase event mapping for Google Ads conversion\n */\nexport const Purchase: DestinationDataManager.Rule = {\n name: 'purchase',\n data: {\n map: {\n // Required fields\n transactionId: 'data.id',\n conversionValue: 'data.total',\n currency: { key: 'data.currency', value: 'USD' },\n eventName: { value: 'purchase' },\n\n // User identification\n userId: 'user.id',\n email: 'user.id', // Will be hashed automatically\n\n // Attribution identifiers (captured by browser source from URL)\n gclid: 'context.gclid', // Google Click ID\n gbraid: 'context.gbraid', // iOS attribution\n wbraid: 'context.wbraid', // Web-to-app\n\n // Shopping cart data\n cartData: {\n map: {\n items: {\n loop: [\n 'nested',\n {\n condition: (entity) =>\n isObject(entity) && entity.entity === 'product',\n map: {\n merchantProductId: 'data.id',\n price: 'data.price',\n quantity: { key: 'data.quantity', value: 1 },\n },\n },\n ],\n },\n },\n },\n },\n },\n};\n\n/**\n * Lead event mapping\n */\nexport const Lead: DestinationDataManager.Rule = {\n name: 'generate_lead',\n data: {\n map: {\n eventName: { value: 'generate_lead' },\n conversionValue: { value: 10 },\n currency: { value: 'USD' },\n },\n },\n};\n\n/**\n * Page view mapping for GA4\n */\nexport const PageView: DestinationDataManager.Rule = {\n name: 'page_view',\n data: {\n map: {\n eventName: { value: 'page_view' },\n },\n },\n};\n\n/**\n * Complete mapping configuration\n */\nexport const mapping = {\n order: {\n complete: Purchase,\n },\n lead: {\n submit: Lead,\n },\n page: {\n view: PageView,\n },\n} satisfies DestinationDataManager.Rules;\n\n/**\n * User data mapping configuration\n * Maps walkerOS user properties to Data Manager user identifiers\n */\nexport const userDataMapping: DestinationDataManager.Config = {\n settings: {\n keyFilename: './service-account.json',\n destinations: [\n {\n operatingAccount: {\n accountId: '123-456-7890',\n accountType: 'GOOGLE_ADS',\n },\n productDestinationId: 'AW-CONVERSION-123',\n },\n ],\n },\n data: {\n map: {\n email: 'user.id',\n phone: 'data.phone',\n firstName: 'data.firstName',\n lastName: 'data.lastName',\n regionCode: 'data.country',\n postalCode: 'data.zip',\n },\n },\n mapping,\n};\n"],"mappings":"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","names":["import_dev","import_dev","import_dev","mapping"]}
|
package/dist/dev.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var e=Object.defineProperty,t=(t,a)=>{for(var n in a)e(t,n,{get:a[n],enumerable:!0})},a={};t(a,{mapping:()=>
|
|
1
|
+
var e=Object.defineProperty,t=(t,a)=>{for(var n in a)e(t,n,{get:a[n],enumerable:!0})},a={};t(a,{mapping:()=>O,settings:()=>E});import{z as n}from"@walkeros/core/dev";var i=n.enum(["GOOGLE_ADS","DISPLAY_VIDEO_ADVERTISER","DISPLAY_VIDEO_PARTNER","GOOGLE_ANALYTICS_PROPERTY"]),o=n.enum(["WEB","APP","IN_STORE","PHONE","OTHER"]),s=n.enum(["CONSENT_GRANTED","CONSENT_DENIED"]),c=n.object({adUserData:s.describe("Consent for data collection and use").optional(),adPersonalization:s.describe("Consent for ad personalization").optional()}),r=n.object({accountId:n.string().min(1).describe('Account ID (e.g., "123-456-7890" for Google Ads)'),accountType:i.describe("Type of account")}),d=n.object({operatingAccount:r.describe("Operating account details"),productDestinationId:n.string().min(1).describe("Product-specific destination ID (conversion action or user list)")});import{z as l}from"@walkeros/core/dev";var u=l.object({client_email:l.string().email().describe("Service account email"),private_key:l.string().min(1).describe("Service account private key (PEM format)")}),p=l.object({credentials:u.optional().describe("Service account credentials (client_email + private_key). Recommended for serverless environments."),keyFilename:l.string().optional().describe("Path to service account JSON file. For local development or environments with filesystem access."),scopes:l.array(l.string()).optional().describe("OAuth scopes for Data Manager API. Defaults to datamanager scope."),destinations:l.array(d).min(1).max(10).describe("Array of destination accounts and conversion actions/user lists (max 10)"),eventSource:o.optional().default("WEB").describe("Event source for all events. Defaults to WEB. Values: WEB, APP, IN_STORE, PHONE, OTHER"),batchSize:l.number().int().min(1).max(2e3).describe("Maximum number of events to batch before sending (max 2000, like 100)").optional(),batchInterval:l.number().int().min(0).describe("Time in milliseconds to wait before auto-flushing batch (like 5000)").optional(),validateOnly:l.boolean().describe("If true, validate request without ingestion (testing mode)").optional(),url:l.string().url().describe("Override API endpoint for testing (like https://datamanager.googleapis.com/v1)").optional(),consent:c.describe("Request-level consent for all events").optional(),testEventCode:l.string().describe("Test event code for debugging (like TEST12345)").optional(),logLevel:l.enum(["debug","info","warn","error","none"]).describe("Log level for debugging (debug shows all API calls)").optional(),userData:l.record(l.string(),l.unknown()).describe("Guided helper: User data mapping for all events (like { email: 'user.id', phone: 'data.phone' })").optional(),userId:l.any().describe("Guided helper: First-party user ID for all events (like 'user.id')").optional(),clientId:l.any().describe("Guided helper: GA4 client ID for all events (like 'user.device')").optional(),sessionAttributes:l.any().describe("Guided helper: Privacy-safe attribution for all events (like 'context.sessionAttributes')").optional(),consentAdUserData:l.union([l.string(),l.boolean()]).describe("Consent mapping: Field name from event.consent (like 'marketing') or static boolean value").optional(),consentAdPersonalization:l.union([l.string(),l.boolean()]).describe("Consent mapping: Field name from event.consent (like 'targeting') or static boolean value").optional()});import{z as m}from"@walkeros/core/dev";var g=m.object({});import{zodToSchema as v}from"@walkeros/core/dev";var E=v(p),O=v(g),I={};t(I,{auth:()=>b,basic:()=>y,mapping:()=>R});var b={};t(b,{awsLambda:()=>A,customScopes:()=>G,dockerKubernetes:()=>_,gcpCloudFunctions:()=>N,localDevelopment:()=>D});var A={settings:{credentials:{client_email:process.env.GOOGLE_CLIENT_EMAIL||"",private_key:(process.env.GOOGLE_PRIVATE_KEY||"").replace(/\\n/g,"\n")},destinations:[{operatingAccount:{accountId:"123-456-7890",accountType:"GOOGLE_ADS"},productDestinationId:"AW-CONVERSION-123"}]}},N={settings:{destinations:[{operatingAccount:{accountId:"123-456-7890",accountType:"GOOGLE_ADS"},productDestinationId:"AW-CONVERSION-123"}]}},D={settings:{keyFilename:"./service-account.json",destinations:[{operatingAccount:{accountId:"123-456-7890",accountType:"GOOGLE_ADS"},productDestinationId:"AW-CONVERSION-123"}]}},_={settings:{destinations:[{operatingAccount:{accountId:"123-456-7890",accountType:"GOOGLE_ADS"},productDestinationId:"AW-CONVERSION-123"}]}},G={settings:{credentials:{client_email:process.env.GOOGLE_CLIENT_EMAIL||"",private_key:(process.env.GOOGLE_PRIVATE_KEY||"").replace(/\\n/g,"\n")},scopes:["https://www.googleapis.com/auth/datamanager"],destinations:[{operatingAccount:{accountId:"123-456-7890",accountType:"GOOGLE_ADS"},productDestinationId:"AW-CONVERSION-123"}]}},y={};t(y,{complete:()=>f,debug:()=>P,ga4:()=>S,minimal:()=>T});var T={settings:{credentials:{client_email:"service-account@project.iam.gserviceaccount.com",private_key:"-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n"},destinations:[{operatingAccount:{accountId:"123-456-7890",accountType:"GOOGLE_ADS"},productDestinationId:"AW-CONVERSION-123"}]}},f={settings:{credentials:{client_email:"service-account@project.iam.gserviceaccount.com",private_key:"-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n"},destinations:[{operatingAccount:{accountId:"123-456-7890",accountType:"GOOGLE_ADS"},productDestinationId:"AW-CONVERSION-123"},{operatingAccount:{accountId:"987654321",accountType:"GOOGLE_ANALYTICS_PROPERTY"},productDestinationId:"G-XXXXXXXXXX"}],batchSize:100,batchInterval:5e3,validateOnly:!1,consent:{adUserData:"CONSENT_GRANTED",adPersonalization:"CONSENT_GRANTED"},userData:{email:"user.id",phone:"data.phone",firstName:"data.firstName",lastName:"data.lastName"},userId:"user.id",clientId:"user.device",sessionAttributes:"context.sessionAttributes"}},S={settings:{destinations:[{operatingAccount:{accountId:"123456789",accountType:"GOOGLE_ANALYTICS_PROPERTY"},productDestinationId:"G-XXXXXXXXXX"}]}},P={settings:{keyFilename:"./service-account.json",destinations:[{operatingAccount:{accountId:"123-456-7890",accountType:"GOOGLE_ADS"},productDestinationId:"AW-CONVERSION-123"}]}},R={};t(R,{Lead:()=>L,PageView:()=>C,Purchase:()=>k,mapping:()=>V,userDataMapping:()=>w});import{isObject as h}from"@walkeros/core";var k={name:"purchase",data:{map:{transactionId:"data.id",conversionValue:"data.total",currency:{key:"data.currency",value:"USD"},eventName:{value:"purchase"},userId:"user.id",email:"user.id",gclid:"context.gclid",gbraid:"context.gbraid",wbraid:"context.wbraid",cartData:{map:{items:{loop:["nested",{condition:e=>h(e)&&"product"===e.entity,map:{merchantProductId:"data.id",price:"data.price",quantity:{key:"data.quantity",value:1}}}]}}}}}},L={name:"generate_lead",data:{map:{eventName:{value:"generate_lead"},conversionValue:{value:10},currency:{value:"USD"}}}},C={name:"page_view",data:{map:{eventName:{value:"page_view"}}}},V={order:{complete:k},lead:{submit:L},page:{view:C}},w={settings:{keyFilename:"./service-account.json",destinations:[{operatingAccount:{accountId:"123-456-7890",accountType:"GOOGLE_ADS"},productDestinationId:"AW-CONVERSION-123"}]},data:{map:{email:"user.id",phone:"data.phone",firstName:"data.firstName",lastName:"data.lastName",regionCode:"data.country",postalCode:"data.zip"}},mapping:V};export{I as examples,a as schemas};//# sourceMappingURL=dev.mjs.map
|
package/dist/dev.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/schemas.ts","../src/schemas/primitives.ts","../src/schemas/settings.ts","../src/schemas/mapping.ts","../src/schemas/index.ts","../src/examples/index.ts","../src/examples/auth.ts","../src/examples/basic.ts","../src/examples/mapping.ts"],"sourcesContent":["// Browser-safe schema-only exports\n// This file exports ONLY schemas without any Node.js dependencies\nexport { settings, mapping } from './schemas/index';\n","import { z } from '@walkeros/core/dev';\n\nexport const AccountTypeSchema = z.enum([\n 'GOOGLE_ADS',\n 'DISPLAY_VIDEO_ADVERTISER',\n 'DISPLAY_VIDEO_PARTNER',\n 'GOOGLE_ANALYTICS_PROPERTY',\n]);\n\nexport const EventSourceSchema = z.enum([\n 'WEB',\n 'APP',\n 'IN_STORE',\n 'PHONE',\n 'OTHER',\n]);\n\nexport const ConsentStatusSchema = z.enum([\n 'CONSENT_GRANTED',\n 'CONSENT_DENIED',\n]);\n\nexport const ConsentSchema = z.object({\n adUserData: ConsentStatusSchema.describe(\n 'Consent for data collection and use',\n ).optional(),\n adPersonalization: ConsentStatusSchema.describe(\n 'Consent for ad personalization',\n ).optional(),\n});\n\nexport const OperatingAccountSchema = z.object({\n accountId: z\n .string()\n .min(1)\n .describe('Account ID (e.g., \"123-456-7890\" for Google Ads)'),\n accountType: AccountTypeSchema.describe('Type of account'),\n});\n\nexport const DestinationSchema = z.object({\n operatingAccount: OperatingAccountSchema.describe(\n 'Operating account details',\n ),\n productDestinationId: z\n .string()\n .min(1)\n .describe(\n 'Product-specific destination ID (conversion action or user list)',\n ),\n});\n","import { z } from '@walkeros/core/dev';\nimport {\n DestinationSchema,\n EventSourceSchema,\n ConsentSchema,\n} from './primitives';\n\nexport const SettingsSchema = z.object({\n accessToken: z\n .string()\n .min(1)\n .describe(\n 'OAuth 2.0 access token with datamanager scope (like ya29.c.xxx)',\n ),\n destinations: z\n .array(DestinationSchema)\n .min(1)\n .max(10)\n .describe(\n 'Array of destination accounts and conversion actions/user lists (max 10)',\n ),\n eventSource: EventSourceSchema.optional()\n .default('WEB')\n .describe(\n 'Event source for all events. Defaults to WEB. Values: WEB, APP, IN_STORE, PHONE, OTHER',\n ),\n batchSize: z\n .number()\n .int()\n .min(1)\n .max(2000)\n .describe(\n 'Maximum number of events to batch before sending (max 2000, like 100)',\n )\n .optional(),\n batchInterval: z\n .number()\n .int()\n .min(0)\n .describe(\n 'Time in milliseconds to wait before auto-flushing batch (like 5000)',\n )\n .optional(),\n validateOnly: z\n .boolean()\n .describe('If true, validate request without ingestion (testing mode)')\n .optional(),\n url: z\n .string()\n .url()\n .describe(\n 'Override API endpoint for testing (like https://datamanager.googleapis.com/v1)',\n )\n .optional(),\n consent: ConsentSchema.describe(\n 'Request-level consent for all events',\n ).optional(),\n testEventCode: z\n .string()\n .describe('Test event code for debugging (like TEST12345)')\n .optional(),\n logLevel: z\n .enum(['debug', 'info', 'warn', 'error', 'none'])\n .describe('Log level for debugging (debug shows all API calls)')\n .optional(),\n userData: z\n .record(z.string(), z.unknown())\n .describe(\n \"Guided helper: User data mapping for all events (like { email: 'user.id', phone: 'data.phone' })\",\n )\n .optional(),\n userId: z\n .any()\n .describe(\n \"Guided helper: First-party user ID for all events (like 'user.id')\",\n )\n .optional(),\n clientId: z\n .any()\n .describe(\n \"Guided helper: GA4 client ID for all events (like 'user.device')\",\n )\n .optional(),\n sessionAttributes: z\n .any()\n .describe(\n \"Guided helper: Privacy-safe attribution for all events (like 'context.sessionAttributes')\",\n )\n .optional(),\n consentAdUserData: z\n .union([z.string(), z.boolean()])\n .describe(\n \"Consent mapping: Field name from event.consent (like 'marketing') or static boolean value\",\n )\n .optional(),\n consentAdPersonalization: z\n .union([z.string(), z.boolean()])\n .describe(\n \"Consent mapping: Field name from event.consent (like 'targeting') or static boolean value\",\n )\n .optional(),\n});\n\nexport type Settings = z.infer<typeof SettingsSchema>;\n","import { z } from '@walkeros/core/dev';\n\n// Data Manager uses flexible mapping via walkerOS mapping system\n// No event-specific mapping schema needed (similar to Meta CAPI pattern)\nexport const MappingSchema = z.object({});\n\nexport type Mapping = z.infer<typeof MappingSchema>;\n","export * from './primitives';\nexport * from './settings';\nexport * from './mapping';\n\nimport { zodToSchema } from '@walkeros/core/dev';\nimport { SettingsSchema } from './settings';\nimport { MappingSchema } from './mapping';\n\nexport const settings = zodToSchema(SettingsSchema);\nexport const mapping = zodToSchema(MappingSchema);\n","export * as auth from './auth';\nexport * as basic from './basic';\nexport * as mapping from './mapping';\n","import type { DestinationDataManager } from '..';\n\n/**\n * AWS Lambda / Serverless Configuration\n * Uses inline credentials from environment variables\n * Best for: AWS Lambda, Docker, Kubernetes, any serverless environment\n */\nexport const awsLambda: DestinationDataManager.Config = {\n settings: {\n credentials: {\n client_email: process.env.GOOGLE_CLIENT_EMAIL || '',\n private_key: (process.env.GOOGLE_PRIVATE_KEY || '').replace(/\\\\n/g, '\\n'),\n },\n destinations: [\n {\n operatingAccount: {\n accountId: '123-456-7890',\n accountType: 'GOOGLE_ADS',\n },\n productDestinationId: 'AW-CONVERSION-123',\n },\n ],\n },\n};\n\n/**\n * GCP Cloud Functions / Cloud Run Configuration\n * Uses Application Default Credentials (ADC) - no explicit auth config needed\n * Best for: Google Cloud Functions, Cloud Run, GCE, GKE\n */\nexport const gcpCloudFunctions: DestinationDataManager.Config = {\n settings: {\n // No auth config needed - ADC works automatically on GCP!\n destinations: [\n {\n operatingAccount: {\n accountId: '123-456-7890',\n accountType: 'GOOGLE_ADS',\n },\n productDestinationId: 'AW-CONVERSION-123',\n },\n ],\n },\n};\n\n/**\n * Local Development Configuration\n * Uses service account JSON file\n * Best for: Local development, testing\n */\nexport const localDevelopment: DestinationDataManager.Config = {\n settings: {\n keyFilename: './service-account.json',\n destinations: [\n {\n operatingAccount: {\n accountId: '123-456-7890',\n accountType: 'GOOGLE_ADS',\n },\n productDestinationId: 'AW-CONVERSION-123',\n },\n ],\n },\n};\n\n/**\n * Docker / Kubernetes Configuration\n * Uses ADC via GOOGLE_APPLICATION_CREDENTIALS environment variable\n * Best for: Docker containers, Kubernetes pods\n *\n * Setup:\n * 1. Mount service account JSON as secret/configmap\n * 2. Set GOOGLE_APPLICATION_CREDENTIALS=/path/to/service-account.json\n * 3. ADC will automatically use it\n */\nexport const dockerKubernetes: DestinationDataManager.Config = {\n settings: {\n // No explicit config - ADC uses GOOGLE_APPLICATION_CREDENTIALS env var\n destinations: [\n {\n operatingAccount: {\n accountId: '123-456-7890',\n accountType: 'GOOGLE_ADS',\n },\n productDestinationId: 'AW-CONVERSION-123',\n },\n ],\n },\n};\n\n/**\n * Custom Scopes Configuration\n * For specific use cases requiring different OAuth scopes\n */\nexport const customScopes: DestinationDataManager.Config = {\n settings: {\n credentials: {\n client_email: process.env.GOOGLE_CLIENT_EMAIL || '',\n private_key: (process.env.GOOGLE_PRIVATE_KEY || '').replace(/\\\\n/g, '\\n'),\n },\n scopes: ['https://www.googleapis.com/auth/datamanager'],\n destinations: [\n {\n operatingAccount: {\n accountId: '123-456-7890',\n accountType: 'GOOGLE_ADS',\n },\n productDestinationId: 'AW-CONVERSION-123',\n },\n ],\n },\n};\n","import type { DestinationDataManager } from '..';\n\n/**\n * Minimal configuration for Google Data Manager with inline credentials\n */\nexport const minimal: DestinationDataManager.Config = {\n settings: {\n credentials: {\n client_email: 'service-account@project.iam.gserviceaccount.com',\n private_key:\n '-----BEGIN PRIVATE KEY-----\\n...\\n-----END PRIVATE KEY-----\\n',\n },\n destinations: [\n {\n operatingAccount: {\n accountId: '123-456-7890',\n accountType: 'GOOGLE_ADS',\n },\n productDestinationId: 'AW-CONVERSION-123',\n },\n ],\n },\n};\n\n/**\n * Complete configuration with all options\n */\nexport const complete: DestinationDataManager.Config = {\n settings: {\n credentials: {\n client_email: 'service-account@project.iam.gserviceaccount.com',\n private_key:\n '-----BEGIN PRIVATE KEY-----\\n...\\n-----END PRIVATE KEY-----\\n',\n },\n destinations: [\n {\n operatingAccount: {\n accountId: '123-456-7890',\n accountType: 'GOOGLE_ADS',\n },\n productDestinationId: 'AW-CONVERSION-123',\n },\n {\n operatingAccount: {\n accountId: '987654321',\n accountType: 'GOOGLE_ANALYTICS_PROPERTY',\n },\n productDestinationId: 'G-XXXXXXXXXX',\n },\n ],\n batchSize: 100,\n batchInterval: 5000,\n validateOnly: false,\n consent: {\n adUserData: 'CONSENT_GRANTED',\n adPersonalization: 'CONSENT_GRANTED',\n },\n\n // Guided helpers (apply to all events)\n userData: {\n email: 'user.id',\n phone: 'data.phone',\n firstName: 'data.firstName',\n lastName: 'data.lastName',\n },\n userId: 'user.id',\n clientId: 'user.device',\n sessionAttributes: 'context.sessionAttributes',\n },\n};\n\n/**\n * GA4-specific configuration using Application Default Credentials\n */\nexport const ga4: DestinationDataManager.Config = {\n settings: {\n destinations: [\n {\n operatingAccount: {\n accountId: '123456789',\n accountType: 'GOOGLE_ANALYTICS_PROPERTY',\n },\n productDestinationId: 'G-XXXXXXXXXX',\n },\n ],\n },\n};\n\n/**\n * Debug configuration with logging enabled using keyFilename\n */\nexport const debug: DestinationDataManager.Config = {\n settings: {\n keyFilename: './service-account.json',\n destinations: [\n {\n operatingAccount: {\n accountId: '123-456-7890',\n accountType: 'GOOGLE_ADS',\n },\n productDestinationId: 'AW-CONVERSION-123',\n },\n ],\n },\n};\n","import type { DestinationDataManager } from '..';\nimport { isObject } from '@walkeros/core';\n\n/**\n * Purchase event mapping for Google Ads conversion\n */\nexport const Purchase: DestinationDataManager.Rule = {\n name: 'purchase',\n data: {\n map: {\n // Required fields\n transactionId: 'data.id',\n conversionValue: 'data.total',\n currency: { key: 'data.currency', value: 'USD' },\n eventName: { value: 'purchase' },\n\n // User identification\n userId: 'user.id',\n email: 'user.id', // Will be hashed automatically\n\n // Attribution identifiers (captured by browser source from URL)\n gclid: 'context.gclid', // Google Click ID\n gbraid: 'context.gbraid', // iOS attribution\n wbraid: 'context.wbraid', // Web-to-app\n\n // Shopping cart data\n cartData: {\n map: {\n items: {\n loop: [\n 'nested',\n {\n condition: (entity) =>\n isObject(entity) && entity.entity === 'product',\n map: {\n merchantProductId: 'data.id',\n price: 'data.price',\n quantity: { key: 'data.quantity', value: 1 },\n },\n },\n ],\n },\n },\n },\n },\n },\n};\n\n/**\n * Lead event mapping\n */\nexport const Lead: DestinationDataManager.Rule = {\n name: 'generate_lead',\n data: {\n map: {\n eventName: { value: 'generate_lead' },\n conversionValue: { value: 10 },\n currency: { value: 'USD' },\n },\n },\n};\n\n/**\n * Page view mapping for GA4\n */\nexport const PageView: DestinationDataManager.Rule = {\n name: 'page_view',\n data: {\n map: {\n eventName: { value: 'page_view' },\n },\n },\n};\n\n/**\n * Complete mapping configuration\n */\nexport const mapping = {\n order: {\n complete: Purchase,\n },\n lead: {\n submit: Lead,\n },\n page: {\n view: PageView,\n },\n} satisfies DestinationDataManager.Rules;\n\n/**\n * User data mapping configuration\n * Maps walkerOS user properties to Data Manager user identifiers\n */\nexport const userDataMapping: DestinationDataManager.Config = {\n settings: {\n keyFilename: './service-account.json',\n destinations: [\n {\n operatingAccount: {\n accountId: '123-456-7890',\n accountType: 'GOOGLE_ADS',\n },\n productDestinationId: 'AW-CONVERSION-123',\n },\n ],\n },\n data: {\n map: {\n email: 'user.id',\n phone: 'data.phone',\n firstName: 'data.firstName',\n lastName: 'data.lastName',\n regionCode: 'data.country',\n postalCode: 'data.zip',\n },\n },\n mapping,\n};\n"],"mappings":"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","names":["z","z","z","mapping"]}
|
|
1
|
+
{"version":3,"sources":["../src/schemas.ts","../src/schemas/primitives.ts","../src/schemas/settings.ts","../src/schemas/mapping.ts","../src/schemas/index.ts","../src/examples/index.ts","../src/examples/auth.ts","../src/examples/basic.ts","../src/examples/mapping.ts"],"sourcesContent":["// Browser-safe schema-only exports\n// This file exports ONLY schemas without any Node.js dependencies\nexport { settings, mapping } from './schemas/index';\n","import { z } from '@walkeros/core/dev';\n\nexport const AccountTypeSchema = z.enum([\n 'GOOGLE_ADS',\n 'DISPLAY_VIDEO_ADVERTISER',\n 'DISPLAY_VIDEO_PARTNER',\n 'GOOGLE_ANALYTICS_PROPERTY',\n]);\n\nexport const EventSourceSchema = z.enum([\n 'WEB',\n 'APP',\n 'IN_STORE',\n 'PHONE',\n 'OTHER',\n]);\n\nexport const ConsentStatusSchema = z.enum([\n 'CONSENT_GRANTED',\n 'CONSENT_DENIED',\n]);\n\nexport const ConsentSchema = z.object({\n adUserData: ConsentStatusSchema.describe(\n 'Consent for data collection and use',\n ).optional(),\n adPersonalization: ConsentStatusSchema.describe(\n 'Consent for ad personalization',\n ).optional(),\n});\n\nexport const OperatingAccountSchema = z.object({\n accountId: z\n .string()\n .min(1)\n .describe('Account ID (e.g., \"123-456-7890\" for Google Ads)'),\n accountType: AccountTypeSchema.describe('Type of account'),\n});\n\nexport const DestinationSchema = z.object({\n operatingAccount: OperatingAccountSchema.describe(\n 'Operating account details',\n ),\n productDestinationId: z\n .string()\n .min(1)\n .describe(\n 'Product-specific destination ID (conversion action or user list)',\n ),\n});\n","import { z } from '@walkeros/core/dev';\nimport {\n DestinationSchema,\n EventSourceSchema,\n ConsentSchema,\n} from './primitives';\n\n/**\n * Service account credentials schema\n */\nconst CredentialsSchema = z.object({\n client_email: z.string().email().describe('Service account email'),\n private_key: z\n .string()\n .min(1)\n .describe('Service account private key (PEM format)'),\n});\n\nexport const SettingsSchema = z.object({\n credentials: CredentialsSchema.optional().describe(\n 'Service account credentials (client_email + private_key). Recommended for serverless environments.',\n ),\n keyFilename: z\n .string()\n .optional()\n .describe(\n 'Path to service account JSON file. For local development or environments with filesystem access.',\n ),\n scopes: z\n .array(z.string())\n .optional()\n .describe(\n 'OAuth scopes for Data Manager API. Defaults to datamanager scope.',\n ),\n destinations: z\n .array(DestinationSchema)\n .min(1)\n .max(10)\n .describe(\n 'Array of destination accounts and conversion actions/user lists (max 10)',\n ),\n eventSource: EventSourceSchema.optional()\n .default('WEB')\n .describe(\n 'Event source for all events. Defaults to WEB. Values: WEB, APP, IN_STORE, PHONE, OTHER',\n ),\n batchSize: z\n .number()\n .int()\n .min(1)\n .max(2000)\n .describe(\n 'Maximum number of events to batch before sending (max 2000, like 100)',\n )\n .optional(),\n batchInterval: z\n .number()\n .int()\n .min(0)\n .describe(\n 'Time in milliseconds to wait before auto-flushing batch (like 5000)',\n )\n .optional(),\n validateOnly: z\n .boolean()\n .describe('If true, validate request without ingestion (testing mode)')\n .optional(),\n url: z\n .string()\n .url()\n .describe(\n 'Override API endpoint for testing (like https://datamanager.googleapis.com/v1)',\n )\n .optional(),\n consent: ConsentSchema.describe(\n 'Request-level consent for all events',\n ).optional(),\n testEventCode: z\n .string()\n .describe('Test event code for debugging (like TEST12345)')\n .optional(),\n logLevel: z\n .enum(['debug', 'info', 'warn', 'error', 'none'])\n .describe('Log level for debugging (debug shows all API calls)')\n .optional(),\n userData: z\n .record(z.string(), z.unknown())\n .describe(\n \"Guided helper: User data mapping for all events (like { email: 'user.id', phone: 'data.phone' })\",\n )\n .optional(),\n userId: z\n .any()\n .describe(\n \"Guided helper: First-party user ID for all events (like 'user.id')\",\n )\n .optional(),\n clientId: z\n .any()\n .describe(\n \"Guided helper: GA4 client ID for all events (like 'user.device')\",\n )\n .optional(),\n sessionAttributes: z\n .any()\n .describe(\n \"Guided helper: Privacy-safe attribution for all events (like 'context.sessionAttributes')\",\n )\n .optional(),\n consentAdUserData: z\n .union([z.string(), z.boolean()])\n .describe(\n \"Consent mapping: Field name from event.consent (like 'marketing') or static boolean value\",\n )\n .optional(),\n consentAdPersonalization: z\n .union([z.string(), z.boolean()])\n .describe(\n \"Consent mapping: Field name from event.consent (like 'targeting') or static boolean value\",\n )\n .optional(),\n});\n\nexport type Settings = z.infer<typeof SettingsSchema>;\n","import { z } from '@walkeros/core/dev';\n\n// Data Manager uses flexible mapping via walkerOS mapping system\n// No event-specific mapping schema needed (similar to Meta CAPI pattern)\nexport const MappingSchema = z.object({});\n\nexport type Mapping = z.infer<typeof MappingSchema>;\n","export * from './primitives';\nexport * from './settings';\nexport * from './mapping';\n\nimport { zodToSchema } from '@walkeros/core/dev';\nimport { SettingsSchema } from './settings';\nimport { MappingSchema } from './mapping';\n\nexport const settings = zodToSchema(SettingsSchema);\nexport const mapping = zodToSchema(MappingSchema);\n","export * as auth from './auth';\nexport * as basic from './basic';\nexport * as mapping from './mapping';\n","import type { DestinationDataManager } from '..';\n\n/**\n * AWS Lambda / Serverless Configuration\n * Uses inline credentials from environment variables\n * Best for: AWS Lambda, Docker, Kubernetes, any serverless environment\n */\nexport const awsLambda: DestinationDataManager.Config = {\n settings: {\n credentials: {\n client_email: process.env.GOOGLE_CLIENT_EMAIL || '',\n private_key: (process.env.GOOGLE_PRIVATE_KEY || '').replace(/\\\\n/g, '\\n'),\n },\n destinations: [\n {\n operatingAccount: {\n accountId: '123-456-7890',\n accountType: 'GOOGLE_ADS',\n },\n productDestinationId: 'AW-CONVERSION-123',\n },\n ],\n },\n};\n\n/**\n * GCP Cloud Functions / Cloud Run Configuration\n * Uses Application Default Credentials (ADC) - no explicit auth config needed\n * Best for: Google Cloud Functions, Cloud Run, GCE, GKE\n */\nexport const gcpCloudFunctions: DestinationDataManager.Config = {\n settings: {\n // No auth config needed - ADC works automatically on GCP!\n destinations: [\n {\n operatingAccount: {\n accountId: '123-456-7890',\n accountType: 'GOOGLE_ADS',\n },\n productDestinationId: 'AW-CONVERSION-123',\n },\n ],\n },\n};\n\n/**\n * Local Development Configuration\n * Uses service account JSON file\n * Best for: Local development, testing\n */\nexport const localDevelopment: DestinationDataManager.Config = {\n settings: {\n keyFilename: './service-account.json',\n destinations: [\n {\n operatingAccount: {\n accountId: '123-456-7890',\n accountType: 'GOOGLE_ADS',\n },\n productDestinationId: 'AW-CONVERSION-123',\n },\n ],\n },\n};\n\n/**\n * Docker / Kubernetes Configuration\n * Uses ADC via GOOGLE_APPLICATION_CREDENTIALS environment variable\n * Best for: Docker containers, Kubernetes pods\n *\n * Setup:\n * 1. Mount service account JSON as secret/configmap\n * 2. Set GOOGLE_APPLICATION_CREDENTIALS=/path/to/service-account.json\n * 3. ADC will automatically use it\n */\nexport const dockerKubernetes: DestinationDataManager.Config = {\n settings: {\n // No explicit config - ADC uses GOOGLE_APPLICATION_CREDENTIALS env var\n destinations: [\n {\n operatingAccount: {\n accountId: '123-456-7890',\n accountType: 'GOOGLE_ADS',\n },\n productDestinationId: 'AW-CONVERSION-123',\n },\n ],\n },\n};\n\n/**\n * Custom Scopes Configuration\n * For specific use cases requiring different OAuth scopes\n */\nexport const customScopes: DestinationDataManager.Config = {\n settings: {\n credentials: {\n client_email: process.env.GOOGLE_CLIENT_EMAIL || '',\n private_key: (process.env.GOOGLE_PRIVATE_KEY || '').replace(/\\\\n/g, '\\n'),\n },\n scopes: ['https://www.googleapis.com/auth/datamanager'],\n destinations: [\n {\n operatingAccount: {\n accountId: '123-456-7890',\n accountType: 'GOOGLE_ADS',\n },\n productDestinationId: 'AW-CONVERSION-123',\n },\n ],\n },\n};\n","import type { DestinationDataManager } from '..';\n\n/**\n * Minimal configuration for Google Data Manager with inline credentials\n */\nexport const minimal: DestinationDataManager.Config = {\n settings: {\n credentials: {\n client_email: 'service-account@project.iam.gserviceaccount.com',\n private_key:\n '-----BEGIN PRIVATE KEY-----\\n...\\n-----END PRIVATE KEY-----\\n',\n },\n destinations: [\n {\n operatingAccount: {\n accountId: '123-456-7890',\n accountType: 'GOOGLE_ADS',\n },\n productDestinationId: 'AW-CONVERSION-123',\n },\n ],\n },\n};\n\n/**\n * Complete configuration with all options\n */\nexport const complete: DestinationDataManager.Config = {\n settings: {\n credentials: {\n client_email: 'service-account@project.iam.gserviceaccount.com',\n private_key:\n '-----BEGIN PRIVATE KEY-----\\n...\\n-----END PRIVATE KEY-----\\n',\n },\n destinations: [\n {\n operatingAccount: {\n accountId: '123-456-7890',\n accountType: 'GOOGLE_ADS',\n },\n productDestinationId: 'AW-CONVERSION-123',\n },\n {\n operatingAccount: {\n accountId: '987654321',\n accountType: 'GOOGLE_ANALYTICS_PROPERTY',\n },\n productDestinationId: 'G-XXXXXXXXXX',\n },\n ],\n batchSize: 100,\n batchInterval: 5000,\n validateOnly: false,\n consent: {\n adUserData: 'CONSENT_GRANTED',\n adPersonalization: 'CONSENT_GRANTED',\n },\n\n // Guided helpers (apply to all events)\n userData: {\n email: 'user.id',\n phone: 'data.phone',\n firstName: 'data.firstName',\n lastName: 'data.lastName',\n },\n userId: 'user.id',\n clientId: 'user.device',\n sessionAttributes: 'context.sessionAttributes',\n },\n};\n\n/**\n * GA4-specific configuration using Application Default Credentials\n */\nexport const ga4: DestinationDataManager.Config = {\n settings: {\n destinations: [\n {\n operatingAccount: {\n accountId: '123456789',\n accountType: 'GOOGLE_ANALYTICS_PROPERTY',\n },\n productDestinationId: 'G-XXXXXXXXXX',\n },\n ],\n },\n};\n\n/**\n * Debug configuration with logging enabled using keyFilename\n */\nexport const debug: DestinationDataManager.Config = {\n settings: {\n keyFilename: './service-account.json',\n destinations: [\n {\n operatingAccount: {\n accountId: '123-456-7890',\n accountType: 'GOOGLE_ADS',\n },\n productDestinationId: 'AW-CONVERSION-123',\n },\n ],\n },\n};\n","import type { DestinationDataManager } from '..';\nimport { isObject } from '@walkeros/core';\n\n/**\n * Purchase event mapping for Google Ads conversion\n */\nexport const Purchase: DestinationDataManager.Rule = {\n name: 'purchase',\n data: {\n map: {\n // Required fields\n transactionId: 'data.id',\n conversionValue: 'data.total',\n currency: { key: 'data.currency', value: 'USD' },\n eventName: { value: 'purchase' },\n\n // User identification\n userId: 'user.id',\n email: 'user.id', // Will be hashed automatically\n\n // Attribution identifiers (captured by browser source from URL)\n gclid: 'context.gclid', // Google Click ID\n gbraid: 'context.gbraid', // iOS attribution\n wbraid: 'context.wbraid', // Web-to-app\n\n // Shopping cart data\n cartData: {\n map: {\n items: {\n loop: [\n 'nested',\n {\n condition: (entity) =>\n isObject(entity) && entity.entity === 'product',\n map: {\n merchantProductId: 'data.id',\n price: 'data.price',\n quantity: { key: 'data.quantity', value: 1 },\n },\n },\n ],\n },\n },\n },\n },\n },\n};\n\n/**\n * Lead event mapping\n */\nexport const Lead: DestinationDataManager.Rule = {\n name: 'generate_lead',\n data: {\n map: {\n eventName: { value: 'generate_lead' },\n conversionValue: { value: 10 },\n currency: { value: 'USD' },\n },\n },\n};\n\n/**\n * Page view mapping for GA4\n */\nexport const PageView: DestinationDataManager.Rule = {\n name: 'page_view',\n data: {\n map: {\n eventName: { value: 'page_view' },\n },\n },\n};\n\n/**\n * Complete mapping configuration\n */\nexport const mapping = {\n order: {\n complete: Purchase,\n },\n lead: {\n submit: Lead,\n },\n page: {\n view: PageView,\n },\n} satisfies DestinationDataManager.Rules;\n\n/**\n * User data mapping configuration\n * Maps walkerOS user properties to Data Manager user identifiers\n */\nexport const userDataMapping: DestinationDataManager.Config = {\n settings: {\n keyFilename: './service-account.json',\n destinations: [\n {\n operatingAccount: {\n accountId: '123-456-7890',\n accountType: 'GOOGLE_ADS',\n },\n productDestinationId: 'AW-CONVERSION-123',\n },\n ],\n },\n data: {\n map: {\n email: 'user.id',\n phone: 'data.phone',\n firstName: 'data.firstName',\n lastName: 'data.lastName',\n regionCode: 'data.country',\n postalCode: 'data.zip',\n },\n },\n mapping,\n};\n"],"mappings":";;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,SAAS,SAAS;AAEX,IAAM,oBAAoB,EAAE,KAAK;AAAA,EACtC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAEM,IAAM,oBAAoB,EAAE,KAAK;AAAA,EACtC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAEM,IAAM,sBAAsB,EAAE,KAAK;AAAA,EACxC;AAAA,EACA;AACF,CAAC;AAEM,IAAM,gBAAgB,EAAE,OAAO;AAAA,EACpC,YAAY,oBAAoB;AAAA,IAC9B;AAAA,EACF,EAAE,SAAS;AAAA,EACX,mBAAmB,oBAAoB;AAAA,IACrC;AAAA,EACF,EAAE,SAAS;AACb,CAAC;AAEM,IAAM,yBAAyB,EAAE,OAAO;AAAA,EAC7C,WAAW,EACR,OAAO,EACP,IAAI,CAAC,EACL,SAAS,kDAAkD;AAAA,EAC9D,aAAa,kBAAkB,SAAS,iBAAiB;AAC3D,CAAC;AAEM,IAAM,oBAAoB,EAAE,OAAO;AAAA,EACxC,kBAAkB,uBAAuB;AAAA,IACvC;AAAA,EACF;AAAA,EACA,sBAAsB,EACnB,OAAO,EACP,IAAI,CAAC,EACL;AAAA,IACC;AAAA,EACF;AACJ,CAAC;;;ACjDD,SAAS,KAAAA,UAAS;AAUlB,IAAM,oBAAoBC,GAAE,OAAO;AAAA,EACjC,cAAcA,GAAE,OAAO,EAAE,MAAM,EAAE,SAAS,uBAAuB;AAAA,EACjE,aAAaA,GACV,OAAO,EACP,IAAI,CAAC,EACL,SAAS,0CAA0C;AACxD,CAAC;AAEM,IAAM,iBAAiBA,GAAE,OAAO;AAAA,EACrC,aAAa,kBAAkB,SAAS,EAAE;AAAA,IACxC;AAAA,EACF;AAAA,EACA,aAAaA,GACV,OAAO,EACP,SAAS,EACT;AAAA,IACC;AAAA,EACF;AAAA,EACF,QAAQA,GACL,MAAMA,GAAE,OAAO,CAAC,EAChB,SAAS,EACT;AAAA,IACC;AAAA,EACF;AAAA,EACF,cAAcA,GACX,MAAM,iBAAiB,EACvB,IAAI,CAAC,EACL,IAAI,EAAE,EACN;AAAA,IACC;AAAA,EACF;AAAA,EACF,aAAa,kBAAkB,SAAS,EACrC,QAAQ,KAAK,EACb;AAAA,IACC;AAAA,EACF;AAAA,EACF,WAAWA,GACR,OAAO,EACP,IAAI,EACJ,IAAI,CAAC,EACL,IAAI,GAAI,EACR;AAAA,IACC;AAAA,EACF,EACC,SAAS;AAAA,EACZ,eAAeA,GACZ,OAAO,EACP,IAAI,EACJ,IAAI,CAAC,EACL;AAAA,IACC;AAAA,EACF,EACC,SAAS;AAAA,EACZ,cAAcA,GACX,QAAQ,EACR,SAAS,4DAA4D,EACrE,SAAS;AAAA,EACZ,KAAKA,GACF,OAAO,EACP,IAAI,EACJ;AAAA,IACC;AAAA,EACF,EACC,SAAS;AAAA,EACZ,SAAS,cAAc;AAAA,IACrB;AAAA,EACF,EAAE,SAAS;AAAA,EACX,eAAeA,GACZ,OAAO,EACP,SAAS,gDAAgD,EACzD,SAAS;AAAA,EACZ,UAAUA,GACP,KAAK,CAAC,SAAS,QAAQ,QAAQ,SAAS,MAAM,CAAC,EAC/C,SAAS,qDAAqD,EAC9D,SAAS;AAAA,EACZ,UAAUA,GACP,OAAOA,GAAE,OAAO,GAAGA,GAAE,QAAQ,CAAC,EAC9B;AAAA,IACC;AAAA,EACF,EACC,SAAS;AAAA,EACZ,QAAQA,GACL,IAAI,EACJ;AAAA,IACC;AAAA,EACF,EACC,SAAS;AAAA,EACZ,UAAUA,GACP,IAAI,EACJ;AAAA,IACC;AAAA,EACF,EACC,SAAS;AAAA,EACZ,mBAAmBA,GAChB,IAAI,EACJ;AAAA,IACC;AAAA,EACF,EACC,SAAS;AAAA,EACZ,mBAAmBA,GAChB,MAAM,CAACA,GAAE,OAAO,GAAGA,GAAE,QAAQ,CAAC,CAAC,EAC/B;AAAA,IACC;AAAA,EACF,EACC,SAAS;AAAA,EACZ,0BAA0BA,GACvB,MAAM,CAACA,GAAE,OAAO,GAAGA,GAAE,QAAQ,CAAC,CAAC,EAC/B;AAAA,IACC;AAAA,EACF,EACC,SAAS;AACd,CAAC;;;ACzHD,SAAS,KAAAC,UAAS;AAIX,IAAM,gBAAgBA,GAAE,OAAO,CAAC,CAAC;;;ACAxC,SAAS,mBAAmB;AAIrB,IAAM,WAAW,YAAY,cAAc;AAC3C,IAAM,UAAU,YAAY,aAAa;;;ACThD;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAOO,IAAM,YAA2C;AAAA,EACtD,UAAU;AAAA,IACR,aAAa;AAAA,MACX,cAAc,QAAQ,IAAI,uBAAuB;AAAA,MACjD,cAAc,QAAQ,IAAI,sBAAsB,IAAI,QAAQ,QAAQ,IAAI;AAAA,IAC1E;AAAA,IACA,cAAc;AAAA,MACZ;AAAA,QACE,kBAAkB;AAAA,UAChB,WAAW;AAAA,UACX,aAAa;AAAA,QACf;AAAA,QACA,sBAAsB;AAAA,MACxB;AAAA,IACF;AAAA,EACF;AACF;AAOO,IAAM,oBAAmD;AAAA,EAC9D,UAAU;AAAA;AAAA,IAER,cAAc;AAAA,MACZ;AAAA,QACE,kBAAkB;AAAA,UAChB,WAAW;AAAA,UACX,aAAa;AAAA,QACf;AAAA,QACA,sBAAsB;AAAA,MACxB;AAAA,IACF;AAAA,EACF;AACF;AAOO,IAAM,mBAAkD;AAAA,EAC7D,UAAU;AAAA,IACR,aAAa;AAAA,IACb,cAAc;AAAA,MACZ;AAAA,QACE,kBAAkB;AAAA,UAChB,WAAW;AAAA,UACX,aAAa;AAAA,QACf;AAAA,QACA,sBAAsB;AAAA,MACxB;AAAA,IACF;AAAA,EACF;AACF;AAYO,IAAM,mBAAkD;AAAA,EAC7D,UAAU;AAAA;AAAA,IAER,cAAc;AAAA,MACZ;AAAA,QACE,kBAAkB;AAAA,UAChB,WAAW;AAAA,UACX,aAAa;AAAA,QACf;AAAA,QACA,sBAAsB;AAAA,MACxB;AAAA,IACF;AAAA,EACF;AACF;AAMO,IAAM,eAA8C;AAAA,EACzD,UAAU;AAAA,IACR,aAAa;AAAA,MACX,cAAc,QAAQ,IAAI,uBAAuB;AAAA,MACjD,cAAc,QAAQ,IAAI,sBAAsB,IAAI,QAAQ,QAAQ,IAAI;AAAA,IAC1E;AAAA,IACA,QAAQ,CAAC,6CAA6C;AAAA,IACtD,cAAc;AAAA,MACZ;AAAA,QACE,kBAAkB;AAAA,UAChB,WAAW;AAAA,UACX,aAAa;AAAA,QACf;AAAA,QACA,sBAAsB;AAAA,MACxB;AAAA,IACF;AAAA,EACF;AACF;;;AC/GA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAKO,IAAM,UAAyC;AAAA,EACpD,UAAU;AAAA,IACR,aAAa;AAAA,MACX,cAAc;AAAA,MACd,aACE;AAAA,IACJ;AAAA,IACA,cAAc;AAAA,MACZ;AAAA,QACE,kBAAkB;AAAA,UAChB,WAAW;AAAA,UACX,aAAa;AAAA,QACf;AAAA,QACA,sBAAsB;AAAA,MACxB;AAAA,IACF;AAAA,EACF;AACF;AAKO,IAAM,WAA0C;AAAA,EACrD,UAAU;AAAA,IACR,aAAa;AAAA,MACX,cAAc;AAAA,MACd,aACE;AAAA,IACJ;AAAA,IACA,cAAc;AAAA,MACZ;AAAA,QACE,kBAAkB;AAAA,UAChB,WAAW;AAAA,UACX,aAAa;AAAA,QACf;AAAA,QACA,sBAAsB;AAAA,MACxB;AAAA,MACA;AAAA,QACE,kBAAkB;AAAA,UAChB,WAAW;AAAA,UACX,aAAa;AAAA,QACf;AAAA,QACA,sBAAsB;AAAA,MACxB;AAAA,IACF;AAAA,IACA,WAAW;AAAA,IACX,eAAe;AAAA,IACf,cAAc;AAAA,IACd,SAAS;AAAA,MACP,YAAY;AAAA,MACZ,mBAAmB;AAAA,IACrB;AAAA;AAAA,IAGA,UAAU;AAAA,MACR,OAAO;AAAA,MACP,OAAO;AAAA,MACP,WAAW;AAAA,MACX,UAAU;AAAA,IACZ;AAAA,IACA,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,mBAAmB;AAAA,EACrB;AACF;AAKO,IAAM,MAAqC;AAAA,EAChD,UAAU;AAAA,IACR,cAAc;AAAA,MACZ;AAAA,QACE,kBAAkB;AAAA,UAChB,WAAW;AAAA,UACX,aAAa;AAAA,QACf;AAAA,QACA,sBAAsB;AAAA,MACxB;AAAA,IACF;AAAA,EACF;AACF;AAKO,IAAM,QAAuC;AAAA,EAClD,UAAU;AAAA,IACR,aAAa;AAAA,IACb,cAAc;AAAA,MACZ;AAAA,QACE,kBAAkB;AAAA,UAChB,WAAW;AAAA,UACX,aAAa;AAAA,QACf;AAAA,QACA,sBAAsB;AAAA,MACxB;AAAA,IACF;AAAA,EACF;AACF;;;ACxGA;AAAA;AAAA;AAAA;AAAA;AAAA,iBAAAC;AAAA,EAAA;AAAA;AACA,SAAS,gBAAgB;AAKlB,IAAM,WAAwC;AAAA,EACnD,MAAM;AAAA,EACN,MAAM;AAAA,IACJ,KAAK;AAAA;AAAA,MAEH,eAAe;AAAA,MACf,iBAAiB;AAAA,MACjB,UAAU,EAAE,KAAK,iBAAiB,OAAO,MAAM;AAAA,MAC/C,WAAW,EAAE,OAAO,WAAW;AAAA;AAAA,MAG/B,QAAQ;AAAA,MACR,OAAO;AAAA;AAAA;AAAA,MAGP,OAAO;AAAA;AAAA,MACP,QAAQ;AAAA;AAAA,MACR,QAAQ;AAAA;AAAA;AAAA,MAGR,UAAU;AAAA,QACR,KAAK;AAAA,UACH,OAAO;AAAA,YACL,MAAM;AAAA,cACJ;AAAA,cACA;AAAA,gBACE,WAAW,CAAC,WACV,SAAS,MAAM,KAAK,OAAO,WAAW;AAAA,gBACxC,KAAK;AAAA,kBACH,mBAAmB;AAAA,kBACnB,OAAO;AAAA,kBACP,UAAU,EAAE,KAAK,iBAAiB,OAAO,EAAE;AAAA,gBAC7C;AAAA,cACF;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAKO,IAAM,OAAoC;AAAA,EAC/C,MAAM;AAAA,EACN,MAAM;AAAA,IACJ,KAAK;AAAA,MACH,WAAW,EAAE,OAAO,gBAAgB;AAAA,MACpC,iBAAiB,EAAE,OAAO,GAAG;AAAA,MAC7B,UAAU,EAAE,OAAO,MAAM;AAAA,IAC3B;AAAA,EACF;AACF;AAKO,IAAM,WAAwC;AAAA,EACnD,MAAM;AAAA,EACN,MAAM;AAAA,IACJ,KAAK;AAAA,MACH,WAAW,EAAE,OAAO,YAAY;AAAA,IAClC;AAAA,EACF;AACF;AAKO,IAAMA,WAAU;AAAA,EACrB,OAAO;AAAA,IACL,UAAU;AAAA,EACZ;AAAA,EACA,MAAM;AAAA,IACJ,QAAQ;AAAA,EACV;AAAA,EACA,MAAM;AAAA,IACJ,MAAM;AAAA,EACR;AACF;AAMO,IAAM,kBAAiD;AAAA,EAC5D,UAAU;AAAA,IACR,aAAa;AAAA,IACb,cAAc;AAAA,MACZ;AAAA,QACE,kBAAkB;AAAA,UAChB,WAAW;AAAA,UACX,aAAa;AAAA,QACf;AAAA,QACA,sBAAsB;AAAA,MACxB;AAAA,IACF;AAAA,EACF;AAAA,EACA,MAAM;AAAA,IACJ,KAAK;AAAA,MACH,OAAO;AAAA,MACP,OAAO;AAAA,MACP,WAAW;AAAA,MACX,UAAU;AAAA,MACV,YAAY;AAAA,MACZ,YAAY;AAAA,IACd;AAAA,EACF;AAAA,EACA,SAAAA;AACF;","names":["z","z","z","mapping"]}
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var e,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,i=Object.getOwnPropertyNames,a=Object.prototype.hasOwnProperty,
|
|
1
|
+
"use strict";var e,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,i=Object.getOwnPropertyNames,a=Object.prototype.hasOwnProperty,r={};function s(e={},t){const n=e.settings||{},{destinations:i,eventSource:a="WEB"}=n;i&&0!==i.length||t.throw("Config settings destinations missing or empty");const r={...n,destinations:i,eventSource:a};return{...e,settings:r}}((e,n)=>{for(var i in n)t(e,i,{get:n[i],enumerable:!0})})(r,{DestinationDataManager:()=>w,default:()=>b,destinationDataManager:()=>y}),module.exports=(e=r,((e,r,s,o)=>{if(r&&"object"==typeof r||"function"==typeof r)for(let c of i(r))a.call(e,c)||c===s||t(e,c,{get:()=>r[c],enumerable:!(o=n(r,c))||o.enumerable});return e})(t({},"__esModule",{value:!0}),e));var o=require("@walkeros/core"),c=require("@walkeros/core"),l=require("@walkeros/core"),g=require("@walkeros/server-core");async function d(e,t="given"){if(!(0,l.isString)(e)||!e)return"";let n=e.trim().toLowerCase();if("given"===t){const e=["mr.","mrs.","ms.","miss.","dr.","prof."];for(const t of e)if(n.startsWith(t)){n=n.substring(t.length).trim();break}}if("family"===t){const e=["jr.","sr.","iii","ii","iv","v"];for(const t of e){const e=` ${t}`;if(n.endsWith(e)){n=n.substring(0,n.length-e.length).trim();break}if(n.endsWith(t)){n=n.substring(0,n.length-t.length).trim();break}}}return(0,g.getHashServer)(n)}async function u(e){const t=[];if((0,c.isString)(e.email)&&e.email){const n=await async function(e){if(!(0,l.isString)(e)||!e)return"";let t=e.trim().toLowerCase();if(t.endsWith("@gmail.com")||t.endsWith("@googlemail.com")){const[e,n]=t.split("@");t=`${e.replace(/\./g,"")}@${n}`}return(0,g.getHashServer)(t)}(e.email);n&&t.push({emailAddress:n})}if((0,c.isString)(e.phone)&&e.phone){const n=await async function(e){if(!(0,l.isString)(e)||!e)return"";let t=e.trim();const n=t.startsWith("+");return t=t.replace(/\D/g,""),t=n||t.length>10?`+${t}`:`+1${t}`,(0,g.getHashServer)(t)}(e.phone);n&&t.push({phoneNumber:n})}if(e.firstName||e.lastName||e.regionCode||e.postalCode){const n={};(0,c.isString)(e.firstName)&&e.firstName&&(n.givenName=await d(e.firstName,"given")),(0,c.isString)(e.lastName)&&e.lastName&&(n.familyName=await d(e.lastName,"family")),(0,c.isString)(e.regionCode)&&e.regionCode&&(n.regionCode=e.regionCode.toUpperCase()),(0,c.isString)(e.postalCode)&&e.postalCode&&(n.postalCode=e.postalCode),Object.keys(n).length>0&&t.push({address:n})}if(0!==t.length)return{userIdentifiers:t.slice(0,10)}}async function f(e,t){const n={eventTimestamp:(i=e.timestamp,new Date(i).toISOString())};var i;const a=t||{};(0,c.isString)(a.transactionId)&&a.transactionId&&(n.transactionId=a.transactionId.substring(0,512)),(0,c.isString)(a.clientId)&&a.clientId&&(n.clientId=a.clientId.substring(0,255)),(0,c.isString)(a.userId)&&a.userId&&(n.userId=a.userId.substring(0,256));const r=await u(a);r&&(n.userData=r);const s=function(e){const t={};return(0,c.isString)(e.gclid)&&e.gclid&&(t.gclid=e.gclid),(0,c.isString)(e.gbraid)&&e.gbraid&&(t.gbraid=e.gbraid),(0,c.isString)(e.wbraid)&&e.wbraid&&(t.wbraid=e.wbraid),(0,c.isString)(e.sessionAttributes)&&e.sessionAttributes&&(t.sessionAttributes=e.sessionAttributes),Object.keys(t).length>0?t:void 0}(a);s&&(n.adIdentifiers=s),"number"==typeof a.conversionValue&&(n.conversionValue=a.conversionValue),(0,c.isString)(a.currency)&&a.currency&&(n.currency=a.currency.substring(0,3).toUpperCase()),a.cartData&&"object"==typeof a.cartData&&(n.cartData=a.cartData),(0,c.isString)(a.eventName)&&a.eventName&&(n.eventName=a.eventName.substring(0,40)),(0,c.isString)(a.eventSource)&&a.eventSource&&(n.eventSource=a.eventSource);const o={};if("boolean"==typeof a.adUserData&&(o.adUserData=a.adUserData?"CONSENT_GRANTED":"CONSENT_DENIED"),"boolean"==typeof a.adPersonalization&&(o.adPersonalization=a.adPersonalization?"CONSENT_GRANTED":"CONSENT_DENIED"),0===Object.keys(o).length){const t=function(e){if(!e)return;const t={};return(0,c.isDefined)(e.marketing)&&(t.adUserData=e.marketing?"CONSENT_GRANTED":"CONSENT_DENIED"),(0,c.isDefined)(e.personalization)&&(t.adPersonalization=e.personalization?"CONSENT_GRANTED":"CONSENT_DENIED"),Object.keys(t).length>0?t:void 0}(e.consent);t&&(n.consent=t)}else n.consent=o;return n}var p=require("google-auth-library"),h=["https://www.googleapis.com/auth/datamanager"],v=class extends Error{constructor(e,t){super(e),this.cause=t,this.name="DataManagerAuthError"}};var m=async function(e,{config:t,mapping:n,data:i,collector:a,env:r,logger:c}){const l=s(t,c),{destinations:g,eventSource:d,validateOnly:u=!1,url:p="https://datamanager.googleapis.com/v1",consent:h,testEventCode:m,userData:w,userId:y,clientId:b,sessionAttributes:N,consentAdUserData:S,consentAdPersonalization:D}=l.settings,E=w?await(0,o.getMappingValue)(e,{map:w}):{},C=y?await(0,o.getMappingValue)(e,y):void 0,O=b?await(0,o.getMappingValue)(e,b):void 0,I=N?await(0,o.getMappingValue)(e,N):void 0,A="boolean"==typeof S?S:"string"==typeof S&&e.consent?e.consent[S]:void 0,k="boolean"==typeof D?D:"string"==typeof D&&e.consent?e.consent[D]:void 0,T={};(0,o.isObject)(E)&&Object.assign(T,E),void 0!==C&&(T.userId=C),void 0!==O&&(T.clientId=O),void 0!==I&&(T.sessionAttributes=I),void 0!==A&&(T.adUserData=A),void 0!==k&&(T.adPersonalization=k);const P=l.data?await(0,o.getMappingValue)(e,l.data):{},j=(0,o.isObject)(i)?i:{},_={...T,...(0,o.isObject)(P)?P:{},...j},G=await f(e,_);G.eventSource||(G.eventSource=d),!G.consent&&h&&(G.consent=h),G.transactionId||c.throw("transactionId is required");g.some(e=>{var t;return"GOOGLE_ANALYTICS_PROPERTY"===(null==(t=e.operatingAccount)?void 0:t.accountType)})&&!G.eventName&&c.throw("eventName is required for GA4 destinations");const M={events:[G],destinations:g};h&&(M.consent=h),u&&(M.validateOnly=!0),m&&(M.testEventCode=m);const $=null==r?void 0:r.authClient;if(!$)return c.throw("Auth client not initialized. Ensure init() was called successfully.");let z;try{z=await async function(e){try{const t=await e.getAccessToken();if(!t.token)throw new v("Auth client returned empty token");return t.token}catch(e){throw new v("Failed to obtain access token",e instanceof Error?e:void 0)}}($)}catch(e){throw c.error("Authentication failed",{error:e}),e}const q=(null==r?void 0:r.fetch)||fetch,U=`${p}/events:ingest`;c.debug("Sending to Data Manager API",{endpoint:U,eventCount:M.events.length,destinations:g.length,validateOnly:u});const V=await q(U,{method:"POST",headers:{Authorization:`Bearer ${z}`,"Content-Type":"application/json"},body:JSON.stringify(M)});if(!V.ok){const e=await V.text();c.throw(`Data Manager API error (${V.status}): ${e}`)}const L=await V.json();c.debug("API response",{status:V.status,requestId:L.requestId}),L.validationErrors&&L.validationErrors.length>0&&c.throw(`Validation errors: ${JSON.stringify(L.validationErrors)}`)},w={},y={type:"datamanager",config:{},async init({config:e,env:t,logger:n}){const i=s(e,n);try{const e=await async function(e){const{credentials:t,keyFilename:n,scopes:i=h}=e;try{if(t){const e=new p.GoogleAuth({credentials:t,scopes:i});return await e.getClient()}if(n){const e=new p.GoogleAuth({keyFilename:n,scopes:i});return await e.getClient()}const e=new p.GoogleAuth({scopes:i});return await e.getClient()}catch(e){throw new v("Failed to create auth client. Check credentials configuration or ensure GOOGLE_APPLICATION_CREDENTIALS is set.",e instanceof Error?e:void 0)}}(i.settings);return n.debug("Auth client created"),{...i,env:{...t,authClient:e}}}catch(e){n.throw(`Data Manager authentication failed: ${e instanceof Error?e.message:"Unknown error"}`)}},push:async(e,{config:t,mapping:n,data:i,collector:a,env:r,logger:s})=>await m(e,{config:t,mapping:n,data:i,collector:a,env:r,logger:s})},b=y;//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/config.ts","../src/push.ts","../src/format.ts","../src/hash.ts","../src/auth.ts","../src/types/index.ts"],"sourcesContent":["import type { DestinationInterface } from './types';\nimport { getConfig } from './config';\nimport { push } from './push';\nimport { createAuthClient } from './auth';\n\nexport * as DestinationDataManager from './types';\n\nexport const destinationDataManager: DestinationInterface = {\n type: 'datamanager',\n\n config: {},\n\n async init({ config: partialConfig, env, logger }) {\n logger.debug('Data Manager init started');\n logger.info('Data Manager initializing...');\n\n // getConfig validates required fields and returns ValidatedConfig\n const config = getConfig(partialConfig, logger);\n\n logger.debug('Settings validated', {\n validateOnly: config.settings.validateOnly,\n destinationCount: config.settings.destinations.length,\n eventSource: config.settings.eventSource,\n });\n\n try {\n logger.debug('Creating auth client...');\n const authClient = await createAuthClient(config.settings);\n logger.debug('Auth client created successfully');\n\n return {\n ...config,\n env: {\n ...env,\n authClient,\n },\n };\n } catch (error) {\n logger.throw(\n `Data Manager authentication failed: ${error instanceof Error ? error.message : 'Unknown error'}`,\n );\n }\n },\n\n async push(event, { config, mapping, data, collector, env, logger }) {\n return await push(event, { config, mapping, data, collector, env, logger });\n },\n};\n\nexport default destinationDataManager;\n","import type {\n ValidatedConfig,\n Settings,\n PartialConfig,\n EventSource,\n} from './types';\nimport type { Logger } from '@walkeros/core';\n\nexport function getConfig(\n partialConfig: PartialConfig = {},\n logger: Logger.Instance,\n): ValidatedConfig {\n const settings = (partialConfig.settings || {}) as Partial<Settings>;\n const { destinations, eventSource = 'WEB' } = settings;\n\n if (!destinations || destinations.length === 0)\n logger.throw('Config settings destinations missing or empty');\n\n const settingsConfig: Settings & { eventSource: EventSource } = {\n ...settings,\n destinations,\n eventSource,\n };\n\n return { ...partialConfig, settings: settingsConfig };\n}\n","import type { PushFn } from './types';\nimport type { IngestEventsRequest, IngestEventsResponse } from './types';\nimport { getMappingValue, isObject } from '@walkeros/core';\nimport { formatEvent, formatConsent } from './format';\nimport { getAccessToken } from './auth';\nimport { getConfig } from './config';\n\nexport const push: PushFn = async function (\n event,\n { config, mapping, data, collector, env, logger },\n) {\n // Validate config and get typed settings\n const validatedConfig = getConfig(config, logger);\n const {\n destinations,\n eventSource,\n validateOnly = false,\n url = 'https://datamanager.googleapis.com/v1',\n consent: requestConsent,\n testEventCode,\n userData,\n userId,\n clientId,\n sessionAttributes,\n consentAdUserData,\n consentAdPersonalization,\n } = validatedConfig.settings;\n\n // Extract Settings guided helpers\n const userDataMapped = userData\n ? await getMappingValue(event, { map: userData })\n : {};\n const userIdMapped = userId\n ? await getMappingValue(event, userId)\n : undefined;\n const clientIdMapped = clientId\n ? await getMappingValue(event, clientId)\n : undefined;\n const sessionAttributesMapped = sessionAttributes\n ? await getMappingValue(event, sessionAttributes)\n : undefined;\n\n // Extract consent from Settings\n const consentAdUserDataValue =\n typeof consentAdUserData === 'boolean'\n ? consentAdUserData\n : typeof consentAdUserData === 'string' && event.consent\n ? event.consent[consentAdUserData]\n : undefined;\n\n const consentAdPersonalizationValue =\n typeof consentAdPersonalization === 'boolean'\n ? consentAdPersonalization\n : typeof consentAdPersonalization === 'string' && event.consent\n ? event.consent[consentAdPersonalization]\n : undefined;\n\n // Build Settings helpers object\n const settingsHelpers: Record<string, unknown> = {};\n if (isObject(userDataMapped)) {\n Object.assign(settingsHelpers, userDataMapped);\n }\n if (userIdMapped !== undefined) settingsHelpers.userId = userIdMapped;\n if (clientIdMapped !== undefined) settingsHelpers.clientId = clientIdMapped;\n if (sessionAttributesMapped !== undefined)\n settingsHelpers.sessionAttributes = sessionAttributesMapped;\n if (consentAdUserDataValue !== undefined)\n settingsHelpers.adUserData = consentAdUserDataValue;\n if (consentAdPersonalizationValue !== undefined)\n settingsHelpers.adPersonalization = consentAdPersonalizationValue;\n\n // Get mapped data from destination config and event mapping\n const configData = validatedConfig.data\n ? await getMappingValue(event, validatedConfig.data)\n : {};\n const eventData = isObject(data) ? data : {};\n\n // Merge: Settings helpers < config.data < event mapping data\n const finalData = {\n ...settingsHelpers,\n ...(isObject(configData) ? configData : {}),\n ...eventData,\n };\n\n // Format event for Data Manager API\n const dataManagerEvent = await formatEvent(event, finalData);\n\n logger.debug('Processing event', {\n name: event.name,\n id: event.id,\n timestamp: event.timestamp,\n });\n\n // Apply event source from settings (required)\n if (!dataManagerEvent.eventSource) {\n dataManagerEvent.eventSource = eventSource;\n }\n\n // Apply request-level consent if event doesn't have consent\n if (!dataManagerEvent.consent && requestConsent) {\n dataManagerEvent.consent = requestConsent;\n }\n\n // Validate required fields before API call\n if (!dataManagerEvent.transactionId) {\n logger.throw('transactionId is required');\n }\n\n // Check if any destination is GA4 (requires eventName)\n const hasGA4Destination = destinations.some(\n (d) => d.operatingAccount?.accountType === 'GOOGLE_ANALYTICS_PROPERTY',\n );\n\n if (hasGA4Destination && !dataManagerEvent.eventName) {\n logger.throw('eventName is required for GA4 destinations');\n }\n\n // Build API request\n const requestBody: IngestEventsRequest = {\n events: [dataManagerEvent],\n destinations,\n };\n\n // Add optional parameters\n if (requestConsent) {\n requestBody.consent = requestConsent;\n }\n\n if (validateOnly) {\n requestBody.validateOnly = true;\n }\n\n if (testEventCode) {\n requestBody.testEventCode = testEventCode;\n }\n\n const authClient = env?.authClient;\n if (!authClient) {\n return logger.throw(\n 'Auth client not initialized. Ensure init() was called successfully.',\n );\n }\n\n let accessToken: string;\n try {\n accessToken = await getAccessToken(authClient);\n } catch (error) {\n logger.error('Authentication failed', { error });\n throw error;\n }\n\n const fetchFn = env?.fetch || fetch;\n const endpoint = `${url}/events:ingest`;\n\n logger.debug('Sending to Data Manager API', {\n endpoint,\n eventCount: requestBody.events.length,\n destinations: destinations.length,\n validateOnly,\n });\n\n const response = await fetchFn(endpoint, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${accessToken}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(requestBody),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n logger.throw(`Data Manager API error (${response.status}): ${errorText}`);\n }\n\n const result: IngestEventsResponse = await response.json();\n\n logger.debug('API response', {\n status: response.status,\n requestId: result.requestId,\n });\n\n // If validation errors exist, throw them\n if (result.validationErrors && result.validationErrors.length > 0) {\n logger.throw(\n `Validation errors: ${JSON.stringify(result.validationErrors)}`,\n );\n }\n\n logger.info('Event processed successfully', {\n requestId: result.requestId,\n });\n};\n","import type { WalkerOS } from '@walkeros/core';\nimport { isString, isDefined } from '@walkeros/core';\nimport type {\n Event,\n UserData,\n UserIdentifier,\n AdIdentifiers,\n Consent,\n ConsentStatus,\n} from './types';\nimport { hashEmail, hashPhone, hashName } from './hash';\n\n/**\n * Format walkerOS event timestamp to RFC 3339 format\n * https://developers.google.com/data-manager/api/reference/rest/v1/Event\n *\n * walkerOS timestamp is in milliseconds, RFC 3339 format: \"2024-01-15T10:30:00Z\"\n */\nexport function formatTimestamp(timestamp: number): string {\n return new Date(timestamp).toISOString();\n}\n\n/**\n * Format user identifiers from mapped data\n * https://developers.google.com/data-manager/api/reference/rest/v1/UserData\n *\n * User data must be explicitly mapped in the mapping configuration.\n * Max 10 identifiers per event\n */\nexport async function formatUserData(\n data: Record<string, unknown>,\n): Promise<UserData | undefined> {\n const identifiers: UserIdentifier[] = [];\n\n // Extract from mapped data only\n // Email\n if (isString(data.email) && data.email) {\n const hashedEmail = await hashEmail(data.email);\n if (hashedEmail) {\n identifiers.push({ emailAddress: hashedEmail });\n }\n }\n\n // Phone\n if (isString(data.phone) && data.phone) {\n const hashedPhone = await hashPhone(data.phone);\n if (hashedPhone) {\n identifiers.push({ phoneNumber: hashedPhone });\n }\n }\n\n // Address from mapped properties\n const hasAddress =\n data.firstName || data.lastName || data.regionCode || data.postalCode;\n\n if (hasAddress) {\n const address: Record<string, string> = {};\n\n if (isString(data.firstName) && data.firstName) {\n address.givenName = await hashName(data.firstName, 'given');\n }\n\n if (isString(data.lastName) && data.lastName) {\n address.familyName = await hashName(data.lastName, 'family');\n }\n\n // Region code is NOT hashed\n if (isString(data.regionCode) && data.regionCode) {\n address.regionCode = data.regionCode.toUpperCase();\n }\n\n // Postal code is NOT hashed\n if (isString(data.postalCode) && data.postalCode) {\n address.postalCode = data.postalCode;\n }\n\n if (Object.keys(address).length > 0) {\n identifiers.push({ address });\n }\n }\n\n // Limit to 10 identifiers\n if (identifiers.length === 0) return undefined;\n\n return {\n userIdentifiers: identifiers.slice(0, 10),\n };\n}\n\n/**\n * Extract and format attribution identifiers from mapped data\n * https://developers.google.com/data-manager/api/reference/rest/v1/AdIdentifiers\n *\n * Attribution identifiers should be mapped explicitly in the mapping configuration.\n * Example: { gclid: 'context.gclid', gbraid: 'context.gbraid' }\n */\nexport function formatAdIdentifiers(\n data: Record<string, unknown>,\n): AdIdentifiers | undefined {\n const identifiers: AdIdentifiers = {};\n\n // Extract from mapped data (already processed by mapping system)\n if (isString(data.gclid) && data.gclid) {\n identifiers.gclid = data.gclid;\n }\n if (isString(data.gbraid) && data.gbraid) {\n identifiers.gbraid = data.gbraid;\n }\n if (isString(data.wbraid) && data.wbraid) {\n identifiers.wbraid = data.wbraid;\n }\n if (isString(data.sessionAttributes) && data.sessionAttributes) {\n identifiers.sessionAttributes = data.sessionAttributes;\n }\n\n return Object.keys(identifiers).length > 0 ? identifiers : undefined;\n}\n\n/**\n * Map walkerOS consent to Data Manager consent format\n * https://developers.google.com/data-manager/api/devguides/concepts/dma\n *\n * walkerOS: { marketing: true, personalization: false }\n * Data Manager: { adUserData: 'CONSENT_GRANTED', adPersonalization: 'CONSENT_DENIED' }\n */\nexport function formatConsent(\n walkerOSConsent: WalkerOS.Consent | undefined,\n): Consent | undefined {\n if (!walkerOSConsent) return undefined;\n\n const consent: Consent = {};\n\n // Map marketing consent to adUserData\n if (isDefined(walkerOSConsent.marketing)) {\n consent.adUserData = walkerOSConsent.marketing\n ? 'CONSENT_GRANTED'\n : 'CONSENT_DENIED';\n }\n\n // Map personalization consent to adPersonalization\n if (isDefined(walkerOSConsent.personalization)) {\n consent.adPersonalization = walkerOSConsent.personalization\n ? 'CONSENT_GRANTED'\n : 'CONSENT_DENIED';\n }\n\n return Object.keys(consent).length > 0 ? consent : undefined;\n}\n\n/**\n * Format complete event for Data Manager API\n * https://developers.google.com/data-manager/api/reference/rest/v1/Event\n */\nexport async function formatEvent(\n event: WalkerOS.Event,\n mappedData?: Record<string, unknown>,\n): Promise<Event> {\n const dataManagerEvent: Event = {\n eventTimestamp: formatTimestamp(event.timestamp),\n };\n\n // Use only mapped data (no fallback to event.data)\n const data = mappedData || {};\n\n // Transaction ID for deduplication\n if (isString(data.transactionId) && data.transactionId) {\n dataManagerEvent.transactionId = data.transactionId.substring(0, 512);\n }\n\n // Client ID (GA)\n if (isString(data.clientId) && data.clientId) {\n dataManagerEvent.clientId = data.clientId.substring(0, 255);\n }\n\n // User ID\n if (isString(data.userId) && data.userId) {\n dataManagerEvent.userId = data.userId.substring(0, 256);\n }\n\n // User data\n const userData = await formatUserData(data);\n if (userData) {\n dataManagerEvent.userData = userData;\n }\n\n // Attribution identifiers\n const adIdentifiers = formatAdIdentifiers(data);\n if (adIdentifiers) {\n dataManagerEvent.adIdentifiers = adIdentifiers;\n }\n\n // Conversion value\n if (typeof data.conversionValue === 'number') {\n dataManagerEvent.conversionValue = data.conversionValue;\n }\n\n // Currency\n if (isString(data.currency) && data.currency) {\n dataManagerEvent.currency = data.currency.substring(0, 3).toUpperCase();\n }\n\n // Cart data\n if (data.cartData && typeof data.cartData === 'object') {\n dataManagerEvent.cartData = data.cartData as Event['cartData'];\n }\n\n // Event name (for GA4)\n if (isString(data.eventName) && data.eventName) {\n dataManagerEvent.eventName = data.eventName.substring(0, 40);\n }\n\n // Event source\n if (isString(data.eventSource) && data.eventSource) {\n dataManagerEvent.eventSource = data.eventSource as Event['eventSource'];\n }\n\n // Consent - check mapped data first, then fallback to event.consent\n const mappedConsent: Consent = {};\n\n // Check for mapped consent values (from Settings or event mapping)\n if (typeof data.adUserData === 'boolean') {\n mappedConsent.adUserData = data.adUserData\n ? 'CONSENT_GRANTED'\n : 'CONSENT_DENIED';\n }\n if (typeof data.adPersonalization === 'boolean') {\n mappedConsent.adPersonalization = data.adPersonalization\n ? 'CONSENT_GRANTED'\n : 'CONSENT_DENIED';\n }\n\n // If no mapped consent, fall back to event.consent\n if (Object.keys(mappedConsent).length === 0) {\n const eventConsent = formatConsent(event.consent);\n if (eventConsent) {\n dataManagerEvent.consent = eventConsent;\n }\n } else {\n dataManagerEvent.consent = mappedConsent;\n }\n\n return dataManagerEvent;\n}\n","import { isString } from '@walkeros/core';\nimport { getHashServer } from '@walkeros/server-core';\n\n/**\n * Normalize email address according to Google Data Manager requirements\n * https://developers.google.com/data-manager/api/devguides/concepts/formatting#email\n *\n * 1. Trim whitespace\n * 2. Convert to lowercase\n * 3. Remove dots (.) for gmail.com and googlemail.com\n * 4. SHA-256 hash\n */\nexport async function hashEmail(email: string): Promise<string> {\n if (!isString(email) || !email) return '';\n\n // Trim and lowercase\n let normalized = email.trim().toLowerCase();\n\n // Remove dots for Gmail addresses\n if (\n normalized.endsWith('@gmail.com') ||\n normalized.endsWith('@googlemail.com')\n ) {\n const [localPart, domain] = normalized.split('@');\n normalized = `${localPart.replace(/\\./g, '')}@${domain}`;\n }\n\n return getHashServer(normalized);\n}\n\n/**\n * Normalize phone number to E.164 format and hash\n * https://developers.google.com/data-manager/api/devguides/concepts/formatting#phone\n *\n * E.164 format: +[country code][number] (max 15 digits after +)\n * Example: +18005550100\n *\n * 1. Remove all non-digit characters except leading +\n * 2. Ensure it starts with +\n * 3. SHA-256 hash\n */\nexport async function hashPhone(phone: string): Promise<string> {\n if (!isString(phone) || !phone) return '';\n\n // Remove all non-digit characters except + at the start\n let normalized = phone.trim();\n\n // Extract country code if present\n const hasPlus = normalized.startsWith('+');\n\n // Remove all non-digits\n normalized = normalized.replace(/\\D/g, '');\n\n // Add + prefix if it was there or if number is long enough\n if (hasPlus || normalized.length > 10) {\n normalized = `+${normalized}`;\n } else {\n // Assume US number if no country code (default behavior)\n normalized = `+1${normalized}`;\n }\n\n return getHashServer(normalized);\n}\n\n/**\n * Normalize and hash a name (first or last name)\n * https://developers.google.com/data-manager/api/devguides/concepts/formatting#name\n *\n * 1. Trim whitespace\n * 2. Convert to lowercase\n * 3. Remove common prefixes (Mr., Mrs., Dr.) for first names\n * 4. Remove common suffixes (Jr., Sr., III) for last names\n * 5. SHA-256 hash\n */\nexport async function hashName(\n name: string,\n type: 'given' | 'family' = 'given',\n): Promise<string> {\n if (!isString(name) || !name) return '';\n\n // Trim and lowercase\n let normalized = name.trim().toLowerCase();\n\n // Remove prefixes for given names\n if (type === 'given') {\n const prefixes = ['mr.', 'mrs.', 'ms.', 'miss.', 'dr.', 'prof.'];\n for (const prefix of prefixes) {\n if (normalized.startsWith(prefix)) {\n normalized = normalized.substring(prefix.length).trim();\n break;\n }\n }\n }\n\n // Remove suffixes for family names (check with and without space)\n // Sort by length (longest first) to match \"iii\" before \"ii\"\n if (type === 'family') {\n const suffixes = ['jr.', 'sr.', 'iii', 'ii', 'iv', 'v'];\n for (const suffix of suffixes) {\n // Check for suffix with space before it (e.g., \" jr.\")\n const suffixWithSpace = ` ${suffix}`;\n if (normalized.endsWith(suffixWithSpace)) {\n normalized = normalized\n .substring(0, normalized.length - suffixWithSpace.length)\n .trim();\n break;\n }\n // Check for suffix without space\n if (normalized.endsWith(suffix)) {\n normalized = normalized\n .substring(0, normalized.length - suffix.length)\n .trim();\n break;\n }\n }\n }\n\n return getHashServer(normalized);\n}\n\n/**\n * Hash multiple email addresses\n */\nexport async function hashEmails(emails: string[]): Promise<string[]> {\n return Promise.all(emails.map((email) => hashEmail(email)));\n}\n\n/**\n * Hash multiple phone numbers\n */\nexport async function hashPhones(phones: string[]): Promise<string[]> {\n return Promise.all(phones.map((phone) => hashPhone(phone)));\n}\n","import { GoogleAuth, type OAuth2Client } from 'google-auth-library';\nimport type { Settings } from './types';\n\nconst DEFAULT_SCOPES = ['https://www.googleapis.com/auth/datamanager'];\n\n/**\n * Authentication error with cause tracking\n */\nexport class AuthError extends Error {\n constructor(\n message: string,\n public cause?: Error,\n ) {\n super(message);\n this.name = 'DataManagerAuthError';\n }\n}\n\n/**\n * Creates Google Auth client based on settings\n *\n * Authentication priority:\n * 1. credentials (inline service account) - if provided\n * 2. keyFilename (service account file) - if provided\n * 3. Application Default Credentials (ADC) - automatic fallback\n * - GOOGLE_APPLICATION_CREDENTIALS env var\n * - GCP metadata server (Cloud Functions, Cloud Run, GCE)\n *\n * @param settings - Configuration with auth options\n * @returns OAuth2Client for token retrieval\n * @throws AuthError if authentication fails\n */\nexport async function createAuthClient(\n settings: Settings,\n): Promise<OAuth2Client> {\n const { credentials, keyFilename, scopes = DEFAULT_SCOPES } = settings;\n\n try {\n if (credentials) {\n const auth = new GoogleAuth({\n credentials,\n scopes,\n });\n return (await auth.getClient()) as OAuth2Client;\n }\n\n if (keyFilename) {\n const auth = new GoogleAuth({\n keyFilename,\n scopes,\n });\n return (await auth.getClient()) as OAuth2Client;\n }\n\n const auth = new GoogleAuth({ scopes });\n return (await auth.getClient()) as OAuth2Client;\n } catch (error) {\n throw new AuthError(\n 'Failed to create auth client. Check credentials configuration or ensure GOOGLE_APPLICATION_CREDENTIALS is set.',\n error instanceof Error ? error : undefined,\n );\n }\n}\n\n/**\n * Gets access token from auth client\n * Automatically returns cached token if valid or refreshes if expired\n *\n * @param authClient - OAuth2 client from createAuthClient()\n * @returns Fresh access token\n * @throws AuthError if token retrieval fails\n */\nexport async function getAccessToken(\n authClient: OAuth2Client,\n): Promise<string> {\n try {\n const tokenResponse = await authClient.getAccessToken();\n\n if (!tokenResponse.token) {\n throw new AuthError('Auth client returned empty token');\n }\n\n return tokenResponse.token;\n } catch (error) {\n throw new AuthError(\n 'Failed to obtain access token',\n error instanceof Error ? error : undefined,\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';\nimport type { OAuth2Client } from 'google-auth-library';\n\nexport interface Settings {\n /**\n * Service account credentials (client_email + private_key)\n * Recommended for serverless environments (AWS Lambda, Docker, etc.)\n */\n credentials?: {\n client_email: string;\n private_key: string;\n };\n\n /**\n * Path to service account JSON file\n * For local development or environments with filesystem access\n */\n keyFilename?: string;\n\n /**\n * OAuth scopes for Data Manager API\n * @default ['https://www.googleapis.com/auth/datamanager']\n */\n scopes?: string[];\n\n /** Array of destination accounts and conversion actions/user lists */\n destinations: Destination[];\n\n /** Event source for all events. Defaults to WEB if not specified */\n eventSource?: EventSource;\n\n /** Maximum number of events to batch before sending (max 2000) */\n batchSize?: number;\n\n /** Time in milliseconds to wait before auto-flushing batch */\n batchInterval?: number;\n\n /** If true, validate request without ingestion (testing mode) */\n validateOnly?: boolean;\n\n /** Override API endpoint (for testing) */\n url?: string;\n\n /** Request-level consent for all events */\n consent?: Consent;\n\n /** Test event code for debugging (optional) */\n testEventCode?: string;\n\n /** Guided helpers: User data mapping (applies to all events) */\n userData?: WalkerOSMapping.Map;\n\n /** Guided helper: First-party user ID */\n userId?: WalkerOSMapping.Value;\n\n /** Guided helper: GA4 client ID */\n clientId?: WalkerOSMapping.Value;\n\n /** Guided helper: Privacy-safe attribution (Google's sessionAttributes) */\n sessionAttributes?: WalkerOSMapping.Value;\n\n /** Consent mapping: Map consent field to adUserData (string = field name, boolean = static value) */\n consentAdUserData?: string | boolean;\n\n /** Consent mapping: Map consent field to adPersonalization (string = field name, boolean = static value) */\n consentAdPersonalization?: string | boolean;\n}\n\nexport interface Mapping {\n // Attribution identifiers (optional, for explicit mapping)\n gclid?: WalkerOSMapping.Value;\n gbraid?: WalkerOSMapping.Value;\n wbraid?: WalkerOSMapping.Value;\n sessionAttributes?: WalkerOSMapping.Value;\n}\n\nexport interface Env extends DestinationServer.Env {\n fetch?: typeof fetch;\n authClient?: OAuth2Client | null;\n}\n\nexport type InitSettings = Partial<Settings>;\n\nexport type Types = CoreDestination.Types<Settings, Mapping, Env, InitSettings>;\n\nexport interface DestinationInterface\n extends DestinationServer.Destination<Types> {\n init: DestinationServer.InitFn<Types>;\n}\n\nexport type Config = {\n settings: Settings;\n} & DestinationServer.Config<Types>;\n\n/**\n * Config after validation - settings is guaranteed to exist with required fields\n * Use this type after calling getConfig() to get proper type narrowing\n * After validation, eventSource is always set (defaults to 'WEB')\n */\nexport type ValidatedConfig = Omit<Config, 'settings'> & {\n settings: Settings & { eventSource: EventSource };\n};\n\nexport type InitFn = DestinationServer.InitFn<Types>;\nexport type PushFn = DestinationServer.PushFn<Types>;\n\nexport type PartialConfig = DestinationServer.PartialConfig<Types>;\n\nexport type PushEvents = DestinationServer.PushEvents<Mapping>;\n\nexport type Rule = WalkerOSMapping.Rule<Mapping>;\nexport type Rules = WalkerOSMapping.Rules<Rule>;\n\n// Google Data Manager API Types\n// https://developers.google.com/data-manager/api/reference\n\n/**\n * Destination account and product identifier\n * https://developers.google.com/data-manager/api/reference/rest/v1/Destination\n */\nexport interface Destination {\n /** Reference identifier for this destination */\n reference?: string;\n\n /** Login account (account initiating the request) */\n loginAccount?: ProductAccount;\n\n /** Linked account (child account linked to login account) */\n linkedAccount?: ProductAccount;\n\n /** Operating account (account where data is sent) */\n operatingAccount?: ProductAccount;\n\n /** Product-specific destination ID (conversion action or user list) */\n productDestinationId?: string;\n}\n\n/**\n * Product account information\n */\nexport interface ProductAccount {\n /** Account ID (e.g., \"123-456-7890\" for Google Ads) */\n accountId: string;\n\n /** Type of account */\n accountType: AccountType;\n}\n\nexport type AccountType =\n | 'ACCOUNT_TYPE_UNSPECIFIED'\n | 'GOOGLE_ADS'\n | 'DISPLAY_VIDEO_ADVERTISER'\n | 'DISPLAY_VIDEO_PARTNER'\n | 'GOOGLE_ANALYTICS_PROPERTY'\n | 'DATA_PARTNER';\n\nexport type EventSource = 'WEB' | 'APP' | 'IN_STORE' | 'PHONE' | 'OTHER';\n\n/**\n * Consent for Digital Markets Act (DMA) compliance\n * https://developers.google.com/data-manager/api/devguides/concepts/dma\n */\nexport interface Consent {\n /** Consent for data collection and use */\n adUserData?: ConsentStatus;\n\n /** Consent for ad personalization */\n adPersonalization?: ConsentStatus;\n}\n\nexport type ConsentStatus = 'CONSENT_GRANTED' | 'CONSENT_DENIED';\n\n/**\n * Request body for events.ingest API\n * https://developers.google.com/data-manager/api/reference/rest/v1/events/ingest\n */\nexport interface IngestEventsRequest {\n /** Array of destinations for these events (max 10) */\n destinations: Destination[];\n\n /** Array of events to ingest (max 2000) */\n events: Event[];\n\n /** Request-level consent (overridden by event-level) */\n consent?: Consent;\n\n /** If true, validate without ingestion */\n validateOnly?: boolean;\n\n /** Test event code for debugging */\n testEventCode?: string;\n}\n\n/**\n * Single event for ingestion\n * https://developers.google.com/data-manager/api/reference/rest/v1/Event\n */\nexport interface Event {\n /** Destination references for routing */\n destinationReferences?: string[];\n\n /** Transaction ID for deduplication (max 512 chars) */\n transactionId?: string;\n\n /** Event timestamp in RFC 3339 format */\n eventTimestamp?: string;\n\n /** Last updated timestamp in RFC 3339 format */\n lastUpdatedTimestamp?: string;\n\n /** User data with identifiers (max 10 identifiers) */\n userData?: UserData;\n\n /** Event-level consent (overrides request-level) */\n consent?: Consent;\n\n /** Attribution identifiers */\n adIdentifiers?: AdIdentifiers;\n\n /** Currency code (ISO 4217, 3 chars) */\n currency?: string;\n\n /** Conversion value */\n conversionValue?: number;\n\n /** Source of the event */\n eventSource?: EventSource;\n\n /** Device information for the event */\n eventDeviceInfo?: DeviceInfo;\n\n /** Shopping cart data */\n cartData?: CartData;\n\n /** Custom variables for the event */\n customVariables?: CustomVariable[];\n\n /** Experimental fields (subject to change) */\n experimentalFields?: ExperimentalField[];\n\n /** User properties */\n userProperties?: UserProperties;\n\n /** Event name for GA4 (max 40 chars, required for GA4) */\n eventName?: string;\n\n /** Google Analytics client ID (max 255 chars) */\n clientId?: string;\n\n /** First-party user ID (max 256 chars) */\n userId?: string;\n\n /** Additional event parameters */\n additionalEventParameters?: EventParameter[];\n}\n\n/**\n * Device information\n */\nexport interface DeviceInfo {\n /** User agent string */\n userAgent?: string;\n}\n\n/**\n * Custom variable\n */\nexport interface CustomVariable {\n /** Variable name */\n name?: string;\n\n /** Variable value */\n value?: string;\n}\n\n/**\n * Experimental field\n */\nexport interface ExperimentalField {\n /** Field name */\n name?: string;\n\n /** Field value */\n value?: string;\n}\n\n/**\n * User properties\n */\nexport interface UserProperties {\n /** Property values */\n [key: string]: string | number | boolean | undefined;\n}\n\n/**\n * Event parameter\n */\nexport interface EventParameter {\n /** Parameter name */\n name?: string;\n\n /** Parameter value */\n value?: string | number;\n}\n\n/**\n * User data with identifiers\n * https://developers.google.com/data-manager/api/reference/rest/v1/UserData\n */\nexport interface UserData {\n /** Array of user identifiers (max 10) */\n userIdentifiers: UserIdentifier[];\n}\n\n/**\n * User identifier (email, phone, or address)\n */\nexport type UserIdentifier =\n | { emailAddress: string }\n | { phoneNumber: string }\n | { address: Address };\n\n/**\n * Address for user identification\n * https://developers.google.com/data-manager/api/reference/rest/v1/Address\n */\nexport interface Address {\n /** Given name (first name) - SHA-256 hashed */\n givenName?: string;\n\n /** Family name (last name) - SHA-256 hashed */\n familyName?: string;\n\n /** ISO-3166-1 alpha-2 country code - NOT hashed (e.g., \"US\", \"GB\") */\n regionCode?: string;\n\n /** Postal code - NOT hashed */\n postalCode?: string;\n}\n\n/**\n * Attribution identifiers\n * https://developers.google.com/data-manager/api/reference/rest/v1/AdIdentifiers\n */\nexport interface AdIdentifiers {\n /** Session attributes (privacy-safe attribution) */\n sessionAttributes?: string;\n\n /** Google Click ID (primary attribution) */\n gclid?: string;\n\n /** iOS attribution identifier (post-ATT) */\n gbraid?: string;\n\n /** Web-to-app attribution identifier */\n wbraid?: string;\n\n /** Device information for landing page */\n landingPageDeviceInfo?: DeviceInfo;\n}\n\n/**\n * Shopping cart data\n * https://developers.google.com/data-manager/api/reference/rest/v1/CartData\n */\nexport interface CartData {\n /** Array of cart items (max 200) */\n items: CartItem[];\n}\n\n/**\n * Single cart item\n * https://developers.google.com/data-manager/api/reference/rest/v1/CartItem\n */\nexport interface CartItem {\n /** Merchant product ID (max 127 chars) */\n merchantProductId?: string;\n\n /** Item price */\n price?: number;\n\n /** Item quantity */\n quantity?: number;\n}\n\n/**\n * Response from events.ingest API\n * https://developers.google.com/data-manager/api/reference/rest/v1/IngestEventsResponse\n */\nexport interface IngestEventsResponse {\n /** Unique request ID for status checking */\n requestId: string;\n\n /** Validation errors (only if validateOnly=true) */\n validationErrors?: ValidationError[];\n}\n\n/**\n * Validation error\n */\nexport interface ValidationError {\n /** Error code */\n code: string;\n\n /** Human-readable error message */\n message: string;\n\n /** Field path that caused the error */\n fieldPath?: string;\n}\n\n/**\n * Request status response\n * https://developers.google.com/data-manager/api/reference/rest/v1/requestStatus/retrieve\n */\nexport interface RequestStatusResponse {\n /** Unique request ID */\n requestId: string;\n\n /** Processing state */\n state: RequestState;\n\n /** Number of events successfully ingested */\n eventsIngested?: number;\n\n /** Number of events that failed */\n eventsFailed?: number;\n\n /** Array of errors (if any) */\n errors?: RequestError[];\n}\n\nexport type RequestState =\n | 'STATE_UNSPECIFIED'\n | 'PENDING'\n | 'PROCESSING'\n | 'SUCCEEDED'\n | 'FAILED'\n | 'PARTIALLY_SUCCEEDED';\n\n/**\n * Request error\n */\nexport interface RequestError {\n /** Error code */\n code: string;\n\n /** Human-readable error message */\n message: string;\n\n /** Number of events affected by this error */\n eventCount?: number;\n}\n"],"mappings":"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","names":["import_core","import_core","auth"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/config.ts","../src/push.ts","../src/format.ts","../src/hash.ts","../src/auth.ts","../src/types/index.ts"],"sourcesContent":["import type { DestinationInterface } from './types';\nimport { getConfig } from './config';\nimport { push } from './push';\nimport { createAuthClient } from './auth';\n\nexport * as DestinationDataManager from './types';\n\nexport const destinationDataManager: DestinationInterface = {\n type: 'datamanager',\n\n config: {},\n\n async init({ config: partialConfig, env, logger }) {\n // getConfig validates required fields and returns ValidatedConfig\n const config = getConfig(partialConfig, logger);\n\n try {\n const authClient = await createAuthClient(config.settings);\n logger.debug('Auth client created');\n\n return {\n ...config,\n env: {\n ...env,\n authClient,\n },\n };\n } catch (error) {\n logger.throw(\n `Data Manager authentication failed: ${error instanceof Error ? error.message : 'Unknown error'}`,\n );\n }\n },\n\n async push(event, { config, mapping, data, collector, env, logger }) {\n return await push(event, { config, mapping, data, collector, env, logger });\n },\n};\n\nexport default destinationDataManager;\n","import type {\n ValidatedConfig,\n Settings,\n PartialConfig,\n EventSource,\n} from './types';\nimport type { Logger } from '@walkeros/core';\n\nexport function getConfig(\n partialConfig: PartialConfig = {},\n logger: Logger.Instance,\n): ValidatedConfig {\n const settings = (partialConfig.settings || {}) as Partial<Settings>;\n const { destinations, eventSource = 'WEB' } = settings;\n\n if (!destinations || destinations.length === 0)\n logger.throw('Config settings destinations missing or empty');\n\n const settingsConfig: Settings & { eventSource: EventSource } = {\n ...settings,\n destinations,\n eventSource,\n };\n\n return { ...partialConfig, settings: settingsConfig };\n}\n","import type { PushFn } from './types';\nimport type { IngestEventsRequest, IngestEventsResponse } from './types';\nimport { getMappingValue, isObject } from '@walkeros/core';\nimport { formatEvent, formatConsent } from './format';\nimport { getAccessToken } from './auth';\nimport { getConfig } from './config';\n\nexport const push: PushFn = async function (\n event,\n { config, mapping, data, collector, env, logger },\n) {\n // Validate config and get typed settings\n const validatedConfig = getConfig(config, logger);\n const {\n destinations,\n eventSource,\n validateOnly = false,\n url = 'https://datamanager.googleapis.com/v1',\n consent: requestConsent,\n testEventCode,\n userData,\n userId,\n clientId,\n sessionAttributes,\n consentAdUserData,\n consentAdPersonalization,\n } = validatedConfig.settings;\n\n // Extract Settings guided helpers\n const userDataMapped = userData\n ? await getMappingValue(event, { map: userData })\n : {};\n const userIdMapped = userId\n ? await getMappingValue(event, userId)\n : undefined;\n const clientIdMapped = clientId\n ? await getMappingValue(event, clientId)\n : undefined;\n const sessionAttributesMapped = sessionAttributes\n ? await getMappingValue(event, sessionAttributes)\n : undefined;\n\n // Extract consent from Settings\n const consentAdUserDataValue =\n typeof consentAdUserData === 'boolean'\n ? consentAdUserData\n : typeof consentAdUserData === 'string' && event.consent\n ? event.consent[consentAdUserData]\n : undefined;\n\n const consentAdPersonalizationValue =\n typeof consentAdPersonalization === 'boolean'\n ? consentAdPersonalization\n : typeof consentAdPersonalization === 'string' && event.consent\n ? event.consent[consentAdPersonalization]\n : undefined;\n\n // Build Settings helpers object\n const settingsHelpers: Record<string, unknown> = {};\n if (isObject(userDataMapped)) {\n Object.assign(settingsHelpers, userDataMapped);\n }\n if (userIdMapped !== undefined) settingsHelpers.userId = userIdMapped;\n if (clientIdMapped !== undefined) settingsHelpers.clientId = clientIdMapped;\n if (sessionAttributesMapped !== undefined)\n settingsHelpers.sessionAttributes = sessionAttributesMapped;\n if (consentAdUserDataValue !== undefined)\n settingsHelpers.adUserData = consentAdUserDataValue;\n if (consentAdPersonalizationValue !== undefined)\n settingsHelpers.adPersonalization = consentAdPersonalizationValue;\n\n // Get mapped data from destination config and event mapping\n const configData = validatedConfig.data\n ? await getMappingValue(event, validatedConfig.data)\n : {};\n const eventData = isObject(data) ? data : {};\n\n // Merge: Settings helpers < config.data < event mapping data\n const finalData = {\n ...settingsHelpers,\n ...(isObject(configData) ? configData : {}),\n ...eventData,\n };\n\n // Format event for Data Manager API\n const dataManagerEvent = await formatEvent(event, finalData);\n\n // Apply event source from settings (required)\n if (!dataManagerEvent.eventSource) {\n dataManagerEvent.eventSource = eventSource;\n }\n\n // Apply request-level consent if event doesn't have consent\n if (!dataManagerEvent.consent && requestConsent) {\n dataManagerEvent.consent = requestConsent;\n }\n\n // Validate required fields before API call\n if (!dataManagerEvent.transactionId) {\n logger.throw('transactionId is required');\n }\n\n // Check if any destination is GA4 (requires eventName)\n const hasGA4Destination = destinations.some(\n (d) => d.operatingAccount?.accountType === 'GOOGLE_ANALYTICS_PROPERTY',\n );\n\n if (hasGA4Destination && !dataManagerEvent.eventName) {\n logger.throw('eventName is required for GA4 destinations');\n }\n\n // Build API request\n const requestBody: IngestEventsRequest = {\n events: [dataManagerEvent],\n destinations,\n };\n\n // Add optional parameters\n if (requestConsent) {\n requestBody.consent = requestConsent;\n }\n\n if (validateOnly) {\n requestBody.validateOnly = true;\n }\n\n if (testEventCode) {\n requestBody.testEventCode = testEventCode;\n }\n\n const authClient = env?.authClient;\n if (!authClient) {\n return logger.throw(\n 'Auth client not initialized. Ensure init() was called successfully.',\n );\n }\n\n let accessToken: string;\n try {\n accessToken = await getAccessToken(authClient);\n } catch (error) {\n logger.error('Authentication failed', { error });\n throw error;\n }\n\n const fetchFn = env?.fetch || fetch;\n const endpoint = `${url}/events:ingest`;\n\n logger.debug('Sending to Data Manager API', {\n endpoint,\n eventCount: requestBody.events.length,\n destinations: destinations.length,\n validateOnly,\n });\n\n const response = await fetchFn(endpoint, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${accessToken}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(requestBody),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n logger.throw(`Data Manager API error (${response.status}): ${errorText}`);\n }\n\n const result: IngestEventsResponse = await response.json();\n\n logger.debug('API response', {\n status: response.status,\n requestId: result.requestId,\n });\n\n // If validation errors exist, throw them\n if (result.validationErrors && result.validationErrors.length > 0) {\n logger.throw(\n `Validation errors: ${JSON.stringify(result.validationErrors)}`,\n );\n }\n};\n","import type { WalkerOS } from '@walkeros/core';\nimport { isString, isDefined } from '@walkeros/core';\nimport type {\n Event,\n UserData,\n UserIdentifier,\n AdIdentifiers,\n Consent,\n ConsentStatus,\n} from './types';\nimport { hashEmail, hashPhone, hashName } from './hash';\n\n/**\n * Format walkerOS event timestamp to RFC 3339 format\n * https://developers.google.com/data-manager/api/reference/rest/v1/Event\n *\n * walkerOS timestamp is in milliseconds, RFC 3339 format: \"2024-01-15T10:30:00Z\"\n */\nexport function formatTimestamp(timestamp: number): string {\n return new Date(timestamp).toISOString();\n}\n\n/**\n * Format user identifiers from mapped data\n * https://developers.google.com/data-manager/api/reference/rest/v1/UserData\n *\n * User data must be explicitly mapped in the mapping configuration.\n * Max 10 identifiers per event\n */\nexport async function formatUserData(\n data: Record<string, unknown>,\n): Promise<UserData | undefined> {\n const identifiers: UserIdentifier[] = [];\n\n // Extract from mapped data only\n // Email\n if (isString(data.email) && data.email) {\n const hashedEmail = await hashEmail(data.email);\n if (hashedEmail) {\n identifiers.push({ emailAddress: hashedEmail });\n }\n }\n\n // Phone\n if (isString(data.phone) && data.phone) {\n const hashedPhone = await hashPhone(data.phone);\n if (hashedPhone) {\n identifiers.push({ phoneNumber: hashedPhone });\n }\n }\n\n // Address from mapped properties\n const hasAddress =\n data.firstName || data.lastName || data.regionCode || data.postalCode;\n\n if (hasAddress) {\n const address: Record<string, string> = {};\n\n if (isString(data.firstName) && data.firstName) {\n address.givenName = await hashName(data.firstName, 'given');\n }\n\n if (isString(data.lastName) && data.lastName) {\n address.familyName = await hashName(data.lastName, 'family');\n }\n\n // Region code is NOT hashed\n if (isString(data.regionCode) && data.regionCode) {\n address.regionCode = data.regionCode.toUpperCase();\n }\n\n // Postal code is NOT hashed\n if (isString(data.postalCode) && data.postalCode) {\n address.postalCode = data.postalCode;\n }\n\n if (Object.keys(address).length > 0) {\n identifiers.push({ address });\n }\n }\n\n // Limit to 10 identifiers\n if (identifiers.length === 0) return undefined;\n\n return {\n userIdentifiers: identifiers.slice(0, 10),\n };\n}\n\n/**\n * Extract and format attribution identifiers from mapped data\n * https://developers.google.com/data-manager/api/reference/rest/v1/AdIdentifiers\n *\n * Attribution identifiers should be mapped explicitly in the mapping configuration.\n * Example: { gclid: 'context.gclid', gbraid: 'context.gbraid' }\n */\nexport function formatAdIdentifiers(\n data: Record<string, unknown>,\n): AdIdentifiers | undefined {\n const identifiers: AdIdentifiers = {};\n\n // Extract from mapped data (already processed by mapping system)\n if (isString(data.gclid) && data.gclid) {\n identifiers.gclid = data.gclid;\n }\n if (isString(data.gbraid) && data.gbraid) {\n identifiers.gbraid = data.gbraid;\n }\n if (isString(data.wbraid) && data.wbraid) {\n identifiers.wbraid = data.wbraid;\n }\n if (isString(data.sessionAttributes) && data.sessionAttributes) {\n identifiers.sessionAttributes = data.sessionAttributes;\n }\n\n return Object.keys(identifiers).length > 0 ? identifiers : undefined;\n}\n\n/**\n * Map walkerOS consent to Data Manager consent format\n * https://developers.google.com/data-manager/api/devguides/concepts/dma\n *\n * walkerOS: { marketing: true, personalization: false }\n * Data Manager: { adUserData: 'CONSENT_GRANTED', adPersonalization: 'CONSENT_DENIED' }\n */\nexport function formatConsent(\n walkerOSConsent: WalkerOS.Consent | undefined,\n): Consent | undefined {\n if (!walkerOSConsent) return undefined;\n\n const consent: Consent = {};\n\n // Map marketing consent to adUserData\n if (isDefined(walkerOSConsent.marketing)) {\n consent.adUserData = walkerOSConsent.marketing\n ? 'CONSENT_GRANTED'\n : 'CONSENT_DENIED';\n }\n\n // Map personalization consent to adPersonalization\n if (isDefined(walkerOSConsent.personalization)) {\n consent.adPersonalization = walkerOSConsent.personalization\n ? 'CONSENT_GRANTED'\n : 'CONSENT_DENIED';\n }\n\n return Object.keys(consent).length > 0 ? consent : undefined;\n}\n\n/**\n * Format complete event for Data Manager API\n * https://developers.google.com/data-manager/api/reference/rest/v1/Event\n */\nexport async function formatEvent(\n event: WalkerOS.Event,\n mappedData?: Record<string, unknown>,\n): Promise<Event> {\n const dataManagerEvent: Event = {\n eventTimestamp: formatTimestamp(event.timestamp),\n };\n\n // Use only mapped data (no fallback to event.data)\n const data = mappedData || {};\n\n // Transaction ID for deduplication\n if (isString(data.transactionId) && data.transactionId) {\n dataManagerEvent.transactionId = data.transactionId.substring(0, 512);\n }\n\n // Client ID (GA)\n if (isString(data.clientId) && data.clientId) {\n dataManagerEvent.clientId = data.clientId.substring(0, 255);\n }\n\n // User ID\n if (isString(data.userId) && data.userId) {\n dataManagerEvent.userId = data.userId.substring(0, 256);\n }\n\n // User data\n const userData = await formatUserData(data);\n if (userData) {\n dataManagerEvent.userData = userData;\n }\n\n // Attribution identifiers\n const adIdentifiers = formatAdIdentifiers(data);\n if (adIdentifiers) {\n dataManagerEvent.adIdentifiers = adIdentifiers;\n }\n\n // Conversion value\n if (typeof data.conversionValue === 'number') {\n dataManagerEvent.conversionValue = data.conversionValue;\n }\n\n // Currency\n if (isString(data.currency) && data.currency) {\n dataManagerEvent.currency = data.currency.substring(0, 3).toUpperCase();\n }\n\n // Cart data\n if (data.cartData && typeof data.cartData === 'object') {\n dataManagerEvent.cartData = data.cartData as Event['cartData'];\n }\n\n // Event name (for GA4)\n if (isString(data.eventName) && data.eventName) {\n dataManagerEvent.eventName = data.eventName.substring(0, 40);\n }\n\n // Event source\n if (isString(data.eventSource) && data.eventSource) {\n dataManagerEvent.eventSource = data.eventSource as Event['eventSource'];\n }\n\n // Consent - check mapped data first, then fallback to event.consent\n const mappedConsent: Consent = {};\n\n // Check for mapped consent values (from Settings or event mapping)\n if (typeof data.adUserData === 'boolean') {\n mappedConsent.adUserData = data.adUserData\n ? 'CONSENT_GRANTED'\n : 'CONSENT_DENIED';\n }\n if (typeof data.adPersonalization === 'boolean') {\n mappedConsent.adPersonalization = data.adPersonalization\n ? 'CONSENT_GRANTED'\n : 'CONSENT_DENIED';\n }\n\n // If no mapped consent, fall back to event.consent\n if (Object.keys(mappedConsent).length === 0) {\n const eventConsent = formatConsent(event.consent);\n if (eventConsent) {\n dataManagerEvent.consent = eventConsent;\n }\n } else {\n dataManagerEvent.consent = mappedConsent;\n }\n\n return dataManagerEvent;\n}\n","import { isString } from '@walkeros/core';\nimport { getHashServer } from '@walkeros/server-core';\n\n/**\n * Normalize email address according to Google Data Manager requirements\n * https://developers.google.com/data-manager/api/devguides/concepts/formatting#email\n *\n * 1. Trim whitespace\n * 2. Convert to lowercase\n * 3. Remove dots (.) for gmail.com and googlemail.com\n * 4. SHA-256 hash\n */\nexport async function hashEmail(email: string): Promise<string> {\n if (!isString(email) || !email) return '';\n\n // Trim and lowercase\n let normalized = email.trim().toLowerCase();\n\n // Remove dots for Gmail addresses\n if (\n normalized.endsWith('@gmail.com') ||\n normalized.endsWith('@googlemail.com')\n ) {\n const [localPart, domain] = normalized.split('@');\n normalized = `${localPart.replace(/\\./g, '')}@${domain}`;\n }\n\n return getHashServer(normalized);\n}\n\n/**\n * Normalize phone number to E.164 format and hash\n * https://developers.google.com/data-manager/api/devguides/concepts/formatting#phone\n *\n * E.164 format: +[country code][number] (max 15 digits after +)\n * Example: +18005550100\n *\n * 1. Remove all non-digit characters except leading +\n * 2. Ensure it starts with +\n * 3. SHA-256 hash\n */\nexport async function hashPhone(phone: string): Promise<string> {\n if (!isString(phone) || !phone) return '';\n\n // Remove all non-digit characters except + at the start\n let normalized = phone.trim();\n\n // Extract country code if present\n const hasPlus = normalized.startsWith('+');\n\n // Remove all non-digits\n normalized = normalized.replace(/\\D/g, '');\n\n // Add + prefix if it was there or if number is long enough\n if (hasPlus || normalized.length > 10) {\n normalized = `+${normalized}`;\n } else {\n // Assume US number if no country code (default behavior)\n normalized = `+1${normalized}`;\n }\n\n return getHashServer(normalized);\n}\n\n/**\n * Normalize and hash a name (first or last name)\n * https://developers.google.com/data-manager/api/devguides/concepts/formatting#name\n *\n * 1. Trim whitespace\n * 2. Convert to lowercase\n * 3. Remove common prefixes (Mr., Mrs., Dr.) for first names\n * 4. Remove common suffixes (Jr., Sr., III) for last names\n * 5. SHA-256 hash\n */\nexport async function hashName(\n name: string,\n type: 'given' | 'family' = 'given',\n): Promise<string> {\n if (!isString(name) || !name) return '';\n\n // Trim and lowercase\n let normalized = name.trim().toLowerCase();\n\n // Remove prefixes for given names\n if (type === 'given') {\n const prefixes = ['mr.', 'mrs.', 'ms.', 'miss.', 'dr.', 'prof.'];\n for (const prefix of prefixes) {\n if (normalized.startsWith(prefix)) {\n normalized = normalized.substring(prefix.length).trim();\n break;\n }\n }\n }\n\n // Remove suffixes for family names (check with and without space)\n // Sort by length (longest first) to match \"iii\" before \"ii\"\n if (type === 'family') {\n const suffixes = ['jr.', 'sr.', 'iii', 'ii', 'iv', 'v'];\n for (const suffix of suffixes) {\n // Check for suffix with space before it (e.g., \" jr.\")\n const suffixWithSpace = ` ${suffix}`;\n if (normalized.endsWith(suffixWithSpace)) {\n normalized = normalized\n .substring(0, normalized.length - suffixWithSpace.length)\n .trim();\n break;\n }\n // Check for suffix without space\n if (normalized.endsWith(suffix)) {\n normalized = normalized\n .substring(0, normalized.length - suffix.length)\n .trim();\n break;\n }\n }\n }\n\n return getHashServer(normalized);\n}\n\n/**\n * Hash multiple email addresses\n */\nexport async function hashEmails(emails: string[]): Promise<string[]> {\n return Promise.all(emails.map((email) => hashEmail(email)));\n}\n\n/**\n * Hash multiple phone numbers\n */\nexport async function hashPhones(phones: string[]): Promise<string[]> {\n return Promise.all(phones.map((phone) => hashPhone(phone)));\n}\n","import { GoogleAuth, type OAuth2Client } from 'google-auth-library';\nimport type { Settings } from './types';\n\nconst DEFAULT_SCOPES = ['https://www.googleapis.com/auth/datamanager'];\n\n/**\n * Authentication error with cause tracking\n */\nexport class AuthError extends Error {\n constructor(\n message: string,\n public cause?: Error,\n ) {\n super(message);\n this.name = 'DataManagerAuthError';\n }\n}\n\n/**\n * Creates Google Auth client based on settings\n *\n * Authentication priority:\n * 1. credentials (inline service account) - if provided\n * 2. keyFilename (service account file) - if provided\n * 3. Application Default Credentials (ADC) - automatic fallback\n * - GOOGLE_APPLICATION_CREDENTIALS env var\n * - GCP metadata server (Cloud Functions, Cloud Run, GCE)\n *\n * @param settings - Configuration with auth options\n * @returns OAuth2Client for token retrieval\n * @throws AuthError if authentication fails\n */\nexport async function createAuthClient(\n settings: Settings,\n): Promise<OAuth2Client> {\n const { credentials, keyFilename, scopes = DEFAULT_SCOPES } = settings;\n\n try {\n if (credentials) {\n const auth = new GoogleAuth({\n credentials,\n scopes,\n });\n return (await auth.getClient()) as OAuth2Client;\n }\n\n if (keyFilename) {\n const auth = new GoogleAuth({\n keyFilename,\n scopes,\n });\n return (await auth.getClient()) as OAuth2Client;\n }\n\n const auth = new GoogleAuth({ scopes });\n return (await auth.getClient()) as OAuth2Client;\n } catch (error) {\n throw new AuthError(\n 'Failed to create auth client. Check credentials configuration or ensure GOOGLE_APPLICATION_CREDENTIALS is set.',\n error instanceof Error ? error : undefined,\n );\n }\n}\n\n/**\n * Gets access token from auth client\n * Automatically returns cached token if valid or refreshes if expired\n *\n * @param authClient - OAuth2 client from createAuthClient()\n * @returns Fresh access token\n * @throws AuthError if token retrieval fails\n */\nexport async function getAccessToken(\n authClient: OAuth2Client,\n): Promise<string> {\n try {\n const tokenResponse = await authClient.getAccessToken();\n\n if (!tokenResponse.token) {\n throw new AuthError('Auth client returned empty token');\n }\n\n return tokenResponse.token;\n } catch (error) {\n throw new AuthError(\n 'Failed to obtain access token',\n error instanceof Error ? error : undefined,\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';\nimport type { OAuth2Client } from 'google-auth-library';\n\nexport interface Settings {\n /**\n * Service account credentials (client_email + private_key)\n * Recommended for serverless environments (AWS Lambda, Docker, etc.)\n */\n credentials?: {\n client_email: string;\n private_key: string;\n };\n\n /**\n * Path to service account JSON file\n * For local development or environments with filesystem access\n */\n keyFilename?: string;\n\n /**\n * OAuth scopes for Data Manager API\n * @default ['https://www.googleapis.com/auth/datamanager']\n */\n scopes?: string[];\n\n /** Array of destination accounts and conversion actions/user lists */\n destinations: Destination[];\n\n /** Event source for all events. Defaults to WEB if not specified */\n eventSource?: EventSource;\n\n /** Maximum number of events to batch before sending (max 2000) */\n batchSize?: number;\n\n /** Time in milliseconds to wait before auto-flushing batch */\n batchInterval?: number;\n\n /** If true, validate request without ingestion (testing mode) */\n validateOnly?: boolean;\n\n /** Override API endpoint (for testing) */\n url?: string;\n\n /** Request-level consent for all events */\n consent?: Consent;\n\n /** Test event code for debugging (optional) */\n testEventCode?: string;\n\n /** Guided helpers: User data mapping (applies to all events) */\n userData?: WalkerOSMapping.Map;\n\n /** Guided helper: First-party user ID */\n userId?: WalkerOSMapping.Value;\n\n /** Guided helper: GA4 client ID */\n clientId?: WalkerOSMapping.Value;\n\n /** Guided helper: Privacy-safe attribution (Google's sessionAttributes) */\n sessionAttributes?: WalkerOSMapping.Value;\n\n /** Consent mapping: Map consent field to adUserData (string = field name, boolean = static value) */\n consentAdUserData?: string | boolean;\n\n /** Consent mapping: Map consent field to adPersonalization (string = field name, boolean = static value) */\n consentAdPersonalization?: string | boolean;\n}\n\nexport interface Mapping {\n // Attribution identifiers (optional, for explicit mapping)\n gclid?: WalkerOSMapping.Value;\n gbraid?: WalkerOSMapping.Value;\n wbraid?: WalkerOSMapping.Value;\n sessionAttributes?: WalkerOSMapping.Value;\n}\n\nexport interface Env extends DestinationServer.Env {\n fetch?: typeof fetch;\n authClient?: OAuth2Client | null;\n}\n\nexport type InitSettings = Partial<Settings>;\n\nexport type Types = CoreDestination.Types<Settings, Mapping, Env, InitSettings>;\n\nexport interface DestinationInterface\n extends DestinationServer.Destination<Types> {\n init: DestinationServer.InitFn<Types>;\n}\n\nexport type Config = {\n settings: Settings;\n} & DestinationServer.Config<Types>;\n\n/**\n * Config after validation - settings is guaranteed to exist with required fields\n * Use this type after calling getConfig() to get proper type narrowing\n * After validation, eventSource is always set (defaults to 'WEB')\n */\nexport type ValidatedConfig = Omit<Config, 'settings'> & {\n settings: Settings & { eventSource: EventSource };\n};\n\nexport type InitFn = DestinationServer.InitFn<Types>;\nexport type PushFn = DestinationServer.PushFn<Types>;\n\nexport type PartialConfig = DestinationServer.PartialConfig<Types>;\n\nexport type PushEvents = DestinationServer.PushEvents<Mapping>;\n\nexport type Rule = WalkerOSMapping.Rule<Mapping>;\nexport type Rules = WalkerOSMapping.Rules<Rule>;\n\n// Google Data Manager API Types\n// https://developers.google.com/data-manager/api/reference\n\n/**\n * Destination account and product identifier\n * https://developers.google.com/data-manager/api/reference/rest/v1/Destination\n */\nexport interface Destination {\n /** Reference identifier for this destination */\n reference?: string;\n\n /** Login account (account initiating the request) */\n loginAccount?: ProductAccount;\n\n /** Linked account (child account linked to login account) */\n linkedAccount?: ProductAccount;\n\n /** Operating account (account where data is sent) */\n operatingAccount?: ProductAccount;\n\n /** Product-specific destination ID (conversion action or user list) */\n productDestinationId?: string;\n}\n\n/**\n * Product account information\n */\nexport interface ProductAccount {\n /** Account ID (e.g., \"123-456-7890\" for Google Ads) */\n accountId: string;\n\n /** Type of account */\n accountType: AccountType;\n}\n\nexport type AccountType =\n | 'ACCOUNT_TYPE_UNSPECIFIED'\n | 'GOOGLE_ADS'\n | 'DISPLAY_VIDEO_ADVERTISER'\n | 'DISPLAY_VIDEO_PARTNER'\n | 'GOOGLE_ANALYTICS_PROPERTY'\n | 'DATA_PARTNER';\n\nexport type EventSource = 'WEB' | 'APP' | 'IN_STORE' | 'PHONE' | 'OTHER';\n\n/**\n * Consent for Digital Markets Act (DMA) compliance\n * https://developers.google.com/data-manager/api/devguides/concepts/dma\n */\nexport interface Consent {\n /** Consent for data collection and use */\n adUserData?: ConsentStatus;\n\n /** Consent for ad personalization */\n adPersonalization?: ConsentStatus;\n}\n\nexport type ConsentStatus = 'CONSENT_GRANTED' | 'CONSENT_DENIED';\n\n/**\n * Request body for events.ingest API\n * https://developers.google.com/data-manager/api/reference/rest/v1/events/ingest\n */\nexport interface IngestEventsRequest {\n /** Array of destinations for these events (max 10) */\n destinations: Destination[];\n\n /** Array of events to ingest (max 2000) */\n events: Event[];\n\n /** Request-level consent (overridden by event-level) */\n consent?: Consent;\n\n /** If true, validate without ingestion */\n validateOnly?: boolean;\n\n /** Test event code for debugging */\n testEventCode?: string;\n}\n\n/**\n * Single event for ingestion\n * https://developers.google.com/data-manager/api/reference/rest/v1/Event\n */\nexport interface Event {\n /** Destination references for routing */\n destinationReferences?: string[];\n\n /** Transaction ID for deduplication (max 512 chars) */\n transactionId?: string;\n\n /** Event timestamp in RFC 3339 format */\n eventTimestamp?: string;\n\n /** Last updated timestamp in RFC 3339 format */\n lastUpdatedTimestamp?: string;\n\n /** User data with identifiers (max 10 identifiers) */\n userData?: UserData;\n\n /** Event-level consent (overrides request-level) */\n consent?: Consent;\n\n /** Attribution identifiers */\n adIdentifiers?: AdIdentifiers;\n\n /** Currency code (ISO 4217, 3 chars) */\n currency?: string;\n\n /** Conversion value */\n conversionValue?: number;\n\n /** Source of the event */\n eventSource?: EventSource;\n\n /** Device information for the event */\n eventDeviceInfo?: DeviceInfo;\n\n /** Shopping cart data */\n cartData?: CartData;\n\n /** Custom variables for the event */\n customVariables?: CustomVariable[];\n\n /** Experimental fields (subject to change) */\n experimentalFields?: ExperimentalField[];\n\n /** User properties */\n userProperties?: UserProperties;\n\n /** Event name for GA4 (max 40 chars, required for GA4) */\n eventName?: string;\n\n /** Google Analytics client ID (max 255 chars) */\n clientId?: string;\n\n /** First-party user ID (max 256 chars) */\n userId?: string;\n\n /** Additional event parameters */\n additionalEventParameters?: EventParameter[];\n}\n\n/**\n * Device information\n */\nexport interface DeviceInfo {\n /** User agent string */\n userAgent?: string;\n}\n\n/**\n * Custom variable\n */\nexport interface CustomVariable {\n /** Variable name */\n name?: string;\n\n /** Variable value */\n value?: string;\n}\n\n/**\n * Experimental field\n */\nexport interface ExperimentalField {\n /** Field name */\n name?: string;\n\n /** Field value */\n value?: string;\n}\n\n/**\n * User properties\n */\nexport interface UserProperties {\n /** Property values */\n [key: string]: string | number | boolean | undefined;\n}\n\n/**\n * Event parameter\n */\nexport interface EventParameter {\n /** Parameter name */\n name?: string;\n\n /** Parameter value */\n value?: string | number;\n}\n\n/**\n * User data with identifiers\n * https://developers.google.com/data-manager/api/reference/rest/v1/UserData\n */\nexport interface UserData {\n /** Array of user identifiers (max 10) */\n userIdentifiers: UserIdentifier[];\n}\n\n/**\n * User identifier (email, phone, or address)\n */\nexport type UserIdentifier =\n | { emailAddress: string }\n | { phoneNumber: string }\n | { address: Address };\n\n/**\n * Address for user identification\n * https://developers.google.com/data-manager/api/reference/rest/v1/Address\n */\nexport interface Address {\n /** Given name (first name) - SHA-256 hashed */\n givenName?: string;\n\n /** Family name (last name) - SHA-256 hashed */\n familyName?: string;\n\n /** ISO-3166-1 alpha-2 country code - NOT hashed (e.g., \"US\", \"GB\") */\n regionCode?: string;\n\n /** Postal code - NOT hashed */\n postalCode?: string;\n}\n\n/**\n * Attribution identifiers\n * https://developers.google.com/data-manager/api/reference/rest/v1/AdIdentifiers\n */\nexport interface AdIdentifiers {\n /** Session attributes (privacy-safe attribution) */\n sessionAttributes?: string;\n\n /** Google Click ID (primary attribution) */\n gclid?: string;\n\n /** iOS attribution identifier (post-ATT) */\n gbraid?: string;\n\n /** Web-to-app attribution identifier */\n wbraid?: string;\n\n /** Device information for landing page */\n landingPageDeviceInfo?: DeviceInfo;\n}\n\n/**\n * Shopping cart data\n * https://developers.google.com/data-manager/api/reference/rest/v1/CartData\n */\nexport interface CartData {\n /** Array of cart items (max 200) */\n items: CartItem[];\n}\n\n/**\n * Single cart item\n * https://developers.google.com/data-manager/api/reference/rest/v1/CartItem\n */\nexport interface CartItem {\n /** Merchant product ID (max 127 chars) */\n merchantProductId?: string;\n\n /** Item price */\n price?: number;\n\n /** Item quantity */\n quantity?: number;\n}\n\n/**\n * Response from events.ingest API\n * https://developers.google.com/data-manager/api/reference/rest/v1/IngestEventsResponse\n */\nexport interface IngestEventsResponse {\n /** Unique request ID for status checking */\n requestId: string;\n\n /** Validation errors (only if validateOnly=true) */\n validationErrors?: ValidationError[];\n}\n\n/**\n * Validation error\n */\nexport interface ValidationError {\n /** Error code */\n code: string;\n\n /** Human-readable error message */\n message: string;\n\n /** Field path that caused the error */\n fieldPath?: string;\n}\n\n/**\n * Request status response\n * https://developers.google.com/data-manager/api/reference/rest/v1/requestStatus/retrieve\n */\nexport interface RequestStatusResponse {\n /** Unique request ID */\n requestId: string;\n\n /** Processing state */\n state: RequestState;\n\n /** Number of events successfully ingested */\n eventsIngested?: number;\n\n /** Number of events that failed */\n eventsFailed?: number;\n\n /** Array of errors (if any) */\n errors?: RequestError[];\n}\n\nexport type RequestState =\n | 'STATE_UNSPECIFIED'\n | 'PENDING'\n | 'PROCESSING'\n | 'SUCCEEDED'\n | 'FAILED'\n | 'PARTIALLY_SUCCEEDED';\n\n/**\n * Request error\n */\nexport interface RequestError {\n /** Error code */\n code: string;\n\n /** Human-readable error message */\n message: string;\n\n /** Number of events affected by this error */\n eventCount?: number;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACQO,SAAS,UACd,gBAA+B,CAAC,GAChC,QACiB;AACjB,QAAM,WAAY,cAAc,YAAY,CAAC;AAC7C,QAAM,EAAE,cAAc,cAAc,MAAM,IAAI;AAE9C,MAAI,CAAC,gBAAgB,aAAa,WAAW;AAC3C,WAAO,MAAM,+CAA+C;AAE9D,QAAM,iBAA0D;AAAA,IAC9D,GAAG;AAAA,IACH;AAAA,IACA;AAAA,EACF;AAEA,SAAO,EAAE,GAAG,eAAe,UAAU,eAAe;AACtD;;;ACvBA,IAAAA,eAA0C;;;ACD1C,IAAAC,eAAoC;;;ACDpC,kBAAyB;AACzB,yBAA8B;AAW9B,eAAsB,UAAU,OAAgC;AAC9D,MAAI,KAAC,sBAAS,KAAK,KAAK,CAAC,MAAO,QAAO;AAGvC,MAAI,aAAa,MAAM,KAAK,EAAE,YAAY;AAG1C,MACE,WAAW,SAAS,YAAY,KAChC,WAAW,SAAS,iBAAiB,GACrC;AACA,UAAM,CAAC,WAAW,MAAM,IAAI,WAAW,MAAM,GAAG;AAChD,iBAAa,GAAG,UAAU,QAAQ,OAAO,EAAE,CAAC,IAAI,MAAM;AAAA,EACxD;AAEA,aAAO,kCAAc,UAAU;AACjC;AAaA,eAAsB,UAAU,OAAgC;AAC9D,MAAI,KAAC,sBAAS,KAAK,KAAK,CAAC,MAAO,QAAO;AAGvC,MAAI,aAAa,MAAM,KAAK;AAG5B,QAAM,UAAU,WAAW,WAAW,GAAG;AAGzC,eAAa,WAAW,QAAQ,OAAO,EAAE;AAGzC,MAAI,WAAW,WAAW,SAAS,IAAI;AACrC,iBAAa,IAAI,UAAU;AAAA,EAC7B,OAAO;AAEL,iBAAa,KAAK,UAAU;AAAA,EAC9B;AAEA,aAAO,kCAAc,UAAU;AACjC;AAYA,eAAsB,SACpB,MACA,OAA2B,SACV;AACjB,MAAI,KAAC,sBAAS,IAAI,KAAK,CAAC,KAAM,QAAO;AAGrC,MAAI,aAAa,KAAK,KAAK,EAAE,YAAY;AAGzC,MAAI,SAAS,SAAS;AACpB,UAAM,WAAW,CAAC,OAAO,QAAQ,OAAO,SAAS,OAAO,OAAO;AAC/D,eAAW,UAAU,UAAU;AAC7B,UAAI,WAAW,WAAW,MAAM,GAAG;AACjC,qBAAa,WAAW,UAAU,OAAO,MAAM,EAAE,KAAK;AACtD;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAIA,MAAI,SAAS,UAAU;AACrB,UAAM,WAAW,CAAC,OAAO,OAAO,OAAO,MAAM,MAAM,GAAG;AACtD,eAAW,UAAU,UAAU;AAE7B,YAAM,kBAAkB,IAAI,MAAM;AAClC,UAAI,WAAW,SAAS,eAAe,GAAG;AACxC,qBAAa,WACV,UAAU,GAAG,WAAW,SAAS,gBAAgB,MAAM,EACvD,KAAK;AACR;AAAA,MACF;AAEA,UAAI,WAAW,SAAS,MAAM,GAAG;AAC/B,qBAAa,WACV,UAAU,GAAG,WAAW,SAAS,OAAO,MAAM,EAC9C,KAAK;AACR;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,aAAO,kCAAc,UAAU;AACjC;;;ADpGO,SAAS,gBAAgB,WAA2B;AACzD,SAAO,IAAI,KAAK,SAAS,EAAE,YAAY;AACzC;AASA,eAAsB,eACpB,MAC+B;AAC/B,QAAM,cAAgC,CAAC;AAIvC,UAAI,uBAAS,KAAK,KAAK,KAAK,KAAK,OAAO;AACtC,UAAM,cAAc,MAAM,UAAU,KAAK,KAAK;AAC9C,QAAI,aAAa;AACf,kBAAY,KAAK,EAAE,cAAc,YAAY,CAAC;AAAA,IAChD;AAAA,EACF;AAGA,UAAI,uBAAS,KAAK,KAAK,KAAK,KAAK,OAAO;AACtC,UAAM,cAAc,MAAM,UAAU,KAAK,KAAK;AAC9C,QAAI,aAAa;AACf,kBAAY,KAAK,EAAE,aAAa,YAAY,CAAC;AAAA,IAC/C;AAAA,EACF;AAGA,QAAM,aACJ,KAAK,aAAa,KAAK,YAAY,KAAK,cAAc,KAAK;AAE7D,MAAI,YAAY;AACd,UAAM,UAAkC,CAAC;AAEzC,YAAI,uBAAS,KAAK,SAAS,KAAK,KAAK,WAAW;AAC9C,cAAQ,YAAY,MAAM,SAAS,KAAK,WAAW,OAAO;AAAA,IAC5D;AAEA,YAAI,uBAAS,KAAK,QAAQ,KAAK,KAAK,UAAU;AAC5C,cAAQ,aAAa,MAAM,SAAS,KAAK,UAAU,QAAQ;AAAA,IAC7D;AAGA,YAAI,uBAAS,KAAK,UAAU,KAAK,KAAK,YAAY;AAChD,cAAQ,aAAa,KAAK,WAAW,YAAY;AAAA,IACnD;AAGA,YAAI,uBAAS,KAAK,UAAU,KAAK,KAAK,YAAY;AAChD,cAAQ,aAAa,KAAK;AAAA,IAC5B;AAEA,QAAI,OAAO,KAAK,OAAO,EAAE,SAAS,GAAG;AACnC,kBAAY,KAAK,EAAE,QAAQ,CAAC;AAAA,IAC9B;AAAA,EACF;AAGA,MAAI,YAAY,WAAW,EAAG,QAAO;AAErC,SAAO;AAAA,IACL,iBAAiB,YAAY,MAAM,GAAG,EAAE;AAAA,EAC1C;AACF;AASO,SAAS,oBACd,MAC2B;AAC3B,QAAM,cAA6B,CAAC;AAGpC,UAAI,uBAAS,KAAK,KAAK,KAAK,KAAK,OAAO;AACtC,gBAAY,QAAQ,KAAK;AAAA,EAC3B;AACA,UAAI,uBAAS,KAAK,MAAM,KAAK,KAAK,QAAQ;AACxC,gBAAY,SAAS,KAAK;AAAA,EAC5B;AACA,UAAI,uBAAS,KAAK,MAAM,KAAK,KAAK,QAAQ;AACxC,gBAAY,SAAS,KAAK;AAAA,EAC5B;AACA,UAAI,uBAAS,KAAK,iBAAiB,KAAK,KAAK,mBAAmB;AAC9D,gBAAY,oBAAoB,KAAK;AAAA,EACvC;AAEA,SAAO,OAAO,KAAK,WAAW,EAAE,SAAS,IAAI,cAAc;AAC7D;AASO,SAAS,cACd,iBACqB;AACrB,MAAI,CAAC,gBAAiB,QAAO;AAE7B,QAAM,UAAmB,CAAC;AAG1B,UAAI,wBAAU,gBAAgB,SAAS,GAAG;AACxC,YAAQ,aAAa,gBAAgB,YACjC,oBACA;AAAA,EACN;AAGA,UAAI,wBAAU,gBAAgB,eAAe,GAAG;AAC9C,YAAQ,oBAAoB,gBAAgB,kBACxC,oBACA;AAAA,EACN;AAEA,SAAO,OAAO,KAAK,OAAO,EAAE,SAAS,IAAI,UAAU;AACrD;AAMA,eAAsB,YACpB,OACA,YACgB;AAChB,QAAM,mBAA0B;AAAA,IAC9B,gBAAgB,gBAAgB,MAAM,SAAS;AAAA,EACjD;AAGA,QAAM,OAAO,cAAc,CAAC;AAG5B,UAAI,uBAAS,KAAK,aAAa,KAAK,KAAK,eAAe;AACtD,qBAAiB,gBAAgB,KAAK,cAAc,UAAU,GAAG,GAAG;AAAA,EACtE;AAGA,UAAI,uBAAS,KAAK,QAAQ,KAAK,KAAK,UAAU;AAC5C,qBAAiB,WAAW,KAAK,SAAS,UAAU,GAAG,GAAG;AAAA,EAC5D;AAGA,UAAI,uBAAS,KAAK,MAAM,KAAK,KAAK,QAAQ;AACxC,qBAAiB,SAAS,KAAK,OAAO,UAAU,GAAG,GAAG;AAAA,EACxD;AAGA,QAAM,WAAW,MAAM,eAAe,IAAI;AAC1C,MAAI,UAAU;AACZ,qBAAiB,WAAW;AAAA,EAC9B;AAGA,QAAM,gBAAgB,oBAAoB,IAAI;AAC9C,MAAI,eAAe;AACjB,qBAAiB,gBAAgB;AAAA,EACnC;AAGA,MAAI,OAAO,KAAK,oBAAoB,UAAU;AAC5C,qBAAiB,kBAAkB,KAAK;AAAA,EAC1C;AAGA,UAAI,uBAAS,KAAK,QAAQ,KAAK,KAAK,UAAU;AAC5C,qBAAiB,WAAW,KAAK,SAAS,UAAU,GAAG,CAAC,EAAE,YAAY;AAAA,EACxE;AAGA,MAAI,KAAK,YAAY,OAAO,KAAK,aAAa,UAAU;AACtD,qBAAiB,WAAW,KAAK;AAAA,EACnC;AAGA,UAAI,uBAAS,KAAK,SAAS,KAAK,KAAK,WAAW;AAC9C,qBAAiB,YAAY,KAAK,UAAU,UAAU,GAAG,EAAE;AAAA,EAC7D;AAGA,UAAI,uBAAS,KAAK,WAAW,KAAK,KAAK,aAAa;AAClD,qBAAiB,cAAc,KAAK;AAAA,EACtC;AAGA,QAAM,gBAAyB,CAAC;AAGhC,MAAI,OAAO,KAAK,eAAe,WAAW;AACxC,kBAAc,aAAa,KAAK,aAC5B,oBACA;AAAA,EACN;AACA,MAAI,OAAO,KAAK,sBAAsB,WAAW;AAC/C,kBAAc,oBAAoB,KAAK,oBACnC,oBACA;AAAA,EACN;AAGA,MAAI,OAAO,KAAK,aAAa,EAAE,WAAW,GAAG;AAC3C,UAAM,eAAe,cAAc,MAAM,OAAO;AAChD,QAAI,cAAc;AAChB,uBAAiB,UAAU;AAAA,IAC7B;AAAA,EACF,OAAO;AACL,qBAAiB,UAAU;AAAA,EAC7B;AAEA,SAAO;AACT;;;AElPA,iCAA8C;AAG9C,IAAM,iBAAiB,CAAC,6CAA6C;AAK9D,IAAM,YAAN,cAAwB,MAAM;AAAA,EACnC,YACE,SACO,OACP;AACA,UAAM,OAAO;AAFN;AAGP,SAAK,OAAO;AAAA,EACd;AACF;AAgBA,eAAsB,iBACpB,UACuB;AACvB,QAAM,EAAE,aAAa,aAAa,SAAS,eAAe,IAAI;AAE9D,MAAI;AACF,QAAI,aAAa;AACf,YAAMC,QAAO,IAAI,sCAAW;AAAA,QAC1B;AAAA,QACA;AAAA,MACF,CAAC;AACD,aAAQ,MAAMA,MAAK,UAAU;AAAA,IAC/B;AAEA,QAAI,aAAa;AACf,YAAMA,QAAO,IAAI,sCAAW;AAAA,QAC1B;AAAA,QACA;AAAA,MACF,CAAC;AACD,aAAQ,MAAMA,MAAK,UAAU;AAAA,IAC/B;AAEA,UAAM,OAAO,IAAI,sCAAW,EAAE,OAAO,CAAC;AACtC,WAAQ,MAAM,KAAK,UAAU;AAAA,EAC/B,SAAS,OAAO;AACd,UAAM,IAAI;AAAA,MACR;AAAA,MACA,iBAAiB,QAAQ,QAAQ;AAAA,IACnC;AAAA,EACF;AACF;AAUA,eAAsB,eACpB,YACiB;AACjB,MAAI;AACF,UAAM,gBAAgB,MAAM,WAAW,eAAe;AAEtD,QAAI,CAAC,cAAc,OAAO;AACxB,YAAM,IAAI,UAAU,kCAAkC;AAAA,IACxD;AAEA,WAAO,cAAc;AAAA,EACvB,SAAS,OAAO;AACd,UAAM,IAAI;AAAA,MACR;AAAA,MACA,iBAAiB,QAAQ,QAAQ;AAAA,IACnC;AAAA,EACF;AACF;;;AHlFO,IAAM,OAAe,eAC1B,OACA,EAAE,QAAQ,SAAS,MAAM,WAAW,KAAK,OAAO,GAChD;AAEA,QAAM,kBAAkB,UAAU,QAAQ,MAAM;AAChD,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA,eAAe;AAAA,IACf,MAAM;AAAA,IACN,SAAS;AAAA,IACT;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI,gBAAgB;AAGpB,QAAM,iBAAiB,WACnB,UAAM,8BAAgB,OAAO,EAAE,KAAK,SAAS,CAAC,IAC9C,CAAC;AACL,QAAM,eAAe,SACjB,UAAM,8BAAgB,OAAO,MAAM,IACnC;AACJ,QAAM,iBAAiB,WACnB,UAAM,8BAAgB,OAAO,QAAQ,IACrC;AACJ,QAAM,0BAA0B,oBAC5B,UAAM,8BAAgB,OAAO,iBAAiB,IAC9C;AAGJ,QAAM,yBACJ,OAAO,sBAAsB,YACzB,oBACA,OAAO,sBAAsB,YAAY,MAAM,UAC7C,MAAM,QAAQ,iBAAiB,IAC/B;AAER,QAAM,gCACJ,OAAO,6BAA6B,YAChC,2BACA,OAAO,6BAA6B,YAAY,MAAM,UACpD,MAAM,QAAQ,wBAAwB,IACtC;AAGR,QAAM,kBAA2C,CAAC;AAClD,UAAI,uBAAS,cAAc,GAAG;AAC5B,WAAO,OAAO,iBAAiB,cAAc;AAAA,EAC/C;AACA,MAAI,iBAAiB,OAAW,iBAAgB,SAAS;AACzD,MAAI,mBAAmB,OAAW,iBAAgB,WAAW;AAC7D,MAAI,4BAA4B;AAC9B,oBAAgB,oBAAoB;AACtC,MAAI,2BAA2B;AAC7B,oBAAgB,aAAa;AAC/B,MAAI,kCAAkC;AACpC,oBAAgB,oBAAoB;AAGtC,QAAM,aAAa,gBAAgB,OAC/B,UAAM,8BAAgB,OAAO,gBAAgB,IAAI,IACjD,CAAC;AACL,QAAM,gBAAY,uBAAS,IAAI,IAAI,OAAO,CAAC;AAG3C,QAAM,YAAY;AAAA,IAChB,GAAG;AAAA,IACH,OAAI,uBAAS,UAAU,IAAI,aAAa,CAAC;AAAA,IACzC,GAAG;AAAA,EACL;AAGA,QAAM,mBAAmB,MAAM,YAAY,OAAO,SAAS;AAG3D,MAAI,CAAC,iBAAiB,aAAa;AACjC,qBAAiB,cAAc;AAAA,EACjC;AAGA,MAAI,CAAC,iBAAiB,WAAW,gBAAgB;AAC/C,qBAAiB,UAAU;AAAA,EAC7B;AAGA,MAAI,CAAC,iBAAiB,eAAe;AACnC,WAAO,MAAM,2BAA2B;AAAA,EAC1C;AAGA,QAAM,oBAAoB,aAAa;AAAA,IACrC,CAAC,MAAG;AAxGR;AAwGW,sBAAE,qBAAF,mBAAoB,iBAAgB;AAAA;AAAA,EAC7C;AAEA,MAAI,qBAAqB,CAAC,iBAAiB,WAAW;AACpD,WAAO,MAAM,4CAA4C;AAAA,EAC3D;AAGA,QAAM,cAAmC;AAAA,IACvC,QAAQ,CAAC,gBAAgB;AAAA,IACzB;AAAA,EACF;AAGA,MAAI,gBAAgB;AAClB,gBAAY,UAAU;AAAA,EACxB;AAEA,MAAI,cAAc;AAChB,gBAAY,eAAe;AAAA,EAC7B;AAEA,MAAI,eAAe;AACjB,gBAAY,gBAAgB;AAAA,EAC9B;AAEA,QAAM,aAAa,2BAAK;AACxB,MAAI,CAAC,YAAY;AACf,WAAO,OAAO;AAAA,MACZ;AAAA,IACF;AAAA,EACF;AAEA,MAAI;AACJ,MAAI;AACF,kBAAc,MAAM,eAAe,UAAU;AAAA,EAC/C,SAAS,OAAO;AACd,WAAO,MAAM,yBAAyB,EAAE,MAAM,CAAC;AAC/C,UAAM;AAAA,EACR;AAEA,QAAM,WAAU,2BAAK,UAAS;AAC9B,QAAM,WAAW,GAAG,GAAG;AAEvB,SAAO,MAAM,+BAA+B;AAAA,IAC1C;AAAA,IACA,YAAY,YAAY,OAAO;AAAA,IAC/B,cAAc,aAAa;AAAA,IAC3B;AAAA,EACF,CAAC;AAED,QAAM,WAAW,MAAM,QAAQ,UAAU;AAAA,IACvC,QAAQ;AAAA,IACR,SAAS;AAAA,MACP,eAAe,UAAU,WAAW;AAAA,MACpC,gBAAgB;AAAA,IAClB;AAAA,IACA,MAAM,KAAK,UAAU,WAAW;AAAA,EAClC,CAAC;AAED,MAAI,CAAC,SAAS,IAAI;AAChB,UAAM,YAAY,MAAM,SAAS,KAAK;AACtC,WAAO,MAAM,2BAA2B,SAAS,MAAM,MAAM,SAAS,EAAE;AAAA,EAC1E;AAEA,QAAM,SAA+B,MAAM,SAAS,KAAK;AAEzD,SAAO,MAAM,gBAAgB;AAAA,IAC3B,QAAQ,SAAS;AAAA,IACjB,WAAW,OAAO;AAAA,EACpB,CAAC;AAGD,MAAI,OAAO,oBAAoB,OAAO,iBAAiB,SAAS,GAAG;AACjE,WAAO;AAAA,MACL,sBAAsB,KAAK,UAAU,OAAO,gBAAgB,CAAC;AAAA,IAC/D;AAAA,EACF;AACF;;;AItLA;;;ANOO,IAAM,yBAA+C;AAAA,EAC1D,MAAM;AAAA,EAEN,QAAQ,CAAC;AAAA,EAET,MAAM,KAAK,EAAE,QAAQ,eAAe,KAAK,OAAO,GAAG;AAEjD,UAAM,SAAS,UAAU,eAAe,MAAM;AAE9C,QAAI;AACF,YAAM,aAAa,MAAM,iBAAiB,OAAO,QAAQ;AACzD,aAAO,MAAM,qBAAqB;AAElC,aAAO;AAAA,QACL,GAAG;AAAA,QACH,KAAK;AAAA,UACH,GAAG;AAAA,UACH;AAAA,QACF;AAAA,MACF;AAAA,IACF,SAAS,OAAO;AACd,aAAO;AAAA,QACL,uCAAuC,iBAAiB,QAAQ,MAAM,UAAU,eAAe;AAAA,MACjG;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,KAAK,OAAO,EAAE,QAAQ,SAAS,MAAM,WAAW,KAAK,OAAO,GAAG;AACnE,WAAO,MAAM,KAAK,OAAO,EAAE,QAAQ,SAAS,MAAM,WAAW,KAAK,OAAO,CAAC;AAAA,EAC5E;AACF;AAEA,IAAO,gBAAQ;","names":["import_core","import_core","auth"]}
|
package/dist/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
function t(t={},e){const n=t.settings||{},{destinations:a,eventSource:
|
|
1
|
+
function t(t={},e){const n=t.settings||{},{destinations:a,eventSource:o="WEB"}=n;a&&0!==a.length||e.throw("Config settings destinations missing or empty");const i={...n,destinations:a,eventSource:o};return{...t,settings:i}}import{getMappingValue as e,isObject as n}from"@walkeros/core";import{isString as a,isDefined as o}from"@walkeros/core";import{isString as i}from"@walkeros/core";import{getHashServer as s}from"@walkeros/server-core";async function r(t,e="given"){if(!i(t)||!t)return"";let n=t.trim().toLowerCase();if("given"===e){const t=["mr.","mrs.","ms.","miss.","dr.","prof."];for(const e of t)if(n.startsWith(e)){n=n.substring(e.length).trim();break}}if("family"===e){const t=["jr.","sr.","iii","ii","iv","v"];for(const e of t){const t=` ${e}`;if(n.endsWith(t)){n=n.substring(0,n.length-t.length).trim();break}if(n.endsWith(e)){n=n.substring(0,n.length-e.length).trim();break}}}return s(n)}async function c(t){const e=[];if(a(t.email)&&t.email){const n=await async function(t){if(!i(t)||!t)return"";let e=t.trim().toLowerCase();if(e.endsWith("@gmail.com")||e.endsWith("@googlemail.com")){const[t,n]=e.split("@");e=`${t.replace(/\./g,"")}@${n}`}return s(e)}(t.email);n&&e.push({emailAddress:n})}if(a(t.phone)&&t.phone){const n=await async function(t){if(!i(t)||!t)return"";let e=t.trim();const n=e.startsWith("+");return e=e.replace(/\D/g,""),e=n||e.length>10?`+${e}`:`+1${e}`,s(e)}(t.phone);n&&e.push({phoneNumber:n})}if(t.firstName||t.lastName||t.regionCode||t.postalCode){const n={};a(t.firstName)&&t.firstName&&(n.givenName=await r(t.firstName,"given")),a(t.lastName)&&t.lastName&&(n.familyName=await r(t.lastName,"family")),a(t.regionCode)&&t.regionCode&&(n.regionCode=t.regionCode.toUpperCase()),a(t.postalCode)&&t.postalCode&&(n.postalCode=t.postalCode),Object.keys(n).length>0&&e.push({address:n})}if(0!==e.length)return{userIdentifiers:e.slice(0,10)}}async function d(t,e){const n={eventTimestamp:(i=t.timestamp,new Date(i).toISOString())};var i;const s=e||{};a(s.transactionId)&&s.transactionId&&(n.transactionId=s.transactionId.substring(0,512)),a(s.clientId)&&s.clientId&&(n.clientId=s.clientId.substring(0,255)),a(s.userId)&&s.userId&&(n.userId=s.userId.substring(0,256));const r=await c(s);r&&(n.userData=r);const d=function(t){const e={};return a(t.gclid)&&t.gclid&&(e.gclid=t.gclid),a(t.gbraid)&&t.gbraid&&(e.gbraid=t.gbraid),a(t.wbraid)&&t.wbraid&&(e.wbraid=t.wbraid),a(t.sessionAttributes)&&t.sessionAttributes&&(e.sessionAttributes=t.sessionAttributes),Object.keys(e).length>0?e:void 0}(s);d&&(n.adIdentifiers=d),"number"==typeof s.conversionValue&&(n.conversionValue=s.conversionValue),a(s.currency)&&s.currency&&(n.currency=s.currency.substring(0,3).toUpperCase()),s.cartData&&"object"==typeof s.cartData&&(n.cartData=s.cartData),a(s.eventName)&&s.eventName&&(n.eventName=s.eventName.substring(0,40)),a(s.eventSource)&&s.eventSource&&(n.eventSource=s.eventSource);const l={};if("boolean"==typeof s.adUserData&&(l.adUserData=s.adUserData?"CONSENT_GRANTED":"CONSENT_DENIED"),"boolean"==typeof s.adPersonalization&&(l.adPersonalization=s.adPersonalization?"CONSENT_GRANTED":"CONSENT_DENIED"),0===Object.keys(l).length){const e=function(t){if(!t)return;const e={};return o(t.marketing)&&(e.adUserData=t.marketing?"CONSENT_GRANTED":"CONSENT_DENIED"),o(t.personalization)&&(e.adPersonalization=t.personalization?"CONSENT_GRANTED":"CONSENT_DENIED"),Object.keys(e).length>0?e:void 0}(t.consent);e&&(n.consent=e)}else n.consent=l;return n}import{GoogleAuth as l}from"google-auth-library";var u=["https://www.googleapis.com/auth/datamanager"],g=class extends Error{constructor(t,e){super(t),this.cause=e,this.name="DataManagerAuthError"}};var f=async function(a,{config:o,mapping:i,data:s,collector:r,env:c,logger:l}){const u=t(o,l),{destinations:f,eventSource:m,validateOnly:h=!1,url:p="https://datamanager.googleapis.com/v1",consent:v,testEventCode:w,userData:y,userId:N,clientId:b,sessionAttributes:E,consentAdUserData:C,consentAdPersonalization:I}=u.settings,D=y?await e(a,{map:y}):{},A=N?await e(a,N):void 0,O=b?await e(a,b):void 0,S=E?await e(a,E):void 0,k="boolean"==typeof C?C:"string"==typeof C&&a.consent?a.consent[C]:void 0,T="boolean"==typeof I?I:"string"==typeof I&&a.consent?a.consent[I]:void 0,P={};n(D)&&Object.assign(P,D),void 0!==A&&(P.userId=A),void 0!==O&&(P.clientId=O),void 0!==S&&(P.sessionAttributes=S),void 0!==k&&(P.adUserData=k),void 0!==T&&(P.adPersonalization=T);const _=u.data?await e(a,u.data):{},$=n(s)?s:{},z={...P,...n(_)?_:{},...$},j=await d(a,z);j.eventSource||(j.eventSource=m),!j.consent&&v&&(j.consent=v),j.transactionId||l.throw("transactionId is required");f.some(t=>{var e;return"GOOGLE_ANALYTICS_PROPERTY"===(null==(e=t.operatingAccount)?void 0:e.accountType)})&&!j.eventName&&l.throw("eventName is required for GA4 destinations");const G={events:[j],destinations:f};v&&(G.consent=v),h&&(G.validateOnly=!0),w&&(G.testEventCode=w);const U=null==c?void 0:c.authClient;if(!U)return l.throw("Auth client not initialized. Ensure init() was called successfully.");let L;try{L=await async function(t){try{const e=await t.getAccessToken();if(!e.token)throw new g("Auth client returned empty token");return e.token}catch(t){throw new g("Failed to obtain access token",t instanceof Error?t:void 0)}}(U)}catch(t){throw l.error("Authentication failed",{error:t}),t}const R=(null==c?void 0:c.fetch)||fetch,W=`${p}/events:ingest`;l.debug("Sending to Data Manager API",{endpoint:W,eventCount:G.events.length,destinations:f.length,validateOnly:h});const M=await R(W,{method:"POST",headers:{Authorization:`Bearer ${L}`,"Content-Type":"application/json"},body:JSON.stringify(G)});if(!M.ok){const t=await M.text();l.throw(`Data Manager API error (${M.status}): ${t}`)}const q=await M.json();l.debug("API response",{status:M.status,requestId:q.requestId}),q.validationErrors&&q.validationErrors.length>0&&l.throw(`Validation errors: ${JSON.stringify(q.validationErrors)}`)},m={},h={type:"datamanager",config:{},async init({config:e,env:n,logger:a}){const o=t(e,a);try{const t=await async function(t){const{credentials:e,keyFilename:n,scopes:a=u}=t;try{if(e){const t=new l({credentials:e,scopes:a});return await t.getClient()}if(n){const t=new l({keyFilename:n,scopes:a});return await t.getClient()}const t=new l({scopes:a});return await t.getClient()}catch(t){throw new g("Failed to create auth client. Check credentials configuration or ensure GOOGLE_APPLICATION_CREDENTIALS is set.",t instanceof Error?t:void 0)}}(o.settings);return a.debug("Auth client created"),{...o,env:{...n,authClient:t}}}catch(t){a.throw(`Data Manager authentication failed: ${t instanceof Error?t.message:"Unknown error"}`)}},push:async(t,{config:e,mapping:n,data:a,collector:o,env:i,logger:s})=>await f(t,{config:e,mapping:n,data:a,collector:o,env:i,logger:s})},p=h;export{m as DestinationDataManager,p as default,h as destinationDataManager};//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/config.ts","../src/push.ts","../src/format.ts","../src/hash.ts","../src/auth.ts","../src/types/index.ts","../src/index.ts"],"sourcesContent":["import type {\n ValidatedConfig,\n Settings,\n PartialConfig,\n EventSource,\n} from './types';\nimport type { Logger } from '@walkeros/core';\n\nexport function getConfig(\n partialConfig: PartialConfig = {},\n logger: Logger.Instance,\n): ValidatedConfig {\n const settings = (partialConfig.settings || {}) as Partial<Settings>;\n const { destinations, eventSource = 'WEB' } = settings;\n\n if (!destinations || destinations.length === 0)\n logger.throw('Config settings destinations missing or empty');\n\n const settingsConfig: Settings & { eventSource: EventSource } = {\n ...settings,\n destinations,\n eventSource,\n };\n\n return { ...partialConfig, settings: settingsConfig };\n}\n","import type { PushFn } from './types';\nimport type { IngestEventsRequest, IngestEventsResponse } from './types';\nimport { getMappingValue, isObject } from '@walkeros/core';\nimport { formatEvent, formatConsent } from './format';\nimport { getAccessToken } from './auth';\nimport { getConfig } from './config';\n\nexport const push: PushFn = async function (\n event,\n { config, mapping, data, collector, env, logger },\n) {\n // Validate config and get typed settings\n const validatedConfig = getConfig(config, logger);\n const {\n destinations,\n eventSource,\n validateOnly = false,\n url = 'https://datamanager.googleapis.com/v1',\n consent: requestConsent,\n testEventCode,\n userData,\n userId,\n clientId,\n sessionAttributes,\n consentAdUserData,\n consentAdPersonalization,\n } = validatedConfig.settings;\n\n // Extract Settings guided helpers\n const userDataMapped = userData\n ? await getMappingValue(event, { map: userData })\n : {};\n const userIdMapped = userId\n ? await getMappingValue(event, userId)\n : undefined;\n const clientIdMapped = clientId\n ? await getMappingValue(event, clientId)\n : undefined;\n const sessionAttributesMapped = sessionAttributes\n ? await getMappingValue(event, sessionAttributes)\n : undefined;\n\n // Extract consent from Settings\n const consentAdUserDataValue =\n typeof consentAdUserData === 'boolean'\n ? consentAdUserData\n : typeof consentAdUserData === 'string' && event.consent\n ? event.consent[consentAdUserData]\n : undefined;\n\n const consentAdPersonalizationValue =\n typeof consentAdPersonalization === 'boolean'\n ? consentAdPersonalization\n : typeof consentAdPersonalization === 'string' && event.consent\n ? event.consent[consentAdPersonalization]\n : undefined;\n\n // Build Settings helpers object\n const settingsHelpers: Record<string, unknown> = {};\n if (isObject(userDataMapped)) {\n Object.assign(settingsHelpers, userDataMapped);\n }\n if (userIdMapped !== undefined) settingsHelpers.userId = userIdMapped;\n if (clientIdMapped !== undefined) settingsHelpers.clientId = clientIdMapped;\n if (sessionAttributesMapped !== undefined)\n settingsHelpers.sessionAttributes = sessionAttributesMapped;\n if (consentAdUserDataValue !== undefined)\n settingsHelpers.adUserData = consentAdUserDataValue;\n if (consentAdPersonalizationValue !== undefined)\n settingsHelpers.adPersonalization = consentAdPersonalizationValue;\n\n // Get mapped data from destination config and event mapping\n const configData = validatedConfig.data\n ? await getMappingValue(event, validatedConfig.data)\n : {};\n const eventData = isObject(data) ? data : {};\n\n // Merge: Settings helpers < config.data < event mapping data\n const finalData = {\n ...settingsHelpers,\n ...(isObject(configData) ? configData : {}),\n ...eventData,\n };\n\n // Format event for Data Manager API\n const dataManagerEvent = await formatEvent(event, finalData);\n\n logger.debug('Processing event', {\n name: event.name,\n id: event.id,\n timestamp: event.timestamp,\n });\n\n // Apply event source from settings (required)\n if (!dataManagerEvent.eventSource) {\n dataManagerEvent.eventSource = eventSource;\n }\n\n // Apply request-level consent if event doesn't have consent\n if (!dataManagerEvent.consent && requestConsent) {\n dataManagerEvent.consent = requestConsent;\n }\n\n // Validate required fields before API call\n if (!dataManagerEvent.transactionId) {\n logger.throw('transactionId is required');\n }\n\n // Check if any destination is GA4 (requires eventName)\n const hasGA4Destination = destinations.some(\n (d) => d.operatingAccount?.accountType === 'GOOGLE_ANALYTICS_PROPERTY',\n );\n\n if (hasGA4Destination && !dataManagerEvent.eventName) {\n logger.throw('eventName is required for GA4 destinations');\n }\n\n // Build API request\n const requestBody: IngestEventsRequest = {\n events: [dataManagerEvent],\n destinations,\n };\n\n // Add optional parameters\n if (requestConsent) {\n requestBody.consent = requestConsent;\n }\n\n if (validateOnly) {\n requestBody.validateOnly = true;\n }\n\n if (testEventCode) {\n requestBody.testEventCode = testEventCode;\n }\n\n const authClient = env?.authClient;\n if (!authClient) {\n return logger.throw(\n 'Auth client not initialized. Ensure init() was called successfully.',\n );\n }\n\n let accessToken: string;\n try {\n accessToken = await getAccessToken(authClient);\n } catch (error) {\n logger.error('Authentication failed', { error });\n throw error;\n }\n\n const fetchFn = env?.fetch || fetch;\n const endpoint = `${url}/events:ingest`;\n\n logger.debug('Sending to Data Manager API', {\n endpoint,\n eventCount: requestBody.events.length,\n destinations: destinations.length,\n validateOnly,\n });\n\n const response = await fetchFn(endpoint, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${accessToken}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(requestBody),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n logger.throw(`Data Manager API error (${response.status}): ${errorText}`);\n }\n\n const result: IngestEventsResponse = await response.json();\n\n logger.debug('API response', {\n status: response.status,\n requestId: result.requestId,\n });\n\n // If validation errors exist, throw them\n if (result.validationErrors && result.validationErrors.length > 0) {\n logger.throw(\n `Validation errors: ${JSON.stringify(result.validationErrors)}`,\n );\n }\n\n logger.info('Event processed successfully', {\n requestId: result.requestId,\n });\n};\n","import type { WalkerOS } from '@walkeros/core';\nimport { isString, isDefined } from '@walkeros/core';\nimport type {\n Event,\n UserData,\n UserIdentifier,\n AdIdentifiers,\n Consent,\n ConsentStatus,\n} from './types';\nimport { hashEmail, hashPhone, hashName } from './hash';\n\n/**\n * Format walkerOS event timestamp to RFC 3339 format\n * https://developers.google.com/data-manager/api/reference/rest/v1/Event\n *\n * walkerOS timestamp is in milliseconds, RFC 3339 format: \"2024-01-15T10:30:00Z\"\n */\nexport function formatTimestamp(timestamp: number): string {\n return new Date(timestamp).toISOString();\n}\n\n/**\n * Format user identifiers from mapped data\n * https://developers.google.com/data-manager/api/reference/rest/v1/UserData\n *\n * User data must be explicitly mapped in the mapping configuration.\n * Max 10 identifiers per event\n */\nexport async function formatUserData(\n data: Record<string, unknown>,\n): Promise<UserData | undefined> {\n const identifiers: UserIdentifier[] = [];\n\n // Extract from mapped data only\n // Email\n if (isString(data.email) && data.email) {\n const hashedEmail = await hashEmail(data.email);\n if (hashedEmail) {\n identifiers.push({ emailAddress: hashedEmail });\n }\n }\n\n // Phone\n if (isString(data.phone) && data.phone) {\n const hashedPhone = await hashPhone(data.phone);\n if (hashedPhone) {\n identifiers.push({ phoneNumber: hashedPhone });\n }\n }\n\n // Address from mapped properties\n const hasAddress =\n data.firstName || data.lastName || data.regionCode || data.postalCode;\n\n if (hasAddress) {\n const address: Record<string, string> = {};\n\n if (isString(data.firstName) && data.firstName) {\n address.givenName = await hashName(data.firstName, 'given');\n }\n\n if (isString(data.lastName) && data.lastName) {\n address.familyName = await hashName(data.lastName, 'family');\n }\n\n // Region code is NOT hashed\n if (isString(data.regionCode) && data.regionCode) {\n address.regionCode = data.regionCode.toUpperCase();\n }\n\n // Postal code is NOT hashed\n if (isString(data.postalCode) && data.postalCode) {\n address.postalCode = data.postalCode;\n }\n\n if (Object.keys(address).length > 0) {\n identifiers.push({ address });\n }\n }\n\n // Limit to 10 identifiers\n if (identifiers.length === 0) return undefined;\n\n return {\n userIdentifiers: identifiers.slice(0, 10),\n };\n}\n\n/**\n * Extract and format attribution identifiers from mapped data\n * https://developers.google.com/data-manager/api/reference/rest/v1/AdIdentifiers\n *\n * Attribution identifiers should be mapped explicitly in the mapping configuration.\n * Example: { gclid: 'context.gclid', gbraid: 'context.gbraid' }\n */\nexport function formatAdIdentifiers(\n data: Record<string, unknown>,\n): AdIdentifiers | undefined {\n const identifiers: AdIdentifiers = {};\n\n // Extract from mapped data (already processed by mapping system)\n if (isString(data.gclid) && data.gclid) {\n identifiers.gclid = data.gclid;\n }\n if (isString(data.gbraid) && data.gbraid) {\n identifiers.gbraid = data.gbraid;\n }\n if (isString(data.wbraid) && data.wbraid) {\n identifiers.wbraid = data.wbraid;\n }\n if (isString(data.sessionAttributes) && data.sessionAttributes) {\n identifiers.sessionAttributes = data.sessionAttributes;\n }\n\n return Object.keys(identifiers).length > 0 ? identifiers : undefined;\n}\n\n/**\n * Map walkerOS consent to Data Manager consent format\n * https://developers.google.com/data-manager/api/devguides/concepts/dma\n *\n * walkerOS: { marketing: true, personalization: false }\n * Data Manager: { adUserData: 'CONSENT_GRANTED', adPersonalization: 'CONSENT_DENIED' }\n */\nexport function formatConsent(\n walkerOSConsent: WalkerOS.Consent | undefined,\n): Consent | undefined {\n if (!walkerOSConsent) return undefined;\n\n const consent: Consent = {};\n\n // Map marketing consent to adUserData\n if (isDefined(walkerOSConsent.marketing)) {\n consent.adUserData = walkerOSConsent.marketing\n ? 'CONSENT_GRANTED'\n : 'CONSENT_DENIED';\n }\n\n // Map personalization consent to adPersonalization\n if (isDefined(walkerOSConsent.personalization)) {\n consent.adPersonalization = walkerOSConsent.personalization\n ? 'CONSENT_GRANTED'\n : 'CONSENT_DENIED';\n }\n\n return Object.keys(consent).length > 0 ? consent : undefined;\n}\n\n/**\n * Format complete event for Data Manager API\n * https://developers.google.com/data-manager/api/reference/rest/v1/Event\n */\nexport async function formatEvent(\n event: WalkerOS.Event,\n mappedData?: Record<string, unknown>,\n): Promise<Event> {\n const dataManagerEvent: Event = {\n eventTimestamp: formatTimestamp(event.timestamp),\n };\n\n // Use only mapped data (no fallback to event.data)\n const data = mappedData || {};\n\n // Transaction ID for deduplication\n if (isString(data.transactionId) && data.transactionId) {\n dataManagerEvent.transactionId = data.transactionId.substring(0, 512);\n }\n\n // Client ID (GA)\n if (isString(data.clientId) && data.clientId) {\n dataManagerEvent.clientId = data.clientId.substring(0, 255);\n }\n\n // User ID\n if (isString(data.userId) && data.userId) {\n dataManagerEvent.userId = data.userId.substring(0, 256);\n }\n\n // User data\n const userData = await formatUserData(data);\n if (userData) {\n dataManagerEvent.userData = userData;\n }\n\n // Attribution identifiers\n const adIdentifiers = formatAdIdentifiers(data);\n if (adIdentifiers) {\n dataManagerEvent.adIdentifiers = adIdentifiers;\n }\n\n // Conversion value\n if (typeof data.conversionValue === 'number') {\n dataManagerEvent.conversionValue = data.conversionValue;\n }\n\n // Currency\n if (isString(data.currency) && data.currency) {\n dataManagerEvent.currency = data.currency.substring(0, 3).toUpperCase();\n }\n\n // Cart data\n if (data.cartData && typeof data.cartData === 'object') {\n dataManagerEvent.cartData = data.cartData as Event['cartData'];\n }\n\n // Event name (for GA4)\n if (isString(data.eventName) && data.eventName) {\n dataManagerEvent.eventName = data.eventName.substring(0, 40);\n }\n\n // Event source\n if (isString(data.eventSource) && data.eventSource) {\n dataManagerEvent.eventSource = data.eventSource as Event['eventSource'];\n }\n\n // Consent - check mapped data first, then fallback to event.consent\n const mappedConsent: Consent = {};\n\n // Check for mapped consent values (from Settings or event mapping)\n if (typeof data.adUserData === 'boolean') {\n mappedConsent.adUserData = data.adUserData\n ? 'CONSENT_GRANTED'\n : 'CONSENT_DENIED';\n }\n if (typeof data.adPersonalization === 'boolean') {\n mappedConsent.adPersonalization = data.adPersonalization\n ? 'CONSENT_GRANTED'\n : 'CONSENT_DENIED';\n }\n\n // If no mapped consent, fall back to event.consent\n if (Object.keys(mappedConsent).length === 0) {\n const eventConsent = formatConsent(event.consent);\n if (eventConsent) {\n dataManagerEvent.consent = eventConsent;\n }\n } else {\n dataManagerEvent.consent = mappedConsent;\n }\n\n return dataManagerEvent;\n}\n","import { isString } from '@walkeros/core';\nimport { getHashServer } from '@walkeros/server-core';\n\n/**\n * Normalize email address according to Google Data Manager requirements\n * https://developers.google.com/data-manager/api/devguides/concepts/formatting#email\n *\n * 1. Trim whitespace\n * 2. Convert to lowercase\n * 3. Remove dots (.) for gmail.com and googlemail.com\n * 4. SHA-256 hash\n */\nexport async function hashEmail(email: string): Promise<string> {\n if (!isString(email) || !email) return '';\n\n // Trim and lowercase\n let normalized = email.trim().toLowerCase();\n\n // Remove dots for Gmail addresses\n if (\n normalized.endsWith('@gmail.com') ||\n normalized.endsWith('@googlemail.com')\n ) {\n const [localPart, domain] = normalized.split('@');\n normalized = `${localPart.replace(/\\./g, '')}@${domain}`;\n }\n\n return getHashServer(normalized);\n}\n\n/**\n * Normalize phone number to E.164 format and hash\n * https://developers.google.com/data-manager/api/devguides/concepts/formatting#phone\n *\n * E.164 format: +[country code][number] (max 15 digits after +)\n * Example: +18005550100\n *\n * 1. Remove all non-digit characters except leading +\n * 2. Ensure it starts with +\n * 3. SHA-256 hash\n */\nexport async function hashPhone(phone: string): Promise<string> {\n if (!isString(phone) || !phone) return '';\n\n // Remove all non-digit characters except + at the start\n let normalized = phone.trim();\n\n // Extract country code if present\n const hasPlus = normalized.startsWith('+');\n\n // Remove all non-digits\n normalized = normalized.replace(/\\D/g, '');\n\n // Add + prefix if it was there or if number is long enough\n if (hasPlus || normalized.length > 10) {\n normalized = `+${normalized}`;\n } else {\n // Assume US number if no country code (default behavior)\n normalized = `+1${normalized}`;\n }\n\n return getHashServer(normalized);\n}\n\n/**\n * Normalize and hash a name (first or last name)\n * https://developers.google.com/data-manager/api/devguides/concepts/formatting#name\n *\n * 1. Trim whitespace\n * 2. Convert to lowercase\n * 3. Remove common prefixes (Mr., Mrs., Dr.) for first names\n * 4. Remove common suffixes (Jr., Sr., III) for last names\n * 5. SHA-256 hash\n */\nexport async function hashName(\n name: string,\n type: 'given' | 'family' = 'given',\n): Promise<string> {\n if (!isString(name) || !name) return '';\n\n // Trim and lowercase\n let normalized = name.trim().toLowerCase();\n\n // Remove prefixes for given names\n if (type === 'given') {\n const prefixes = ['mr.', 'mrs.', 'ms.', 'miss.', 'dr.', 'prof.'];\n for (const prefix of prefixes) {\n if (normalized.startsWith(prefix)) {\n normalized = normalized.substring(prefix.length).trim();\n break;\n }\n }\n }\n\n // Remove suffixes for family names (check with and without space)\n // Sort by length (longest first) to match \"iii\" before \"ii\"\n if (type === 'family') {\n const suffixes = ['jr.', 'sr.', 'iii', 'ii', 'iv', 'v'];\n for (const suffix of suffixes) {\n // Check for suffix with space before it (e.g., \" jr.\")\n const suffixWithSpace = ` ${suffix}`;\n if (normalized.endsWith(suffixWithSpace)) {\n normalized = normalized\n .substring(0, normalized.length - suffixWithSpace.length)\n .trim();\n break;\n }\n // Check for suffix without space\n if (normalized.endsWith(suffix)) {\n normalized = normalized\n .substring(0, normalized.length - suffix.length)\n .trim();\n break;\n }\n }\n }\n\n return getHashServer(normalized);\n}\n\n/**\n * Hash multiple email addresses\n */\nexport async function hashEmails(emails: string[]): Promise<string[]> {\n return Promise.all(emails.map((email) => hashEmail(email)));\n}\n\n/**\n * Hash multiple phone numbers\n */\nexport async function hashPhones(phones: string[]): Promise<string[]> {\n return Promise.all(phones.map((phone) => hashPhone(phone)));\n}\n","import { GoogleAuth, type OAuth2Client } from 'google-auth-library';\nimport type { Settings } from './types';\n\nconst DEFAULT_SCOPES = ['https://www.googleapis.com/auth/datamanager'];\n\n/**\n * Authentication error with cause tracking\n */\nexport class AuthError extends Error {\n constructor(\n message: string,\n public cause?: Error,\n ) {\n super(message);\n this.name = 'DataManagerAuthError';\n }\n}\n\n/**\n * Creates Google Auth client based on settings\n *\n * Authentication priority:\n * 1. credentials (inline service account) - if provided\n * 2. keyFilename (service account file) - if provided\n * 3. Application Default Credentials (ADC) - automatic fallback\n * - GOOGLE_APPLICATION_CREDENTIALS env var\n * - GCP metadata server (Cloud Functions, Cloud Run, GCE)\n *\n * @param settings - Configuration with auth options\n * @returns OAuth2Client for token retrieval\n * @throws AuthError if authentication fails\n */\nexport async function createAuthClient(\n settings: Settings,\n): Promise<OAuth2Client> {\n const { credentials, keyFilename, scopes = DEFAULT_SCOPES } = settings;\n\n try {\n if (credentials) {\n const auth = new GoogleAuth({\n credentials,\n scopes,\n });\n return (await auth.getClient()) as OAuth2Client;\n }\n\n if (keyFilename) {\n const auth = new GoogleAuth({\n keyFilename,\n scopes,\n });\n return (await auth.getClient()) as OAuth2Client;\n }\n\n const auth = new GoogleAuth({ scopes });\n return (await auth.getClient()) as OAuth2Client;\n } catch (error) {\n throw new AuthError(\n 'Failed to create auth client. Check credentials configuration or ensure GOOGLE_APPLICATION_CREDENTIALS is set.',\n error instanceof Error ? error : undefined,\n );\n }\n}\n\n/**\n * Gets access token from auth client\n * Automatically returns cached token if valid or refreshes if expired\n *\n * @param authClient - OAuth2 client from createAuthClient()\n * @returns Fresh access token\n * @throws AuthError if token retrieval fails\n */\nexport async function getAccessToken(\n authClient: OAuth2Client,\n): Promise<string> {\n try {\n const tokenResponse = await authClient.getAccessToken();\n\n if (!tokenResponse.token) {\n throw new AuthError('Auth client returned empty token');\n }\n\n return tokenResponse.token;\n } catch (error) {\n throw new AuthError(\n 'Failed to obtain access token',\n error instanceof Error ? error : undefined,\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';\nimport type { OAuth2Client } from 'google-auth-library';\n\nexport interface Settings {\n /**\n * Service account credentials (client_email + private_key)\n * Recommended for serverless environments (AWS Lambda, Docker, etc.)\n */\n credentials?: {\n client_email: string;\n private_key: string;\n };\n\n /**\n * Path to service account JSON file\n * For local development or environments with filesystem access\n */\n keyFilename?: string;\n\n /**\n * OAuth scopes for Data Manager API\n * @default ['https://www.googleapis.com/auth/datamanager']\n */\n scopes?: string[];\n\n /** Array of destination accounts and conversion actions/user lists */\n destinations: Destination[];\n\n /** Event source for all events. Defaults to WEB if not specified */\n eventSource?: EventSource;\n\n /** Maximum number of events to batch before sending (max 2000) */\n batchSize?: number;\n\n /** Time in milliseconds to wait before auto-flushing batch */\n batchInterval?: number;\n\n /** If true, validate request without ingestion (testing mode) */\n validateOnly?: boolean;\n\n /** Override API endpoint (for testing) */\n url?: string;\n\n /** Request-level consent for all events */\n consent?: Consent;\n\n /** Test event code for debugging (optional) */\n testEventCode?: string;\n\n /** Guided helpers: User data mapping (applies to all events) */\n userData?: WalkerOSMapping.Map;\n\n /** Guided helper: First-party user ID */\n userId?: WalkerOSMapping.Value;\n\n /** Guided helper: GA4 client ID */\n clientId?: WalkerOSMapping.Value;\n\n /** Guided helper: Privacy-safe attribution (Google's sessionAttributes) */\n sessionAttributes?: WalkerOSMapping.Value;\n\n /** Consent mapping: Map consent field to adUserData (string = field name, boolean = static value) */\n consentAdUserData?: string | boolean;\n\n /** Consent mapping: Map consent field to adPersonalization (string = field name, boolean = static value) */\n consentAdPersonalization?: string | boolean;\n}\n\nexport interface Mapping {\n // Attribution identifiers (optional, for explicit mapping)\n gclid?: WalkerOSMapping.Value;\n gbraid?: WalkerOSMapping.Value;\n wbraid?: WalkerOSMapping.Value;\n sessionAttributes?: WalkerOSMapping.Value;\n}\n\nexport interface Env extends DestinationServer.Env {\n fetch?: typeof fetch;\n authClient?: OAuth2Client | null;\n}\n\nexport type InitSettings = Partial<Settings>;\n\nexport type Types = CoreDestination.Types<Settings, Mapping, Env, InitSettings>;\n\nexport interface DestinationInterface\n extends DestinationServer.Destination<Types> {\n init: DestinationServer.InitFn<Types>;\n}\n\nexport type Config = {\n settings: Settings;\n} & DestinationServer.Config<Types>;\n\n/**\n * Config after validation - settings is guaranteed to exist with required fields\n * Use this type after calling getConfig() to get proper type narrowing\n * After validation, eventSource is always set (defaults to 'WEB')\n */\nexport type ValidatedConfig = Omit<Config, 'settings'> & {\n settings: Settings & { eventSource: EventSource };\n};\n\nexport type InitFn = DestinationServer.InitFn<Types>;\nexport type PushFn = DestinationServer.PushFn<Types>;\n\nexport type PartialConfig = DestinationServer.PartialConfig<Types>;\n\nexport type PushEvents = DestinationServer.PushEvents<Mapping>;\n\nexport type Rule = WalkerOSMapping.Rule<Mapping>;\nexport type Rules = WalkerOSMapping.Rules<Rule>;\n\n// Google Data Manager API Types\n// https://developers.google.com/data-manager/api/reference\n\n/**\n * Destination account and product identifier\n * https://developers.google.com/data-manager/api/reference/rest/v1/Destination\n */\nexport interface Destination {\n /** Reference identifier for this destination */\n reference?: string;\n\n /** Login account (account initiating the request) */\n loginAccount?: ProductAccount;\n\n /** Linked account (child account linked to login account) */\n linkedAccount?: ProductAccount;\n\n /** Operating account (account where data is sent) */\n operatingAccount?: ProductAccount;\n\n /** Product-specific destination ID (conversion action or user list) */\n productDestinationId?: string;\n}\n\n/**\n * Product account information\n */\nexport interface ProductAccount {\n /** Account ID (e.g., \"123-456-7890\" for Google Ads) */\n accountId: string;\n\n /** Type of account */\n accountType: AccountType;\n}\n\nexport type AccountType =\n | 'ACCOUNT_TYPE_UNSPECIFIED'\n | 'GOOGLE_ADS'\n | 'DISPLAY_VIDEO_ADVERTISER'\n | 'DISPLAY_VIDEO_PARTNER'\n | 'GOOGLE_ANALYTICS_PROPERTY'\n | 'DATA_PARTNER';\n\nexport type EventSource = 'WEB' | 'APP' | 'IN_STORE' | 'PHONE' | 'OTHER';\n\n/**\n * Consent for Digital Markets Act (DMA) compliance\n * https://developers.google.com/data-manager/api/devguides/concepts/dma\n */\nexport interface Consent {\n /** Consent for data collection and use */\n adUserData?: ConsentStatus;\n\n /** Consent for ad personalization */\n adPersonalization?: ConsentStatus;\n}\n\nexport type ConsentStatus = 'CONSENT_GRANTED' | 'CONSENT_DENIED';\n\n/**\n * Request body for events.ingest API\n * https://developers.google.com/data-manager/api/reference/rest/v1/events/ingest\n */\nexport interface IngestEventsRequest {\n /** Array of destinations for these events (max 10) */\n destinations: Destination[];\n\n /** Array of events to ingest (max 2000) */\n events: Event[];\n\n /** Request-level consent (overridden by event-level) */\n consent?: Consent;\n\n /** If true, validate without ingestion */\n validateOnly?: boolean;\n\n /** Test event code for debugging */\n testEventCode?: string;\n}\n\n/**\n * Single event for ingestion\n * https://developers.google.com/data-manager/api/reference/rest/v1/Event\n */\nexport interface Event {\n /** Destination references for routing */\n destinationReferences?: string[];\n\n /** Transaction ID for deduplication (max 512 chars) */\n transactionId?: string;\n\n /** Event timestamp in RFC 3339 format */\n eventTimestamp?: string;\n\n /** Last updated timestamp in RFC 3339 format */\n lastUpdatedTimestamp?: string;\n\n /** User data with identifiers (max 10 identifiers) */\n userData?: UserData;\n\n /** Event-level consent (overrides request-level) */\n consent?: Consent;\n\n /** Attribution identifiers */\n adIdentifiers?: AdIdentifiers;\n\n /** Currency code (ISO 4217, 3 chars) */\n currency?: string;\n\n /** Conversion value */\n conversionValue?: number;\n\n /** Source of the event */\n eventSource?: EventSource;\n\n /** Device information for the event */\n eventDeviceInfo?: DeviceInfo;\n\n /** Shopping cart data */\n cartData?: CartData;\n\n /** Custom variables for the event */\n customVariables?: CustomVariable[];\n\n /** Experimental fields (subject to change) */\n experimentalFields?: ExperimentalField[];\n\n /** User properties */\n userProperties?: UserProperties;\n\n /** Event name for GA4 (max 40 chars, required for GA4) */\n eventName?: string;\n\n /** Google Analytics client ID (max 255 chars) */\n clientId?: string;\n\n /** First-party user ID (max 256 chars) */\n userId?: string;\n\n /** Additional event parameters */\n additionalEventParameters?: EventParameter[];\n}\n\n/**\n * Device information\n */\nexport interface DeviceInfo {\n /** User agent string */\n userAgent?: string;\n}\n\n/**\n * Custom variable\n */\nexport interface CustomVariable {\n /** Variable name */\n name?: string;\n\n /** Variable value */\n value?: string;\n}\n\n/**\n * Experimental field\n */\nexport interface ExperimentalField {\n /** Field name */\n name?: string;\n\n /** Field value */\n value?: string;\n}\n\n/**\n * User properties\n */\nexport interface UserProperties {\n /** Property values */\n [key: string]: string | number | boolean | undefined;\n}\n\n/**\n * Event parameter\n */\nexport interface EventParameter {\n /** Parameter name */\n name?: string;\n\n /** Parameter value */\n value?: string | number;\n}\n\n/**\n * User data with identifiers\n * https://developers.google.com/data-manager/api/reference/rest/v1/UserData\n */\nexport interface UserData {\n /** Array of user identifiers (max 10) */\n userIdentifiers: UserIdentifier[];\n}\n\n/**\n * User identifier (email, phone, or address)\n */\nexport type UserIdentifier =\n | { emailAddress: string }\n | { phoneNumber: string }\n | { address: Address };\n\n/**\n * Address for user identification\n * https://developers.google.com/data-manager/api/reference/rest/v1/Address\n */\nexport interface Address {\n /** Given name (first name) - SHA-256 hashed */\n givenName?: string;\n\n /** Family name (last name) - SHA-256 hashed */\n familyName?: string;\n\n /** ISO-3166-1 alpha-2 country code - NOT hashed (e.g., \"US\", \"GB\") */\n regionCode?: string;\n\n /** Postal code - NOT hashed */\n postalCode?: string;\n}\n\n/**\n * Attribution identifiers\n * https://developers.google.com/data-manager/api/reference/rest/v1/AdIdentifiers\n */\nexport interface AdIdentifiers {\n /** Session attributes (privacy-safe attribution) */\n sessionAttributes?: string;\n\n /** Google Click ID (primary attribution) */\n gclid?: string;\n\n /** iOS attribution identifier (post-ATT) */\n gbraid?: string;\n\n /** Web-to-app attribution identifier */\n wbraid?: string;\n\n /** Device information for landing page */\n landingPageDeviceInfo?: DeviceInfo;\n}\n\n/**\n * Shopping cart data\n * https://developers.google.com/data-manager/api/reference/rest/v1/CartData\n */\nexport interface CartData {\n /** Array of cart items (max 200) */\n items: CartItem[];\n}\n\n/**\n * Single cart item\n * https://developers.google.com/data-manager/api/reference/rest/v1/CartItem\n */\nexport interface CartItem {\n /** Merchant product ID (max 127 chars) */\n merchantProductId?: string;\n\n /** Item price */\n price?: number;\n\n /** Item quantity */\n quantity?: number;\n}\n\n/**\n * Response from events.ingest API\n * https://developers.google.com/data-manager/api/reference/rest/v1/IngestEventsResponse\n */\nexport interface IngestEventsResponse {\n /** Unique request ID for status checking */\n requestId: string;\n\n /** Validation errors (only if validateOnly=true) */\n validationErrors?: ValidationError[];\n}\n\n/**\n * Validation error\n */\nexport interface ValidationError {\n /** Error code */\n code: string;\n\n /** Human-readable error message */\n message: string;\n\n /** Field path that caused the error */\n fieldPath?: string;\n}\n\n/**\n * Request status response\n * https://developers.google.com/data-manager/api/reference/rest/v1/requestStatus/retrieve\n */\nexport interface RequestStatusResponse {\n /** Unique request ID */\n requestId: string;\n\n /** Processing state */\n state: RequestState;\n\n /** Number of events successfully ingested */\n eventsIngested?: number;\n\n /** Number of events that failed */\n eventsFailed?: number;\n\n /** Array of errors (if any) */\n errors?: RequestError[];\n}\n\nexport type RequestState =\n | 'STATE_UNSPECIFIED'\n | 'PENDING'\n | 'PROCESSING'\n | 'SUCCEEDED'\n | 'FAILED'\n | 'PARTIALLY_SUCCEEDED';\n\n/**\n * Request error\n */\nexport interface RequestError {\n /** Error code */\n code: string;\n\n /** Human-readable error message */\n message: string;\n\n /** Number of events affected by this error */\n eventCount?: number;\n}\n","import type { DestinationInterface } from './types';\nimport { getConfig } from './config';\nimport { push } from './push';\nimport { createAuthClient } from './auth';\n\nexport * as DestinationDataManager from './types';\n\nexport const destinationDataManager: DestinationInterface = {\n type: 'datamanager',\n\n config: {},\n\n async init({ config: partialConfig, env, logger }) {\n logger.debug('Data Manager init started');\n logger.info('Data Manager initializing...');\n\n // getConfig validates required fields and returns ValidatedConfig\n const config = getConfig(partialConfig, logger);\n\n logger.debug('Settings validated', {\n validateOnly: config.settings.validateOnly,\n destinationCount: config.settings.destinations.length,\n eventSource: config.settings.eventSource,\n });\n\n try {\n logger.debug('Creating auth client...');\n const authClient = await createAuthClient(config.settings);\n logger.debug('Auth client created successfully');\n\n return {\n ...config,\n env: {\n ...env,\n authClient,\n },\n };\n } catch (error) {\n logger.throw(\n `Data Manager authentication failed: ${error instanceof Error ? error.message : 'Unknown error'}`,\n );\n }\n },\n\n async push(event, { config, mapping, data, collector, env, logger }) {\n return await push(event, { config, mapping, data, collector, env, logger });\n },\n};\n\nexport default destinationDataManager;\n"],"mappings":"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","names":["isString","isString","auth"]}
|
|
1
|
+
{"version":3,"sources":["../src/config.ts","../src/push.ts","../src/format.ts","../src/hash.ts","../src/auth.ts","../src/types/index.ts","../src/index.ts"],"sourcesContent":["import type {\n ValidatedConfig,\n Settings,\n PartialConfig,\n EventSource,\n} from './types';\nimport type { Logger } from '@walkeros/core';\n\nexport function getConfig(\n partialConfig: PartialConfig = {},\n logger: Logger.Instance,\n): ValidatedConfig {\n const settings = (partialConfig.settings || {}) as Partial<Settings>;\n const { destinations, eventSource = 'WEB' } = settings;\n\n if (!destinations || destinations.length === 0)\n logger.throw('Config settings destinations missing or empty');\n\n const settingsConfig: Settings & { eventSource: EventSource } = {\n ...settings,\n destinations,\n eventSource,\n };\n\n return { ...partialConfig, settings: settingsConfig };\n}\n","import type { PushFn } from './types';\nimport type { IngestEventsRequest, IngestEventsResponse } from './types';\nimport { getMappingValue, isObject } from '@walkeros/core';\nimport { formatEvent, formatConsent } from './format';\nimport { getAccessToken } from './auth';\nimport { getConfig } from './config';\n\nexport const push: PushFn = async function (\n event,\n { config, mapping, data, collector, env, logger },\n) {\n // Validate config and get typed settings\n const validatedConfig = getConfig(config, logger);\n const {\n destinations,\n eventSource,\n validateOnly = false,\n url = 'https://datamanager.googleapis.com/v1',\n consent: requestConsent,\n testEventCode,\n userData,\n userId,\n clientId,\n sessionAttributes,\n consentAdUserData,\n consentAdPersonalization,\n } = validatedConfig.settings;\n\n // Extract Settings guided helpers\n const userDataMapped = userData\n ? await getMappingValue(event, { map: userData })\n : {};\n const userIdMapped = userId\n ? await getMappingValue(event, userId)\n : undefined;\n const clientIdMapped = clientId\n ? await getMappingValue(event, clientId)\n : undefined;\n const sessionAttributesMapped = sessionAttributes\n ? await getMappingValue(event, sessionAttributes)\n : undefined;\n\n // Extract consent from Settings\n const consentAdUserDataValue =\n typeof consentAdUserData === 'boolean'\n ? consentAdUserData\n : typeof consentAdUserData === 'string' && event.consent\n ? event.consent[consentAdUserData]\n : undefined;\n\n const consentAdPersonalizationValue =\n typeof consentAdPersonalization === 'boolean'\n ? consentAdPersonalization\n : typeof consentAdPersonalization === 'string' && event.consent\n ? event.consent[consentAdPersonalization]\n : undefined;\n\n // Build Settings helpers object\n const settingsHelpers: Record<string, unknown> = {};\n if (isObject(userDataMapped)) {\n Object.assign(settingsHelpers, userDataMapped);\n }\n if (userIdMapped !== undefined) settingsHelpers.userId = userIdMapped;\n if (clientIdMapped !== undefined) settingsHelpers.clientId = clientIdMapped;\n if (sessionAttributesMapped !== undefined)\n settingsHelpers.sessionAttributes = sessionAttributesMapped;\n if (consentAdUserDataValue !== undefined)\n settingsHelpers.adUserData = consentAdUserDataValue;\n if (consentAdPersonalizationValue !== undefined)\n settingsHelpers.adPersonalization = consentAdPersonalizationValue;\n\n // Get mapped data from destination config and event mapping\n const configData = validatedConfig.data\n ? await getMappingValue(event, validatedConfig.data)\n : {};\n const eventData = isObject(data) ? data : {};\n\n // Merge: Settings helpers < config.data < event mapping data\n const finalData = {\n ...settingsHelpers,\n ...(isObject(configData) ? configData : {}),\n ...eventData,\n };\n\n // Format event for Data Manager API\n const dataManagerEvent = await formatEvent(event, finalData);\n\n // Apply event source from settings (required)\n if (!dataManagerEvent.eventSource) {\n dataManagerEvent.eventSource = eventSource;\n }\n\n // Apply request-level consent if event doesn't have consent\n if (!dataManagerEvent.consent && requestConsent) {\n dataManagerEvent.consent = requestConsent;\n }\n\n // Validate required fields before API call\n if (!dataManagerEvent.transactionId) {\n logger.throw('transactionId is required');\n }\n\n // Check if any destination is GA4 (requires eventName)\n const hasGA4Destination = destinations.some(\n (d) => d.operatingAccount?.accountType === 'GOOGLE_ANALYTICS_PROPERTY',\n );\n\n if (hasGA4Destination && !dataManagerEvent.eventName) {\n logger.throw('eventName is required for GA4 destinations');\n }\n\n // Build API request\n const requestBody: IngestEventsRequest = {\n events: [dataManagerEvent],\n destinations,\n };\n\n // Add optional parameters\n if (requestConsent) {\n requestBody.consent = requestConsent;\n }\n\n if (validateOnly) {\n requestBody.validateOnly = true;\n }\n\n if (testEventCode) {\n requestBody.testEventCode = testEventCode;\n }\n\n const authClient = env?.authClient;\n if (!authClient) {\n return logger.throw(\n 'Auth client not initialized. Ensure init() was called successfully.',\n );\n }\n\n let accessToken: string;\n try {\n accessToken = await getAccessToken(authClient);\n } catch (error) {\n logger.error('Authentication failed', { error });\n throw error;\n }\n\n const fetchFn = env?.fetch || fetch;\n const endpoint = `${url}/events:ingest`;\n\n logger.debug('Sending to Data Manager API', {\n endpoint,\n eventCount: requestBody.events.length,\n destinations: destinations.length,\n validateOnly,\n });\n\n const response = await fetchFn(endpoint, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${accessToken}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(requestBody),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n logger.throw(`Data Manager API error (${response.status}): ${errorText}`);\n }\n\n const result: IngestEventsResponse = await response.json();\n\n logger.debug('API response', {\n status: response.status,\n requestId: result.requestId,\n });\n\n // If validation errors exist, throw them\n if (result.validationErrors && result.validationErrors.length > 0) {\n logger.throw(\n `Validation errors: ${JSON.stringify(result.validationErrors)}`,\n );\n }\n};\n","import type { WalkerOS } from '@walkeros/core';\nimport { isString, isDefined } from '@walkeros/core';\nimport type {\n Event,\n UserData,\n UserIdentifier,\n AdIdentifiers,\n Consent,\n ConsentStatus,\n} from './types';\nimport { hashEmail, hashPhone, hashName } from './hash';\n\n/**\n * Format walkerOS event timestamp to RFC 3339 format\n * https://developers.google.com/data-manager/api/reference/rest/v1/Event\n *\n * walkerOS timestamp is in milliseconds, RFC 3339 format: \"2024-01-15T10:30:00Z\"\n */\nexport function formatTimestamp(timestamp: number): string {\n return new Date(timestamp).toISOString();\n}\n\n/**\n * Format user identifiers from mapped data\n * https://developers.google.com/data-manager/api/reference/rest/v1/UserData\n *\n * User data must be explicitly mapped in the mapping configuration.\n * Max 10 identifiers per event\n */\nexport async function formatUserData(\n data: Record<string, unknown>,\n): Promise<UserData | undefined> {\n const identifiers: UserIdentifier[] = [];\n\n // Extract from mapped data only\n // Email\n if (isString(data.email) && data.email) {\n const hashedEmail = await hashEmail(data.email);\n if (hashedEmail) {\n identifiers.push({ emailAddress: hashedEmail });\n }\n }\n\n // Phone\n if (isString(data.phone) && data.phone) {\n const hashedPhone = await hashPhone(data.phone);\n if (hashedPhone) {\n identifiers.push({ phoneNumber: hashedPhone });\n }\n }\n\n // Address from mapped properties\n const hasAddress =\n data.firstName || data.lastName || data.regionCode || data.postalCode;\n\n if (hasAddress) {\n const address: Record<string, string> = {};\n\n if (isString(data.firstName) && data.firstName) {\n address.givenName = await hashName(data.firstName, 'given');\n }\n\n if (isString(data.lastName) && data.lastName) {\n address.familyName = await hashName(data.lastName, 'family');\n }\n\n // Region code is NOT hashed\n if (isString(data.regionCode) && data.regionCode) {\n address.regionCode = data.regionCode.toUpperCase();\n }\n\n // Postal code is NOT hashed\n if (isString(data.postalCode) && data.postalCode) {\n address.postalCode = data.postalCode;\n }\n\n if (Object.keys(address).length > 0) {\n identifiers.push({ address });\n }\n }\n\n // Limit to 10 identifiers\n if (identifiers.length === 0) return undefined;\n\n return {\n userIdentifiers: identifiers.slice(0, 10),\n };\n}\n\n/**\n * Extract and format attribution identifiers from mapped data\n * https://developers.google.com/data-manager/api/reference/rest/v1/AdIdentifiers\n *\n * Attribution identifiers should be mapped explicitly in the mapping configuration.\n * Example: { gclid: 'context.gclid', gbraid: 'context.gbraid' }\n */\nexport function formatAdIdentifiers(\n data: Record<string, unknown>,\n): AdIdentifiers | undefined {\n const identifiers: AdIdentifiers = {};\n\n // Extract from mapped data (already processed by mapping system)\n if (isString(data.gclid) && data.gclid) {\n identifiers.gclid = data.gclid;\n }\n if (isString(data.gbraid) && data.gbraid) {\n identifiers.gbraid = data.gbraid;\n }\n if (isString(data.wbraid) && data.wbraid) {\n identifiers.wbraid = data.wbraid;\n }\n if (isString(data.sessionAttributes) && data.sessionAttributes) {\n identifiers.sessionAttributes = data.sessionAttributes;\n }\n\n return Object.keys(identifiers).length > 0 ? identifiers : undefined;\n}\n\n/**\n * Map walkerOS consent to Data Manager consent format\n * https://developers.google.com/data-manager/api/devguides/concepts/dma\n *\n * walkerOS: { marketing: true, personalization: false }\n * Data Manager: { adUserData: 'CONSENT_GRANTED', adPersonalization: 'CONSENT_DENIED' }\n */\nexport function formatConsent(\n walkerOSConsent: WalkerOS.Consent | undefined,\n): Consent | undefined {\n if (!walkerOSConsent) return undefined;\n\n const consent: Consent = {};\n\n // Map marketing consent to adUserData\n if (isDefined(walkerOSConsent.marketing)) {\n consent.adUserData = walkerOSConsent.marketing\n ? 'CONSENT_GRANTED'\n : 'CONSENT_DENIED';\n }\n\n // Map personalization consent to adPersonalization\n if (isDefined(walkerOSConsent.personalization)) {\n consent.adPersonalization = walkerOSConsent.personalization\n ? 'CONSENT_GRANTED'\n : 'CONSENT_DENIED';\n }\n\n return Object.keys(consent).length > 0 ? consent : undefined;\n}\n\n/**\n * Format complete event for Data Manager API\n * https://developers.google.com/data-manager/api/reference/rest/v1/Event\n */\nexport async function formatEvent(\n event: WalkerOS.Event,\n mappedData?: Record<string, unknown>,\n): Promise<Event> {\n const dataManagerEvent: Event = {\n eventTimestamp: formatTimestamp(event.timestamp),\n };\n\n // Use only mapped data (no fallback to event.data)\n const data = mappedData || {};\n\n // Transaction ID for deduplication\n if (isString(data.transactionId) && data.transactionId) {\n dataManagerEvent.transactionId = data.transactionId.substring(0, 512);\n }\n\n // Client ID (GA)\n if (isString(data.clientId) && data.clientId) {\n dataManagerEvent.clientId = data.clientId.substring(0, 255);\n }\n\n // User ID\n if (isString(data.userId) && data.userId) {\n dataManagerEvent.userId = data.userId.substring(0, 256);\n }\n\n // User data\n const userData = await formatUserData(data);\n if (userData) {\n dataManagerEvent.userData = userData;\n }\n\n // Attribution identifiers\n const adIdentifiers = formatAdIdentifiers(data);\n if (adIdentifiers) {\n dataManagerEvent.adIdentifiers = adIdentifiers;\n }\n\n // Conversion value\n if (typeof data.conversionValue === 'number') {\n dataManagerEvent.conversionValue = data.conversionValue;\n }\n\n // Currency\n if (isString(data.currency) && data.currency) {\n dataManagerEvent.currency = data.currency.substring(0, 3).toUpperCase();\n }\n\n // Cart data\n if (data.cartData && typeof data.cartData === 'object') {\n dataManagerEvent.cartData = data.cartData as Event['cartData'];\n }\n\n // Event name (for GA4)\n if (isString(data.eventName) && data.eventName) {\n dataManagerEvent.eventName = data.eventName.substring(0, 40);\n }\n\n // Event source\n if (isString(data.eventSource) && data.eventSource) {\n dataManagerEvent.eventSource = data.eventSource as Event['eventSource'];\n }\n\n // Consent - check mapped data first, then fallback to event.consent\n const mappedConsent: Consent = {};\n\n // Check for mapped consent values (from Settings or event mapping)\n if (typeof data.adUserData === 'boolean') {\n mappedConsent.adUserData = data.adUserData\n ? 'CONSENT_GRANTED'\n : 'CONSENT_DENIED';\n }\n if (typeof data.adPersonalization === 'boolean') {\n mappedConsent.adPersonalization = data.adPersonalization\n ? 'CONSENT_GRANTED'\n : 'CONSENT_DENIED';\n }\n\n // If no mapped consent, fall back to event.consent\n if (Object.keys(mappedConsent).length === 0) {\n const eventConsent = formatConsent(event.consent);\n if (eventConsent) {\n dataManagerEvent.consent = eventConsent;\n }\n } else {\n dataManagerEvent.consent = mappedConsent;\n }\n\n return dataManagerEvent;\n}\n","import { isString } from '@walkeros/core';\nimport { getHashServer } from '@walkeros/server-core';\n\n/**\n * Normalize email address according to Google Data Manager requirements\n * https://developers.google.com/data-manager/api/devguides/concepts/formatting#email\n *\n * 1. Trim whitespace\n * 2. Convert to lowercase\n * 3. Remove dots (.) for gmail.com and googlemail.com\n * 4. SHA-256 hash\n */\nexport async function hashEmail(email: string): Promise<string> {\n if (!isString(email) || !email) return '';\n\n // Trim and lowercase\n let normalized = email.trim().toLowerCase();\n\n // Remove dots for Gmail addresses\n if (\n normalized.endsWith('@gmail.com') ||\n normalized.endsWith('@googlemail.com')\n ) {\n const [localPart, domain] = normalized.split('@');\n normalized = `${localPart.replace(/\\./g, '')}@${domain}`;\n }\n\n return getHashServer(normalized);\n}\n\n/**\n * Normalize phone number to E.164 format and hash\n * https://developers.google.com/data-manager/api/devguides/concepts/formatting#phone\n *\n * E.164 format: +[country code][number] (max 15 digits after +)\n * Example: +18005550100\n *\n * 1. Remove all non-digit characters except leading +\n * 2. Ensure it starts with +\n * 3. SHA-256 hash\n */\nexport async function hashPhone(phone: string): Promise<string> {\n if (!isString(phone) || !phone) return '';\n\n // Remove all non-digit characters except + at the start\n let normalized = phone.trim();\n\n // Extract country code if present\n const hasPlus = normalized.startsWith('+');\n\n // Remove all non-digits\n normalized = normalized.replace(/\\D/g, '');\n\n // Add + prefix if it was there or if number is long enough\n if (hasPlus || normalized.length > 10) {\n normalized = `+${normalized}`;\n } else {\n // Assume US number if no country code (default behavior)\n normalized = `+1${normalized}`;\n }\n\n return getHashServer(normalized);\n}\n\n/**\n * Normalize and hash a name (first or last name)\n * https://developers.google.com/data-manager/api/devguides/concepts/formatting#name\n *\n * 1. Trim whitespace\n * 2. Convert to lowercase\n * 3. Remove common prefixes (Mr., Mrs., Dr.) for first names\n * 4. Remove common suffixes (Jr., Sr., III) for last names\n * 5. SHA-256 hash\n */\nexport async function hashName(\n name: string,\n type: 'given' | 'family' = 'given',\n): Promise<string> {\n if (!isString(name) || !name) return '';\n\n // Trim and lowercase\n let normalized = name.trim().toLowerCase();\n\n // Remove prefixes for given names\n if (type === 'given') {\n const prefixes = ['mr.', 'mrs.', 'ms.', 'miss.', 'dr.', 'prof.'];\n for (const prefix of prefixes) {\n if (normalized.startsWith(prefix)) {\n normalized = normalized.substring(prefix.length).trim();\n break;\n }\n }\n }\n\n // Remove suffixes for family names (check with and without space)\n // Sort by length (longest first) to match \"iii\" before \"ii\"\n if (type === 'family') {\n const suffixes = ['jr.', 'sr.', 'iii', 'ii', 'iv', 'v'];\n for (const suffix of suffixes) {\n // Check for suffix with space before it (e.g., \" jr.\")\n const suffixWithSpace = ` ${suffix}`;\n if (normalized.endsWith(suffixWithSpace)) {\n normalized = normalized\n .substring(0, normalized.length - suffixWithSpace.length)\n .trim();\n break;\n }\n // Check for suffix without space\n if (normalized.endsWith(suffix)) {\n normalized = normalized\n .substring(0, normalized.length - suffix.length)\n .trim();\n break;\n }\n }\n }\n\n return getHashServer(normalized);\n}\n\n/**\n * Hash multiple email addresses\n */\nexport async function hashEmails(emails: string[]): Promise<string[]> {\n return Promise.all(emails.map((email) => hashEmail(email)));\n}\n\n/**\n * Hash multiple phone numbers\n */\nexport async function hashPhones(phones: string[]): Promise<string[]> {\n return Promise.all(phones.map((phone) => hashPhone(phone)));\n}\n","import { GoogleAuth, type OAuth2Client } from 'google-auth-library';\nimport type { Settings } from './types';\n\nconst DEFAULT_SCOPES = ['https://www.googleapis.com/auth/datamanager'];\n\n/**\n * Authentication error with cause tracking\n */\nexport class AuthError extends Error {\n constructor(\n message: string,\n public cause?: Error,\n ) {\n super(message);\n this.name = 'DataManagerAuthError';\n }\n}\n\n/**\n * Creates Google Auth client based on settings\n *\n * Authentication priority:\n * 1. credentials (inline service account) - if provided\n * 2. keyFilename (service account file) - if provided\n * 3. Application Default Credentials (ADC) - automatic fallback\n * - GOOGLE_APPLICATION_CREDENTIALS env var\n * - GCP metadata server (Cloud Functions, Cloud Run, GCE)\n *\n * @param settings - Configuration with auth options\n * @returns OAuth2Client for token retrieval\n * @throws AuthError if authentication fails\n */\nexport async function createAuthClient(\n settings: Settings,\n): Promise<OAuth2Client> {\n const { credentials, keyFilename, scopes = DEFAULT_SCOPES } = settings;\n\n try {\n if (credentials) {\n const auth = new GoogleAuth({\n credentials,\n scopes,\n });\n return (await auth.getClient()) as OAuth2Client;\n }\n\n if (keyFilename) {\n const auth = new GoogleAuth({\n keyFilename,\n scopes,\n });\n return (await auth.getClient()) as OAuth2Client;\n }\n\n const auth = new GoogleAuth({ scopes });\n return (await auth.getClient()) as OAuth2Client;\n } catch (error) {\n throw new AuthError(\n 'Failed to create auth client. Check credentials configuration or ensure GOOGLE_APPLICATION_CREDENTIALS is set.',\n error instanceof Error ? error : undefined,\n );\n }\n}\n\n/**\n * Gets access token from auth client\n * Automatically returns cached token if valid or refreshes if expired\n *\n * @param authClient - OAuth2 client from createAuthClient()\n * @returns Fresh access token\n * @throws AuthError if token retrieval fails\n */\nexport async function getAccessToken(\n authClient: OAuth2Client,\n): Promise<string> {\n try {\n const tokenResponse = await authClient.getAccessToken();\n\n if (!tokenResponse.token) {\n throw new AuthError('Auth client returned empty token');\n }\n\n return tokenResponse.token;\n } catch (error) {\n throw new AuthError(\n 'Failed to obtain access token',\n error instanceof Error ? error : undefined,\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';\nimport type { OAuth2Client } from 'google-auth-library';\n\nexport interface Settings {\n /**\n * Service account credentials (client_email + private_key)\n * Recommended for serverless environments (AWS Lambda, Docker, etc.)\n */\n credentials?: {\n client_email: string;\n private_key: string;\n };\n\n /**\n * Path to service account JSON file\n * For local development or environments with filesystem access\n */\n keyFilename?: string;\n\n /**\n * OAuth scopes for Data Manager API\n * @default ['https://www.googleapis.com/auth/datamanager']\n */\n scopes?: string[];\n\n /** Array of destination accounts and conversion actions/user lists */\n destinations: Destination[];\n\n /** Event source for all events. Defaults to WEB if not specified */\n eventSource?: EventSource;\n\n /** Maximum number of events to batch before sending (max 2000) */\n batchSize?: number;\n\n /** Time in milliseconds to wait before auto-flushing batch */\n batchInterval?: number;\n\n /** If true, validate request without ingestion (testing mode) */\n validateOnly?: boolean;\n\n /** Override API endpoint (for testing) */\n url?: string;\n\n /** Request-level consent for all events */\n consent?: Consent;\n\n /** Test event code for debugging (optional) */\n testEventCode?: string;\n\n /** Guided helpers: User data mapping (applies to all events) */\n userData?: WalkerOSMapping.Map;\n\n /** Guided helper: First-party user ID */\n userId?: WalkerOSMapping.Value;\n\n /** Guided helper: GA4 client ID */\n clientId?: WalkerOSMapping.Value;\n\n /** Guided helper: Privacy-safe attribution (Google's sessionAttributes) */\n sessionAttributes?: WalkerOSMapping.Value;\n\n /** Consent mapping: Map consent field to adUserData (string = field name, boolean = static value) */\n consentAdUserData?: string | boolean;\n\n /** Consent mapping: Map consent field to adPersonalization (string = field name, boolean = static value) */\n consentAdPersonalization?: string | boolean;\n}\n\nexport interface Mapping {\n // Attribution identifiers (optional, for explicit mapping)\n gclid?: WalkerOSMapping.Value;\n gbraid?: WalkerOSMapping.Value;\n wbraid?: WalkerOSMapping.Value;\n sessionAttributes?: WalkerOSMapping.Value;\n}\n\nexport interface Env extends DestinationServer.Env {\n fetch?: typeof fetch;\n authClient?: OAuth2Client | null;\n}\n\nexport type InitSettings = Partial<Settings>;\n\nexport type Types = CoreDestination.Types<Settings, Mapping, Env, InitSettings>;\n\nexport interface DestinationInterface\n extends DestinationServer.Destination<Types> {\n init: DestinationServer.InitFn<Types>;\n}\n\nexport type Config = {\n settings: Settings;\n} & DestinationServer.Config<Types>;\n\n/**\n * Config after validation - settings is guaranteed to exist with required fields\n * Use this type after calling getConfig() to get proper type narrowing\n * After validation, eventSource is always set (defaults to 'WEB')\n */\nexport type ValidatedConfig = Omit<Config, 'settings'> & {\n settings: Settings & { eventSource: EventSource };\n};\n\nexport type InitFn = DestinationServer.InitFn<Types>;\nexport type PushFn = DestinationServer.PushFn<Types>;\n\nexport type PartialConfig = DestinationServer.PartialConfig<Types>;\n\nexport type PushEvents = DestinationServer.PushEvents<Mapping>;\n\nexport type Rule = WalkerOSMapping.Rule<Mapping>;\nexport type Rules = WalkerOSMapping.Rules<Rule>;\n\n// Google Data Manager API Types\n// https://developers.google.com/data-manager/api/reference\n\n/**\n * Destination account and product identifier\n * https://developers.google.com/data-manager/api/reference/rest/v1/Destination\n */\nexport interface Destination {\n /** Reference identifier for this destination */\n reference?: string;\n\n /** Login account (account initiating the request) */\n loginAccount?: ProductAccount;\n\n /** Linked account (child account linked to login account) */\n linkedAccount?: ProductAccount;\n\n /** Operating account (account where data is sent) */\n operatingAccount?: ProductAccount;\n\n /** Product-specific destination ID (conversion action or user list) */\n productDestinationId?: string;\n}\n\n/**\n * Product account information\n */\nexport interface ProductAccount {\n /** Account ID (e.g., \"123-456-7890\" for Google Ads) */\n accountId: string;\n\n /** Type of account */\n accountType: AccountType;\n}\n\nexport type AccountType =\n | 'ACCOUNT_TYPE_UNSPECIFIED'\n | 'GOOGLE_ADS'\n | 'DISPLAY_VIDEO_ADVERTISER'\n | 'DISPLAY_VIDEO_PARTNER'\n | 'GOOGLE_ANALYTICS_PROPERTY'\n | 'DATA_PARTNER';\n\nexport type EventSource = 'WEB' | 'APP' | 'IN_STORE' | 'PHONE' | 'OTHER';\n\n/**\n * Consent for Digital Markets Act (DMA) compliance\n * https://developers.google.com/data-manager/api/devguides/concepts/dma\n */\nexport interface Consent {\n /** Consent for data collection and use */\n adUserData?: ConsentStatus;\n\n /** Consent for ad personalization */\n adPersonalization?: ConsentStatus;\n}\n\nexport type ConsentStatus = 'CONSENT_GRANTED' | 'CONSENT_DENIED';\n\n/**\n * Request body for events.ingest API\n * https://developers.google.com/data-manager/api/reference/rest/v1/events/ingest\n */\nexport interface IngestEventsRequest {\n /** Array of destinations for these events (max 10) */\n destinations: Destination[];\n\n /** Array of events to ingest (max 2000) */\n events: Event[];\n\n /** Request-level consent (overridden by event-level) */\n consent?: Consent;\n\n /** If true, validate without ingestion */\n validateOnly?: boolean;\n\n /** Test event code for debugging */\n testEventCode?: string;\n}\n\n/**\n * Single event for ingestion\n * https://developers.google.com/data-manager/api/reference/rest/v1/Event\n */\nexport interface Event {\n /** Destination references for routing */\n destinationReferences?: string[];\n\n /** Transaction ID for deduplication (max 512 chars) */\n transactionId?: string;\n\n /** Event timestamp in RFC 3339 format */\n eventTimestamp?: string;\n\n /** Last updated timestamp in RFC 3339 format */\n lastUpdatedTimestamp?: string;\n\n /** User data with identifiers (max 10 identifiers) */\n userData?: UserData;\n\n /** Event-level consent (overrides request-level) */\n consent?: Consent;\n\n /** Attribution identifiers */\n adIdentifiers?: AdIdentifiers;\n\n /** Currency code (ISO 4217, 3 chars) */\n currency?: string;\n\n /** Conversion value */\n conversionValue?: number;\n\n /** Source of the event */\n eventSource?: EventSource;\n\n /** Device information for the event */\n eventDeviceInfo?: DeviceInfo;\n\n /** Shopping cart data */\n cartData?: CartData;\n\n /** Custom variables for the event */\n customVariables?: CustomVariable[];\n\n /** Experimental fields (subject to change) */\n experimentalFields?: ExperimentalField[];\n\n /** User properties */\n userProperties?: UserProperties;\n\n /** Event name for GA4 (max 40 chars, required for GA4) */\n eventName?: string;\n\n /** Google Analytics client ID (max 255 chars) */\n clientId?: string;\n\n /** First-party user ID (max 256 chars) */\n userId?: string;\n\n /** Additional event parameters */\n additionalEventParameters?: EventParameter[];\n}\n\n/**\n * Device information\n */\nexport interface DeviceInfo {\n /** User agent string */\n userAgent?: string;\n}\n\n/**\n * Custom variable\n */\nexport interface CustomVariable {\n /** Variable name */\n name?: string;\n\n /** Variable value */\n value?: string;\n}\n\n/**\n * Experimental field\n */\nexport interface ExperimentalField {\n /** Field name */\n name?: string;\n\n /** Field value */\n value?: string;\n}\n\n/**\n * User properties\n */\nexport interface UserProperties {\n /** Property values */\n [key: string]: string | number | boolean | undefined;\n}\n\n/**\n * Event parameter\n */\nexport interface EventParameter {\n /** Parameter name */\n name?: string;\n\n /** Parameter value */\n value?: string | number;\n}\n\n/**\n * User data with identifiers\n * https://developers.google.com/data-manager/api/reference/rest/v1/UserData\n */\nexport interface UserData {\n /** Array of user identifiers (max 10) */\n userIdentifiers: UserIdentifier[];\n}\n\n/**\n * User identifier (email, phone, or address)\n */\nexport type UserIdentifier =\n | { emailAddress: string }\n | { phoneNumber: string }\n | { address: Address };\n\n/**\n * Address for user identification\n * https://developers.google.com/data-manager/api/reference/rest/v1/Address\n */\nexport interface Address {\n /** Given name (first name) - SHA-256 hashed */\n givenName?: string;\n\n /** Family name (last name) - SHA-256 hashed */\n familyName?: string;\n\n /** ISO-3166-1 alpha-2 country code - NOT hashed (e.g., \"US\", \"GB\") */\n regionCode?: string;\n\n /** Postal code - NOT hashed */\n postalCode?: string;\n}\n\n/**\n * Attribution identifiers\n * https://developers.google.com/data-manager/api/reference/rest/v1/AdIdentifiers\n */\nexport interface AdIdentifiers {\n /** Session attributes (privacy-safe attribution) */\n sessionAttributes?: string;\n\n /** Google Click ID (primary attribution) */\n gclid?: string;\n\n /** iOS attribution identifier (post-ATT) */\n gbraid?: string;\n\n /** Web-to-app attribution identifier */\n wbraid?: string;\n\n /** Device information for landing page */\n landingPageDeviceInfo?: DeviceInfo;\n}\n\n/**\n * Shopping cart data\n * https://developers.google.com/data-manager/api/reference/rest/v1/CartData\n */\nexport interface CartData {\n /** Array of cart items (max 200) */\n items: CartItem[];\n}\n\n/**\n * Single cart item\n * https://developers.google.com/data-manager/api/reference/rest/v1/CartItem\n */\nexport interface CartItem {\n /** Merchant product ID (max 127 chars) */\n merchantProductId?: string;\n\n /** Item price */\n price?: number;\n\n /** Item quantity */\n quantity?: number;\n}\n\n/**\n * Response from events.ingest API\n * https://developers.google.com/data-manager/api/reference/rest/v1/IngestEventsResponse\n */\nexport interface IngestEventsResponse {\n /** Unique request ID for status checking */\n requestId: string;\n\n /** Validation errors (only if validateOnly=true) */\n validationErrors?: ValidationError[];\n}\n\n/**\n * Validation error\n */\nexport interface ValidationError {\n /** Error code */\n code: string;\n\n /** Human-readable error message */\n message: string;\n\n /** Field path that caused the error */\n fieldPath?: string;\n}\n\n/**\n * Request status response\n * https://developers.google.com/data-manager/api/reference/rest/v1/requestStatus/retrieve\n */\nexport interface RequestStatusResponse {\n /** Unique request ID */\n requestId: string;\n\n /** Processing state */\n state: RequestState;\n\n /** Number of events successfully ingested */\n eventsIngested?: number;\n\n /** Number of events that failed */\n eventsFailed?: number;\n\n /** Array of errors (if any) */\n errors?: RequestError[];\n}\n\nexport type RequestState =\n | 'STATE_UNSPECIFIED'\n | 'PENDING'\n | 'PROCESSING'\n | 'SUCCEEDED'\n | 'FAILED'\n | 'PARTIALLY_SUCCEEDED';\n\n/**\n * Request error\n */\nexport interface RequestError {\n /** Error code */\n code: string;\n\n /** Human-readable error message */\n message: string;\n\n /** Number of events affected by this error */\n eventCount?: number;\n}\n","import type { DestinationInterface } from './types';\nimport { getConfig } from './config';\nimport { push } from './push';\nimport { createAuthClient } from './auth';\n\nexport * as DestinationDataManager from './types';\n\nexport const destinationDataManager: DestinationInterface = {\n type: 'datamanager',\n\n config: {},\n\n async init({ config: partialConfig, env, logger }) {\n // getConfig validates required fields and returns ValidatedConfig\n const config = getConfig(partialConfig, logger);\n\n try {\n const authClient = await createAuthClient(config.settings);\n logger.debug('Auth client created');\n\n return {\n ...config,\n env: {\n ...env,\n authClient,\n },\n };\n } catch (error) {\n logger.throw(\n `Data Manager authentication failed: ${error instanceof Error ? error.message : 'Unknown error'}`,\n );\n }\n },\n\n async push(event, { config, mapping, data, collector, env, logger }) {\n return await push(event, { config, mapping, data, collector, env, logger });\n },\n};\n\nexport default destinationDataManager;\n"],"mappings":"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","names":["isString","isString","auth"]}
|
package/dist/schemas.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var e,
|
|
1
|
+
"use strict";var e,t=Object.defineProperty,o=Object.getOwnPropertyDescriptor,n=Object.getOwnPropertyNames,i=Object.prototype.hasOwnProperty,r={};((e,o)=>{for(var n in o)t(e,n,{get:o[n],enumerable:!0})})(r,{mapping:()=>E,settings:()=>f}),module.exports=(e=r,((e,r,a,s)=>{if(r&&"object"==typeof r||"function"==typeof r)for(let c of n(r))i.call(e,c)||c===a||t(e,c,{get:()=>r[c],enumerable:!(s=o(r,c))||s.enumerable});return e})(t({},"__esModule",{value:!0}),e));var a=require("@walkeros/core/dev"),s=a.z.enum(["GOOGLE_ADS","DISPLAY_VIDEO_ADVERTISER","DISPLAY_VIDEO_PARTNER","GOOGLE_ANALYTICS_PROPERTY"]),c=a.z.enum(["WEB","APP","IN_STORE","PHONE","OTHER"]),l=a.z.enum(["CONSENT_GRANTED","CONSENT_DENIED"]),d=a.z.object({adUserData:l.describe("Consent for data collection and use").optional(),adPersonalization:l.describe("Consent for ad personalization").optional()}),u=a.z.object({accountId:a.z.string().min(1).describe('Account ID (e.g., "123-456-7890" for Google Ads)'),accountType:s.describe("Type of account")}),b=a.z.object({operatingAccount:u.describe("Operating account details"),productDestinationId:a.z.string().min(1).describe("Product-specific destination ID (conversion action or user list)")}),p=require("@walkeros/core/dev"),m=p.z.object({client_email:p.z.string().email().describe("Service account email"),private_key:p.z.string().min(1).describe("Service account private key (PEM format)")}),g=p.z.object({credentials:m.optional().describe("Service account credentials (client_email + private_key). Recommended for serverless environments."),keyFilename:p.z.string().optional().describe("Path to service account JSON file. For local development or environments with filesystem access."),scopes:p.z.array(p.z.string()).optional().describe("OAuth scopes for Data Manager API. Defaults to datamanager scope."),destinations:p.z.array(b).min(1).max(10).describe("Array of destination accounts and conversion actions/user lists (max 10)"),eventSource:c.optional().default("WEB").describe("Event source for all events. Defaults to WEB. Values: WEB, APP, IN_STORE, PHONE, OTHER"),batchSize:p.z.number().int().min(1).max(2e3).describe("Maximum number of events to batch before sending (max 2000, like 100)").optional(),batchInterval:p.z.number().int().min(0).describe("Time in milliseconds to wait before auto-flushing batch (like 5000)").optional(),validateOnly:p.z.boolean().describe("If true, validate request without ingestion (testing mode)").optional(),url:p.z.string().url().describe("Override API endpoint for testing (like https://datamanager.googleapis.com/v1)").optional(),consent:d.describe("Request-level consent for all events").optional(),testEventCode:p.z.string().describe("Test event code for debugging (like TEST12345)").optional(),logLevel:p.z.enum(["debug","info","warn","error","none"]).describe("Log level for debugging (debug shows all API calls)").optional(),userData:p.z.record(p.z.string(),p.z.unknown()).describe("Guided helper: User data mapping for all events (like { email: 'user.id', phone: 'data.phone' })").optional(),userId:p.z.any().describe("Guided helper: First-party user ID for all events (like 'user.id')").optional(),clientId:p.z.any().describe("Guided helper: GA4 client ID for all events (like 'user.device')").optional(),sessionAttributes:p.z.any().describe("Guided helper: Privacy-safe attribution for all events (like 'context.sessionAttributes')").optional(),consentAdUserData:p.z.union([p.z.string(),p.z.boolean()]).describe("Consent mapping: Field name from event.consent (like 'marketing') or static boolean value").optional(),consentAdPersonalization:p.z.union([p.z.string(),p.z.boolean()]).describe("Consent mapping: Field name from event.consent (like 'targeting') or static boolean value").optional()}),v=require("@walkeros/core/dev").z.object({}),z=require("@walkeros/core/dev"),f=(0,z.zodToSchema)(g),E=(0,z.zodToSchema)(v);//# sourceMappingURL=schemas.js.map
|
package/dist/schemas.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/schemas.ts","../src/schemas/primitives.ts","../src/schemas/settings.ts","../src/schemas/mapping.ts","../src/schemas/index.ts"],"sourcesContent":["// Browser-safe schema-only exports\n// This file exports ONLY schemas without any Node.js dependencies\nexport { settings, mapping } from './schemas/index';\n","import { z } from '@walkeros/core/dev';\n\nexport const AccountTypeSchema = z.enum([\n 'GOOGLE_ADS',\n 'DISPLAY_VIDEO_ADVERTISER',\n 'DISPLAY_VIDEO_PARTNER',\n 'GOOGLE_ANALYTICS_PROPERTY',\n]);\n\nexport const EventSourceSchema = z.enum([\n 'WEB',\n 'APP',\n 'IN_STORE',\n 'PHONE',\n 'OTHER',\n]);\n\nexport const ConsentStatusSchema = z.enum([\n 'CONSENT_GRANTED',\n 'CONSENT_DENIED',\n]);\n\nexport const ConsentSchema = z.object({\n adUserData: ConsentStatusSchema.describe(\n 'Consent for data collection and use',\n ).optional(),\n adPersonalization: ConsentStatusSchema.describe(\n 'Consent for ad personalization',\n ).optional(),\n});\n\nexport const OperatingAccountSchema = z.object({\n accountId: z\n .string()\n .min(1)\n .describe('Account ID (e.g., \"123-456-7890\" for Google Ads)'),\n accountType: AccountTypeSchema.describe('Type of account'),\n});\n\nexport const DestinationSchema = z.object({\n operatingAccount: OperatingAccountSchema.describe(\n 'Operating account details',\n ),\n productDestinationId: z\n .string()\n .min(1)\n .describe(\n 'Product-specific destination ID (conversion action or user list)',\n ),\n});\n","import { z } from '@walkeros/core/dev';\nimport {\n DestinationSchema,\n EventSourceSchema,\n ConsentSchema,\n} from './primitives';\n\nexport const SettingsSchema = z.object({\n
|
|
1
|
+
{"version":3,"sources":["../src/schemas.ts","../src/schemas/primitives.ts","../src/schemas/settings.ts","../src/schemas/mapping.ts","../src/schemas/index.ts"],"sourcesContent":["// Browser-safe schema-only exports\n// This file exports ONLY schemas without any Node.js dependencies\nexport { settings, mapping } from './schemas/index';\n","import { z } from '@walkeros/core/dev';\n\nexport const AccountTypeSchema = z.enum([\n 'GOOGLE_ADS',\n 'DISPLAY_VIDEO_ADVERTISER',\n 'DISPLAY_VIDEO_PARTNER',\n 'GOOGLE_ANALYTICS_PROPERTY',\n]);\n\nexport const EventSourceSchema = z.enum([\n 'WEB',\n 'APP',\n 'IN_STORE',\n 'PHONE',\n 'OTHER',\n]);\n\nexport const ConsentStatusSchema = z.enum([\n 'CONSENT_GRANTED',\n 'CONSENT_DENIED',\n]);\n\nexport const ConsentSchema = z.object({\n adUserData: ConsentStatusSchema.describe(\n 'Consent for data collection and use',\n ).optional(),\n adPersonalization: ConsentStatusSchema.describe(\n 'Consent for ad personalization',\n ).optional(),\n});\n\nexport const OperatingAccountSchema = z.object({\n accountId: z\n .string()\n .min(1)\n .describe('Account ID (e.g., \"123-456-7890\" for Google Ads)'),\n accountType: AccountTypeSchema.describe('Type of account'),\n});\n\nexport const DestinationSchema = z.object({\n operatingAccount: OperatingAccountSchema.describe(\n 'Operating account details',\n ),\n productDestinationId: z\n .string()\n .min(1)\n .describe(\n 'Product-specific destination ID (conversion action or user list)',\n ),\n});\n","import { z } from '@walkeros/core/dev';\nimport {\n DestinationSchema,\n EventSourceSchema,\n ConsentSchema,\n} from './primitives';\n\n/**\n * Service account credentials schema\n */\nconst CredentialsSchema = z.object({\n client_email: z.string().email().describe('Service account email'),\n private_key: z\n .string()\n .min(1)\n .describe('Service account private key (PEM format)'),\n});\n\nexport const SettingsSchema = z.object({\n credentials: CredentialsSchema.optional().describe(\n 'Service account credentials (client_email + private_key). Recommended for serverless environments.',\n ),\n keyFilename: z\n .string()\n .optional()\n .describe(\n 'Path to service account JSON file. For local development or environments with filesystem access.',\n ),\n scopes: z\n .array(z.string())\n .optional()\n .describe(\n 'OAuth scopes for Data Manager API. Defaults to datamanager scope.',\n ),\n destinations: z\n .array(DestinationSchema)\n .min(1)\n .max(10)\n .describe(\n 'Array of destination accounts and conversion actions/user lists (max 10)',\n ),\n eventSource: EventSourceSchema.optional()\n .default('WEB')\n .describe(\n 'Event source for all events. Defaults to WEB. Values: WEB, APP, IN_STORE, PHONE, OTHER',\n ),\n batchSize: z\n .number()\n .int()\n .min(1)\n .max(2000)\n .describe(\n 'Maximum number of events to batch before sending (max 2000, like 100)',\n )\n .optional(),\n batchInterval: z\n .number()\n .int()\n .min(0)\n .describe(\n 'Time in milliseconds to wait before auto-flushing batch (like 5000)',\n )\n .optional(),\n validateOnly: z\n .boolean()\n .describe('If true, validate request without ingestion (testing mode)')\n .optional(),\n url: z\n .string()\n .url()\n .describe(\n 'Override API endpoint for testing (like https://datamanager.googleapis.com/v1)',\n )\n .optional(),\n consent: ConsentSchema.describe(\n 'Request-level consent for all events',\n ).optional(),\n testEventCode: z\n .string()\n .describe('Test event code for debugging (like TEST12345)')\n .optional(),\n logLevel: z\n .enum(['debug', 'info', 'warn', 'error', 'none'])\n .describe('Log level for debugging (debug shows all API calls)')\n .optional(),\n userData: z\n .record(z.string(), z.unknown())\n .describe(\n \"Guided helper: User data mapping for all events (like { email: 'user.id', phone: 'data.phone' })\",\n )\n .optional(),\n userId: z\n .any()\n .describe(\n \"Guided helper: First-party user ID for all events (like 'user.id')\",\n )\n .optional(),\n clientId: z\n .any()\n .describe(\n \"Guided helper: GA4 client ID for all events (like 'user.device')\",\n )\n .optional(),\n sessionAttributes: z\n .any()\n .describe(\n \"Guided helper: Privacy-safe attribution for all events (like 'context.sessionAttributes')\",\n )\n .optional(),\n consentAdUserData: z\n .union([z.string(), z.boolean()])\n .describe(\n \"Consent mapping: Field name from event.consent (like 'marketing') or static boolean value\",\n )\n .optional(),\n consentAdPersonalization: z\n .union([z.string(), z.boolean()])\n .describe(\n \"Consent mapping: Field name from event.consent (like 'targeting') or static boolean value\",\n )\n .optional(),\n});\n\nexport type Settings = z.infer<typeof SettingsSchema>;\n","import { z } from '@walkeros/core/dev';\n\n// Data Manager uses flexible mapping via walkerOS mapping system\n// No event-specific mapping schema needed (similar to Meta CAPI pattern)\nexport const MappingSchema = z.object({});\n\nexport type Mapping = z.infer<typeof MappingSchema>;\n","export * from './primitives';\nexport * from './settings';\nexport * from './mapping';\n\nimport { zodToSchema } from '@walkeros/core/dev';\nimport { SettingsSchema } from './settings';\nimport { MappingSchema } from './mapping';\n\nexport const settings = zodToSchema(SettingsSchema);\nexport const mapping = zodToSchema(MappingSchema);\n"],"mappings":"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","names":["import_dev","import_dev","import_dev"]}
|
package/dist/schemas.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{z as e}from"@walkeros/core/dev";var o=e.enum(["GOOGLE_ADS","DISPLAY_VIDEO_ADVERTISER","DISPLAY_VIDEO_PARTNER","GOOGLE_ANALYTICS_PROPERTY"]),n=e.enum(["WEB","APP","IN_STORE","PHONE","OTHER"]),t=e.enum(["CONSENT_GRANTED","CONSENT_DENIED"]),i=e.object({adUserData:t.describe("Consent for data collection and use").optional(),adPersonalization:t.describe("Consent for ad personalization").optional()}),a=e.object({accountId:e.string().min(1).describe('Account ID (e.g., "123-456-7890" for Google Ads)'),accountType:o.describe("Type of account")}),r=e.object({operatingAccount:a.describe("Operating account details"),productDestinationId:e.string().min(1).describe("Product-specific destination ID (conversion action or user list)")});import{z as s}from"@walkeros/core/dev";var l=s.object({
|
|
1
|
+
import{z as e}from"@walkeros/core/dev";var o=e.enum(["GOOGLE_ADS","DISPLAY_VIDEO_ADVERTISER","DISPLAY_VIDEO_PARTNER","GOOGLE_ANALYTICS_PROPERTY"]),n=e.enum(["WEB","APP","IN_STORE","PHONE","OTHER"]),t=e.enum(["CONSENT_GRANTED","CONSENT_DENIED"]),i=e.object({adUserData:t.describe("Consent for data collection and use").optional(),adPersonalization:t.describe("Consent for ad personalization").optional()}),a=e.object({accountId:e.string().min(1).describe('Account ID (e.g., "123-456-7890" for Google Ads)'),accountType:o.describe("Type of account")}),r=e.object({operatingAccount:a.describe("Operating account details"),productDestinationId:e.string().min(1).describe("Product-specific destination ID (conversion action or user list)")});import{z as s}from"@walkeros/core/dev";var l=s.object({client_email:s.string().email().describe("Service account email"),private_key:s.string().min(1).describe("Service account private key (PEM format)")}),c=s.object({credentials:l.optional().describe("Service account credentials (client_email + private_key). Recommended for serverless environments."),keyFilename:s.string().optional().describe("Path to service account JSON file. For local development or environments with filesystem access."),scopes:s.array(s.string()).optional().describe("OAuth scopes for Data Manager API. Defaults to datamanager scope."),destinations:s.array(r).min(1).max(10).describe("Array of destination accounts and conversion actions/user lists (max 10)"),eventSource:n.optional().default("WEB").describe("Event source for all events. Defaults to WEB. Values: WEB, APP, IN_STORE, PHONE, OTHER"),batchSize:s.number().int().min(1).max(2e3).describe("Maximum number of events to batch before sending (max 2000, like 100)").optional(),batchInterval:s.number().int().min(0).describe("Time in milliseconds to wait before auto-flushing batch (like 5000)").optional(),validateOnly:s.boolean().describe("If true, validate request without ingestion (testing mode)").optional(),url:s.string().url().describe("Override API endpoint for testing (like https://datamanager.googleapis.com/v1)").optional(),consent:i.describe("Request-level consent for all events").optional(),testEventCode:s.string().describe("Test event code for debugging (like TEST12345)").optional(),logLevel:s.enum(["debug","info","warn","error","none"]).describe("Log level for debugging (debug shows all API calls)").optional(),userData:s.record(s.string(),s.unknown()).describe("Guided helper: User data mapping for all events (like { email: 'user.id', phone: 'data.phone' })").optional(),userId:s.any().describe("Guided helper: First-party user ID for all events (like 'user.id')").optional(),clientId:s.any().describe("Guided helper: GA4 client ID for all events (like 'user.device')").optional(),sessionAttributes:s.any().describe("Guided helper: Privacy-safe attribution for all events (like 'context.sessionAttributes')").optional(),consentAdUserData:s.union([s.string(),s.boolean()]).describe("Consent mapping: Field name from event.consent (like 'marketing') or static boolean value").optional(),consentAdPersonalization:s.union([s.string(),s.boolean()]).describe("Consent mapping: Field name from event.consent (like 'targeting') or static boolean value").optional()});import{z as d}from"@walkeros/core/dev";var u=d.object({});import{zodToSchema as m}from"@walkeros/core/dev";var p=m(c),b=m(u);export{b as mapping,p as settings};//# sourceMappingURL=schemas.mjs.map
|
package/dist/schemas.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/schemas/primitives.ts","../src/schemas/settings.ts","../src/schemas/mapping.ts","../src/schemas/index.ts"],"sourcesContent":["import { z } from '@walkeros/core/dev';\n\nexport const AccountTypeSchema = z.enum([\n 'GOOGLE_ADS',\n 'DISPLAY_VIDEO_ADVERTISER',\n 'DISPLAY_VIDEO_PARTNER',\n 'GOOGLE_ANALYTICS_PROPERTY',\n]);\n\nexport const EventSourceSchema = z.enum([\n 'WEB',\n 'APP',\n 'IN_STORE',\n 'PHONE',\n 'OTHER',\n]);\n\nexport const ConsentStatusSchema = z.enum([\n 'CONSENT_GRANTED',\n 'CONSENT_DENIED',\n]);\n\nexport const ConsentSchema = z.object({\n adUserData: ConsentStatusSchema.describe(\n 'Consent for data collection and use',\n ).optional(),\n adPersonalization: ConsentStatusSchema.describe(\n 'Consent for ad personalization',\n ).optional(),\n});\n\nexport const OperatingAccountSchema = z.object({\n accountId: z\n .string()\n .min(1)\n .describe('Account ID (e.g., \"123-456-7890\" for Google Ads)'),\n accountType: AccountTypeSchema.describe('Type of account'),\n});\n\nexport const DestinationSchema = z.object({\n operatingAccount: OperatingAccountSchema.describe(\n 'Operating account details',\n ),\n productDestinationId: z\n .string()\n .min(1)\n .describe(\n 'Product-specific destination ID (conversion action or user list)',\n ),\n});\n","import { z } from '@walkeros/core/dev';\nimport {\n DestinationSchema,\n EventSourceSchema,\n ConsentSchema,\n} from './primitives';\n\nexport const SettingsSchema = z.object({\n
|
|
1
|
+
{"version":3,"sources":["../src/schemas/primitives.ts","../src/schemas/settings.ts","../src/schemas/mapping.ts","../src/schemas/index.ts"],"sourcesContent":["import { z } from '@walkeros/core/dev';\n\nexport const AccountTypeSchema = z.enum([\n 'GOOGLE_ADS',\n 'DISPLAY_VIDEO_ADVERTISER',\n 'DISPLAY_VIDEO_PARTNER',\n 'GOOGLE_ANALYTICS_PROPERTY',\n]);\n\nexport const EventSourceSchema = z.enum([\n 'WEB',\n 'APP',\n 'IN_STORE',\n 'PHONE',\n 'OTHER',\n]);\n\nexport const ConsentStatusSchema = z.enum([\n 'CONSENT_GRANTED',\n 'CONSENT_DENIED',\n]);\n\nexport const ConsentSchema = z.object({\n adUserData: ConsentStatusSchema.describe(\n 'Consent for data collection and use',\n ).optional(),\n adPersonalization: ConsentStatusSchema.describe(\n 'Consent for ad personalization',\n ).optional(),\n});\n\nexport const OperatingAccountSchema = z.object({\n accountId: z\n .string()\n .min(1)\n .describe('Account ID (e.g., \"123-456-7890\" for Google Ads)'),\n accountType: AccountTypeSchema.describe('Type of account'),\n});\n\nexport const DestinationSchema = z.object({\n operatingAccount: OperatingAccountSchema.describe(\n 'Operating account details',\n ),\n productDestinationId: z\n .string()\n .min(1)\n .describe(\n 'Product-specific destination ID (conversion action or user list)',\n ),\n});\n","import { z } from '@walkeros/core/dev';\nimport {\n DestinationSchema,\n EventSourceSchema,\n ConsentSchema,\n} from './primitives';\n\n/**\n * Service account credentials schema\n */\nconst CredentialsSchema = z.object({\n client_email: z.string().email().describe('Service account email'),\n private_key: z\n .string()\n .min(1)\n .describe('Service account private key (PEM format)'),\n});\n\nexport const SettingsSchema = z.object({\n credentials: CredentialsSchema.optional().describe(\n 'Service account credentials (client_email + private_key). Recommended for serverless environments.',\n ),\n keyFilename: z\n .string()\n .optional()\n .describe(\n 'Path to service account JSON file. For local development or environments with filesystem access.',\n ),\n scopes: z\n .array(z.string())\n .optional()\n .describe(\n 'OAuth scopes for Data Manager API. Defaults to datamanager scope.',\n ),\n destinations: z\n .array(DestinationSchema)\n .min(1)\n .max(10)\n .describe(\n 'Array of destination accounts and conversion actions/user lists (max 10)',\n ),\n eventSource: EventSourceSchema.optional()\n .default('WEB')\n .describe(\n 'Event source for all events. Defaults to WEB. Values: WEB, APP, IN_STORE, PHONE, OTHER',\n ),\n batchSize: z\n .number()\n .int()\n .min(1)\n .max(2000)\n .describe(\n 'Maximum number of events to batch before sending (max 2000, like 100)',\n )\n .optional(),\n batchInterval: z\n .number()\n .int()\n .min(0)\n .describe(\n 'Time in milliseconds to wait before auto-flushing batch (like 5000)',\n )\n .optional(),\n validateOnly: z\n .boolean()\n .describe('If true, validate request without ingestion (testing mode)')\n .optional(),\n url: z\n .string()\n .url()\n .describe(\n 'Override API endpoint for testing (like https://datamanager.googleapis.com/v1)',\n )\n .optional(),\n consent: ConsentSchema.describe(\n 'Request-level consent for all events',\n ).optional(),\n testEventCode: z\n .string()\n .describe('Test event code for debugging (like TEST12345)')\n .optional(),\n logLevel: z\n .enum(['debug', 'info', 'warn', 'error', 'none'])\n .describe('Log level for debugging (debug shows all API calls)')\n .optional(),\n userData: z\n .record(z.string(), z.unknown())\n .describe(\n \"Guided helper: User data mapping for all events (like { email: 'user.id', phone: 'data.phone' })\",\n )\n .optional(),\n userId: z\n .any()\n .describe(\n \"Guided helper: First-party user ID for all events (like 'user.id')\",\n )\n .optional(),\n clientId: z\n .any()\n .describe(\n \"Guided helper: GA4 client ID for all events (like 'user.device')\",\n )\n .optional(),\n sessionAttributes: z\n .any()\n .describe(\n \"Guided helper: Privacy-safe attribution for all events (like 'context.sessionAttributes')\",\n )\n .optional(),\n consentAdUserData: z\n .union([z.string(), z.boolean()])\n .describe(\n \"Consent mapping: Field name from event.consent (like 'marketing') or static boolean value\",\n )\n .optional(),\n consentAdPersonalization: z\n .union([z.string(), z.boolean()])\n .describe(\n \"Consent mapping: Field name from event.consent (like 'targeting') or static boolean value\",\n )\n .optional(),\n});\n\nexport type Settings = z.infer<typeof SettingsSchema>;\n","import { z } from '@walkeros/core/dev';\n\n// Data Manager uses flexible mapping via walkerOS mapping system\n// No event-specific mapping schema needed (similar to Meta CAPI pattern)\nexport const MappingSchema = z.object({});\n\nexport type Mapping = z.infer<typeof MappingSchema>;\n","export * from './primitives';\nexport * from './settings';\nexport * from './mapping';\n\nimport { zodToSchema } from '@walkeros/core/dev';\nimport { SettingsSchema } from './settings';\nimport { MappingSchema } from './mapping';\n\nexport const settings = zodToSchema(SettingsSchema);\nexport const mapping = zodToSchema(MappingSchema);\n"],"mappings":"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","names":["z","z","z"]}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@walkeros/server-destination-datamanager",
|
|
3
3
|
"description": "Google Data Manager server destination for walkerOS",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.5.0",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"exports": {
|
|
7
7
|
".": {
|
|
@@ -32,8 +32,8 @@
|
|
|
32
32
|
"update": "npx npm-check-updates -u && npm update"
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@walkeros/core": "0.
|
|
36
|
-
"@walkeros/server-core": "0.
|
|
35
|
+
"@walkeros/core": "0.5.0",
|
|
36
|
+
"@walkeros/server-core": "0.5.0",
|
|
37
37
|
"google-auth-library": "^10.5.0"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {},
|