@walkeros/server-source-express 2.0.1 → 2.1.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/dist/dev.d.mts +26 -12
- package/dist/dev.d.ts +26 -12
- 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.d.mts +4 -3
- package/dist/index.d.ts +4 -3
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/dist/walkerOS.json +46 -9
- package/package.json +2 -2
package/dist/dev.d.mts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as _walkeros_core_dev from '@walkeros/core/dev';
|
|
2
2
|
import { z } from '@walkeros/core/dev';
|
|
3
|
+
import { Flow } from '@walkeros/core';
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* HTTP methods enum
|
|
@@ -88,23 +89,36 @@ declare const SettingsSchema: z.ZodObject<{
|
|
|
88
89
|
credentials: z.ZodOptional<z.ZodBoolean>;
|
|
89
90
|
maxAge: z.ZodOptional<z.ZodNumber>;
|
|
90
91
|
}, z.core.$strip>]>>;
|
|
91
|
-
status: z.ZodDefault<z.ZodBoolean>;
|
|
92
92
|
}, z.core.$strip>;
|
|
93
93
|
type Settings = z.infer<typeof SettingsSchema>;
|
|
94
94
|
|
|
95
95
|
declare const settings: _walkeros_core_dev.JSONSchema;
|
|
96
96
|
|
|
97
|
-
type
|
|
98
|
-
declare const
|
|
99
|
-
declare const
|
|
100
|
-
declare const
|
|
101
|
-
declare const
|
|
102
|
-
declare const
|
|
103
|
-
type
|
|
104
|
-
declare const
|
|
105
|
-
declare const
|
|
97
|
+
type index$1_CorsOptions = CorsOptions;
|
|
98
|
+
declare const index$1_CorsOptionsSchema: typeof CorsOptionsSchema;
|
|
99
|
+
declare const index$1_CorsOrigin: typeof CorsOrigin;
|
|
100
|
+
declare const index$1_HttpMethod: typeof HttpMethod;
|
|
101
|
+
declare const index$1_RouteConfigSchema: typeof RouteConfigSchema;
|
|
102
|
+
declare const index$1_RouteMethod: typeof RouteMethod;
|
|
103
|
+
type index$1_Settings = Settings;
|
|
104
|
+
declare const index$1_SettingsSchema: typeof SettingsSchema;
|
|
105
|
+
declare const index$1_settings: typeof settings;
|
|
106
|
+
declare namespace index$1 {
|
|
107
|
+
export { type index$1_CorsOptions as CorsOptions, index$1_CorsOptionsSchema as CorsOptionsSchema, index$1_CorsOrigin as CorsOrigin, index$1_HttpMethod as HttpMethod, index$1_RouteConfigSchema as RouteConfigSchema, index$1_RouteMethod as RouteMethod, type index$1_Settings as Settings, index$1_SettingsSchema as SettingsSchema, index$1_settings as settings };
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
declare const postEvent: Flow.StepExample;
|
|
111
|
+
declare const pixelGet: Flow.StepExample;
|
|
112
|
+
|
|
113
|
+
declare const step_pixelGet: typeof pixelGet;
|
|
114
|
+
declare const step_postEvent: typeof postEvent;
|
|
115
|
+
declare namespace step {
|
|
116
|
+
export { step_pixelGet as pixelGet, step_postEvent as postEvent };
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
declare const index_step: typeof step;
|
|
106
120
|
declare namespace index {
|
|
107
|
-
export {
|
|
121
|
+
export { index_step as step };
|
|
108
122
|
}
|
|
109
123
|
|
|
110
|
-
export { index as schemas };
|
|
124
|
+
export { index as examples, index$1 as schemas };
|
package/dist/dev.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as _walkeros_core_dev from '@walkeros/core/dev';
|
|
2
2
|
import { z } from '@walkeros/core/dev';
|
|
3
|
+
import { Flow } from '@walkeros/core';
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* HTTP methods enum
|
|
@@ -88,23 +89,36 @@ declare const SettingsSchema: z.ZodObject<{
|
|
|
88
89
|
credentials: z.ZodOptional<z.ZodBoolean>;
|
|
89
90
|
maxAge: z.ZodOptional<z.ZodNumber>;
|
|
90
91
|
}, z.core.$strip>]>>;
|
|
91
|
-
status: z.ZodDefault<z.ZodBoolean>;
|
|
92
92
|
}, z.core.$strip>;
|
|
93
93
|
type Settings = z.infer<typeof SettingsSchema>;
|
|
94
94
|
|
|
95
95
|
declare const settings: _walkeros_core_dev.JSONSchema;
|
|
96
96
|
|
|
97
|
-
type
|
|
98
|
-
declare const
|
|
99
|
-
declare const
|
|
100
|
-
declare const
|
|
101
|
-
declare const
|
|
102
|
-
declare const
|
|
103
|
-
type
|
|
104
|
-
declare const
|
|
105
|
-
declare const
|
|
97
|
+
type index$1_CorsOptions = CorsOptions;
|
|
98
|
+
declare const index$1_CorsOptionsSchema: typeof CorsOptionsSchema;
|
|
99
|
+
declare const index$1_CorsOrigin: typeof CorsOrigin;
|
|
100
|
+
declare const index$1_HttpMethod: typeof HttpMethod;
|
|
101
|
+
declare const index$1_RouteConfigSchema: typeof RouteConfigSchema;
|
|
102
|
+
declare const index$1_RouteMethod: typeof RouteMethod;
|
|
103
|
+
type index$1_Settings = Settings;
|
|
104
|
+
declare const index$1_SettingsSchema: typeof SettingsSchema;
|
|
105
|
+
declare const index$1_settings: typeof settings;
|
|
106
|
+
declare namespace index$1 {
|
|
107
|
+
export { type index$1_CorsOptions as CorsOptions, index$1_CorsOptionsSchema as CorsOptionsSchema, index$1_CorsOrigin as CorsOrigin, index$1_HttpMethod as HttpMethod, index$1_RouteConfigSchema as RouteConfigSchema, index$1_RouteMethod as RouteMethod, type index$1_Settings as Settings, index$1_SettingsSchema as SettingsSchema, index$1_settings as settings };
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
declare const postEvent: Flow.StepExample;
|
|
111
|
+
declare const pixelGet: Flow.StepExample;
|
|
112
|
+
|
|
113
|
+
declare const step_pixelGet: typeof pixelGet;
|
|
114
|
+
declare const step_postEvent: typeof postEvent;
|
|
115
|
+
declare namespace step {
|
|
116
|
+
export { step_pixelGet as pixelGet, step_postEvent as postEvent };
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
declare const index_step: typeof step;
|
|
106
120
|
declare namespace index {
|
|
107
|
-
export {
|
|
121
|
+
export { index_step as step };
|
|
108
122
|
}
|
|
109
123
|
|
|
110
|
-
export { index as schemas };
|
|
124
|
+
export { index as examples, index$1 as schemas };
|
package/dist/dev.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var e,
|
|
1
|
+
"use strict";var e,t=Object.defineProperty,o=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,a=Object.prototype.hasOwnProperty,i=(e,o)=>{for(var r in o)t(e,r,{get:o[r],enumerable:!0})},n={};i(n,{examples:()=>v,schemas:()=>s}),module.exports=(e=n,((e,i,n,s)=>{if(i&&"object"==typeof i||"function"==typeof i)for(let l of r(i))a.call(e,l)||l===n||t(e,l,{get:()=>i[l],enumerable:!(s=o(i,l))||s.enumerable});return e})(t({},"__esModule",{value:!0}),e));var s={};i(s,{CorsOptionsSchema:()=>h,CorsOrigin:()=>g,HttpMethod:()=>c,RouteConfigSchema:()=>m,RouteMethod:()=>u,SettingsSchema:()=>b,settings:()=>z});var l=require("@walkeros/core/dev"),d=require("@walkeros/core/dev"),p=require("@walkeros/core/dev"),c=p.z.enum(["GET","POST","PUT","PATCH","DELETE","OPTIONS","HEAD"]),u=p.z.enum(["GET","POST"]),m=p.z.object({path:p.z.string().describe("Express route path (supports wildcards like /api/*)"),methods:p.z.array(u).min(1).describe("HTTP methods to register. OPTIONS always included for CORS.").optional()}),g=p.z.union([p.z.string(),p.z.array(p.z.string()),p.z.literal("*")]),h=p.z.object({origin:g.describe("Allowed origins (* for all, URL string, or array of URLs)").optional(),methods:p.z.array(c).describe("Allowed HTTP methods").optional(),headers:p.z.array(p.z.string()).describe("Allowed request headers").optional(),credentials:p.z.boolean().describe("Allow credentials (cookies, authorization headers)").optional(),maxAge:p.z.number().int().positive().describe("Preflight cache duration in seconds").optional()}),b=d.z.object({port:d.z.number().int().min(0).max(65535).describe("HTTP server port to listen on. Use 0 for random available port. If not provided, server will not start (app only mode)").optional(),path:d.z.string().describe("Deprecated: use paths instead").optional(),paths:d.z.array(d.z.union([d.z.string(),m])).min(1).describe("Route paths to register. String shorthand registers GET+POST. RouteConfig allows per-route method control.").optional(),cors:d.z.union([d.z.boolean(),h]).describe("CORS configuration: false = disabled, true = allow all origins (default), object = custom configuration").default(!0)}),z=(0,l.zodToSchema)(b),v={};i(v,{step:()=>f});var f={};i(f,{pixelGet:()=>T,postEvent:()=>w});var w={in:{method:"POST",path:"/collect",body:{name:"page view",data:{title:"Home",url:"https://example.com/"}}},out:{name:"page view",data:{title:"Home",url:"https://example.com/"},entity:"page",action:"view"}},T={in:{method:"GET",path:"/collect",query:{e:"page view",d:'{"title":"Home"}'}},out:{name:"page view",data:{title:"Home"},entity:"page",action:"view"}};//# sourceMappingURL=dev.js.map
|
package/dist/dev.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/dev.ts","../src/schemas/index.ts","../src/schemas/settings.ts","../src/schemas/primitives.ts"],"sourcesContent":["export * as schemas from './schemas';\n","import { zodToSchema } from '@walkeros/core/dev';\nimport { SettingsSchema } from './settings';\n\nexport * from './primitives';\nexport { SettingsSchema, type Settings } from './settings';\n\n// JSON Schema\nexport const settings = zodToSchema(SettingsSchema);\n","import { z } from '@walkeros/core/dev';\nimport { CorsOptionsSchema, RouteConfigSchema } from './primitives';\n\n/**\n * Express source settings schema.\n */\nexport const SettingsSchema = z.object({\n port: z\n .number()\n .int()\n .min(0)\n .max(65535)\n .describe(\n 'HTTP server port to listen on. Use 0 for random available port. If not provided, server will not start (app only mode)',\n )\n .optional(),\n\n /** @deprecated Use `paths` instead */\n path: z.string().describe('Deprecated: use paths instead').optional(),\n\n paths: z\n .array(z.union([z.string(), RouteConfigSchema]))\n .min(1)\n .describe(\n 'Route paths to register. String shorthand registers GET+POST. RouteConfig allows per-route method control.',\n )\n .optional(),\n\n cors: z\n .union([z.boolean(), CorsOptionsSchema])\n .describe(\n 'CORS configuration: false = disabled, true = allow all origins (default), object = custom configuration',\n )\n .default(true),\n
|
|
1
|
+
{"version":3,"sources":["../src/dev.ts","../src/schemas/index.ts","../src/schemas/settings.ts","../src/schemas/primitives.ts","../src/examples/index.ts","../src/examples/step.ts"],"sourcesContent":["export * as schemas from './schemas';\nexport * as examples from './examples';\n","import { zodToSchema } from '@walkeros/core/dev';\nimport { SettingsSchema } from './settings';\n\nexport * from './primitives';\nexport { SettingsSchema, type Settings } from './settings';\n\n// JSON Schema\nexport const settings = zodToSchema(SettingsSchema);\n","import { z } from '@walkeros/core/dev';\nimport { CorsOptionsSchema, RouteConfigSchema } from './primitives';\n\n/**\n * Express source settings schema.\n */\nexport const SettingsSchema = z.object({\n port: z\n .number()\n .int()\n .min(0)\n .max(65535)\n .describe(\n 'HTTP server port to listen on. Use 0 for random available port. If not provided, server will not start (app only mode)',\n )\n .optional(),\n\n /** @deprecated Use `paths` instead */\n path: z.string().describe('Deprecated: use paths instead').optional(),\n\n paths: z\n .array(z.union([z.string(), RouteConfigSchema]))\n .min(1)\n .describe(\n 'Route paths to register. String shorthand registers GET+POST. RouteConfig allows per-route method control.',\n )\n .optional(),\n\n cors: z\n .union([z.boolean(), CorsOptionsSchema])\n .describe(\n 'CORS configuration: false = disabled, true = allow all origins (default), object = custom configuration',\n )\n .default(true),\n});\n\nexport type Settings = z.infer<typeof SettingsSchema>;\n","import { z } from '@walkeros/core/dev';\n\n/**\n * HTTP methods enum\n */\nexport const HttpMethod = z.enum([\n 'GET',\n 'POST',\n 'PUT',\n 'PATCH',\n 'DELETE',\n 'OPTIONS',\n 'HEAD',\n]);\n\n/**\n * HTTP methods supported for route configuration.\n * OPTIONS is always registered for CORS (not user-configurable per route).\n */\nexport const RouteMethod = z.enum(['GET', 'POST']);\n\n/**\n * Route configuration for multi-path support.\n */\nexport const RouteConfigSchema = z.object({\n path: z\n .string()\n .describe('Express route path (supports wildcards like /api/*)'),\n methods: z\n .array(RouteMethod)\n .min(1)\n .describe('HTTP methods to register. OPTIONS always included for CORS.')\n .optional(),\n});\n\n/**\n * CORS origin configuration\n * Accepts:\n * - '*' for all origins\n * - Single URL string\n * - Array of URL strings\n */\nexport const CorsOrigin = z.union([\n z.string(),\n z.array(z.string()),\n z.literal('*'),\n]);\n\n/**\n * CORS options schema\n * Configuration for Cross-Origin Resource Sharing\n */\nexport const CorsOptionsSchema = z.object({\n origin: CorsOrigin.describe(\n 'Allowed origins (* for all, URL string, or array of URLs)',\n ).optional(),\n\n methods: z.array(HttpMethod).describe('Allowed HTTP methods').optional(),\n\n headers: z.array(z.string()).describe('Allowed request headers').optional(),\n\n credentials: z\n .boolean()\n .describe('Allow credentials (cookies, authorization headers)')\n .optional(),\n\n maxAge: z\n .number()\n .int()\n .positive()\n .describe('Preflight cache duration in seconds')\n .optional(),\n});\n\nexport type CorsOptions = z.infer<typeof CorsOptionsSchema>;\n","export * as step from './step';\n","import type { Flow } from '@walkeros/core';\n\nexport const postEvent: Flow.StepExample = {\n in: {\n method: 'POST',\n path: '/collect',\n body: {\n name: 'page view',\n data: { title: 'Home', url: 'https://example.com/' },\n },\n },\n out: {\n name: 'page view',\n data: { title: 'Home', url: 'https://example.com/' },\n entity: 'page',\n action: 'view',\n },\n};\n\nexport const pixelGet: Flow.StepExample = {\n in: {\n method: 'GET',\n path: '/collect',\n query: { e: 'page view', d: '{\"title\":\"Home\"}' },\n },\n out: {\n name: 'page view',\n data: { title: 'Home' },\n entity: 'page',\n action: 'view',\n },\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAAAA,cAA4B;;;ACA5B,IAAAC,cAAkB;;;ACAlB,iBAAkB;AAKX,IAAM,aAAa,aAAE,KAAK;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAMM,IAAM,cAAc,aAAE,KAAK,CAAC,OAAO,MAAM,CAAC;AAK1C,IAAM,oBAAoB,aAAE,OAAO;AAAA,EACxC,MAAM,aACH,OAAO,EACP,SAAS,qDAAqD;AAAA,EACjE,SAAS,aACN,MAAM,WAAW,EACjB,IAAI,CAAC,EACL,SAAS,6DAA6D,EACtE,SAAS;AACd,CAAC;AASM,IAAM,aAAa,aAAE,MAAM;AAAA,EAChC,aAAE,OAAO;AAAA,EACT,aAAE,MAAM,aAAE,OAAO,CAAC;AAAA,EAClB,aAAE,QAAQ,GAAG;AACf,CAAC;AAMM,IAAM,oBAAoB,aAAE,OAAO;AAAA,EACxC,QAAQ,WAAW;AAAA,IACjB;AAAA,EACF,EAAE,SAAS;AAAA,EAEX,SAAS,aAAE,MAAM,UAAU,EAAE,SAAS,sBAAsB,EAAE,SAAS;AAAA,EAEvE,SAAS,aAAE,MAAM,aAAE,OAAO,CAAC,EAAE,SAAS,yBAAyB,EAAE,SAAS;AAAA,EAE1E,aAAa,aACV,QAAQ,EACR,SAAS,oDAAoD,EAC7D,SAAS;AAAA,EAEZ,QAAQ,aACL,OAAO,EACP,IAAI,EACJ,SAAS,EACT,SAAS,qCAAqC,EAC9C,SAAS;AACd,CAAC;;;ADlEM,IAAM,iBAAiB,cAAE,OAAO;AAAA,EACrC,MAAM,cACH,OAAO,EACP,IAAI,EACJ,IAAI,CAAC,EACL,IAAI,KAAK,EACT;AAAA,IACC;AAAA,EACF,EACC,SAAS;AAAA;AAAA,EAGZ,MAAM,cAAE,OAAO,EAAE,SAAS,+BAA+B,EAAE,SAAS;AAAA,EAEpE,OAAO,cACJ,MAAM,cAAE,MAAM,CAAC,cAAE,OAAO,GAAG,iBAAiB,CAAC,CAAC,EAC9C,IAAI,CAAC,EACL;AAAA,IACC;AAAA,EACF,EACC,SAAS;AAAA,EAEZ,MAAM,cACH,MAAM,CAAC,cAAE,QAAQ,GAAG,iBAAiB,CAAC,EACtC;AAAA,IACC;AAAA,EACF,EACC,QAAQ,IAAI;AACjB,CAAC;;;AD3BM,IAAM,eAAW,yBAAY,cAAc;;;AGPlD;AAAA;AAAA;AAAA;;;ACAA;AAAA;AAAA;AAAA;AAAA;AAEO,IAAM,YAA8B;AAAA,EACzC,IAAI;AAAA,IACF,QAAQ;AAAA,IACR,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,MAAM;AAAA,MACN,MAAM,EAAE,OAAO,QAAQ,KAAK,uBAAuB;AAAA,IACrD;AAAA,EACF;AAAA,EACA,KAAK;AAAA,IACH,MAAM;AAAA,IACN,MAAM,EAAE,OAAO,QAAQ,KAAK,uBAAuB;AAAA,IACnD,QAAQ;AAAA,IACR,QAAQ;AAAA,EACV;AACF;AAEO,IAAM,WAA6B;AAAA,EACxC,IAAI;AAAA,IACF,QAAQ;AAAA,IACR,MAAM;AAAA,IACN,OAAO,EAAE,GAAG,aAAa,GAAG,mBAAmB;AAAA,EACjD;AAAA,EACA,KAAK;AAAA,IACH,MAAM;AAAA,IACN,MAAM,EAAE,OAAO,OAAO;AAAA,IACtB,QAAQ;AAAA,IACR,QAAQ;AAAA,EACV;AACF;","names":["import_dev","import_dev"]}
|
package/dist/dev.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var e=Object.defineProperty,
|
|
1
|
+
var e=Object.defineProperty,t=(t,o)=>{for(var r in o)e(t,r,{get:o[r],enumerable:!0})},o={};t(o,{CorsOptionsSchema:()=>p,CorsOrigin:()=>d,HttpMethod:()=>s,RouteConfigSchema:()=>l,RouteMethod:()=>n,SettingsSchema:()=>c,settings:()=>m});import{zodToSchema as r}from"@walkeros/core/dev";import{z as a}from"@walkeros/core/dev";import{z as i}from"@walkeros/core/dev";var s=i.enum(["GET","POST","PUT","PATCH","DELETE","OPTIONS","HEAD"]),n=i.enum(["GET","POST"]),l=i.object({path:i.string().describe("Express route path (supports wildcards like /api/*)"),methods:i.array(n).min(1).describe("HTTP methods to register. OPTIONS always included for CORS.").optional()}),d=i.union([i.string(),i.array(i.string()),i.literal("*")]),p=i.object({origin:d.describe("Allowed origins (* for all, URL string, or array of URLs)").optional(),methods:i.array(s).describe("Allowed HTTP methods").optional(),headers:i.array(i.string()).describe("Allowed request headers").optional(),credentials:i.boolean().describe("Allow credentials (cookies, authorization headers)").optional(),maxAge:i.number().int().positive().describe("Preflight cache duration in seconds").optional()}),c=a.object({port:a.number().int().min(0).max(65535).describe("HTTP server port to listen on. Use 0 for random available port. If not provided, server will not start (app only mode)").optional(),path:a.string().describe("Deprecated: use paths instead").optional(),paths:a.array(a.union([a.string(),l])).min(1).describe("Route paths to register. String shorthand registers GET+POST. RouteConfig allows per-route method control.").optional(),cors:a.union([a.boolean(),p]).describe("CORS configuration: false = disabled, true = allow all origins (default), object = custom configuration").default(!0)}),m=r(c),h={};t(h,{step:()=>u});var u={};t(u,{pixelGet:()=>b,postEvent:()=>g});var g={in:{method:"POST",path:"/collect",body:{name:"page view",data:{title:"Home",url:"https://example.com/"}}},out:{name:"page view",data:{title:"Home",url:"https://example.com/"},entity:"page",action:"view"}},b={in:{method:"GET",path:"/collect",query:{e:"page view",d:'{"title":"Home"}'}},out:{name:"page view",data:{title:"Home"},entity:"page",action:"view"}};export{h as examples,o as schemas};//# sourceMappingURL=dev.mjs.map
|
package/dist/dev.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/schemas/index.ts","../src/schemas/settings.ts","../src/schemas/primitives.ts"],"sourcesContent":["import { zodToSchema } from '@walkeros/core/dev';\nimport { SettingsSchema } from './settings';\n\nexport * from './primitives';\nexport { SettingsSchema, type Settings } from './settings';\n\n// JSON Schema\nexport const settings = zodToSchema(SettingsSchema);\n","import { z } from '@walkeros/core/dev';\nimport { CorsOptionsSchema, RouteConfigSchema } from './primitives';\n\n/**\n * Express source settings schema.\n */\nexport const SettingsSchema = z.object({\n port: z\n .number()\n .int()\n .min(0)\n .max(65535)\n .describe(\n 'HTTP server port to listen on. Use 0 for random available port. If not provided, server will not start (app only mode)',\n )\n .optional(),\n\n /** @deprecated Use `paths` instead */\n path: z.string().describe('Deprecated: use paths instead').optional(),\n\n paths: z\n .array(z.union([z.string(), RouteConfigSchema]))\n .min(1)\n .describe(\n 'Route paths to register. String shorthand registers GET+POST. RouteConfig allows per-route method control.',\n )\n .optional(),\n\n cors: z\n .union([z.boolean(), CorsOptionsSchema])\n .describe(\n 'CORS configuration: false = disabled, true = allow all origins (default), object = custom configuration',\n )\n .default(true),\n
|
|
1
|
+
{"version":3,"sources":["../src/schemas/index.ts","../src/schemas/settings.ts","../src/schemas/primitives.ts","../src/examples/index.ts","../src/examples/step.ts"],"sourcesContent":["import { zodToSchema } from '@walkeros/core/dev';\nimport { SettingsSchema } from './settings';\n\nexport * from './primitives';\nexport { SettingsSchema, type Settings } from './settings';\n\n// JSON Schema\nexport const settings = zodToSchema(SettingsSchema);\n","import { z } from '@walkeros/core/dev';\nimport { CorsOptionsSchema, RouteConfigSchema } from './primitives';\n\n/**\n * Express source settings schema.\n */\nexport const SettingsSchema = z.object({\n port: z\n .number()\n .int()\n .min(0)\n .max(65535)\n .describe(\n 'HTTP server port to listen on. Use 0 for random available port. If not provided, server will not start (app only mode)',\n )\n .optional(),\n\n /** @deprecated Use `paths` instead */\n path: z.string().describe('Deprecated: use paths instead').optional(),\n\n paths: z\n .array(z.union([z.string(), RouteConfigSchema]))\n .min(1)\n .describe(\n 'Route paths to register. String shorthand registers GET+POST. RouteConfig allows per-route method control.',\n )\n .optional(),\n\n cors: z\n .union([z.boolean(), CorsOptionsSchema])\n .describe(\n 'CORS configuration: false = disabled, true = allow all origins (default), object = custom configuration',\n )\n .default(true),\n});\n\nexport type Settings = z.infer<typeof SettingsSchema>;\n","import { z } from '@walkeros/core/dev';\n\n/**\n * HTTP methods enum\n */\nexport const HttpMethod = z.enum([\n 'GET',\n 'POST',\n 'PUT',\n 'PATCH',\n 'DELETE',\n 'OPTIONS',\n 'HEAD',\n]);\n\n/**\n * HTTP methods supported for route configuration.\n * OPTIONS is always registered for CORS (not user-configurable per route).\n */\nexport const RouteMethod = z.enum(['GET', 'POST']);\n\n/**\n * Route configuration for multi-path support.\n */\nexport const RouteConfigSchema = z.object({\n path: z\n .string()\n .describe('Express route path (supports wildcards like /api/*)'),\n methods: z\n .array(RouteMethod)\n .min(1)\n .describe('HTTP methods to register. OPTIONS always included for CORS.')\n .optional(),\n});\n\n/**\n * CORS origin configuration\n * Accepts:\n * - '*' for all origins\n * - Single URL string\n * - Array of URL strings\n */\nexport const CorsOrigin = z.union([\n z.string(),\n z.array(z.string()),\n z.literal('*'),\n]);\n\n/**\n * CORS options schema\n * Configuration for Cross-Origin Resource Sharing\n */\nexport const CorsOptionsSchema = z.object({\n origin: CorsOrigin.describe(\n 'Allowed origins (* for all, URL string, or array of URLs)',\n ).optional(),\n\n methods: z.array(HttpMethod).describe('Allowed HTTP methods').optional(),\n\n headers: z.array(z.string()).describe('Allowed request headers').optional(),\n\n credentials: z\n .boolean()\n .describe('Allow credentials (cookies, authorization headers)')\n .optional(),\n\n maxAge: z\n .number()\n .int()\n .positive()\n .describe('Preflight cache duration in seconds')\n .optional(),\n});\n\nexport type CorsOptions = z.infer<typeof CorsOptionsSchema>;\n","export * as step from './step';\n","import type { Flow } from '@walkeros/core';\n\nexport const postEvent: Flow.StepExample = {\n in: {\n method: 'POST',\n path: '/collect',\n body: {\n name: 'page view',\n data: { title: 'Home', url: 'https://example.com/' },\n },\n },\n out: {\n name: 'page view',\n data: { title: 'Home', url: 'https://example.com/' },\n entity: 'page',\n action: 'view',\n },\n};\n\nexport const pixelGet: Flow.StepExample = {\n in: {\n method: 'GET',\n path: '/collect',\n query: { e: 'page view', d: '{\"title\":\"Home\"}' },\n },\n out: {\n name: 'page view',\n data: { title: 'Home' },\n entity: 'page',\n action: 'view',\n },\n};\n"],"mappings":";;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,SAAS,mBAAmB;;;ACA5B,SAAS,KAAAA,UAAS;;;ACAlB,SAAS,SAAS;AAKX,IAAM,aAAa,EAAE,KAAK;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAMM,IAAM,cAAc,EAAE,KAAK,CAAC,OAAO,MAAM,CAAC;AAK1C,IAAM,oBAAoB,EAAE,OAAO;AAAA,EACxC,MAAM,EACH,OAAO,EACP,SAAS,qDAAqD;AAAA,EACjE,SAAS,EACN,MAAM,WAAW,EACjB,IAAI,CAAC,EACL,SAAS,6DAA6D,EACtE,SAAS;AACd,CAAC;AASM,IAAM,aAAa,EAAE,MAAM;AAAA,EAChC,EAAE,OAAO;AAAA,EACT,EAAE,MAAM,EAAE,OAAO,CAAC;AAAA,EAClB,EAAE,QAAQ,GAAG;AACf,CAAC;AAMM,IAAM,oBAAoB,EAAE,OAAO;AAAA,EACxC,QAAQ,WAAW;AAAA,IACjB;AAAA,EACF,EAAE,SAAS;AAAA,EAEX,SAAS,EAAE,MAAM,UAAU,EAAE,SAAS,sBAAsB,EAAE,SAAS;AAAA,EAEvE,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,SAAS,yBAAyB,EAAE,SAAS;AAAA,EAE1E,aAAa,EACV,QAAQ,EACR,SAAS,oDAAoD,EAC7D,SAAS;AAAA,EAEZ,QAAQ,EACL,OAAO,EACP,IAAI,EACJ,SAAS,EACT,SAAS,qCAAqC,EAC9C,SAAS;AACd,CAAC;;;ADlEM,IAAM,iBAAiBC,GAAE,OAAO;AAAA,EACrC,MAAMA,GACH,OAAO,EACP,IAAI,EACJ,IAAI,CAAC,EACL,IAAI,KAAK,EACT;AAAA,IACC;AAAA,EACF,EACC,SAAS;AAAA;AAAA,EAGZ,MAAMA,GAAE,OAAO,EAAE,SAAS,+BAA+B,EAAE,SAAS;AAAA,EAEpE,OAAOA,GACJ,MAAMA,GAAE,MAAM,CAACA,GAAE,OAAO,GAAG,iBAAiB,CAAC,CAAC,EAC9C,IAAI,CAAC,EACL;AAAA,IACC;AAAA,EACF,EACC,SAAS;AAAA,EAEZ,MAAMA,GACH,MAAM,CAACA,GAAE,QAAQ,GAAG,iBAAiB,CAAC,EACtC;AAAA,IACC;AAAA,EACF,EACC,QAAQ,IAAI;AACjB,CAAC;;;AD3BM,IAAM,WAAW,YAAY,cAAc;;;AGPlD;AAAA;AAAA;AAAA;;;ACAA;AAAA;AAAA;AAAA;AAAA;AAEO,IAAM,YAA8B;AAAA,EACzC,IAAI;AAAA,IACF,QAAQ;AAAA,IACR,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,MAAM;AAAA,MACN,MAAM,EAAE,OAAO,QAAQ,KAAK,uBAAuB;AAAA,IACrD;AAAA,EACF;AAAA,EACA,KAAK;AAAA,IACH,MAAM;AAAA,IACN,MAAM,EAAE,OAAO,QAAQ,KAAK,uBAAuB;AAAA,IACnD,QAAQ;AAAA,IACR,QAAQ;AAAA,EACV;AACF;AAEO,IAAM,WAA6B;AAAA,EACxC,IAAI;AAAA,IACF,QAAQ;AAAA,IACR,MAAM;AAAA,IACN,OAAO,EAAE,GAAG,aAAa,GAAG,mBAAmB;AAAA,EACjD;AAAA,EACA,KAAK;AAAA,IACH,MAAM;AAAA,IACN,MAAM,EAAE,OAAO,OAAO;AAAA,IACtB,QAAQ;AAAA,IACR,QAAQ;AAAA,EACV;AACF;","names":["z","z"]}
|
package/dist/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Source, WalkerOS } from '@walkeros/core';
|
|
1
|
+
import { Source, WalkerOS, Lifecycle } from '@walkeros/core';
|
|
2
2
|
import { Request, Response, Application } from 'express';
|
|
3
3
|
import { z } from '@walkeros/core/dev';
|
|
4
4
|
|
|
@@ -61,7 +61,6 @@ declare const SettingsSchema: z.ZodObject<{
|
|
|
61
61
|
credentials: z.ZodOptional<z.ZodBoolean>;
|
|
62
62
|
maxAge: z.ZodOptional<z.ZodNumber>;
|
|
63
63
|
}, z.core.$strip>]>>;
|
|
64
|
-
status: z.ZodDefault<z.ZodBoolean>;
|
|
65
64
|
}, z.core.$strip>;
|
|
66
65
|
|
|
67
66
|
type Settings = z.infer<typeof SettingsSchema>;
|
|
@@ -80,8 +79,10 @@ type Config = Source.Config<Types>;
|
|
|
80
79
|
type PartialConfig = Source.PartialConfig<Types>;
|
|
81
80
|
interface ExpressSource extends Omit<Source.Instance<Types>, 'push'> {
|
|
82
81
|
push: Push;
|
|
82
|
+
httpHandler: Application;
|
|
83
83
|
app: Application;
|
|
84
84
|
server?: ReturnType<Application['listen']>;
|
|
85
|
+
destroy(context: Lifecycle.DestroyContext): Promise<void>;
|
|
85
86
|
}
|
|
86
87
|
interface EventRequest {
|
|
87
88
|
event: string;
|
|
@@ -121,7 +122,7 @@ declare const TRANSPARENT_GIF: Buffer<ArrayBuffer>;
|
|
|
121
122
|
* - Sets up middleware (JSON parsing, CORS)
|
|
122
123
|
* - Registers event collection endpoints (POST, GET, OPTIONS)
|
|
123
124
|
* - Starts HTTP server (if port configured)
|
|
124
|
-
* -
|
|
125
|
+
* - Provides destroy() for graceful shutdown (called by runner)
|
|
125
126
|
*
|
|
126
127
|
* @param context Source context with config, env, logger, id
|
|
127
128
|
* @returns Express source instance with app and push handler
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Source, WalkerOS } from '@walkeros/core';
|
|
1
|
+
import { Source, WalkerOS, Lifecycle } from '@walkeros/core';
|
|
2
2
|
import { Request, Response, Application } from 'express';
|
|
3
3
|
import { z } from '@walkeros/core/dev';
|
|
4
4
|
|
|
@@ -61,7 +61,6 @@ declare const SettingsSchema: z.ZodObject<{
|
|
|
61
61
|
credentials: z.ZodOptional<z.ZodBoolean>;
|
|
62
62
|
maxAge: z.ZodOptional<z.ZodNumber>;
|
|
63
63
|
}, z.core.$strip>]>>;
|
|
64
|
-
status: z.ZodDefault<z.ZodBoolean>;
|
|
65
64
|
}, z.core.$strip>;
|
|
66
65
|
|
|
67
66
|
type Settings = z.infer<typeof SettingsSchema>;
|
|
@@ -80,8 +79,10 @@ type Config = Source.Config<Types>;
|
|
|
80
79
|
type PartialConfig = Source.PartialConfig<Types>;
|
|
81
80
|
interface ExpressSource extends Omit<Source.Instance<Types>, 'push'> {
|
|
82
81
|
push: Push;
|
|
82
|
+
httpHandler: Application;
|
|
83
83
|
app: Application;
|
|
84
84
|
server?: ReturnType<Application['listen']>;
|
|
85
|
+
destroy(context: Lifecycle.DestroyContext): Promise<void>;
|
|
85
86
|
}
|
|
86
87
|
interface EventRequest {
|
|
87
88
|
event: string;
|
|
@@ -121,7 +122,7 @@ declare const TRANSPARENT_GIF: Buffer<ArrayBuffer>;
|
|
|
121
122
|
* - Sets up middleware (JSON parsing, CORS)
|
|
122
123
|
* - Registers event collection endpoints (POST, GET, OPTIONS)
|
|
123
124
|
* - Starts HTTP server (if port configured)
|
|
124
|
-
* -
|
|
125
|
+
* - Provides destroy() for graceful shutdown (called by runner)
|
|
125
126
|
*
|
|
126
127
|
* @param context Source context with config, env, logger, id
|
|
127
128
|
* @returns Express source instance with app and push handler
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var mod,__create=Object.create,__defProp=Object.defineProperty,__getOwnPropDesc=Object.getOwnPropertyDescriptor,__getOwnPropNames=Object.getOwnPropertyNames,__getProtoOf=Object.getPrototypeOf,__hasOwnProp=Object.prototype.hasOwnProperty,__copyProps=(to,from,except,desc)=>{if(from&&"object"==typeof from||"function"==typeof from)for(let key of __getOwnPropNames(from))__hasOwnProp.call(to,key)||key===except||__defProp(to,key,{get:()=>from[key],enumerable:!(desc=__getOwnPropDesc(from,key))||desc.enumerable});return to},__toESM=(mod,isNodeMode,target)=>(target=null!=mod?__create(__getProtoOf(mod)):{},__copyProps(!isNodeMode&&mod&&mod.__esModule?target:__defProp(target,"default",{value:mod,enumerable:!0}),mod)),index_exports={};((target,all)=>{for(var name in all)__defProp(target,name,{get:all[name],enumerable:!0})})(index_exports,{TRANSPARENT_GIF:()=>TRANSPARENT_GIF,default:()=>index_default,setCorsHeaders:()=>setCorsHeaders,sourceExpress:()=>sourceExpress}),module.exports=(mod=index_exports,__copyProps(__defProp({},"__esModule",{value:!0}),mod));var import_express=__toESM(require("express")),import_cors=__toESM(require("cors")),import_core=require("@walkeros/core"),import_dev3=require("@walkeros/core/dev"),import_dev2=require("@walkeros/core/dev"),import_dev=require("@walkeros/core/dev"),HttpMethod=import_dev.z.enum(["GET","POST","PUT","PATCH","DELETE","OPTIONS","HEAD"]),RouteMethod=import_dev.z.enum(["GET","POST"]),RouteConfigSchema=import_dev.z.object({path:import_dev.z.string().describe("Express route path (supports wildcards like /api/*)"),methods:import_dev.z.array(RouteMethod).min(1).describe("HTTP methods to register. OPTIONS always included for CORS.").optional()}),CorsOrigin=import_dev.z.union([import_dev.z.string(),import_dev.z.array(import_dev.z.string()),import_dev.z.literal("*")]),CorsOptionsSchema=import_dev.z.object({origin:CorsOrigin.describe("Allowed origins (* for all, URL string, or array of URLs)").optional(),methods:import_dev.z.array(HttpMethod).describe("Allowed HTTP methods").optional(),headers:import_dev.z.array(import_dev.z.string()).describe("Allowed request headers").optional(),credentials:import_dev.z.boolean().describe("Allow credentials (cookies, authorization headers)").optional(),maxAge:import_dev.z.number().int().positive().describe("Preflight cache duration in seconds").optional()}),SettingsSchema=import_dev2.z.object({port:import_dev2.z.number().int().min(0).max(65535).describe("HTTP server port to listen on. Use 0 for random available port. If not provided, server will not start (app only mode)").optional(),path:import_dev2.z.string().describe("Deprecated: use paths instead").optional(),paths:import_dev2.z.array(import_dev2.z.union([import_dev2.z.string(),RouteConfigSchema])).min(1).describe("Route paths to register. String shorthand registers GET+POST. RouteConfig allows per-route method control.").optional(),cors:import_dev2.z.union([import_dev2.z.boolean(),CorsOptionsSchema]).describe("CORS configuration: false = disabled, true = allow all origins (default), object = custom configuration").default(!0)
|
|
1
|
+
"use strict";var mod,__create=Object.create,__defProp=Object.defineProperty,__getOwnPropDesc=Object.getOwnPropertyDescriptor,__getOwnPropNames=Object.getOwnPropertyNames,__getProtoOf=Object.getPrototypeOf,__hasOwnProp=Object.prototype.hasOwnProperty,__copyProps=(to,from,except,desc)=>{if(from&&"object"==typeof from||"function"==typeof from)for(let key of __getOwnPropNames(from))__hasOwnProp.call(to,key)||key===except||__defProp(to,key,{get:()=>from[key],enumerable:!(desc=__getOwnPropDesc(from,key))||desc.enumerable});return to},__toESM=(mod,isNodeMode,target)=>(target=null!=mod?__create(__getProtoOf(mod)):{},__copyProps(!isNodeMode&&mod&&mod.__esModule?target:__defProp(target,"default",{value:mod,enumerable:!0}),mod)),index_exports={};((target,all)=>{for(var name in all)__defProp(target,name,{get:all[name],enumerable:!0})})(index_exports,{TRANSPARENT_GIF:()=>TRANSPARENT_GIF,default:()=>index_default,setCorsHeaders:()=>setCorsHeaders,sourceExpress:()=>sourceExpress}),module.exports=(mod=index_exports,__copyProps(__defProp({},"__esModule",{value:!0}),mod));var import_express=__toESM(require("express")),import_cors=__toESM(require("cors")),import_core=require("@walkeros/core"),import_dev3=require("@walkeros/core/dev"),import_dev2=require("@walkeros/core/dev"),import_dev=require("@walkeros/core/dev"),HttpMethod=import_dev.z.enum(["GET","POST","PUT","PATCH","DELETE","OPTIONS","HEAD"]),RouteMethod=import_dev.z.enum(["GET","POST"]),RouteConfigSchema=import_dev.z.object({path:import_dev.z.string().describe("Express route path (supports wildcards like /api/*)"),methods:import_dev.z.array(RouteMethod).min(1).describe("HTTP methods to register. OPTIONS always included for CORS.").optional()}),CorsOrigin=import_dev.z.union([import_dev.z.string(),import_dev.z.array(import_dev.z.string()),import_dev.z.literal("*")]),CorsOptionsSchema=import_dev.z.object({origin:CorsOrigin.describe("Allowed origins (* for all, URL string, or array of URLs)").optional(),methods:import_dev.z.array(HttpMethod).describe("Allowed HTTP methods").optional(),headers:import_dev.z.array(import_dev.z.string()).describe("Allowed request headers").optional(),credentials:import_dev.z.boolean().describe("Allow credentials (cookies, authorization headers)").optional(),maxAge:import_dev.z.number().int().positive().describe("Preflight cache duration in seconds").optional()}),SettingsSchema=import_dev2.z.object({port:import_dev2.z.number().int().min(0).max(65535).describe("HTTP server port to listen on. Use 0 for random available port. If not provided, server will not start (app only mode)").optional(),path:import_dev2.z.string().describe("Deprecated: use paths instead").optional(),paths:import_dev2.z.array(import_dev2.z.union([import_dev2.z.string(),RouteConfigSchema])).min(1).describe("Route paths to register. String shorthand registers GET+POST. RouteConfig allows per-route method control.").optional(),cors:import_dev2.z.union([import_dev2.z.boolean(),CorsOptionsSchema]).describe("CORS configuration: false = disabled, true = allow all origins (default), object = custom configuration").default(!0)});(0,import_dev3.zodToSchema)(SettingsSchema);function setCorsHeaders(res,corsConfig=!0){if(!1!==corsConfig)if(!0===corsConfig)res.set("Access-Control-Allow-Origin","*"),res.set("Access-Control-Allow-Methods","GET, POST, OPTIONS"),res.set("Access-Control-Allow-Headers","Content-Type");else{if(corsConfig.origin){const origin=Array.isArray(corsConfig.origin)?corsConfig.origin.join(", "):corsConfig.origin;res.set("Access-Control-Allow-Origin",origin)}corsConfig.methods&&res.set("Access-Control-Allow-Methods",corsConfig.methods.join(", ")),corsConfig.headers&&res.set("Access-Control-Allow-Headers",corsConfig.headers.join(", ")),corsConfig.credentials&&res.set("Access-Control-Allow-Credentials","true"),corsConfig.maxAge&&res.set("Access-Control-Max-Age",String(corsConfig.maxAge))}}var TRANSPARENT_GIF=Buffer.from("R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7","base64"),sourceExpress=async context=>{var _a;const{config:config={},env:env}=context,parsed=SettingsSchema.parse(config.settings||{}),settings2={...parsed,paths:null!=(_a=parsed.paths)?_a:parsed.path?[parsed.path]:["/collect"]},app=(0,import_express.default)();if(app.use(import_express.default.json({limit:"1mb"})),!1!==settings2.cors){const corsOptions=!0===settings2.cors?{}:settings2.cors;app.use((0,import_cors.default)(corsOptions))}const push=async(req,res)=>{try{if("OPTIONS"===req.method)return setCorsHeaders(res,settings2.cors),void res.status(204).send();await context.setIngest(req);const respond=(0,import_core.createRespond)(options=>{var _a2;const status=null!=(_a2=options.status)?_a2:200;if(options.headers)for(const[key,value]of Object.entries(options.headers))res.set(key,value);res.status(status),"string"==typeof options.body||Buffer.isBuffer(options.body)?res.send(options.body):res.json(options.body)});if(context.setRespond(respond),"GET"===req.method){const parsedData=(0,import_core.requestToData)(req.url);return parsedData&&"object"==typeof parsedData&&await env.push(parsedData),void respond({body:TRANSPARENT_GIF,headers:{"Content-Type":"image/gif","Cache-Control":"no-cache, no-store, must-revalidate"}})}if("POST"===req.method){const eventData=req.body;return eventData&&"object"==typeof eventData?(await env.push(eventData),void respond({body:{success:!0,timestamp:Date.now()}})):void res.status(400).json({success:!1,error:"Invalid event: body must be an object"})}res.status(405).json({success:!1,error:"Method not allowed. Use POST, GET, or OPTIONS."})}catch(error){res.status(500).json({success:!1,error:error instanceof Error?error.message:"Internal server error"})}},resolvedPaths=settings2.paths.map(entry=>"string"==typeof entry?{path:entry,methods:["GET","POST"]}:{path:entry.path,methods:entry.methods||["GET","POST"]});for(const route of resolvedPaths)route.methods.includes("POST")&&app.post(route.path,push),route.methods.includes("GET")&&app.get(route.path,push),app.options(route.path,push);let server;void 0!==settings2.port&&(server=app.listen(settings2.port,()=>{const routeLines=resolvedPaths.map(r=>` ${[...r.methods,"OPTIONS"].join(", ")} ${r.path}`).join("\n");env.logger.info(`Express source listening on port ${settings2.port}\n`+routeLines)}));return{type:"express",config:{...config,settings:settings2},push:push,httpHandler:app,app:app,server:server,destroy:_context=>new Promise((resolve,reject)=>{if(!server)return resolve();server.close(err=>err?reject(err):resolve())})}},index_default=sourceExpress;//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/schemas/index.ts","../src/schemas/settings.ts","../src/schemas/primitives.ts","../src/utils.ts"],"sourcesContent":["import express, { type Request, type Response } from 'express';\nimport cors from 'cors';\nimport { requestToData } from '@walkeros/core';\nimport type { Source } from '@walkeros/core';\nimport type { ExpressSource, Types, EventRequest } from './types';\nimport { SettingsSchema } from './schemas';\nimport { setCorsHeaders, TRANSPARENT_GIF } from './utils';\n\n/**\n * Express source initialization\n *\n * This source OWNS its HTTP server infrastructure:\n * - Creates Express application\n * - Sets up middleware (JSON parsing, CORS)\n * - Registers event collection endpoints (POST, GET, OPTIONS)\n * - Starts HTTP server (if port configured)\n * - Handles graceful shutdown\n *\n * @param context Source context with config, env, logger, id\n * @returns Express source instance with app and push handler\n */\nexport const sourceExpress = async (\n context: Source.Context<Types>,\n): Promise<ExpressSource> => {\n const { config = {}, env } = context;\n\n // Validate and apply default settings\n const parsed = SettingsSchema.parse(config.settings || {});\n const settings = {\n ...parsed,\n paths: parsed.paths ?? (parsed.path ? [parsed.path] : ['/collect']),\n };\n\n const app = express();\n\n // Middleware setup - JSON body parsing with 10mb default limit\n app.use(express.json({ limit: '1mb' }));\n\n // CORS middleware (enabled by default)\n if (settings.cors !== false) {\n const corsOptions = settings.cors === true ? {} : settings.cors;\n app.use(cors(corsOptions));\n }\n\n /**\n * Request handler - transforms HTTP requests into walker events\n * Supports POST (JSON body), GET (query params), and OPTIONS (CORS preflight)\n */\n const push = async (req: Request, res: Response): Promise<void> => {\n try {\n // Handle OPTIONS for CORS preflight\n if (req.method === 'OPTIONS') {\n setCorsHeaders(res, settings.cors);\n res.status(204).send();\n return;\n }\n\n // Extract ingest metadata from request (if config.ingest is defined)\n await context.setIngest(req);\n\n // Handle GET requests (pixel tracking)\n if (req.method === 'GET') {\n // Parse query parameters to event data using requestToData\n const parsedData = requestToData(req.url);\n\n // Send to collector\n if (parsedData && typeof parsedData === 'object') {\n await env.push(parsedData);\n }\n\n // Return 1x1 transparent GIF for pixel tracking\n res.set('Content-Type', 'image/gif');\n res.set('Cache-Control', 'no-cache, no-store, must-revalidate');\n res.send(TRANSPARENT_GIF);\n return;\n }\n\n // Handle POST requests (standard event ingestion)\n if (req.method === 'POST') {\n const eventData = req.body;\n\n if (!eventData || typeof eventData !== 'object') {\n res.status(400).json({\n success: false,\n error: 'Invalid event: body must be an object',\n });\n return;\n }\n\n // Send event to collector\n await env.push(eventData);\n\n res.json({\n success: true,\n timestamp: Date.now(),\n });\n return;\n }\n\n // Unsupported method\n res.status(405).json({\n success: false,\n error: 'Method not allowed. Use POST, GET, or OPTIONS.',\n });\n } catch (error) {\n res.status(500).json({\n success: false,\n error: error instanceof Error ? error.message : 'Internal server error',\n });\n }\n };\n\n // Register handlers per route config\n const resolvedPaths = settings.paths.map((entry) =>\n typeof entry === 'string'\n ? { path: entry, methods: ['GET', 'POST'] as const }\n : {\n path: entry.path,\n methods: entry.methods || (['GET', 'POST'] as const),\n },\n );\n\n for (const route of resolvedPaths) {\n if (route.methods.includes('POST')) app.post(route.path, push);\n if (route.methods.includes('GET')) app.get(route.path, push);\n app.options(route.path, push); // Always register OPTIONS for CORS\n }\n\n // Health check endpoints (if enabled)\n if (settings.status) {\n app.get('/health', (req, res) => {\n res.json({\n status: 'ok',\n timestamp: Date.now(),\n source: 'express',\n });\n });\n\n app.get('/ready', (req, res) => {\n res.json({\n status: 'ready',\n timestamp: Date.now(),\n source: 'express',\n });\n });\n }\n\n // Source owns the HTTP server (if port configured)\n let server: ReturnType<typeof app.listen> | undefined;\n\n if (settings.port !== undefined) {\n server = app.listen(settings.port, () => {\n const statusRoutes = settings.status\n ? `\\n GET /health - Health check\\n GET /ready - Readiness check`\n : '';\n const routeLines = resolvedPaths\n .map((r) => {\n const methods = [...r.methods, 'OPTIONS'].join(', ');\n return ` ${methods} ${r.path}`;\n })\n .join('\\n');\n env.logger.info(\n `Express source listening on port ${settings.port}\\n` +\n routeLines +\n statusRoutes,\n );\n });\n\n // Graceful shutdown handlers\n const shutdownHandler = () => {\n if (server) {\n server.close();\n }\n };\n\n process.on('SIGTERM', shutdownHandler);\n process.on('SIGINT', shutdownHandler);\n }\n\n const instance: ExpressSource = {\n type: 'express',\n config: {\n ...config,\n settings,\n },\n push,\n app, // Expose app for advanced usage\n server, // Expose server (if started)\n };\n\n return instance;\n};\n\n// Export types (avoid re-exporting duplicates from schemas)\nexport type {\n ExpressSource,\n Config,\n PartialConfig,\n Types,\n EventRequest,\n EventResponse,\n RequestBody,\n ResponseBody,\n Push,\n Env,\n Mapping,\n InitSettings,\n Settings,\n RouteConfig,\n RouteMethod,\n} from './types';\n\n// Export utils\nexport { setCorsHeaders, TRANSPARENT_GIF } from './utils';\n\nexport default sourceExpress;\n","import { zodToSchema } from '@walkeros/core/dev';\nimport { SettingsSchema } from './settings';\n\nexport * from './primitives';\nexport { SettingsSchema, type Settings } from './settings';\n\n// JSON Schema\nexport const settings = zodToSchema(SettingsSchema);\n","import { z } from '@walkeros/core/dev';\nimport { CorsOptionsSchema, RouteConfigSchema } from './primitives';\n\n/**\n * Express source settings schema.\n */\nexport const SettingsSchema = z.object({\n port: z\n .number()\n .int()\n .min(0)\n .max(65535)\n .describe(\n 'HTTP server port to listen on. Use 0 for random available port. If not provided, server will not start (app only mode)',\n )\n .optional(),\n\n /** @deprecated Use `paths` instead */\n path: z.string().describe('Deprecated: use paths instead').optional(),\n\n paths: z\n .array(z.union([z.string(), RouteConfigSchema]))\n .min(1)\n .describe(\n 'Route paths to register. String shorthand registers GET+POST. RouteConfig allows per-route method control.',\n )\n .optional(),\n\n cors: z\n .union([z.boolean(), CorsOptionsSchema])\n .describe(\n 'CORS configuration: false = disabled, true = allow all origins (default), object = custom configuration',\n )\n .default(true),\n\n status: z\n .boolean()\n .describe('Enable health check endpoints (/health, /ready)')\n .default(true),\n});\n\nexport type Settings = z.infer<typeof SettingsSchema>;\n","import { z } from '@walkeros/core/dev';\n\n/**\n * HTTP methods enum\n */\nexport const HttpMethod = z.enum([\n 'GET',\n 'POST',\n 'PUT',\n 'PATCH',\n 'DELETE',\n 'OPTIONS',\n 'HEAD',\n]);\n\n/**\n * HTTP methods supported for route configuration.\n * OPTIONS is always registered for CORS (not user-configurable per route).\n */\nexport const RouteMethod = z.enum(['GET', 'POST']);\n\n/**\n * Route configuration for multi-path support.\n */\nexport const RouteConfigSchema = z.object({\n path: z\n .string()\n .describe('Express route path (supports wildcards like /api/*)'),\n methods: z\n .array(RouteMethod)\n .min(1)\n .describe('HTTP methods to register. OPTIONS always included for CORS.')\n .optional(),\n});\n\n/**\n * CORS origin configuration\n * Accepts:\n * - '*' for all origins\n * - Single URL string\n * - Array of URL strings\n */\nexport const CorsOrigin = z.union([\n z.string(),\n z.array(z.string()),\n z.literal('*'),\n]);\n\n/**\n * CORS options schema\n * Configuration for Cross-Origin Resource Sharing\n */\nexport const CorsOptionsSchema = z.object({\n origin: CorsOrigin.describe(\n 'Allowed origins (* for all, URL string, or array of URLs)',\n ).optional(),\n\n methods: z.array(HttpMethod).describe('Allowed HTTP methods').optional(),\n\n headers: z.array(z.string()).describe('Allowed request headers').optional(),\n\n credentials: z\n .boolean()\n .describe('Allow credentials (cookies, authorization headers)')\n .optional(),\n\n maxAge: z\n .number()\n .int()\n .positive()\n .describe('Preflight cache duration in seconds')\n .optional(),\n});\n\nexport type CorsOptions = z.infer<typeof CorsOptionsSchema>;\n","import type { Response } from 'express';\nimport type { CorsOptions } from './schemas';\n\n/**\n * Set CORS headers on response\n *\n * @param res Express response object\n * @param corsConfig CORS configuration (false = disabled, true = allow all, object = custom)\n */\nexport function setCorsHeaders(\n res: Response,\n corsConfig: boolean | CorsOptions = true,\n): void {\n if (corsConfig === false) return;\n\n if (corsConfig === true) {\n // Simple CORS - allow all\n res.set('Access-Control-Allow-Origin', '*');\n res.set('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');\n res.set('Access-Control-Allow-Headers', 'Content-Type');\n } else {\n // Custom CORS configuration\n if (corsConfig.origin) {\n const origin = Array.isArray(corsConfig.origin)\n ? corsConfig.origin.join(', ')\n : corsConfig.origin;\n res.set('Access-Control-Allow-Origin', origin);\n }\n\n if (corsConfig.methods) {\n res.set('Access-Control-Allow-Methods', corsConfig.methods.join(', '));\n }\n\n if (corsConfig.headers) {\n res.set('Access-Control-Allow-Headers', corsConfig.headers.join(', '));\n }\n\n if (corsConfig.credentials) {\n res.set('Access-Control-Allow-Credentials', 'true');\n }\n\n if (corsConfig.maxAge) {\n res.set('Access-Control-Max-Age', String(corsConfig.maxAge));\n }\n }\n}\n\n/**\n * 1x1 transparent GIF for pixel tracking\n * Base64-encoded GIF (43 bytes)\n */\nexport const TRANSPARENT_GIF = Buffer.from(\n 'R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7',\n 'base64',\n);\n"],"mappings":"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","names":["import_dev","import_dev","settings","express","cors"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/schemas/index.ts","../src/schemas/settings.ts","../src/schemas/primitives.ts","../src/utils.ts"],"sourcesContent":["import express, { type Request, type Response } from 'express';\nimport cors from 'cors';\nimport { requestToData, createRespond } from '@walkeros/core';\nimport type { Source } from '@walkeros/core';\nimport type { ExpressSource, Types, EventRequest } from './types';\nimport { SettingsSchema } from './schemas';\nimport { setCorsHeaders, TRANSPARENT_GIF } from './utils';\n\n/**\n * Express source initialization\n *\n * This source OWNS its HTTP server infrastructure:\n * - Creates Express application\n * - Sets up middleware (JSON parsing, CORS)\n * - Registers event collection endpoints (POST, GET, OPTIONS)\n * - Starts HTTP server (if port configured)\n * - Provides destroy() for graceful shutdown (called by runner)\n *\n * @param context Source context with config, env, logger, id\n * @returns Express source instance with app and push handler\n */\nexport const sourceExpress = async (\n context: Source.Context<Types>,\n): Promise<ExpressSource> => {\n const { config = {}, env } = context;\n\n // Validate and apply default settings\n const parsed = SettingsSchema.parse(config.settings || {});\n const settings = {\n ...parsed,\n paths: parsed.paths ?? (parsed.path ? [parsed.path] : ['/collect']),\n };\n\n const app = express();\n\n // Middleware setup - JSON body parsing with 10mb default limit\n app.use(express.json({ limit: '1mb' }));\n\n // CORS middleware (enabled by default)\n if (settings.cors !== false) {\n const corsOptions = settings.cors === true ? {} : settings.cors;\n app.use(cors(corsOptions));\n }\n\n /**\n * Request handler - transforms HTTP requests into walker events\n * Supports POST (JSON body), GET (query params), and OPTIONS (CORS preflight)\n */\n const push = async (req: Request, res: Response): Promise<void> => {\n try {\n // Handle OPTIONS for CORS preflight\n if (req.method === 'OPTIONS') {\n setCorsHeaders(res, settings.cors);\n res.status(204).send();\n return;\n }\n\n // Extract ingest metadata from request (if config.ingest is defined)\n await context.setIngest(req);\n\n // Create per-request respond — first call wins (idempotent)\n const respond = createRespond((options) => {\n const status = options.status ?? 200;\n if (options.headers) {\n for (const [key, value] of Object.entries(options.headers)) {\n res.set(key, value);\n }\n }\n res.status(status);\n if (typeof options.body === 'string' || Buffer.isBuffer(options.body)) {\n res.send(options.body);\n } else {\n res.json(options.body);\n }\n });\n context.setRespond(respond);\n\n // Handle GET requests (pixel tracking)\n if (req.method === 'GET') {\n // Parse query parameters to event data using requestToData\n const parsedData = requestToData(req.url);\n\n // Send to collector\n if (parsedData && typeof parsedData === 'object') {\n await env.push(parsedData);\n }\n\n // Default: 1x1 GIF (skipped if a step already called respond)\n respond({\n body: TRANSPARENT_GIF,\n headers: {\n 'Content-Type': 'image/gif',\n 'Cache-Control': 'no-cache, no-store, must-revalidate',\n },\n });\n return;\n }\n\n // Handle POST requests (standard event ingestion)\n if (req.method === 'POST') {\n const eventData = req.body;\n\n if (!eventData || typeof eventData !== 'object') {\n res.status(400).json({\n success: false,\n error: 'Invalid event: body must be an object',\n });\n return;\n }\n\n // Send event to collector\n await env.push(eventData);\n\n // Default: JSON success (skipped if a step already called respond)\n respond({ body: { success: true, timestamp: Date.now() } });\n return;\n }\n\n // Unsupported method\n res.status(405).json({\n success: false,\n error: 'Method not allowed. Use POST, GET, or OPTIONS.',\n });\n } catch (error) {\n res.status(500).json({\n success: false,\n error: error instanceof Error ? error.message : 'Internal server error',\n });\n }\n };\n\n // Register handlers per route config\n const resolvedPaths = settings.paths.map((entry) =>\n typeof entry === 'string'\n ? { path: entry, methods: ['GET', 'POST'] as const }\n : {\n path: entry.path,\n methods: entry.methods || (['GET', 'POST'] as const),\n },\n );\n\n for (const route of resolvedPaths) {\n if (route.methods.includes('POST')) app.post(route.path, push);\n if (route.methods.includes('GET')) app.get(route.path, push);\n app.options(route.path, push); // Always register OPTIONS for CORS\n }\n\n // Source owns the HTTP server (if port configured)\n let server: ReturnType<typeof app.listen> | undefined;\n\n if (settings.port !== undefined) {\n server = app.listen(settings.port, () => {\n const routeLines = resolvedPaths\n .map((r) => {\n const methods = [...r.methods, 'OPTIONS'].join(', ');\n return ` ${methods} ${r.path}`;\n })\n .join('\\n');\n env.logger.info(\n `Express source listening on port ${settings.port}\\n` + routeLines,\n );\n });\n }\n\n const instance: ExpressSource = {\n type: 'express',\n config: {\n ...config,\n settings,\n },\n push,\n httpHandler: app,\n app,\n server,\n destroy: (_context) =>\n new Promise<void>((resolve, reject) => {\n if (!server) return resolve();\n server.close((err) => (err ? reject(err) : resolve()));\n }),\n };\n\n return instance;\n};\n\n// Export types (avoid re-exporting duplicates from schemas)\nexport type {\n ExpressSource,\n Config,\n PartialConfig,\n Types,\n EventRequest,\n EventResponse,\n RequestBody,\n ResponseBody,\n Push,\n Env,\n Mapping,\n InitSettings,\n Settings,\n RouteConfig,\n RouteMethod,\n} from './types';\n\n// Export utils\nexport { setCorsHeaders, TRANSPARENT_GIF } from './utils';\n\nexport default sourceExpress;\n","import { zodToSchema } from '@walkeros/core/dev';\nimport { SettingsSchema } from './settings';\n\nexport * from './primitives';\nexport { SettingsSchema, type Settings } from './settings';\n\n// JSON Schema\nexport const settings = zodToSchema(SettingsSchema);\n","import { z } from '@walkeros/core/dev';\nimport { CorsOptionsSchema, RouteConfigSchema } from './primitives';\n\n/**\n * Express source settings schema.\n */\nexport const SettingsSchema = z.object({\n port: z\n .number()\n .int()\n .min(0)\n .max(65535)\n .describe(\n 'HTTP server port to listen on. Use 0 for random available port. If not provided, server will not start (app only mode)',\n )\n .optional(),\n\n /** @deprecated Use `paths` instead */\n path: z.string().describe('Deprecated: use paths instead').optional(),\n\n paths: z\n .array(z.union([z.string(), RouteConfigSchema]))\n .min(1)\n .describe(\n 'Route paths to register. String shorthand registers GET+POST. RouteConfig allows per-route method control.',\n )\n .optional(),\n\n cors: z\n .union([z.boolean(), CorsOptionsSchema])\n .describe(\n 'CORS configuration: false = disabled, true = allow all origins (default), object = custom configuration',\n )\n .default(true),\n});\n\nexport type Settings = z.infer<typeof SettingsSchema>;\n","import { z } from '@walkeros/core/dev';\n\n/**\n * HTTP methods enum\n */\nexport const HttpMethod = z.enum([\n 'GET',\n 'POST',\n 'PUT',\n 'PATCH',\n 'DELETE',\n 'OPTIONS',\n 'HEAD',\n]);\n\n/**\n * HTTP methods supported for route configuration.\n * OPTIONS is always registered for CORS (not user-configurable per route).\n */\nexport const RouteMethod = z.enum(['GET', 'POST']);\n\n/**\n * Route configuration for multi-path support.\n */\nexport const RouteConfigSchema = z.object({\n path: z\n .string()\n .describe('Express route path (supports wildcards like /api/*)'),\n methods: z\n .array(RouteMethod)\n .min(1)\n .describe('HTTP methods to register. OPTIONS always included for CORS.')\n .optional(),\n});\n\n/**\n * CORS origin configuration\n * Accepts:\n * - '*' for all origins\n * - Single URL string\n * - Array of URL strings\n */\nexport const CorsOrigin = z.union([\n z.string(),\n z.array(z.string()),\n z.literal('*'),\n]);\n\n/**\n * CORS options schema\n * Configuration for Cross-Origin Resource Sharing\n */\nexport const CorsOptionsSchema = z.object({\n origin: CorsOrigin.describe(\n 'Allowed origins (* for all, URL string, or array of URLs)',\n ).optional(),\n\n methods: z.array(HttpMethod).describe('Allowed HTTP methods').optional(),\n\n headers: z.array(z.string()).describe('Allowed request headers').optional(),\n\n credentials: z\n .boolean()\n .describe('Allow credentials (cookies, authorization headers)')\n .optional(),\n\n maxAge: z\n .number()\n .int()\n .positive()\n .describe('Preflight cache duration in seconds')\n .optional(),\n});\n\nexport type CorsOptions = z.infer<typeof CorsOptionsSchema>;\n","import type { Response } from 'express';\nimport type { CorsOptions } from './schemas';\n\n/**\n * Set CORS headers on response\n *\n * @param res Express response object\n * @param corsConfig CORS configuration (false = disabled, true = allow all, object = custom)\n */\nexport function setCorsHeaders(\n res: Response,\n corsConfig: boolean | CorsOptions = true,\n): void {\n if (corsConfig === false) return;\n\n if (corsConfig === true) {\n // Simple CORS - allow all\n res.set('Access-Control-Allow-Origin', '*');\n res.set('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');\n res.set('Access-Control-Allow-Headers', 'Content-Type');\n } else {\n // Custom CORS configuration\n if (corsConfig.origin) {\n const origin = Array.isArray(corsConfig.origin)\n ? corsConfig.origin.join(', ')\n : corsConfig.origin;\n res.set('Access-Control-Allow-Origin', origin);\n }\n\n if (corsConfig.methods) {\n res.set('Access-Control-Allow-Methods', corsConfig.methods.join(', '));\n }\n\n if (corsConfig.headers) {\n res.set('Access-Control-Allow-Headers', corsConfig.headers.join(', '));\n }\n\n if (corsConfig.credentials) {\n res.set('Access-Control-Allow-Credentials', 'true');\n }\n\n if (corsConfig.maxAge) {\n res.set('Access-Control-Max-Age', String(corsConfig.maxAge));\n }\n }\n}\n\n/**\n * 1x1 transparent GIF for pixel tracking\n * Base64-encoded GIF (43 bytes)\n */\nexport const TRANSPARENT_GIF = Buffer.from(\n 'R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7',\n 'base64',\n);\n"],"mappings":"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","names":["import_dev","import_dev","settings","express","cors","_a"]}
|
package/dist/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import express from"express";import cors from"cors";import{requestToData}from"@walkeros/core";import{zodToSchema}from"@walkeros/core/dev";import{z as z2}from"@walkeros/core/dev";import{z}from"@walkeros/core/dev";var HttpMethod=z.enum(["GET","POST","PUT","PATCH","DELETE","OPTIONS","HEAD"]),RouteMethod=z.enum(["GET","POST"]),RouteConfigSchema=z.object({path:z.string().describe("Express route path (supports wildcards like /api/*)"),methods:z.array(RouteMethod).min(1).describe("HTTP methods to register. OPTIONS always included for CORS.").optional()}),CorsOrigin=z.union([z.string(),z.array(z.string()),z.literal("*")]),CorsOptionsSchema=z.object({origin:CorsOrigin.describe("Allowed origins (* for all, URL string, or array of URLs)").optional(),methods:z.array(HttpMethod).describe("Allowed HTTP methods").optional(),headers:z.array(z.string()).describe("Allowed request headers").optional(),credentials:z.boolean().describe("Allow credentials (cookies, authorization headers)").optional(),maxAge:z.number().int().positive().describe("Preflight cache duration in seconds").optional()}),SettingsSchema=z2.object({port:z2.number().int().min(0).max(65535).describe("HTTP server port to listen on. Use 0 for random available port. If not provided, server will not start (app only mode)").optional(),path:z2.string().describe("Deprecated: use paths instead").optional(),paths:z2.array(z2.union([z2.string(),RouteConfigSchema])).min(1).describe("Route paths to register. String shorthand registers GET+POST. RouteConfig allows per-route method control.").optional(),cors:z2.union([z2.boolean(),CorsOptionsSchema]).describe("CORS configuration: false = disabled, true = allow all origins (default), object = custom configuration").default(!0)
|
|
1
|
+
import express from"express";import cors from"cors";import{requestToData,createRespond}from"@walkeros/core";import{zodToSchema}from"@walkeros/core/dev";import{z as z2}from"@walkeros/core/dev";import{z}from"@walkeros/core/dev";var HttpMethod=z.enum(["GET","POST","PUT","PATCH","DELETE","OPTIONS","HEAD"]),RouteMethod=z.enum(["GET","POST"]),RouteConfigSchema=z.object({path:z.string().describe("Express route path (supports wildcards like /api/*)"),methods:z.array(RouteMethod).min(1).describe("HTTP methods to register. OPTIONS always included for CORS.").optional()}),CorsOrigin=z.union([z.string(),z.array(z.string()),z.literal("*")]),CorsOptionsSchema=z.object({origin:CorsOrigin.describe("Allowed origins (* for all, URL string, or array of URLs)").optional(),methods:z.array(HttpMethod).describe("Allowed HTTP methods").optional(),headers:z.array(z.string()).describe("Allowed request headers").optional(),credentials:z.boolean().describe("Allow credentials (cookies, authorization headers)").optional(),maxAge:z.number().int().positive().describe("Preflight cache duration in seconds").optional()}),SettingsSchema=z2.object({port:z2.number().int().min(0).max(65535).describe("HTTP server port to listen on. Use 0 for random available port. If not provided, server will not start (app only mode)").optional(),path:z2.string().describe("Deprecated: use paths instead").optional(),paths:z2.array(z2.union([z2.string(),RouteConfigSchema])).min(1).describe("Route paths to register. String shorthand registers GET+POST. RouteConfig allows per-route method control.").optional(),cors:z2.union([z2.boolean(),CorsOptionsSchema]).describe("CORS configuration: false = disabled, true = allow all origins (default), object = custom configuration").default(!0)});zodToSchema(SettingsSchema);function setCorsHeaders(res,corsConfig=!0){if(!1!==corsConfig)if(!0===corsConfig)res.set("Access-Control-Allow-Origin","*"),res.set("Access-Control-Allow-Methods","GET, POST, OPTIONS"),res.set("Access-Control-Allow-Headers","Content-Type");else{if(corsConfig.origin){const origin=Array.isArray(corsConfig.origin)?corsConfig.origin.join(", "):corsConfig.origin;res.set("Access-Control-Allow-Origin",origin)}corsConfig.methods&&res.set("Access-Control-Allow-Methods",corsConfig.methods.join(", ")),corsConfig.headers&&res.set("Access-Control-Allow-Headers",corsConfig.headers.join(", ")),corsConfig.credentials&&res.set("Access-Control-Allow-Credentials","true"),corsConfig.maxAge&&res.set("Access-Control-Max-Age",String(corsConfig.maxAge))}}var TRANSPARENT_GIF=Buffer.from("R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7","base64"),sourceExpress=async context=>{var _a;const{config:config={},env:env}=context,parsed=SettingsSchema.parse(config.settings||{}),settings2={...parsed,paths:null!=(_a=parsed.paths)?_a:parsed.path?[parsed.path]:["/collect"]},app=express();if(app.use(express.json({limit:"1mb"})),!1!==settings2.cors){const corsOptions=!0===settings2.cors?{}:settings2.cors;app.use(cors(corsOptions))}const push=async(req,res)=>{try{if("OPTIONS"===req.method)return setCorsHeaders(res,settings2.cors),void res.status(204).send();await context.setIngest(req);const respond=createRespond(options=>{var _a2;const status=null!=(_a2=options.status)?_a2:200;if(options.headers)for(const[key,value]of Object.entries(options.headers))res.set(key,value);res.status(status),"string"==typeof options.body||Buffer.isBuffer(options.body)?res.send(options.body):res.json(options.body)});if(context.setRespond(respond),"GET"===req.method){const parsedData=requestToData(req.url);return parsedData&&"object"==typeof parsedData&&await env.push(parsedData),void respond({body:TRANSPARENT_GIF,headers:{"Content-Type":"image/gif","Cache-Control":"no-cache, no-store, must-revalidate"}})}if("POST"===req.method){const eventData=req.body;return eventData&&"object"==typeof eventData?(await env.push(eventData),void respond({body:{success:!0,timestamp:Date.now()}})):void res.status(400).json({success:!1,error:"Invalid event: body must be an object"})}res.status(405).json({success:!1,error:"Method not allowed. Use POST, GET, or OPTIONS."})}catch(error){res.status(500).json({success:!1,error:error instanceof Error?error.message:"Internal server error"})}},resolvedPaths=settings2.paths.map(entry=>"string"==typeof entry?{path:entry,methods:["GET","POST"]}:{path:entry.path,methods:entry.methods||["GET","POST"]});for(const route of resolvedPaths)route.methods.includes("POST")&&app.post(route.path,push),route.methods.includes("GET")&&app.get(route.path,push),app.options(route.path,push);let server;void 0!==settings2.port&&(server=app.listen(settings2.port,()=>{const routeLines=resolvedPaths.map(r=>` ${[...r.methods,"OPTIONS"].join(", ")} ${r.path}`).join("\n");env.logger.info(`Express source listening on port ${settings2.port}\n`+routeLines)}));return{type:"express",config:{...config,settings:settings2},push:push,httpHandler:app,app:app,server:server,destroy:_context=>new Promise((resolve,reject)=>{if(!server)return resolve();server.close(err=>err?reject(err):resolve())})}},index_default=sourceExpress;export{TRANSPARENT_GIF,index_default as default,setCorsHeaders,sourceExpress};//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/schemas/index.ts","../src/schemas/settings.ts","../src/schemas/primitives.ts","../src/utils.ts"],"sourcesContent":["import express, { type Request, type Response } from 'express';\nimport cors from 'cors';\nimport { requestToData } from '@walkeros/core';\nimport type { Source } from '@walkeros/core';\nimport type { ExpressSource, Types, EventRequest } from './types';\nimport { SettingsSchema } from './schemas';\nimport { setCorsHeaders, TRANSPARENT_GIF } from './utils';\n\n/**\n * Express source initialization\n *\n * This source OWNS its HTTP server infrastructure:\n * - Creates Express application\n * - Sets up middleware (JSON parsing, CORS)\n * - Registers event collection endpoints (POST, GET, OPTIONS)\n * - Starts HTTP server (if port configured)\n * - Handles graceful shutdown\n *\n * @param context Source context with config, env, logger, id\n * @returns Express source instance with app and push handler\n */\nexport const sourceExpress = async (\n context: Source.Context<Types>,\n): Promise<ExpressSource> => {\n const { config = {}, env } = context;\n\n // Validate and apply default settings\n const parsed = SettingsSchema.parse(config.settings || {});\n const settings = {\n ...parsed,\n paths: parsed.paths ?? (parsed.path ? [parsed.path] : ['/collect']),\n };\n\n const app = express();\n\n // Middleware setup - JSON body parsing with 10mb default limit\n app.use(express.json({ limit: '1mb' }));\n\n // CORS middleware (enabled by default)\n if (settings.cors !== false) {\n const corsOptions = settings.cors === true ? {} : settings.cors;\n app.use(cors(corsOptions));\n }\n\n /**\n * Request handler - transforms HTTP requests into walker events\n * Supports POST (JSON body), GET (query params), and OPTIONS (CORS preflight)\n */\n const push = async (req: Request, res: Response): Promise<void> => {\n try {\n // Handle OPTIONS for CORS preflight\n if (req.method === 'OPTIONS') {\n setCorsHeaders(res, settings.cors);\n res.status(204).send();\n return;\n }\n\n // Extract ingest metadata from request (if config.ingest is defined)\n await context.setIngest(req);\n\n // Handle GET requests (pixel tracking)\n if (req.method === 'GET') {\n // Parse query parameters to event data using requestToData\n const parsedData = requestToData(req.url);\n\n // Send to collector\n if (parsedData && typeof parsedData === 'object') {\n await env.push(parsedData);\n }\n\n // Return 1x1 transparent GIF for pixel tracking\n res.set('Content-Type', 'image/gif');\n res.set('Cache-Control', 'no-cache, no-store, must-revalidate');\n res.send(TRANSPARENT_GIF);\n return;\n }\n\n // Handle POST requests (standard event ingestion)\n if (req.method === 'POST') {\n const eventData = req.body;\n\n if (!eventData || typeof eventData !== 'object') {\n res.status(400).json({\n success: false,\n error: 'Invalid event: body must be an object',\n });\n return;\n }\n\n // Send event to collector\n await env.push(eventData);\n\n res.json({\n success: true,\n timestamp: Date.now(),\n });\n return;\n }\n\n // Unsupported method\n res.status(405).json({\n success: false,\n error: 'Method not allowed. Use POST, GET, or OPTIONS.',\n });\n } catch (error) {\n res.status(500).json({\n success: false,\n error: error instanceof Error ? error.message : 'Internal server error',\n });\n }\n };\n\n // Register handlers per route config\n const resolvedPaths = settings.paths.map((entry) =>\n typeof entry === 'string'\n ? { path: entry, methods: ['GET', 'POST'] as const }\n : {\n path: entry.path,\n methods: entry.methods || (['GET', 'POST'] as const),\n },\n );\n\n for (const route of resolvedPaths) {\n if (route.methods.includes('POST')) app.post(route.path, push);\n if (route.methods.includes('GET')) app.get(route.path, push);\n app.options(route.path, push); // Always register OPTIONS for CORS\n }\n\n // Health check endpoints (if enabled)\n if (settings.status) {\n app.get('/health', (req, res) => {\n res.json({\n status: 'ok',\n timestamp: Date.now(),\n source: 'express',\n });\n });\n\n app.get('/ready', (req, res) => {\n res.json({\n status: 'ready',\n timestamp: Date.now(),\n source: 'express',\n });\n });\n }\n\n // Source owns the HTTP server (if port configured)\n let server: ReturnType<typeof app.listen> | undefined;\n\n if (settings.port !== undefined) {\n server = app.listen(settings.port, () => {\n const statusRoutes = settings.status\n ? `\\n GET /health - Health check\\n GET /ready - Readiness check`\n : '';\n const routeLines = resolvedPaths\n .map((r) => {\n const methods = [...r.methods, 'OPTIONS'].join(', ');\n return ` ${methods} ${r.path}`;\n })\n .join('\\n');\n env.logger.info(\n `Express source listening on port ${settings.port}\\n` +\n routeLines +\n statusRoutes,\n );\n });\n\n // Graceful shutdown handlers\n const shutdownHandler = () => {\n if (server) {\n server.close();\n }\n };\n\n process.on('SIGTERM', shutdownHandler);\n process.on('SIGINT', shutdownHandler);\n }\n\n const instance: ExpressSource = {\n type: 'express',\n config: {\n ...config,\n settings,\n },\n push,\n app, // Expose app for advanced usage\n server, // Expose server (if started)\n };\n\n return instance;\n};\n\n// Export types (avoid re-exporting duplicates from schemas)\nexport type {\n ExpressSource,\n Config,\n PartialConfig,\n Types,\n EventRequest,\n EventResponse,\n RequestBody,\n ResponseBody,\n Push,\n Env,\n Mapping,\n InitSettings,\n Settings,\n RouteConfig,\n RouteMethod,\n} from './types';\n\n// Export utils\nexport { setCorsHeaders, TRANSPARENT_GIF } from './utils';\n\nexport default sourceExpress;\n","import { zodToSchema } from '@walkeros/core/dev';\nimport { SettingsSchema } from './settings';\n\nexport * from './primitives';\nexport { SettingsSchema, type Settings } from './settings';\n\n// JSON Schema\nexport const settings = zodToSchema(SettingsSchema);\n","import { z } from '@walkeros/core/dev';\nimport { CorsOptionsSchema, RouteConfigSchema } from './primitives';\n\n/**\n * Express source settings schema.\n */\nexport const SettingsSchema = z.object({\n port: z\n .number()\n .int()\n .min(0)\n .max(65535)\n .describe(\n 'HTTP server port to listen on. Use 0 for random available port. If not provided, server will not start (app only mode)',\n )\n .optional(),\n\n /** @deprecated Use `paths` instead */\n path: z.string().describe('Deprecated: use paths instead').optional(),\n\n paths: z\n .array(z.union([z.string(), RouteConfigSchema]))\n .min(1)\n .describe(\n 'Route paths to register. String shorthand registers GET+POST. RouteConfig allows per-route method control.',\n )\n .optional(),\n\n cors: z\n .union([z.boolean(), CorsOptionsSchema])\n .describe(\n 'CORS configuration: false = disabled, true = allow all origins (default), object = custom configuration',\n )\n .default(true),\n\n status: z\n .boolean()\n .describe('Enable health check endpoints (/health, /ready)')\n .default(true),\n});\n\nexport type Settings = z.infer<typeof SettingsSchema>;\n","import { z } from '@walkeros/core/dev';\n\n/**\n * HTTP methods enum\n */\nexport const HttpMethod = z.enum([\n 'GET',\n 'POST',\n 'PUT',\n 'PATCH',\n 'DELETE',\n 'OPTIONS',\n 'HEAD',\n]);\n\n/**\n * HTTP methods supported for route configuration.\n * OPTIONS is always registered for CORS (not user-configurable per route).\n */\nexport const RouteMethod = z.enum(['GET', 'POST']);\n\n/**\n * Route configuration for multi-path support.\n */\nexport const RouteConfigSchema = z.object({\n path: z\n .string()\n .describe('Express route path (supports wildcards like /api/*)'),\n methods: z\n .array(RouteMethod)\n .min(1)\n .describe('HTTP methods to register. OPTIONS always included for CORS.')\n .optional(),\n});\n\n/**\n * CORS origin configuration\n * Accepts:\n * - '*' for all origins\n * - Single URL string\n * - Array of URL strings\n */\nexport const CorsOrigin = z.union([\n z.string(),\n z.array(z.string()),\n z.literal('*'),\n]);\n\n/**\n * CORS options schema\n * Configuration for Cross-Origin Resource Sharing\n */\nexport const CorsOptionsSchema = z.object({\n origin: CorsOrigin.describe(\n 'Allowed origins (* for all, URL string, or array of URLs)',\n ).optional(),\n\n methods: z.array(HttpMethod).describe('Allowed HTTP methods').optional(),\n\n headers: z.array(z.string()).describe('Allowed request headers').optional(),\n\n credentials: z\n .boolean()\n .describe('Allow credentials (cookies, authorization headers)')\n .optional(),\n\n maxAge: z\n .number()\n .int()\n .positive()\n .describe('Preflight cache duration in seconds')\n .optional(),\n});\n\nexport type CorsOptions = z.infer<typeof CorsOptionsSchema>;\n","import type { Response } from 'express';\nimport type { CorsOptions } from './schemas';\n\n/**\n * Set CORS headers on response\n *\n * @param res Express response object\n * @param corsConfig CORS configuration (false = disabled, true = allow all, object = custom)\n */\nexport function setCorsHeaders(\n res: Response,\n corsConfig: boolean | CorsOptions = true,\n): void {\n if (corsConfig === false) return;\n\n if (corsConfig === true) {\n // Simple CORS - allow all\n res.set('Access-Control-Allow-Origin', '*');\n res.set('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');\n res.set('Access-Control-Allow-Headers', 'Content-Type');\n } else {\n // Custom CORS configuration\n if (corsConfig.origin) {\n const origin = Array.isArray(corsConfig.origin)\n ? corsConfig.origin.join(', ')\n : corsConfig.origin;\n res.set('Access-Control-Allow-Origin', origin);\n }\n\n if (corsConfig.methods) {\n res.set('Access-Control-Allow-Methods', corsConfig.methods.join(', '));\n }\n\n if (corsConfig.headers) {\n res.set('Access-Control-Allow-Headers', corsConfig.headers.join(', '));\n }\n\n if (corsConfig.credentials) {\n res.set('Access-Control-Allow-Credentials', 'true');\n }\n\n if (corsConfig.maxAge) {\n res.set('Access-Control-Max-Age', String(corsConfig.maxAge));\n }\n }\n}\n\n/**\n * 1x1 transparent GIF for pixel tracking\n * Base64-encoded GIF (43 bytes)\n */\nexport const TRANSPARENT_GIF = Buffer.from(\n 'R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7',\n 'base64',\n);\n"],"mappings":"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","names":["z","z","settings"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/schemas/index.ts","../src/schemas/settings.ts","../src/schemas/primitives.ts","../src/utils.ts"],"sourcesContent":["import express, { type Request, type Response } from 'express';\nimport cors from 'cors';\nimport { requestToData, createRespond } from '@walkeros/core';\nimport type { Source } from '@walkeros/core';\nimport type { ExpressSource, Types, EventRequest } from './types';\nimport { SettingsSchema } from './schemas';\nimport { setCorsHeaders, TRANSPARENT_GIF } from './utils';\n\n/**\n * Express source initialization\n *\n * This source OWNS its HTTP server infrastructure:\n * - Creates Express application\n * - Sets up middleware (JSON parsing, CORS)\n * - Registers event collection endpoints (POST, GET, OPTIONS)\n * - Starts HTTP server (if port configured)\n * - Provides destroy() for graceful shutdown (called by runner)\n *\n * @param context Source context with config, env, logger, id\n * @returns Express source instance with app and push handler\n */\nexport const sourceExpress = async (\n context: Source.Context<Types>,\n): Promise<ExpressSource> => {\n const { config = {}, env } = context;\n\n // Validate and apply default settings\n const parsed = SettingsSchema.parse(config.settings || {});\n const settings = {\n ...parsed,\n paths: parsed.paths ?? (parsed.path ? [parsed.path] : ['/collect']),\n };\n\n const app = express();\n\n // Middleware setup - JSON body parsing with 10mb default limit\n app.use(express.json({ limit: '1mb' }));\n\n // CORS middleware (enabled by default)\n if (settings.cors !== false) {\n const corsOptions = settings.cors === true ? {} : settings.cors;\n app.use(cors(corsOptions));\n }\n\n /**\n * Request handler - transforms HTTP requests into walker events\n * Supports POST (JSON body), GET (query params), and OPTIONS (CORS preflight)\n */\n const push = async (req: Request, res: Response): Promise<void> => {\n try {\n // Handle OPTIONS for CORS preflight\n if (req.method === 'OPTIONS') {\n setCorsHeaders(res, settings.cors);\n res.status(204).send();\n return;\n }\n\n // Extract ingest metadata from request (if config.ingest is defined)\n await context.setIngest(req);\n\n // Create per-request respond — first call wins (idempotent)\n const respond = createRespond((options) => {\n const status = options.status ?? 200;\n if (options.headers) {\n for (const [key, value] of Object.entries(options.headers)) {\n res.set(key, value);\n }\n }\n res.status(status);\n if (typeof options.body === 'string' || Buffer.isBuffer(options.body)) {\n res.send(options.body);\n } else {\n res.json(options.body);\n }\n });\n context.setRespond(respond);\n\n // Handle GET requests (pixel tracking)\n if (req.method === 'GET') {\n // Parse query parameters to event data using requestToData\n const parsedData = requestToData(req.url);\n\n // Send to collector\n if (parsedData && typeof parsedData === 'object') {\n await env.push(parsedData);\n }\n\n // Default: 1x1 GIF (skipped if a step already called respond)\n respond({\n body: TRANSPARENT_GIF,\n headers: {\n 'Content-Type': 'image/gif',\n 'Cache-Control': 'no-cache, no-store, must-revalidate',\n },\n });\n return;\n }\n\n // Handle POST requests (standard event ingestion)\n if (req.method === 'POST') {\n const eventData = req.body;\n\n if (!eventData || typeof eventData !== 'object') {\n res.status(400).json({\n success: false,\n error: 'Invalid event: body must be an object',\n });\n return;\n }\n\n // Send event to collector\n await env.push(eventData);\n\n // Default: JSON success (skipped if a step already called respond)\n respond({ body: { success: true, timestamp: Date.now() } });\n return;\n }\n\n // Unsupported method\n res.status(405).json({\n success: false,\n error: 'Method not allowed. Use POST, GET, or OPTIONS.',\n });\n } catch (error) {\n res.status(500).json({\n success: false,\n error: error instanceof Error ? error.message : 'Internal server error',\n });\n }\n };\n\n // Register handlers per route config\n const resolvedPaths = settings.paths.map((entry) =>\n typeof entry === 'string'\n ? { path: entry, methods: ['GET', 'POST'] as const }\n : {\n path: entry.path,\n methods: entry.methods || (['GET', 'POST'] as const),\n },\n );\n\n for (const route of resolvedPaths) {\n if (route.methods.includes('POST')) app.post(route.path, push);\n if (route.methods.includes('GET')) app.get(route.path, push);\n app.options(route.path, push); // Always register OPTIONS for CORS\n }\n\n // Source owns the HTTP server (if port configured)\n let server: ReturnType<typeof app.listen> | undefined;\n\n if (settings.port !== undefined) {\n server = app.listen(settings.port, () => {\n const routeLines = resolvedPaths\n .map((r) => {\n const methods = [...r.methods, 'OPTIONS'].join(', ');\n return ` ${methods} ${r.path}`;\n })\n .join('\\n');\n env.logger.info(\n `Express source listening on port ${settings.port}\\n` + routeLines,\n );\n });\n }\n\n const instance: ExpressSource = {\n type: 'express',\n config: {\n ...config,\n settings,\n },\n push,\n httpHandler: app,\n app,\n server,\n destroy: (_context) =>\n new Promise<void>((resolve, reject) => {\n if (!server) return resolve();\n server.close((err) => (err ? reject(err) : resolve()));\n }),\n };\n\n return instance;\n};\n\n// Export types (avoid re-exporting duplicates from schemas)\nexport type {\n ExpressSource,\n Config,\n PartialConfig,\n Types,\n EventRequest,\n EventResponse,\n RequestBody,\n ResponseBody,\n Push,\n Env,\n Mapping,\n InitSettings,\n Settings,\n RouteConfig,\n RouteMethod,\n} from './types';\n\n// Export utils\nexport { setCorsHeaders, TRANSPARENT_GIF } from './utils';\n\nexport default sourceExpress;\n","import { zodToSchema } from '@walkeros/core/dev';\nimport { SettingsSchema } from './settings';\n\nexport * from './primitives';\nexport { SettingsSchema, type Settings } from './settings';\n\n// JSON Schema\nexport const settings = zodToSchema(SettingsSchema);\n","import { z } from '@walkeros/core/dev';\nimport { CorsOptionsSchema, RouteConfigSchema } from './primitives';\n\n/**\n * Express source settings schema.\n */\nexport const SettingsSchema = z.object({\n port: z\n .number()\n .int()\n .min(0)\n .max(65535)\n .describe(\n 'HTTP server port to listen on. Use 0 for random available port. If not provided, server will not start (app only mode)',\n )\n .optional(),\n\n /** @deprecated Use `paths` instead */\n path: z.string().describe('Deprecated: use paths instead').optional(),\n\n paths: z\n .array(z.union([z.string(), RouteConfigSchema]))\n .min(1)\n .describe(\n 'Route paths to register. String shorthand registers GET+POST. RouteConfig allows per-route method control.',\n )\n .optional(),\n\n cors: z\n .union([z.boolean(), CorsOptionsSchema])\n .describe(\n 'CORS configuration: false = disabled, true = allow all origins (default), object = custom configuration',\n )\n .default(true),\n});\n\nexport type Settings = z.infer<typeof SettingsSchema>;\n","import { z } from '@walkeros/core/dev';\n\n/**\n * HTTP methods enum\n */\nexport const HttpMethod = z.enum([\n 'GET',\n 'POST',\n 'PUT',\n 'PATCH',\n 'DELETE',\n 'OPTIONS',\n 'HEAD',\n]);\n\n/**\n * HTTP methods supported for route configuration.\n * OPTIONS is always registered for CORS (not user-configurable per route).\n */\nexport const RouteMethod = z.enum(['GET', 'POST']);\n\n/**\n * Route configuration for multi-path support.\n */\nexport const RouteConfigSchema = z.object({\n path: z\n .string()\n .describe('Express route path (supports wildcards like /api/*)'),\n methods: z\n .array(RouteMethod)\n .min(1)\n .describe('HTTP methods to register. OPTIONS always included for CORS.')\n .optional(),\n});\n\n/**\n * CORS origin configuration\n * Accepts:\n * - '*' for all origins\n * - Single URL string\n * - Array of URL strings\n */\nexport const CorsOrigin = z.union([\n z.string(),\n z.array(z.string()),\n z.literal('*'),\n]);\n\n/**\n * CORS options schema\n * Configuration for Cross-Origin Resource Sharing\n */\nexport const CorsOptionsSchema = z.object({\n origin: CorsOrigin.describe(\n 'Allowed origins (* for all, URL string, or array of URLs)',\n ).optional(),\n\n methods: z.array(HttpMethod).describe('Allowed HTTP methods').optional(),\n\n headers: z.array(z.string()).describe('Allowed request headers').optional(),\n\n credentials: z\n .boolean()\n .describe('Allow credentials (cookies, authorization headers)')\n .optional(),\n\n maxAge: z\n .number()\n .int()\n .positive()\n .describe('Preflight cache duration in seconds')\n .optional(),\n});\n\nexport type CorsOptions = z.infer<typeof CorsOptionsSchema>;\n","import type { Response } from 'express';\nimport type { CorsOptions } from './schemas';\n\n/**\n * Set CORS headers on response\n *\n * @param res Express response object\n * @param corsConfig CORS configuration (false = disabled, true = allow all, object = custom)\n */\nexport function setCorsHeaders(\n res: Response,\n corsConfig: boolean | CorsOptions = true,\n): void {\n if (corsConfig === false) return;\n\n if (corsConfig === true) {\n // Simple CORS - allow all\n res.set('Access-Control-Allow-Origin', '*');\n res.set('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');\n res.set('Access-Control-Allow-Headers', 'Content-Type');\n } else {\n // Custom CORS configuration\n if (corsConfig.origin) {\n const origin = Array.isArray(corsConfig.origin)\n ? corsConfig.origin.join(', ')\n : corsConfig.origin;\n res.set('Access-Control-Allow-Origin', origin);\n }\n\n if (corsConfig.methods) {\n res.set('Access-Control-Allow-Methods', corsConfig.methods.join(', '));\n }\n\n if (corsConfig.headers) {\n res.set('Access-Control-Allow-Headers', corsConfig.headers.join(', '));\n }\n\n if (corsConfig.credentials) {\n res.set('Access-Control-Allow-Credentials', 'true');\n }\n\n if (corsConfig.maxAge) {\n res.set('Access-Control-Max-Age', String(corsConfig.maxAge));\n }\n }\n}\n\n/**\n * 1x1 transparent GIF for pixel tracking\n * Base64-encoded GIF (43 bytes)\n */\nexport const TRANSPARENT_GIF = Buffer.from(\n 'R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7',\n 'base64',\n);\n"],"mappings":"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","names":["z","z","settings","_a"]}
|
package/dist/walkerOS.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$meta": {
|
|
3
3
|
"package": "@walkeros/server-source-express",
|
|
4
|
-
"version": "2.0.
|
|
4
|
+
"version": "2.0.1",
|
|
5
5
|
"type": "source",
|
|
6
6
|
"platform": "server"
|
|
7
7
|
},
|
|
@@ -122,19 +122,56 @@
|
|
|
122
122
|
}
|
|
123
123
|
],
|
|
124
124
|
"description": "CORS configuration: false = disabled, true = allow all origins (default), object = custom configuration"
|
|
125
|
-
},
|
|
126
|
-
"status": {
|
|
127
|
-
"default": true,
|
|
128
|
-
"type": "boolean",
|
|
129
|
-
"description": "Enable health check endpoints (/health, /ready)"
|
|
130
125
|
}
|
|
131
126
|
},
|
|
132
127
|
"required": [
|
|
133
|
-
"cors"
|
|
134
|
-
"status"
|
|
128
|
+
"cors"
|
|
135
129
|
],
|
|
136
130
|
"additionalProperties": false
|
|
137
131
|
}
|
|
138
132
|
},
|
|
139
|
-
"examples": {
|
|
133
|
+
"examples": {
|
|
134
|
+
"step": {
|
|
135
|
+
"pixelGet": {
|
|
136
|
+
"in": {
|
|
137
|
+
"method": "GET",
|
|
138
|
+
"path": "/collect",
|
|
139
|
+
"query": {
|
|
140
|
+
"e": "page view",
|
|
141
|
+
"d": "{\"title\":\"Home\"}"
|
|
142
|
+
}
|
|
143
|
+
},
|
|
144
|
+
"out": {
|
|
145
|
+
"name": "page view",
|
|
146
|
+
"data": {
|
|
147
|
+
"title": "Home"
|
|
148
|
+
},
|
|
149
|
+
"entity": "page",
|
|
150
|
+
"action": "view"
|
|
151
|
+
}
|
|
152
|
+
},
|
|
153
|
+
"postEvent": {
|
|
154
|
+
"in": {
|
|
155
|
+
"method": "POST",
|
|
156
|
+
"path": "/collect",
|
|
157
|
+
"body": {
|
|
158
|
+
"name": "page view",
|
|
159
|
+
"data": {
|
|
160
|
+
"title": "Home",
|
|
161
|
+
"url": "https://example.com/"
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
},
|
|
165
|
+
"out": {
|
|
166
|
+
"name": "page view",
|
|
167
|
+
"data": {
|
|
168
|
+
"title": "Home",
|
|
169
|
+
"url": "https://example.com/"
|
|
170
|
+
},
|
|
171
|
+
"entity": "page",
|
|
172
|
+
"action": "view"
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
140
177
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@walkeros/server-source-express",
|
|
3
3
|
"description": "Express server source for walkerOS",
|
|
4
|
-
"version": "2.0
|
|
4
|
+
"version": "2.1.0",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "./dist/index.js",
|
|
7
7
|
"module": "./dist/index.mjs",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"update": "npx npm-check-updates -u && npm update"
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@walkeros/core": "^2.
|
|
22
|
+
"@walkeros/core": "^2.1.0",
|
|
23
23
|
"express": "^5.2.1",
|
|
24
24
|
"cors": "^2.8.5"
|
|
25
25
|
},
|