@walkeros/server-source-fetch 4.1.0-next-1778668930820 → 4.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/CHANGELOG.md ADDED
@@ -0,0 +1,335 @@
1
+ # @walkeros/server-source-fetch
2
+
3
+ ## 4.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 13aaeaa: `Source.Context` no longer exposes `setIngest` or `setRespond`.
8
+ Server sources handling concurrent inbound requests must call
9
+ `context.withScope(rawScope, respond, body)` to bind per-request ingest and
10
+ respond. Browser and other single-scope sources keep working without changes.
11
+
12
+ ### Patch Changes
13
+
14
+ - Updated dependencies [e155ff8]
15
+ - Updated dependencies [e800974]
16
+ - Updated dependencies [e155ff8]
17
+ - Updated dependencies [1a8f2d7]
18
+ - Updated dependencies [1a8f2d7]
19
+ - Updated dependencies [b276173]
20
+ - Updated dependencies [dd9f5ad]
21
+ - Updated dependencies [c60ef35]
22
+ - Updated dependencies [adeebea]
23
+ - Updated dependencies [13aaeaa]
24
+ - Updated dependencies [e800974]
25
+ - Updated dependencies [adeebea]
26
+ - Updated dependencies [6cdc362]
27
+ - Updated dependencies [e800974]
28
+ - Updated dependencies [e800974]
29
+ - Updated dependencies [058f7ed]
30
+ - Updated dependencies [28a8ac2]
31
+ - Updated dependencies [fd6076e]
32
+ - @walkeros/core@4.1.0
33
+ - @walkeros/collector@4.1.0
34
+
35
+ ## 4.0.2
36
+
37
+ ### Patch Changes
38
+
39
+ - Updated dependencies [a6a0ea7]
40
+ - @walkeros/core@4.0.2
41
+ - @walkeros/collector@4.0.2
42
+
43
+ ## 4.0.1
44
+
45
+ ### Patch Changes
46
+
47
+ - Updated dependencies [cb265eb]
48
+ - Updated dependencies [381dfe7]
49
+ - Updated dependencies [1524275]
50
+ - Updated dependencies [03d7055]
51
+ - @walkeros/collector@4.0.1
52
+ - @walkeros/core@4.0.1
53
+
54
+ ## 4.0.0
55
+
56
+ ### Major Changes
57
+
58
+ - 93ea9c4: Event model v4: breaking changes to the `Event`, `Source`, and
59
+ `Entity` shapes.
60
+ - `event.id` is now a W3C span_id (16 lowercase hex chars), generated by the
61
+ collector. Reference: W3C Trace Context (W3C Recommendation, January 2020).
62
+ - `event.version`, `event.group`, `event.count` are removed.
63
+ - `source.type` is now the source kind (e.g. `browser`, `gtag`, `mcp`, `cli`).
64
+ New `source.platform` holds the runtime (`web` | `server` | `app` | ...).
65
+ - `source.id` and `source.previous_id` are removed.
66
+ - Browser source now sets `source.url` and `source.referrer`.
67
+ - MCP source sets `source.tool` per emission. CLI source sets
68
+ `source.command`.
69
+ - `Entity.nested` and `Entity.context` are now optional. Root `event.nested`
70
+ and `event.context` remain required.
71
+ - Each source self-registers via TypeScript module augmentation of `SourceMap`
72
+ in `@walkeros/core`.
73
+ - App-side coordination (`/workspaces/developer/app`) is a follow-up plan, not
74
+ part of this release. Telemetry from v4 CLI/MCP will not validate against
75
+ the existing app schema until that follow-up ships.
76
+ - `Mapping.Rule.skip` is renamed to `Mapping.Rule.silent`. Customer flow.json
77
+ configs using `skip: true` in mapping rules must rename to `silent: true`.
78
+ Hard cut: no legacy alias, the field is gone.
79
+
80
+ ### Patch Changes
81
+
82
+ - Updated dependencies [93ea9c4]
83
+ - Updated dependencies [465775c]
84
+ - Updated dependencies [942a7fe]
85
+ - Updated dependencies [cfc7469]
86
+ - Updated dependencies [8e06b1f]
87
+ - Updated dependencies [3d50dd6]
88
+ - Updated dependencies [1ef33d9]
89
+ - @walkeros/core@4.0.0
90
+ - @walkeros/collector@4.0.0
91
+
92
+ ## 3.4.2
93
+
94
+ ### Patch Changes
95
+
96
+ - @walkeros/collector@3.4.2
97
+ - @walkeros/core@3.4.2
98
+
99
+ ## 3.4.1
100
+
101
+ ### Patch Changes
102
+
103
+ - Updated dependencies [12adf24]
104
+ - Updated dependencies [75aa26b]
105
+ - @walkeros/core@3.4.1
106
+ - @walkeros/collector@3.4.1
107
+
108
+ ## 3.4.0
109
+
110
+ ### Minor Changes
111
+
112
+ - 724f97e: Migrate every step example in every walkerOS package to the
113
+ standardized `[callable, ...args][]` shape introduced in `@walkeros/core`.
114
+ Every step example's `out` is now an array of effect tuples whose first
115
+ element is the callable's public SDK name (`'gtag'`, `'analytics.track'`,
116
+ `'fbq'`, `'dataLayer.push'`, `'sendServer'`, `'fetch'`, `'trackClient.track'`,
117
+ `'amplitude.track'`, `'fs.writeFile'`, `'producer.send'`, `'client.xadd'`,
118
+ `'client.send'`, `'dataset.table.insert'`, etc.). Source examples use `'elb'`
119
+ as the callable; transformer examples use the reserved `'return'` keyword;
120
+ store examples use store-operation callables (`'get'`, `'set'`). Tests capture
121
+ real calls on each component's spy and assert against `example.out` directly —
122
+ the hardcoded `PACKAGE_CALLS` registry in the app is no longer consulted
123
+ (emptied; plan #3 removes it structurally).
124
+
125
+ ### Patch Changes
126
+
127
+ - Updated dependencies [74940cc]
128
+ - Updated dependencies [525f5d9]
129
+ - @walkeros/core@3.4.0
130
+ - @walkeros/collector@3.4.0
131
+
132
+ ## 3.3.1
133
+
134
+ ### Patch Changes
135
+
136
+ - Updated dependencies [b10144a]
137
+ - Updated dependencies [206185a]
138
+ - Updated dependencies [50e5d09]
139
+ - Updated dependencies [32ff626]
140
+ - @walkeros/collector@3.3.1
141
+ - @walkeros/core@3.3.1
142
+
143
+ ## 3.3.0
144
+
145
+ ### Patch Changes
146
+
147
+ - Updated dependencies [2849acb]
148
+ - Updated dependencies [08c365a]
149
+ - Updated dependencies [08c365a]
150
+ - Updated dependencies [08c365a]
151
+ - Updated dependencies [08c365a]
152
+ - @walkeros/core@3.3.0
153
+ - @walkeros/collector@3.3.0
154
+
155
+ ## 3.2.0
156
+
157
+ ### Minor Changes
158
+
159
+ - f47d251: Accept non-JSON POST bodies in all server sources
160
+
161
+ Server sources no longer reject non-JSON bodies with HTTP 400. Instead, they
162
+ push an empty event `{}` to the collector, enabling `source.before`
163
+ transformers to process raw input via ingest. Raw body is available through
164
+ ingest mapping (e.g., `"rawBody": "body"`).
165
+
166
+ ### Patch Changes
167
+
168
+ - Updated dependencies [eb865e1]
169
+ - Updated dependencies [c0a53f9]
170
+ - Updated dependencies [8cdc0bb]
171
+ - Updated dependencies [f007c9f]
172
+ - Updated dependencies [bf2dc5b]
173
+ - Updated dependencies [da0b640]
174
+ - Updated dependencies [a5d25bc]
175
+ - Updated dependencies [9a99298]
176
+ - Updated dependencies [884527d]
177
+ - @walkeros/core@3.2.0
178
+ - @walkeros/collector@3.2.0
179
+
180
+ ## 3.1.1
181
+
182
+ ### Patch Changes
183
+
184
+ - @walkeros/core@3.1.1
185
+ - @walkeros/collector@3.1.1
186
+
187
+ ## 3.1.0
188
+
189
+ ### Minor Changes
190
+
191
+ - 956c337: Add createTrigger following unified Trigger.CreateFn interface. Step
192
+ examples updated with trigger metadata.
193
+
194
+ ### Patch Changes
195
+
196
+ - Updated dependencies [a9149e4]
197
+ - Updated dependencies [dfc6738]
198
+ - Updated dependencies [966342b]
199
+ - Updated dependencies [bee8ba7]
200
+ - Updated dependencies [966342b]
201
+ - Updated dependencies [df990d4]
202
+ - @walkeros/collector@3.1.0
203
+ - @walkeros/core@3.1.0
204
+
205
+ ## 3.0.2
206
+
207
+ ### Patch Changes
208
+
209
+ - @walkeros/core@3.0.2
210
+
211
+ ## 3.0.1
212
+
213
+ ### Patch Changes
214
+
215
+ - @walkeros/core@3.0.1
216
+
217
+ ## 3.0.0
218
+
219
+ ### Patch Changes
220
+
221
+ - 499e27a: Add sideEffects declarations to all packages for bundler tree-shaking
222
+ support.
223
+ - Updated dependencies [2b259b6]
224
+ - Updated dependencies [2614014]
225
+ - Updated dependencies [6ae0ee3]
226
+ - Updated dependencies [37299a9]
227
+ - Updated dependencies [499e27a]
228
+ - Updated dependencies [0e5eede]
229
+ - Updated dependencies [d11f574]
230
+ - Updated dependencies [d11f574]
231
+ - Updated dependencies [1fe337a]
232
+ - Updated dependencies [5cb84c1]
233
+ - Updated dependencies [23f218a]
234
+ - Updated dependencies [499e27a]
235
+ - Updated dependencies [c83d909]
236
+ - Updated dependencies [b6c8fa8]
237
+ - @walkeros/core@3.0.0
238
+
239
+ ## 2.1.1
240
+
241
+ ### Patch Changes
242
+
243
+ - Updated dependencies [fab477d]
244
+ - @walkeros/core@2.1.1
245
+
246
+ ## 2.1.0
247
+
248
+ ### Minor Changes
249
+
250
+ - 66aaf2d: Runner-owned health server: The runner now provides /health and
251
+ /ready endpoints independently of flow sources. Express source's `status`
252
+ setting and fetch source's `healthPath` setting have been removed — health
253
+ endpoints are no longer source responsibilities.
254
+ - 97df0b2: Step examples: upgrade all packages to blueprint pattern with inline
255
+ mapping, no intermediate variables, no `all` export
256
+
257
+ ### Patch Changes
258
+
259
+ - Updated dependencies [7fc4cee]
260
+ - Updated dependencies [7fc4cee]
261
+ - Updated dependencies [cb2da05]
262
+ - Updated dependencies [2bbe8c8]
263
+ - Updated dependencies [3eb6416]
264
+ - Updated dependencies [02a7958]
265
+ - Updated dependencies [97df0b2]
266
+ - Updated dependencies [97df0b2]
267
+ - Updated dependencies [026c412]
268
+ - Updated dependencies [7d38d9d]
269
+ - @walkeros/core@2.1.0
270
+
271
+ ## 2.0.1
272
+
273
+ ## 1.1.0
274
+
275
+ ### Minor Changes
276
+
277
+ - bb0ab04: Add multi-path support with per-route method control and path
278
+ matching. The `path` setting is deprecated in favor of `paths` array.
279
+
280
+ ### Patch Changes
281
+
282
+ - Updated dependencies [7b2d750]
283
+ - @walkeros/core@1.4.0
284
+
285
+ ## 1.0.5
286
+
287
+ ### Patch Changes
288
+
289
+ - Updated dependencies [a4cc1ea]
290
+ - @walkeros/core@1.3.0
291
+
292
+ ## 1.0.4
293
+
294
+ ### Patch Changes
295
+
296
+ - Updated dependencies [7ad6cfb]
297
+ - @walkeros/core@1.2.2
298
+
299
+ ## 1.0.3
300
+
301
+ ### Patch Changes
302
+
303
+ - Updated dependencies [6256c12]
304
+ - @walkeros/core@1.2.1
305
+
306
+ ## 1.0.2
307
+
308
+ ### Patch Changes
309
+
310
+ - 6778ab2: Add default exports for simpler CLI flow.json configuration
311
+ - Updated dependencies [f39d9fb]
312
+ - Updated dependencies [888bbdf]
313
+ - @walkeros/core@1.2.0
314
+
315
+ ## 1.0.1
316
+
317
+ ### Patch Changes
318
+
319
+ - Updated dependencies [b65b773]
320
+ - Updated dependencies [20eca6e]
321
+ - @walkeros/core@1.1.0
322
+
323
+ ## 1.0.0
324
+
325
+ ### Major Changes
326
+
327
+ - 67c9e1d: Hello World! walkerOS v1.0.0
328
+
329
+ Open-source event data collection. Collect event data for digital analytics in
330
+ a unified and privacy-centric way.
331
+
332
+ ### Patch Changes
333
+
334
+ - Updated dependencies [67c9e1d]
335
+ - @walkeros/core@1.0.0
package/README.md CHANGED
@@ -1,327 +1,54 @@
1
- # @walkeros/server-source-fetch
2
-
3
- > Web Standard Fetch API source for walkerOS - Deploy to any modern
4
- > edge/serverless platform
5
-
6
- ## What This Source Does
1
+ <p align="left">
2
+ <a href="https://www.walkeros.io">
3
+ <img alt="walkerOS" title="walkerOS" src="https://www.walkeros.io/img/walkerOS_logo.svg" width="256px"/>
4
+ </a>
5
+ </p>
7
6
 
8
- **Accepts** walkerOS events via HTTP (Fetch API) **Forwards** events to
9
- collector for processing **Returns** HTTP responses with CORS support
10
-
11
- This is an HTTP transport layer - it accepts events in walkerOS format and
12
- forwards them to the collector. Not a transformation source.
7
+ # @walkeros/server-source-fetch
13
8
 
14
- ## Features
9
+ Web Standard Fetch API source for walkerOS. A platform-agnostic
10
+ `(Request) => Response` handler that runs on Cloudflare Workers, Vercel Edge,
11
+ Deno, Bun, and Node.js 18+, with batch processing, configurable CORS, and pixel
12
+ tracking.
15
13
 
16
- - ✅ **Web Standard Fetch API** - Native `(Request) => Response` signature
17
- - ✅ **Platform Agnostic** - Cloudflare Workers, Vercel Edge, Deno, Bun, Node.js
18
- 18+
19
- - ✅ **Event Validation** - Zod schema validation with detailed error messages
20
- - ✅ **Batch Processing** - Handle multiple events in single request
21
- - ✅ **CORS Support** - Configurable cross-origin resource sharing
22
- - ✅ **Pixel Tracking** - 1x1 transparent GIF for GET requests
23
- - ✅ **Request Limits** - Configurable size and batch limits
24
- - ✅ **Health Checks** - Built-in `/health` endpoint
14
+ [Documentation](https://www.walkeros.io/docs/sources/server/fetch) &bull;
15
+ [NPM Package](https://www.npmjs.com/package/@walkeros/server-source-fetch)
16
+ &bull;
17
+ [Source Code](https://github.com/elbwalker/walkerOS/tree/main/packages/server/sources/fetch)
25
18
 
26
19
  ## Installation
27
20
 
28
21
  ```bash
29
- npm install @walkeros/server-source-fetch @walkeros/collector @walkeros/core
30
- ```
31
-
32
- ## Quick Start
33
-
34
- ```typescript
35
- import { sourceFetch, type SourceFetch } from '@walkeros/server-source-fetch';
36
- import { startFlow } from '@walkeros/collector';
37
-
38
- const { elb } = await startFlow<SourceFetch.Push>({
39
- sources: { api: { code: sourceFetch } },
40
- });
41
-
42
- export default { fetch: elb };
43
- ```
44
-
45
- ## Multi-Path with Method Control
46
-
47
- ```typescript
48
- const { sources } = await startFlow({
49
- sources: {
50
- api: {
51
- code: sourceFetch,
52
- config: {
53
- settings: {
54
- paths: [
55
- '/collect', // GET + POST (default)
56
- { path: '/pixel', methods: ['GET'] }, // GET only (pixel tracking)
57
- { path: '/ingest', methods: ['POST'] }, // POST only (JSON ingestion)
58
- { path: '/webhooks/*', methods: ['POST'] }, // POST wildcard
59
- ],
60
- },
61
- },
62
- },
63
- },
64
- });
65
- ```
66
-
67
- ## Platform Deployment
68
-
69
- ### Cloudflare Workers
70
-
71
- ```typescript
72
- import { sourceFetch, type SourceFetch } from '@walkeros/server-source-fetch';
73
- import { startFlow } from '@walkeros/collector';
74
-
75
- const { elb } = await startFlow<SourceFetch.Push>({
76
- sources: {
77
- api: {
78
- code: sourceFetch,
79
- config: { settings: { paths: ['/collect'], cors: true } },
80
- },
81
- },
82
- destinations: {
83
- // Your destinations
84
- },
85
- });
86
-
87
- export default { fetch: elb };
88
- ```
89
-
90
- **Deploy:** `wrangler deploy`
91
-
92
- ### Vercel Edge Functions
93
-
94
- ```typescript
95
- // api/collect.ts
96
- export const config = { runtime: 'edge' };
97
-
98
- import { sourceFetch, type SourceFetch } from '@walkeros/server-source-fetch';
99
- import { startFlow } from '@walkeros/collector';
100
-
101
- const { elb } = await startFlow<SourceFetch.Push>({
102
- sources: { api: { code: sourceFetch } },
103
- });
104
-
105
- export default elb;
106
- ```
107
-
108
- ### Deno Deploy
109
-
110
- ```typescript
111
- import { sourceFetch, type SourceFetch } from '@walkeros/server-source-fetch';
112
- import { startFlow } from '@walkeros/collector';
113
-
114
- const { elb } = await startFlow<SourceFetch.Push>({
115
- sources: { api: { code: sourceFetch } },
116
- });
117
-
118
- Deno.serve(elb);
119
- ```
120
-
121
- ### Bun
122
-
123
- ```typescript
124
- import { sourceFetch, type SourceFetch } from '@walkeros/server-source-fetch';
125
- import { startFlow } from '@walkeros/collector';
126
-
127
- const { elb } = await startFlow<SourceFetch.Push>({
128
- sources: { api: { code: sourceFetch } },
129
- });
130
-
131
- Bun.serve({ fetch: elb, port: 3000 });
132
- ```
133
-
134
- ## Usage Examples
135
-
136
- ### Single Event (POST)
137
-
138
- ```javascript
139
- fetch('https://your-endpoint.com/collect', {
140
- method: 'POST',
141
- headers: { 'Content-Type': 'application/json' },
142
- body: JSON.stringify({
143
- name: 'page view',
144
- data: { title: 'Home', path: '/' },
145
- user: { id: 'user-123' },
146
- globals: { language: 'en' },
147
- }),
148
- });
149
- ```
150
-
151
- ### Batch Events (POST)
152
-
153
- ```javascript
154
- fetch('https://your-endpoint.com/collect', {
155
- method: 'POST',
156
- headers: { 'Content-Type': 'application/json' },
157
- body: JSON.stringify({
158
- batch: [
159
- { name: 'page view', data: { title: 'Home' } },
160
- { name: 'button click', data: { id: 'cta' } },
161
- { name: 'form submit', data: { formId: 'contact' } },
162
- ],
163
- }),
164
- });
165
- ```
166
-
167
- ### Pixel Tracking (GET)
168
-
169
- ```html
170
- <img
171
- src="https://your-endpoint.com/collect?event=page%20view&data[title]=Home&user[id]=user123"
172
- width="1"
173
- height="1"
174
- />
175
- ```
176
-
177
- ### Health Check
178
-
179
- ```bash
180
- curl https://your-endpoint.com/health
181
- # {"status":"ok","timestamp":1234567890,"source":"fetch"}
182
- ```
183
-
184
- ## Configuration
185
-
186
- ```typescript
187
- interface Settings {
188
- /**
189
- * Route paths to handle.
190
- * String shorthand accepts GET+POST. RouteConfig allows per-route method control.
191
- * @default ['/collect']
192
- */
193
- paths?: Array<string | RouteConfig>;
194
-
195
- /**
196
- * @deprecated Use `paths` instead. Converted to `paths: [path]` internally.
197
- */
198
- path?: string;
199
-
200
- cors: boolean | CorsOptions; // CORS config (default: true)
201
- healthPath: string; // Health check path (default: '/health')
202
- maxRequestSize: number; // Max bytes (default: 102400 = 100KB)
203
- maxBatchSize: number; // Max events per batch (default: 100)
204
- }
205
-
206
- interface RouteConfig {
207
- /** URL path pattern (supports wildcards like /api/*) */
208
- path: string;
209
- /** HTTP methods to accept. OPTIONS always included for CORS. */
210
- methods?: ('GET' | 'POST')[];
211
- }
212
-
213
- interface CorsOptions {
214
- origin?: string | string[] | '*';
215
- methods?: string[];
216
- headers?: string[];
217
- credentials?: boolean;
218
- maxAge?: number;
219
- }
22
+ npm install @walkeros/server-source-fetch
220
23
  ```
221
24
 
222
- ## Ingest Metadata
223
-
224
- Extract request metadata and forward it to processors and destinations:
225
-
226
- ```typescript
227
- const { elb } = await startFlow<SourceFetch.Push>({
228
- sources: {
229
- api: {
230
- code: sourceFetch,
231
- config: {
232
- settings: { cors: true },
233
- ingest: {
234
- ua: { fn: (req) => req.headers.get('user-agent') },
235
- origin: { fn: (req) => req.headers.get('origin') },
236
- url: 'url',
237
- },
238
- },
239
- },
240
- },
241
- });
242
- ```
243
-
244
- **Available ingest paths:**
245
-
246
- | Path | Description |
247
- | --------------------- | -------------------------------------------------------- |
248
- | `url` | Full request URL |
249
- | `headers.get('name')` | Via function: `{ fn: (req) => req.headers.get('name') }` |
250
-
251
- > **Note:** The Fetch API uses `Request` objects where headers are accessed via
252
- > `.get()` method. Use mapping functions for header extraction.
253
-
254
- ## Error Responses
255
-
256
- ### Validation Error
25
+ ## Quick start
257
26
 
258
27
  ```json
259
28
  {
260
- "success": false,
261
- "error": "Event validation failed",
262
- "validationErrors": [
263
- { "path": "name", "message": "Event name is required" },
264
- { "path": "nested.0.entity", "message": "Required" }
265
- ]
29
+ "version": 4,
30
+ "flows": {
31
+ "default": {
32
+ "config": { "platform": "server" },
33
+ "sources": {
34
+ "fetch": { "package": "@walkeros/server-source-fetch", "config": {} }
35
+ }
36
+ }
37
+ }
266
38
  }
267
39
  ```
268
40
 
269
- ### Batch Partial Failure (207 Multi-Status)
270
-
271
- ```json
272
- {
273
- "success": false,
274
- "processed": 2,
275
- "failed": 1,
276
- "errors": [
277
- { "index": 1, "error": "Validation failed: Event name is required" }
278
- ]
279
- }
280
- ```
281
-
282
- ## Input Format
283
-
284
- Accepts standard walkerOS events. See
285
- [@walkeros/core Event documentation](../../../core#event-structure).
286
-
287
- Required field:
288
-
289
- - `name` (string) - Event name in "entity action" format (e.g., "page view")
290
-
291
- Optional fields:
292
-
293
- - `data` - Event-specific properties
294
- - `user` - User identification
295
- - `context` - Ordered context properties
296
- - `globals` - Global properties
297
- - `custom` - Custom properties
298
- - `nested` - Nested entities
299
- - `consent` - Consent flags
300
-
301
- ## Testing
302
-
303
- ```bash
304
- npm test # Run tests
305
- npm run dev # Watch mode
306
- npm run lint # Type check + lint
307
- npm run build # Build package
308
- ```
309
-
310
- ## Development
311
-
312
- Follows walkerOS XP principles:
313
-
314
- - **DRY** - Uses @walkeros/core utilities
315
- - **KISS** - Minimal HTTP wrapper
316
- - **TDD** - Example-driven tests
317
- - **No `any`** - Strict TypeScript
41
+ ## Documentation
318
42
 
319
- See [AGENT.md](../../../../AGENT.md) for walkerOS development guide.
43
+ Full configuration, mapping, and examples live in the docs:
44
+ **https://www.walkeros.io/docs/sources/server/fetch**
320
45
 
321
- ## Related
46
+ ## Contribute
322
47
 
323
- - [@walkeros/server-source-express](../express/) - Alternative for Express.js
324
- - [@walkeros/core](../../../../packages/core/) - Core utilities
48
+ Feel free to contribute by submitting an
49
+ [issue](https://github.com/elbwalker/walkerOS/issues), starting a
50
+ [discussion](https://github.com/elbwalker/walkerOS/discussions), or getting in
51
+ [contact](https://calendly.com/elb-alexander/30min).
325
52
 
326
53
  ## License
327
54
 
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- "use strict";var mod,__defProp=Object.defineProperty,__getOwnPropDesc=Object.getOwnPropertyDescriptor,__getOwnPropNames=Object.getOwnPropertyNames,__hasOwnProp=Object.prototype.hasOwnProperty,__export=(target,all)=>{for(var name in all)__defProp(target,name,{get:all[name],enumerable:!0})},index_exports={};__export(index_exports,{SourceFetch:()=>types_exports,TRANSPARENT_GIF_BASE64:()=>TRANSPARENT_GIF_BASE64,createCorsHeaders:()=>createCorsHeaders,createJsonResponse:()=>createJsonResponse,createPixelResponse:()=>createPixelResponse,default:()=>index_default,examples:()=>examples_exports,matchPath:()=>matchPath,sourceFetch:()=>sourceFetch}),module.exports=(mod=index_exports,((to,from,except,desc)=>{if(from&&"object"==typeof from||"function"==typeof from)for(let key of __getOwnPropNames(from))__hasOwnProp.call(to,key)||key===except||__defProp(to,key,{get:()=>from[key],enumerable:!(desc=__getOwnPropDesc(from,key))||desc.enumerable});return to})(__defProp({},"__esModule",{value:!0}),mod));var import_core=require("@walkeros/core");function createCorsHeaders(corsConfig=!0,requestOrigin){const headers=new Headers;if(!1===corsConfig)return headers;if(!0===corsConfig)headers.set("Access-Control-Allow-Origin","*"),headers.set("Access-Control-Allow-Methods","GET, POST, OPTIONS"),headers.set("Access-Control-Allow-Headers","Content-Type");else{if(corsConfig.origin){let origin;origin=Array.isArray(corsConfig.origin)?requestOrigin&&corsConfig.origin.includes(requestOrigin)?requestOrigin:corsConfig.origin[0]:corsConfig.origin,headers.set("Access-Control-Allow-Origin",origin)}corsConfig.methods&&headers.set("Access-Control-Allow-Methods",corsConfig.methods.join(", ")),corsConfig.headers&&headers.set("Access-Control-Allow-Headers",corsConfig.headers.join(", ")),corsConfig.credentials&&headers.set("Access-Control-Allow-Credentials","true"),corsConfig.maxAge&&headers.set("Access-Control-Max-Age",String(corsConfig.maxAge))}return headers}var TRANSPARENT_GIF_BASE64="R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7";function createPixelResponse(corsHeaders){const binaryString=atob(TRANSPARENT_GIF_BASE64),bytes=new Uint8Array(binaryString.length);for(let i=0;i<binaryString.length;i++)bytes[i]=binaryString.charCodeAt(i);const headers=new Headers(corsHeaders);return headers.set("Content-Type","image/gif"),headers.set("Cache-Control","no-cache, no-store, must-revalidate"),new Response(bytes,{status:200,headers:headers})}function createJsonResponse(body,status=200,corsHeaders){const headers=new Headers(corsHeaders);return headers.set("Content-Type","application/json"),new Response(JSON.stringify(body),{status:status,headers:headers})}function matchPath(requestPath,pattern){if(pattern.endsWith("/*")){const prefix=pattern.slice(0,-2);return requestPath===prefix||requestPath.startsWith(prefix+"/")}return requestPath===pattern}var types_exports={},examples_exports={};__export(examples_exports,{createTrigger:()=>createTrigger,inputs:()=>inputs_exports,requests:()=>requests_exports,step:()=>step_exports});var inputs_exports={};__export(inputs_exports,{batch:()=>batch,completeEvent:()=>completeEvent,minimal:()=>minimal,pageView:()=>pageView,productAdd:()=>productAdd});var pageView={name:"page view",data:{title:"Home Page",path:"/",referrer:"https://google.com"},user:{id:"user-123",session:"session-456"},timestamp:17e11},productAdd={name:"product add",data:{id:"P-123",name:"Laptop",price:999.99,quantity:1},context:{stage:["shopping",1]},globals:{language:"en",currency:"USD"},user:{id:"user-123"},nested:[{entity:"category",data:{name:"Electronics",path:"/electronics"}}],consent:{functional:!0,marketing:!0}},completeEvent={name:"order complete",data:{id:"ORDER-123",total:999.99,currency:"USD"},context:{stage:["checkout",3],test:["variant-A",0]},globals:{language:"en",country:"US"},custom:{campaignId:"summer-sale",source:"email"},user:{id:"user-123",email:"user@example.com",session:"session-456"},nested:[{entity:"product",data:{id:"P-123",price:999.99}}],consent:{functional:!0,marketing:!0,analytics:!1},trigger:"click"},minimal={name:"ping"},batch=[pageView,productAdd,{name:"button click",data:{id:"cta"}}],requests_exports={};__export(requests_exports,{batchPostRequest:()=>batchPostRequest,healthCheckRequest:()=>healthCheckRequest,invalidJsonRequest:()=>invalidJsonRequest,optionsRequest:()=>optionsRequest,oversizedRequest:()=>oversizedRequest,pixelGetRequest:()=>pixelGetRequest,validPostRequest:()=>validPostRequest});var validPostRequest={method:"POST",url:"https://example.com/collect",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:"page view",data:{title:"Home"}})},batchPostRequest={method:"POST",url:"https://example.com/collect",headers:{"Content-Type":"application/json"},body:JSON.stringify({batch:[{name:"page view",data:{title:"Home"}},{name:"button click",data:{id:"cta"}}]})},pixelGetRequest={method:"GET",url:"https://example.com/collect?event=page%20view&data[title]=Home&user[id]=user123"},healthCheckRequest={method:"GET",url:"https://example.com/health"},optionsRequest={method:"OPTIONS",url:"https://example.com/collect",headers:{Origin:"https://example.com"}},invalidJsonRequest={method:"POST",url:"https://example.com/collect",headers:{"Content-Type":"application/json"},body:"invalid json{"},oversizedRequest={method:"POST",url:"https://example.com/collect",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:"test",data:{payload:"x".repeat(2e5)}})},step_exports={};__export(step_exports,{batchRequest:()=>batchRequest,pixelGet:()=>pixelGet,postEvent:()=>postEvent});var postEvent={title:"POST event",description:"A fetch POST request with a JSON body becomes a single walker elb event in a fetch-based server.",trigger:{type:"POST"},in:{method:"POST",url:"http://localhost/collect",body:{name:"page view",data:{title:"Docs",url:"https://example.com/docs"}}},out:[["elb",{name:"page view",data:{title:"Docs",url:"https://example.com/docs"}}]]},batchRequest={title:"Batch POST",description:"A fetch POST with a batch array produces one walker elb event per batched item preserving order.",trigger:{type:"POST"},in:{method:"POST",url:"http://localhost/collect",body:{batch:[{name:"page view",data:{title:"Home"}},{name:"button click",data:{id:"cta"}}]}},out:[["elb",{name:"page view",data:{title:"Home"}}],["elb",{name:"button click",data:{id:"cta"}}]]},pixelGet={title:"Pixel GET",description:"A fetch GET with query parameters in the URL is parsed into an elb event payload for pixel-style tracking.",trigger:{type:"GET"},in:{method:"GET",url:"http://localhost/collect?e=page+view&d=%7B%22title%22%3A%22Home%22%7D"},out:[["elb",{e:"page view",d:'{"title":"Home"}'}]]},import_collector=require("@walkeros/collector");var createTrigger=async config=>{let flow;return{get flow(){return flow},trigger:()=>async content=>{if(!flow){const result=await(0,import_collector.startFlow)(config);flow={collector:result.collector,elb:result.elb}}const source=function(collector){for(const source of Object.values(collector.sources||{}))if("fetch"===source.type)return source}(flow.collector);if(!source)throw new Error("Fetch source not found in collector");const init={method:content.method,headers:{"Content-Type":"application/json",...content.headers}};"GET"!==content.method&&void 0!==content.body&&(init.body=JSON.stringify(content.body));const request=new Request(content.url,init),response=await source.push(request),responseHeaders={};response.headers.forEach((v,k)=>{responseHeaders[k]=v});const body=(response.headers.get("content-type")||"").includes("json")?await response.json():await response.text();return{status:response.status,body:body,headers:responseHeaders}}}},sourceFetch=async context=>{const{config:config={},env:env,setIngest:setIngest}=context,userSettings=config.settings||{},settings={...userSettings,cors:userSettings.cors??!0,maxRequestSize:userSettings.maxRequestSize??102400,maxBatchSize:userSettings.maxBatchSize??100,paths:userSettings.paths??(userSettings.path?[userSettings.path]:["/collect"])},{logger:logger}=env;return{type:"fetch",config:{...config,settings:settings},push:async request=>{Date.now();try{const url=new URL(request.url),method=request.method.toUpperCase(),origin=request.headers.get("Origin"),corsHeaders=createCorsHeaders(settings.cors,origin),matchedRoute=settings.paths.map(entry=>"string"==typeof entry?{path:entry,methods:["GET","POST"]}:{path:entry.path,methods:entry.methods||["GET","POST"]}).find(route=>matchPath(url.pathname,route.path));if(!matchedRoute)return createJsonResponse({success:!1,error:"Not found"},404,corsHeaders);if("OPTIONS"===method)return new Response(null,{status:204,headers:corsHeaders});if(!matchedRoute.methods.includes(method))return createJsonResponse({success:!1,error:"Method not allowed"},405,corsHeaders);if(await setIngest(request),"GET"===method){const parsedData=(0,import_core.requestToData)(url.search);return parsedData&&(0,import_core.isObject)(parsedData)&&await env.push(parsedData),createPixelResponse(corsHeaders)}if("POST"===method){const contentLength=request.headers.get("Content-Length");if(contentLength){const size=parseInt(contentLength,10);if(size>settings.maxRequestSize)return logger.error("Request too large",{size:size,limit:settings.maxRequestSize}),createJsonResponse({success:!1,error:`Request too large. Maximum size: ${settings.maxRequestSize} bytes`},413,corsHeaders)}let eventData,bodyText,rawBody=!1;try{if(bodyText=await request.text(),bodyText.length>settings.maxRequestSize)return logger.error("Request body too large",{size:bodyText.length,limit:settings.maxRequestSize}),createJsonResponse({success:!1,error:`Request too large. Maximum size: ${settings.maxRequestSize} bytes`},413,corsHeaders);eventData=JSON.parse(bodyText)}catch{eventData={},rawBody=!0}if((0,import_core.isDefined)(eventData)&&(0,import_core.isObject)(eventData)||(eventData={},rawBody=!0),rawBody){const result2=await processEvent(eventData,env.push);return result2.error?(logger.error("Event processing failed",{error:result2.error}),createJsonResponse({success:!1,error:result2.error},400,corsHeaders)):createJsonResponse({success:!0,id:result2.id,timestamp:Date.now()},200,corsHeaders)}const validData=eventData;if("batch"in validData&&Array.isArray(validData.batch)){const batch2=validData.batch;if(batch2.length>settings.maxBatchSize)return logger.error("Batch too large",{size:batch2.length,limit:settings.maxBatchSize}),createJsonResponse({success:!1,error:`Batch too large. Maximum size: ${settings.maxBatchSize} events`},400,corsHeaders);const results=await async function(events,push,logger){const results={successful:0,failed:0,ids:[],errors:[]};for(let i=0;i<events.length;i++){const event=events[i];try{const result=await push(event);result?.event?.id&&results.ids.push(result.event.id),results.successful++}catch(error){results.failed++,results.errors.push({index:i,error:error instanceof Error?error.message:"Unknown error"}),logger.error(`Batch event ${i} processing failed`,error)}}return results}(batch2,env.push,logger);return results.failed>0?createJsonResponse({success:!1,processed:results.successful,failed:results.failed,errors:results.errors},207,corsHeaders):createJsonResponse({success:!0,processed:results.successful,ids:results.ids},200,corsHeaders)}const result=await processEvent(eventData,env.push);return result.error?(logger.error("Event processing failed",{error:result.error}),createJsonResponse({success:!1,error:result.error},400,corsHeaders)):createJsonResponse({success:!0,id:result.id,timestamp:Date.now()},200,corsHeaders)}return createJsonResponse({success:!1,error:"Method not allowed"},405,corsHeaders)}catch(error){logger.error("Internal server error",error);const corsHeaders=createCorsHeaders(settings.cors);return createJsonResponse({success:!1,error:error instanceof Error?error.message:"Internal server error"},500,corsHeaders)}}}};async function processEvent(event,push){try{const result=await push(event);return{id:result?.event?.id}}catch(error){return{error:error instanceof Error?error.message:"Unknown error"}}}var index_default=sourceFetch;//# sourceMappingURL=index.js.map
1
+ "use strict";var mod,__defProp=Object.defineProperty,__getOwnPropDesc=Object.getOwnPropertyDescriptor,__getOwnPropNames=Object.getOwnPropertyNames,__hasOwnProp=Object.prototype.hasOwnProperty,__export=(target,all)=>{for(var name in all)__defProp(target,name,{get:all[name],enumerable:!0})},index_exports={};__export(index_exports,{SourceFetch:()=>types_exports,TRANSPARENT_GIF_BASE64:()=>TRANSPARENT_GIF_BASE64,createCorsHeaders:()=>createCorsHeaders,createJsonResponse:()=>createJsonResponse,createPixelResponse:()=>createPixelResponse,default:()=>index_default,examples:()=>examples_exports,matchPath:()=>matchPath,sourceFetch:()=>sourceFetch}),module.exports=(mod=index_exports,((to,from,except,desc)=>{if(from&&"object"==typeof from||"function"==typeof from)for(let key of __getOwnPropNames(from))__hasOwnProp.call(to,key)||key===except||__defProp(to,key,{get:()=>from[key],enumerable:!(desc=__getOwnPropDesc(from,key))||desc.enumerable});return to})(__defProp({},"__esModule",{value:!0}),mod));var import_core=require("@walkeros/core");function createCorsHeaders(corsConfig=!0,requestOrigin){const headers=new Headers;if(!1===corsConfig)return headers;if(!0===corsConfig)headers.set("Access-Control-Allow-Origin","*"),headers.set("Access-Control-Allow-Methods","GET, POST, OPTIONS"),headers.set("Access-Control-Allow-Headers","Content-Type");else{if(corsConfig.origin){let origin;origin=Array.isArray(corsConfig.origin)?requestOrigin&&corsConfig.origin.includes(requestOrigin)?requestOrigin:corsConfig.origin[0]:corsConfig.origin,headers.set("Access-Control-Allow-Origin",origin)}corsConfig.methods&&headers.set("Access-Control-Allow-Methods",corsConfig.methods.join(", ")),corsConfig.headers&&headers.set("Access-Control-Allow-Headers",corsConfig.headers.join(", ")),corsConfig.credentials&&headers.set("Access-Control-Allow-Credentials","true"),corsConfig.maxAge&&headers.set("Access-Control-Max-Age",String(corsConfig.maxAge))}return headers}var TRANSPARENT_GIF_BASE64="R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7";function createPixelResponse(corsHeaders){const binaryString=atob(TRANSPARENT_GIF_BASE64),bytes=new Uint8Array(binaryString.length);for(let i=0;i<binaryString.length;i++)bytes[i]=binaryString.charCodeAt(i);const headers=new Headers(corsHeaders);return headers.set("Content-Type","image/gif"),headers.set("Cache-Control","no-cache, no-store, must-revalidate"),new Response(bytes,{status:200,headers:headers})}function createJsonResponse(body,status=200,corsHeaders){const headers=new Headers(corsHeaders);return headers.set("Content-Type","application/json"),new Response(JSON.stringify(body),{status:status,headers:headers})}function matchPath(requestPath,pattern){if(pattern.endsWith("/*")){const prefix=pattern.slice(0,-2);return requestPath===prefix||requestPath.startsWith(prefix+"/")}return requestPath===pattern}var types_exports={},examples_exports={};__export(examples_exports,{createTrigger:()=>createTrigger,inputs:()=>inputs_exports,requests:()=>requests_exports,step:()=>step_exports});var inputs_exports={};__export(inputs_exports,{batch:()=>batch,completeEvent:()=>completeEvent,minimal:()=>minimal,pageView:()=>pageView,productAdd:()=>productAdd});var pageView={name:"page view",data:{title:"Home Page",path:"/",referrer:"https://google.com"},user:{id:"user-123",session:"session-456"},timestamp:17e11},productAdd={name:"product add",data:{id:"P-123",name:"Laptop",price:999.99,quantity:1},context:{stage:["shopping",1]},globals:{language:"en",currency:"USD"},user:{id:"user-123"},nested:[{entity:"category",data:{name:"Electronics",path:"/electronics"}}],consent:{functional:!0,marketing:!0}},completeEvent={name:"order complete",data:{id:"ORDER-123",total:999.99,currency:"USD"},context:{stage:["checkout",3],test:["variant-A",0]},globals:{language:"en",country:"US"},custom:{campaignId:"summer-sale",source:"email"},user:{id:"user-123",email:"user@example.com",session:"session-456"},nested:[{entity:"product",data:{id:"P-123",price:999.99}}],consent:{functional:!0,marketing:!0,analytics:!1},trigger:"click"},minimal={name:"ping"},batch=[pageView,productAdd,{name:"button click",data:{id:"cta"}}],requests_exports={};__export(requests_exports,{batchPostRequest:()=>batchPostRequest,healthCheckRequest:()=>healthCheckRequest,invalidJsonRequest:()=>invalidJsonRequest,optionsRequest:()=>optionsRequest,oversizedRequest:()=>oversizedRequest,pixelGetRequest:()=>pixelGetRequest,validPostRequest:()=>validPostRequest});var validPostRequest={method:"POST",url:"https://example.com/collect",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:"page view",data:{title:"Home"}})},batchPostRequest={method:"POST",url:"https://example.com/collect",headers:{"Content-Type":"application/json"},body:JSON.stringify({batch:[{name:"page view",data:{title:"Home"}},{name:"button click",data:{id:"cta"}}]})},pixelGetRequest={method:"GET",url:"https://example.com/collect?event=page%20view&data[title]=Home&user[id]=user123"},healthCheckRequest={method:"GET",url:"https://example.com/health"},optionsRequest={method:"OPTIONS",url:"https://example.com/collect",headers:{Origin:"https://example.com"}},invalidJsonRequest={method:"POST",url:"https://example.com/collect",headers:{"Content-Type":"application/json"},body:"invalid json{"},oversizedRequest={method:"POST",url:"https://example.com/collect",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:"test",data:{payload:"x".repeat(2e5)}})},step_exports={};__export(step_exports,{batchRequest:()=>batchRequest,pixelGet:()=>pixelGet,postEvent:()=>postEvent});var postEvent={title:"POST event",description:"A fetch POST request with a JSON body becomes a single walker elb event in a fetch-based server.",trigger:{type:"POST"},in:{method:"POST",url:"http://localhost/collect",body:{name:"page view",data:{title:"Docs",url:"https://example.com/docs"}}},out:[["elb",{name:"page view",data:{title:"Docs",url:"https://example.com/docs"}}]]},batchRequest={title:"Batch POST",description:"A fetch POST with a batch array produces one walker elb event per batched item preserving order.",trigger:{type:"POST"},in:{method:"POST",url:"http://localhost/collect",body:{batch:[{name:"page view",data:{title:"Home"}},{name:"button click",data:{id:"cta"}}]}},out:[["elb",{name:"page view",data:{title:"Home"}}],["elb",{name:"button click",data:{id:"cta"}}]]},pixelGet={title:"Pixel GET",description:"A fetch GET with query parameters in the URL is parsed into an elb event payload for pixel-style tracking.",trigger:{type:"GET"},in:{method:"GET",url:"http://localhost/collect?e=page+view&d=%7B%22title%22%3A%22Home%22%7D"},out:[["elb",{e:"page view",d:'{"title":"Home"}'}]]},import_collector=require("@walkeros/collector");var createTrigger=async config=>{let flow;return{get flow(){return flow},trigger:()=>async content=>{if(!flow){const result=await(0,import_collector.startFlow)(config);flow={collector:result.collector,elb:result.elb}}const source=function(collector){for(const source of Object.values(collector.sources||{}))if("fetch"===source.type)return source}(flow.collector);if(!source)throw new Error("Fetch source not found in collector");const init={method:content.method,headers:{"Content-Type":"application/json",...content.headers}};"GET"!==content.method&&void 0!==content.body&&(init.body=JSON.stringify(content.body));const request=new Request(content.url,init),response=await source.push(request),responseHeaders={};response.headers.forEach((v,k)=>{responseHeaders[k]=v});const body=(response.headers.get("content-type")||"").includes("json")?await response.json():await response.text();return{status:response.status,body:body,headers:responseHeaders}}}},sourceFetch=async context=>{const{config:config={},env:env}=context,userSettings=config.settings||{},settings={...userSettings,cors:userSettings.cors??!0,maxRequestSize:userSettings.maxRequestSize??102400,maxBatchSize:userSettings.maxBatchSize??100,paths:userSettings.paths??(userSettings.path?[userSettings.path]:["/collect"])},{logger:logger}=env;return{type:"fetch",config:{...config,settings:settings},push:async request=>{Date.now();try{const url=new URL(request.url),method=request.method.toUpperCase(),origin=request.headers.get("Origin"),corsHeaders=createCorsHeaders(settings.cors,origin),matchedRoute=settings.paths.map(entry=>"string"==typeof entry?{path:entry,methods:["GET","POST"]}:{path:entry.path,methods:entry.methods||["GET","POST"]}).find(route=>matchPath(url.pathname,route.path));return matchedRoute?"OPTIONS"===method?new Response(null,{status:204,headers:corsHeaders}):matchedRoute.methods.includes(method)?await context.withScope(request,void 0,async scopeEnv=>{const envPush=scopeEnv.push;if("GET"===method){const parsedData=(0,import_core.requestToData)(url.search);return parsedData&&(0,import_core.isObject)(parsedData)&&await envPush(parsedData),createPixelResponse(corsHeaders)}if("POST"===method){const contentLength=request.headers.get("Content-Length");if(contentLength){const size=parseInt(contentLength,10);if(size>settings.maxRequestSize)return logger.error("Request too large",{size:size,limit:settings.maxRequestSize}),createJsonResponse({success:!1,error:`Request too large. Maximum size: ${settings.maxRequestSize} bytes`},413,corsHeaders)}let eventData,bodyText,rawBody=!1;try{if(bodyText=await request.text(),bodyText.length>settings.maxRequestSize)return logger.error("Request body too large",{size:bodyText.length,limit:settings.maxRequestSize}),createJsonResponse({success:!1,error:`Request too large. Maximum size: ${settings.maxRequestSize} bytes`},413,corsHeaders);eventData=JSON.parse(bodyText)}catch{eventData={},rawBody=!0}if((0,import_core.isDefined)(eventData)&&(0,import_core.isObject)(eventData)||(eventData={},rawBody=!0),rawBody){const result2=await processEvent(eventData,envPush);return result2.error?(logger.error("Event processing failed",{error:result2.error}),createJsonResponse({success:!1,error:result2.error},400,corsHeaders)):createJsonResponse({success:!0,id:result2.id,timestamp:Date.now()},200,corsHeaders)}const validData=eventData;if("batch"in validData&&Array.isArray(validData.batch)){const batch2=validData.batch;if(batch2.length>settings.maxBatchSize)return logger.error("Batch too large",{size:batch2.length,limit:settings.maxBatchSize}),createJsonResponse({success:!1,error:`Batch too large. Maximum size: ${settings.maxBatchSize} events`},400,corsHeaders);const results=await async function(events,push,logger){const results={successful:0,failed:0,ids:[],errors:[]};for(let i=0;i<events.length;i++){const event=events[i];try{const result=await push(event);result?.event?.id&&results.ids.push(result.event.id),results.successful++}catch(error){results.failed++,results.errors.push({index:i,error:error instanceof Error?error.message:"Unknown error"}),logger.error(`Batch event ${i} processing failed`,error)}}return results}(batch2,envPush,logger);return results.failed>0?createJsonResponse({success:!1,processed:results.successful,failed:results.failed,errors:results.errors},207,corsHeaders):createJsonResponse({success:!0,processed:results.successful,ids:results.ids},200,corsHeaders)}const result=await processEvent(eventData,envPush);return result.error?(logger.error("Event processing failed",{error:result.error}),createJsonResponse({success:!1,error:result.error},400,corsHeaders)):createJsonResponse({success:!0,id:result.id,timestamp:Date.now()},200,corsHeaders)}return createJsonResponse({success:!1,error:"Method not allowed"},405,corsHeaders)}):createJsonResponse({success:!1,error:"Method not allowed"},405,corsHeaders):createJsonResponse({success:!1,error:"Not found"},404,corsHeaders)}catch(error){logger.error("Internal server error",error);const corsHeaders=createCorsHeaders(settings.cors);return createJsonResponse({success:!1,error:error instanceof Error?error.message:"Internal server error"},500,corsHeaders)}}}};async function processEvent(event,push){try{const result=await push(event);return{id:result?.event?.id}}catch(error){return{error:error instanceof Error?error.message:"Unknown error"}}}var index_default=sourceFetch;//# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/utils.ts","../src/types.ts","../src/examples/index.ts","../src/examples/inputs.ts","../src/examples/requests.ts","../src/examples/step.ts","../src/examples/trigger.ts"],"sourcesContent":["import { requestToData, isObject, isDefined } from '@walkeros/core';\nimport type { WalkerOS, Collector, Source } from '@walkeros/core';\nimport type { FetchSource, Types } from './types';\nimport {\n createCorsHeaders,\n createPixelResponse,\n createJsonResponse,\n matchPath,\n} from './utils';\n\nexport const sourceFetch: Source.Init<Types> = async (context) => {\n const { config = {}, env, setIngest } = context;\n const userSettings = config.settings || {};\n const settings = {\n ...userSettings,\n cors: userSettings.cors ?? true,\n maxRequestSize: userSettings.maxRequestSize ?? 102400,\n maxBatchSize: userSettings.maxBatchSize ?? 100,\n paths:\n userSettings.paths ??\n (userSettings.path ? [userSettings.path] : ['/collect']),\n };\n const { logger } = env;\n\n const push = async (request: Request): Promise<Response> => {\n const startTime = Date.now();\n\n try {\n const url = new URL(request.url);\n const method = request.method.toUpperCase();\n const origin = request.headers.get('Origin');\n const corsHeaders = createCorsHeaders(settings.cors, origin);\n\n // Resolve route configs\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 // Match request path against configured routes\n const matchedRoute = resolvedPaths.find((route) =>\n matchPath(url.pathname, route.path),\n );\n\n if (!matchedRoute) {\n return createJsonResponse(\n { success: false, error: 'Not found' },\n 404,\n corsHeaders,\n );\n }\n\n // OPTIONS (CORS preflight - no logging, routine)\n if (method === 'OPTIONS') {\n return new Response(null, { status: 204, headers: corsHeaders });\n }\n\n // Check method is allowed for this route\n if (!matchedRoute.methods.includes(method as 'GET' | 'POST')) {\n return createJsonResponse(\n { success: false, error: 'Method not allowed' },\n 405,\n corsHeaders,\n );\n }\n\n // Extract ingest metadata from request (if config.ingest is defined)\n await setIngest(request);\n\n // GET (pixel tracking - no logging, routine)\n if (method === 'GET') {\n const parsedData = requestToData(url.search);\n if (parsedData && isObject(parsedData)) {\n await env.push(parsedData);\n }\n return createPixelResponse(corsHeaders);\n }\n\n // POST\n if (method === 'POST') {\n // Check request size\n const contentLength = request.headers.get('Content-Length');\n if (contentLength) {\n const size = parseInt(contentLength, 10);\n if (size > settings.maxRequestSize) {\n logger.error('Request too large', {\n size,\n limit: settings.maxRequestSize,\n });\n return createJsonResponse(\n {\n success: false,\n error: `Request too large. Maximum size: ${settings.maxRequestSize} bytes`,\n },\n 413,\n corsHeaders,\n );\n }\n }\n\n let eventData: unknown;\n let bodyText: string;\n let rawBody = false;\n\n try {\n bodyText = await request.text();\n\n // Check actual body size\n if (bodyText.length > settings.maxRequestSize) {\n logger.error('Request body too large', {\n size: bodyText.length,\n limit: settings.maxRequestSize,\n });\n return createJsonResponse(\n {\n success: false,\n error: `Request too large. Maximum size: ${settings.maxRequestSize} bytes`,\n },\n 413,\n corsHeaders,\n );\n }\n\n eventData = JSON.parse(bodyText);\n } catch {\n // Non-JSON body: push empty event for source.before transformers\n eventData = {};\n rawBody = true;\n }\n\n if (!isDefined(eventData) || !isObject(eventData)) {\n // Non-object body: push empty event for source.before transformers\n eventData = {};\n rawBody = true;\n }\n\n // Raw body: push empty event directly, skip validation\n if (rawBody) {\n const result = await processEvent(\n eventData as WalkerOS.DeepPartialEvent,\n env.push,\n );\n if (result.error) {\n logger.error('Event processing failed', { error: result.error });\n return createJsonResponse(\n { success: false, error: result.error },\n 400,\n corsHeaders,\n );\n }\n\n return createJsonResponse(\n { success: true, id: result.id, timestamp: Date.now() },\n 200,\n corsHeaders,\n );\n }\n\n // Check for batch (eventData is a validated object at this point)\n const validData = eventData as Record<string, unknown>;\n const isBatch = 'batch' in validData && Array.isArray(validData.batch);\n\n if (isBatch) {\n const batch = validData.batch as unknown[];\n\n if (batch.length > settings.maxBatchSize) {\n logger.error('Batch too large', {\n size: batch.length,\n limit: settings.maxBatchSize,\n });\n return createJsonResponse(\n {\n success: false,\n error: `Batch too large. Maximum size: ${settings.maxBatchSize} events`,\n },\n 400,\n corsHeaders,\n );\n }\n\n const results = await processBatch(batch, env.push, logger);\n\n if (results.failed > 0) {\n return createJsonResponse(\n {\n success: false,\n processed: results.successful,\n failed: results.failed,\n errors: results.errors,\n },\n 207,\n corsHeaders,\n );\n }\n\n return createJsonResponse(\n {\n success: true,\n processed: results.successful,\n ids: results.ids,\n },\n 200,\n corsHeaders,\n );\n }\n\n // Forward event directly — validation is not the source's responsibility.\n const result = await processEvent(\n eventData as WalkerOS.DeepPartialEvent,\n env.push,\n );\n if (result.error) {\n logger.error('Event processing failed', { error: result.error });\n return createJsonResponse(\n { success: false, error: result.error },\n 400,\n corsHeaders,\n );\n }\n\n return createJsonResponse(\n { success: true, id: result.id, timestamp: Date.now() },\n 200,\n corsHeaders,\n );\n }\n\n return createJsonResponse(\n { success: false, error: 'Method not allowed' },\n 405,\n corsHeaders,\n );\n } catch (error) {\n logger.error('Internal server error', error);\n const corsHeaders = createCorsHeaders(settings.cors);\n return createJsonResponse(\n {\n success: false,\n error:\n error instanceof Error ? error.message : 'Internal server error',\n },\n 500,\n corsHeaders,\n );\n }\n };\n\n return { type: 'fetch', config: { ...config, settings }, push };\n};\n\nasync function processEvent(\n event: WalkerOS.DeepPartialEvent,\n push: Collector.PushFn,\n): Promise<{ id?: string; error?: string }> {\n try {\n const result = await push(event);\n return { id: result?.event?.id };\n } catch (error) {\n return { error: error instanceof Error ? error.message : 'Unknown error' };\n }\n}\n\nasync function processBatch(\n events: unknown[],\n push: Collector.PushFn,\n logger: Types['env']['logger'],\n): Promise<{\n successful: number;\n failed: number;\n ids: string[];\n errors: Array<{ index: number; error: string }>;\n}> {\n const results = {\n successful: 0,\n failed: 0,\n ids: [] as string[],\n errors: [] as Array<{ index: number; error: string }>,\n };\n\n for (let i = 0; i < events.length; i++) {\n const event = events[i];\n\n try {\n const result = await push(event as WalkerOS.DeepPartialEvent);\n if (result?.event?.id) {\n results.ids.push(result.event.id);\n }\n results.successful++;\n } catch (error) {\n results.failed++;\n results.errors.push({\n index: i,\n error: error instanceof Error ? error.message : 'Unknown error',\n });\n logger.error(`Batch event ${i} processing failed`, error);\n }\n }\n\n return results;\n}\n\nexport type * from './types';\nexport * as SourceFetch from './types';\nexport * from './utils';\nexport * as examples from './examples';\n\nexport default sourceFetch;\n","import type { CorsOptions } from './schemas';\n\nexport function createCorsHeaders(\n corsConfig: boolean | CorsOptions = true,\n requestOrigin?: string | null,\n): Headers {\n const headers = new Headers();\n\n if (corsConfig === false) return headers;\n\n if (corsConfig === true) {\n headers.set('Access-Control-Allow-Origin', '*');\n headers.set('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');\n headers.set('Access-Control-Allow-Headers', 'Content-Type');\n } else {\n if (corsConfig.origin) {\n let origin: string;\n if (Array.isArray(corsConfig.origin)) {\n origin =\n requestOrigin && corsConfig.origin.includes(requestOrigin)\n ? requestOrigin\n : corsConfig.origin[0];\n } else {\n origin = corsConfig.origin;\n }\n headers.set('Access-Control-Allow-Origin', origin);\n }\n\n if (corsConfig.methods) {\n headers.set(\n 'Access-Control-Allow-Methods',\n corsConfig.methods.join(', '),\n );\n }\n\n if (corsConfig.headers) {\n headers.set(\n 'Access-Control-Allow-Headers',\n corsConfig.headers.join(', '),\n );\n }\n\n if (corsConfig.credentials) {\n headers.set('Access-Control-Allow-Credentials', 'true');\n }\n\n if (corsConfig.maxAge) {\n headers.set('Access-Control-Max-Age', String(corsConfig.maxAge));\n }\n }\n\n return headers;\n}\n\nexport const TRANSPARENT_GIF_BASE64 =\n 'R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';\n\nexport function createPixelResponse(corsHeaders?: Headers): Response {\n const binaryString = atob(TRANSPARENT_GIF_BASE64);\n const bytes = new Uint8Array(binaryString.length);\n for (let i = 0; i < binaryString.length; i++) {\n bytes[i] = binaryString.charCodeAt(i);\n }\n\n const headers = new Headers(corsHeaders);\n headers.set('Content-Type', 'image/gif');\n headers.set('Cache-Control', 'no-cache, no-store, must-revalidate');\n\n return new Response(bytes, { status: 200, headers });\n}\n\nexport function createJsonResponse(\n body: unknown,\n status = 200,\n corsHeaders?: Headers,\n): Response {\n const headers = new Headers(corsHeaders);\n headers.set('Content-Type', 'application/json');\n\n return new Response(JSON.stringify(body), { status, headers });\n}\n\n/**\n * Match a request pathname against a route pattern.\n * Supports exact matches and wildcard patterns (e.g., /api/*).\n */\nexport function matchPath(requestPath: string, pattern: string): boolean {\n if (pattern.endsWith('/*')) {\n const prefix = pattern.slice(0, -2);\n return requestPath === prefix || requestPath.startsWith(prefix + '/');\n }\n return requestPath === pattern;\n}\n","import type { WalkerOS, Source as CoreSource } from '@walkeros/core';\nimport type {\n SettingsSchema,\n CorsOptionsSchema,\n RouteConfigSchema,\n} from './schemas';\nimport type { z } from '@walkeros/core/dev';\n\ndeclare module '@walkeros/core' {\n interface SourceMap {\n fetch: { type: 'fetch'; platform: 'server' };\n }\n}\n\nexport type Settings = z.infer<typeof SettingsSchema>;\nexport type CorsOptions = z.infer<typeof CorsOptionsSchema>;\nexport type RouteConfig = z.infer<typeof RouteConfigSchema>;\nexport type RouteMethod = 'GET' | 'POST';\nexport type InitSettings = Partial<Settings>;\n\nexport interface Mapping {}\n\nexport type Push = (request: Request) => Response | Promise<Response>;\n\nexport interface Env extends CoreSource.Env {\n request?: Request;\n}\n\nexport type Types = CoreSource.Types<\n Settings,\n Mapping,\n Push,\n Env,\n InitSettings\n>;\nexport type Config = CoreSource.Config<Types>;\nexport type PartialConfig = CoreSource.PartialConfig<Types>;\n\nexport interface FetchSource extends Omit<CoreSource.Instance<Types>, 'push'> {\n push: Push;\n}\n\nexport interface EventResponse {\n success: boolean;\n id?: string;\n timestamp?: number;\n error?: string;\n}\n","export * as inputs from './inputs';\nexport * as requests from './requests';\nexport * as step from './step';\nexport { createTrigger } from './trigger';\n","import type { WalkerOS } from '@walkeros/core';\n\n/**\n * Example walkerOS events that HTTP clients send to this source.\n * These are the CONTRACT - tests verify implementation handles these inputs.\n */\n\n// Simple page view event\nexport const pageView: WalkerOS.DeepPartialEvent = {\n name: 'page view',\n data: {\n title: 'Home Page',\n path: '/',\n referrer: 'https://google.com',\n },\n user: {\n id: 'user-123',\n session: 'session-456',\n },\n timestamp: 1700000000000,\n};\n\n// E-commerce event with nested entities\nexport const productAdd: WalkerOS.DeepPartialEvent = {\n name: 'product add',\n data: {\n id: 'P-123',\n name: 'Laptop',\n price: 999.99,\n quantity: 1,\n },\n context: {\n stage: ['shopping', 1],\n },\n globals: {\n language: 'en',\n currency: 'USD',\n },\n user: {\n id: 'user-123',\n },\n nested: [\n {\n entity: 'category',\n data: {\n name: 'Electronics',\n path: '/electronics',\n },\n },\n ],\n consent: {\n functional: true,\n marketing: true,\n },\n};\n\n// Complete event with all optional fields\nexport const completeEvent: WalkerOS.DeepPartialEvent = {\n name: 'order complete',\n data: {\n id: 'ORDER-123',\n total: 999.99,\n currency: 'USD',\n },\n context: {\n stage: ['checkout', 3],\n test: ['variant-A', 0],\n },\n globals: {\n language: 'en',\n country: 'US',\n },\n custom: {\n campaignId: 'summer-sale',\n source: 'email',\n },\n user: {\n id: 'user-123',\n email: 'user@example.com',\n session: 'session-456',\n },\n nested: [\n {\n entity: 'product',\n data: {\n id: 'P-123',\n price: 999.99,\n },\n },\n ],\n consent: {\n functional: true,\n marketing: true,\n analytics: false,\n },\n trigger: 'click',\n};\n\n// Minimal valid event\nexport const minimal: WalkerOS.DeepPartialEvent = {\n name: 'ping',\n};\n\n// Batch of events\nexport const batch: WalkerOS.DeepPartialEvent[] = [\n pageView,\n productAdd,\n { name: 'button click', data: { id: 'cta' } },\n];\n","/**\n * HTTP request examples for testing the fetch source.\n * Shows what external HTTP clients will send.\n */\n\nexport const validPostRequest = {\n method: 'POST',\n url: 'https://example.com/collect',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n name: 'page view',\n data: { title: 'Home' },\n }),\n};\n\nexport const batchPostRequest = {\n method: 'POST',\n url: 'https://example.com/collect',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n batch: [\n { name: 'page view', data: { title: 'Home' } },\n { name: 'button click', data: { id: 'cta' } },\n ],\n }),\n};\n\nexport const pixelGetRequest = {\n method: 'GET',\n url: 'https://example.com/collect?event=page%20view&data[title]=Home&user[id]=user123',\n};\n\nexport const healthCheckRequest = {\n method: 'GET',\n url: 'https://example.com/health',\n};\n\nexport const optionsRequest = {\n method: 'OPTIONS',\n url: 'https://example.com/collect',\n headers: { Origin: 'https://example.com' },\n};\n\nexport const invalidJsonRequest = {\n method: 'POST',\n url: 'https://example.com/collect',\n headers: { 'Content-Type': 'application/json' },\n body: 'invalid json{',\n};\n\nexport const oversizedRequest = {\n method: 'POST',\n url: 'https://example.com/collect',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n name: 'test',\n data: { payload: 'x'.repeat(200000) }, // 200KB\n }),\n};\n","import type { Flow } from '@walkeros/core';\n\nexport const postEvent: Flow.StepExample = {\n title: 'POST event',\n description:\n 'A fetch POST request with a JSON body becomes a single walker elb event in a fetch-based server.',\n trigger: { type: 'POST' },\n in: {\n method: 'POST',\n url: 'http://localhost/collect',\n body: {\n name: 'page view',\n data: { title: 'Docs', url: 'https://example.com/docs' },\n },\n },\n out: [\n [\n 'elb',\n {\n name: 'page view',\n data: { title: 'Docs', url: 'https://example.com/docs' },\n },\n ],\n ],\n};\n\nexport const batchRequest: Flow.StepExample = {\n title: 'Batch POST',\n description:\n 'A fetch POST with a batch array produces one walker elb event per batched item preserving order.',\n trigger: { type: 'POST' },\n in: {\n method: 'POST',\n url: 'http://localhost/collect',\n body: {\n batch: [\n { name: 'page view', data: { title: 'Home' } },\n { name: 'button click', data: { id: 'cta' } },\n ],\n },\n },\n out: [\n ['elb', { name: 'page view', data: { title: 'Home' } }],\n ['elb', { name: 'button click', data: { id: 'cta' } }],\n ],\n};\n\nexport const pixelGet: Flow.StepExample = {\n title: 'Pixel GET',\n description:\n 'A fetch GET with query parameters in the URL is parsed into an elb event payload for pixel-style tracking.',\n trigger: { type: 'GET' },\n in: {\n method: 'GET',\n url: 'http://localhost/collect?e=page+view&d=%7B%22title%22%3A%22Home%22%7D',\n },\n out: [\n [\n 'elb',\n {\n e: 'page view',\n d: '{\"title\":\"Home\"}',\n },\n ],\n ],\n};\n","import type { Trigger, Collector } from '@walkeros/core';\nimport { startFlow } from '@walkeros/collector';\n\nexport interface Content {\n method: string;\n url: string;\n body?: unknown;\n headers?: Record<string, string>;\n}\n\nexport interface Result {\n status: number;\n body: unknown;\n headers: Record<string, string>;\n}\n\nfunction findFetchSource(collector: Collector.Instance) {\n for (const source of Object.values(collector.sources || {})) {\n if ((source as { type?: string }).type === 'fetch') return source;\n }\n}\n\nconst createTrigger: Trigger.CreateFn<Content, Result> = async (\n config: Collector.InitConfig,\n) => {\n let flow: Trigger.FlowHandle | undefined;\n\n const trigger: Trigger.Fn<Content, Result> =\n () =>\n async (content: Content): Promise<Result> => {\n if (!flow) {\n const result = await startFlow(config);\n flow = { collector: result.collector, elb: result.elb };\n }\n\n const source = findFetchSource(flow.collector);\n if (!source) throw new Error('Fetch source not found in collector');\n\n // Construct real Request from content\n const init: RequestInit = {\n method: content.method,\n headers: { 'Content-Type': 'application/json', ...content.headers },\n };\n if (content.method !== 'GET' && content.body !== undefined) {\n init.body = JSON.stringify(content.body);\n }\n const request = new Request(content.url, init);\n\n // Call source.push with the real Request\n const response = await (\n source as unknown as { push: (r: Request) => Promise<Response> }\n ).push(request);\n\n // Convert Response to serializable result\n const responseHeaders: Record<string, string> = {};\n response.headers.forEach((v, k) => {\n responseHeaders[k] = v;\n });\n\n const ct = response.headers.get('content-type') || '';\n const body = ct.includes('json')\n ? await response.json()\n : await response.text();\n\n return { status: response.status, body, headers: responseHeaders };\n };\n\n return {\n get flow() {\n return flow;\n },\n trigger,\n };\n};\n\nexport { createTrigger };\n"],"mappings":"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","names":["result","batch"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/utils.ts","../src/types.ts","../src/examples/index.ts","../src/examples/inputs.ts","../src/examples/requests.ts","../src/examples/step.ts","../src/examples/trigger.ts"],"sourcesContent":["import { requestToData, isObject, isDefined } from '@walkeros/core';\nimport type { WalkerOS, Collector, Source } from '@walkeros/core';\nimport type { FetchSource, Types } from './types';\nimport {\n createCorsHeaders,\n createPixelResponse,\n createJsonResponse,\n matchPath,\n} from './utils';\n\nexport const sourceFetch: Source.Init<Types> = async (context) => {\n const { config = {}, env } = context;\n const userSettings = config.settings || {};\n const settings = {\n ...userSettings,\n cors: userSettings.cors ?? true,\n maxRequestSize: userSettings.maxRequestSize ?? 102400,\n maxBatchSize: userSettings.maxBatchSize ?? 100,\n paths:\n userSettings.paths ??\n (userSettings.path ? [userSettings.path] : ['/collect']),\n };\n const { logger } = env;\n\n const push = async (request: Request): Promise<Response> => {\n const startTime = Date.now();\n void startTime;\n\n try {\n const url = new URL(request.url);\n const method = request.method.toUpperCase();\n const origin = request.headers.get('Origin');\n const corsHeaders = createCorsHeaders(settings.cors, origin);\n\n // Resolve route configs\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 // Match request path against configured routes\n const matchedRoute = resolvedPaths.find((route) =>\n matchPath(url.pathname, route.path),\n );\n\n if (!matchedRoute) {\n return createJsonResponse(\n { success: false, error: 'Not found' },\n 404,\n corsHeaders,\n );\n }\n\n // OPTIONS (CORS preflight - no logging, routine)\n if (method === 'OPTIONS') {\n return new Response(null, { status: 204, headers: corsHeaders });\n }\n\n // Check method is allowed for this route\n if (!matchedRoute.methods.includes(method as 'GET' | 'POST')) {\n return createJsonResponse(\n { success: false, error: 'Method not allowed' },\n 405,\n corsHeaders,\n );\n }\n\n // Per-request scope: each fetch invocation gets its own ingest.\n // Fetch sources return a Response directly, not via async respond.\n return await context.withScope(request, undefined, async (scopeEnv) => {\n const envPush = scopeEnv.push;\n\n // GET (pixel tracking - no logging, routine)\n if (method === 'GET') {\n const parsedData = requestToData(url.search);\n if (parsedData && isObject(parsedData)) {\n await envPush(parsedData);\n }\n return createPixelResponse(corsHeaders);\n }\n\n // POST\n if (method === 'POST') {\n // Check request size\n const contentLength = request.headers.get('Content-Length');\n if (contentLength) {\n const size = parseInt(contentLength, 10);\n if (size > settings.maxRequestSize) {\n logger.error('Request too large', {\n size,\n limit: settings.maxRequestSize,\n });\n return createJsonResponse(\n {\n success: false,\n error: `Request too large. Maximum size: ${settings.maxRequestSize} bytes`,\n },\n 413,\n corsHeaders,\n );\n }\n }\n\n let eventData: unknown;\n let bodyText: string;\n let rawBody = false;\n\n try {\n bodyText = await request.text();\n\n // Check actual body size\n if (bodyText.length > settings.maxRequestSize) {\n logger.error('Request body too large', {\n size: bodyText.length,\n limit: settings.maxRequestSize,\n });\n return createJsonResponse(\n {\n success: false,\n error: `Request too large. Maximum size: ${settings.maxRequestSize} bytes`,\n },\n 413,\n corsHeaders,\n );\n }\n\n eventData = JSON.parse(bodyText);\n } catch {\n // Non-JSON body: push empty event for source.before transformers\n eventData = {};\n rawBody = true;\n }\n\n if (!isDefined(eventData) || !isObject(eventData)) {\n // Non-object body: push empty event for source.before transformers\n eventData = {};\n rawBody = true;\n }\n\n // Raw body: push empty event directly, skip validation\n if (rawBody) {\n const result = await processEvent(\n eventData as WalkerOS.DeepPartialEvent,\n envPush,\n );\n if (result.error) {\n logger.error('Event processing failed', { error: result.error });\n return createJsonResponse(\n { success: false, error: result.error },\n 400,\n corsHeaders,\n );\n }\n\n return createJsonResponse(\n { success: true, id: result.id, timestamp: Date.now() },\n 200,\n corsHeaders,\n );\n }\n\n // Check for batch (eventData is a validated object at this point)\n const validData = eventData as Record<string, unknown>;\n const isBatch =\n 'batch' in validData && Array.isArray(validData.batch);\n\n if (isBatch) {\n const batch = validData.batch as unknown[];\n\n if (batch.length > settings.maxBatchSize) {\n logger.error('Batch too large', {\n size: batch.length,\n limit: settings.maxBatchSize,\n });\n return createJsonResponse(\n {\n success: false,\n error: `Batch too large. Maximum size: ${settings.maxBatchSize} events`,\n },\n 400,\n corsHeaders,\n );\n }\n\n const results = await processBatch(batch, envPush, logger);\n\n if (results.failed > 0) {\n return createJsonResponse(\n {\n success: false,\n processed: results.successful,\n failed: results.failed,\n errors: results.errors,\n },\n 207,\n corsHeaders,\n );\n }\n\n return createJsonResponse(\n {\n success: true,\n processed: results.successful,\n ids: results.ids,\n },\n 200,\n corsHeaders,\n );\n }\n\n // Forward event directly — validation is not the source's responsibility.\n const result = await processEvent(\n eventData as WalkerOS.DeepPartialEvent,\n envPush,\n );\n if (result.error) {\n logger.error('Event processing failed', { error: result.error });\n return createJsonResponse(\n { success: false, error: result.error },\n 400,\n corsHeaders,\n );\n }\n\n return createJsonResponse(\n { success: true, id: result.id, timestamp: Date.now() },\n 200,\n corsHeaders,\n );\n }\n\n return createJsonResponse(\n { success: false, error: 'Method not allowed' },\n 405,\n corsHeaders,\n );\n });\n } catch (error) {\n logger.error('Internal server error', error);\n const corsHeaders = createCorsHeaders(settings.cors);\n return createJsonResponse(\n {\n success: false,\n error:\n error instanceof Error ? error.message : 'Internal server error',\n },\n 500,\n corsHeaders,\n );\n }\n };\n\n return { type: 'fetch', config: { ...config, settings }, push };\n};\n\nasync function processEvent(\n event: WalkerOS.DeepPartialEvent,\n push: Collector.PushFn,\n): Promise<{ id?: string; error?: string }> {\n try {\n const result = await push(event);\n return { id: result?.event?.id };\n } catch (error) {\n return { error: error instanceof Error ? error.message : 'Unknown error' };\n }\n}\n\nasync function processBatch(\n events: unknown[],\n push: Collector.PushFn,\n logger: Types['env']['logger'],\n): Promise<{\n successful: number;\n failed: number;\n ids: string[];\n errors: Array<{ index: number; error: string }>;\n}> {\n const results = {\n successful: 0,\n failed: 0,\n ids: [] as string[],\n errors: [] as Array<{ index: number; error: string }>,\n };\n\n for (let i = 0; i < events.length; i++) {\n const event = events[i];\n\n try {\n const result = await push(event as WalkerOS.DeepPartialEvent);\n if (result?.event?.id) {\n results.ids.push(result.event.id);\n }\n results.successful++;\n } catch (error) {\n results.failed++;\n results.errors.push({\n index: i,\n error: error instanceof Error ? error.message : 'Unknown error',\n });\n logger.error(`Batch event ${i} processing failed`, error);\n }\n }\n\n return results;\n}\n\nexport type * from './types';\nexport * as SourceFetch from './types';\nexport * from './utils';\nexport * as examples from './examples';\n\nexport default sourceFetch;\n","import type { CorsOptions } from './schemas';\n\nexport function createCorsHeaders(\n corsConfig: boolean | CorsOptions = true,\n requestOrigin?: string | null,\n): Headers {\n const headers = new Headers();\n\n if (corsConfig === false) return headers;\n\n if (corsConfig === true) {\n headers.set('Access-Control-Allow-Origin', '*');\n headers.set('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');\n headers.set('Access-Control-Allow-Headers', 'Content-Type');\n } else {\n if (corsConfig.origin) {\n let origin: string;\n if (Array.isArray(corsConfig.origin)) {\n origin =\n requestOrigin && corsConfig.origin.includes(requestOrigin)\n ? requestOrigin\n : corsConfig.origin[0];\n } else {\n origin = corsConfig.origin;\n }\n headers.set('Access-Control-Allow-Origin', origin);\n }\n\n if (corsConfig.methods) {\n headers.set(\n 'Access-Control-Allow-Methods',\n corsConfig.methods.join(', '),\n );\n }\n\n if (corsConfig.headers) {\n headers.set(\n 'Access-Control-Allow-Headers',\n corsConfig.headers.join(', '),\n );\n }\n\n if (corsConfig.credentials) {\n headers.set('Access-Control-Allow-Credentials', 'true');\n }\n\n if (corsConfig.maxAge) {\n headers.set('Access-Control-Max-Age', String(corsConfig.maxAge));\n }\n }\n\n return headers;\n}\n\nexport const TRANSPARENT_GIF_BASE64 =\n 'R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';\n\nexport function createPixelResponse(corsHeaders?: Headers): Response {\n const binaryString = atob(TRANSPARENT_GIF_BASE64);\n const bytes = new Uint8Array(binaryString.length);\n for (let i = 0; i < binaryString.length; i++) {\n bytes[i] = binaryString.charCodeAt(i);\n }\n\n const headers = new Headers(corsHeaders);\n headers.set('Content-Type', 'image/gif');\n headers.set('Cache-Control', 'no-cache, no-store, must-revalidate');\n\n return new Response(bytes, { status: 200, headers });\n}\n\nexport function createJsonResponse(\n body: unknown,\n status = 200,\n corsHeaders?: Headers,\n): Response {\n const headers = new Headers(corsHeaders);\n headers.set('Content-Type', 'application/json');\n\n return new Response(JSON.stringify(body), { status, headers });\n}\n\n/**\n * Match a request pathname against a route pattern.\n * Supports exact matches and wildcard patterns (e.g., /api/*).\n */\nexport function matchPath(requestPath: string, pattern: string): boolean {\n if (pattern.endsWith('/*')) {\n const prefix = pattern.slice(0, -2);\n return requestPath === prefix || requestPath.startsWith(prefix + '/');\n }\n return requestPath === pattern;\n}\n","import type { WalkerOS, Source as CoreSource } from '@walkeros/core';\nimport type {\n SettingsSchema,\n CorsOptionsSchema,\n RouteConfigSchema,\n} from './schemas';\nimport type { z } from '@walkeros/core/dev';\n\ndeclare module '@walkeros/core' {\n interface SourceMap {\n fetch: { type: 'fetch'; platform: 'server' };\n }\n}\n\nexport type Settings = z.infer<typeof SettingsSchema>;\nexport type CorsOptions = z.infer<typeof CorsOptionsSchema>;\nexport type RouteConfig = z.infer<typeof RouteConfigSchema>;\nexport type RouteMethod = 'GET' | 'POST';\nexport type InitSettings = Partial<Settings>;\n\nexport interface Mapping {}\n\nexport type Push = (request: Request) => Response | Promise<Response>;\n\nexport interface Env extends CoreSource.Env {\n request?: Request;\n}\n\nexport type Types = CoreSource.Types<\n Settings,\n Mapping,\n Push,\n Env,\n InitSettings\n>;\nexport type Config = CoreSource.Config<Types>;\nexport type PartialConfig = CoreSource.PartialConfig<Types>;\n\nexport interface FetchSource extends Omit<CoreSource.Instance<Types>, 'push'> {\n push: Push;\n}\n\nexport interface EventResponse {\n success: boolean;\n id?: string;\n timestamp?: number;\n error?: string;\n}\n","export * as inputs from './inputs';\nexport * as requests from './requests';\nexport * as step from './step';\nexport { createTrigger } from './trigger';\n","import type { WalkerOS } from '@walkeros/core';\n\n/**\n * Example walkerOS events that HTTP clients send to this source.\n * These are the CONTRACT - tests verify implementation handles these inputs.\n */\n\n// Simple page view event\nexport const pageView: WalkerOS.DeepPartialEvent = {\n name: 'page view',\n data: {\n title: 'Home Page',\n path: '/',\n referrer: 'https://google.com',\n },\n user: {\n id: 'user-123',\n session: 'session-456',\n },\n timestamp: 1700000000000,\n};\n\n// E-commerce event with nested entities\nexport const productAdd: WalkerOS.DeepPartialEvent = {\n name: 'product add',\n data: {\n id: 'P-123',\n name: 'Laptop',\n price: 999.99,\n quantity: 1,\n },\n context: {\n stage: ['shopping', 1],\n },\n globals: {\n language: 'en',\n currency: 'USD',\n },\n user: {\n id: 'user-123',\n },\n nested: [\n {\n entity: 'category',\n data: {\n name: 'Electronics',\n path: '/electronics',\n },\n },\n ],\n consent: {\n functional: true,\n marketing: true,\n },\n};\n\n// Complete event with all optional fields\nexport const completeEvent: WalkerOS.DeepPartialEvent = {\n name: 'order complete',\n data: {\n id: 'ORDER-123',\n total: 999.99,\n currency: 'USD',\n },\n context: {\n stage: ['checkout', 3],\n test: ['variant-A', 0],\n },\n globals: {\n language: 'en',\n country: 'US',\n },\n custom: {\n campaignId: 'summer-sale',\n source: 'email',\n },\n user: {\n id: 'user-123',\n email: 'user@example.com',\n session: 'session-456',\n },\n nested: [\n {\n entity: 'product',\n data: {\n id: 'P-123',\n price: 999.99,\n },\n },\n ],\n consent: {\n functional: true,\n marketing: true,\n analytics: false,\n },\n trigger: 'click',\n};\n\n// Minimal valid event\nexport const minimal: WalkerOS.DeepPartialEvent = {\n name: 'ping',\n};\n\n// Batch of events\nexport const batch: WalkerOS.DeepPartialEvent[] = [\n pageView,\n productAdd,\n { name: 'button click', data: { id: 'cta' } },\n];\n","/**\n * HTTP request examples for testing the fetch source.\n * Shows what external HTTP clients will send.\n */\n\nexport const validPostRequest = {\n method: 'POST',\n url: 'https://example.com/collect',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n name: 'page view',\n data: { title: 'Home' },\n }),\n};\n\nexport const batchPostRequest = {\n method: 'POST',\n url: 'https://example.com/collect',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n batch: [\n { name: 'page view', data: { title: 'Home' } },\n { name: 'button click', data: { id: 'cta' } },\n ],\n }),\n};\n\nexport const pixelGetRequest = {\n method: 'GET',\n url: 'https://example.com/collect?event=page%20view&data[title]=Home&user[id]=user123',\n};\n\nexport const healthCheckRequest = {\n method: 'GET',\n url: 'https://example.com/health',\n};\n\nexport const optionsRequest = {\n method: 'OPTIONS',\n url: 'https://example.com/collect',\n headers: { Origin: 'https://example.com' },\n};\n\nexport const invalidJsonRequest = {\n method: 'POST',\n url: 'https://example.com/collect',\n headers: { 'Content-Type': 'application/json' },\n body: 'invalid json{',\n};\n\nexport const oversizedRequest = {\n method: 'POST',\n url: 'https://example.com/collect',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n name: 'test',\n data: { payload: 'x'.repeat(200000) }, // 200KB\n }),\n};\n","import type { Flow } from '@walkeros/core';\n\nexport const postEvent: Flow.StepExample = {\n title: 'POST event',\n description:\n 'A fetch POST request with a JSON body becomes a single walker elb event in a fetch-based server.',\n trigger: { type: 'POST' },\n in: {\n method: 'POST',\n url: 'http://localhost/collect',\n body: {\n name: 'page view',\n data: { title: 'Docs', url: 'https://example.com/docs' },\n },\n },\n out: [\n [\n 'elb',\n {\n name: 'page view',\n data: { title: 'Docs', url: 'https://example.com/docs' },\n },\n ],\n ],\n};\n\nexport const batchRequest: Flow.StepExample = {\n title: 'Batch POST',\n description:\n 'A fetch POST with a batch array produces one walker elb event per batched item preserving order.',\n trigger: { type: 'POST' },\n in: {\n method: 'POST',\n url: 'http://localhost/collect',\n body: {\n batch: [\n { name: 'page view', data: { title: 'Home' } },\n { name: 'button click', data: { id: 'cta' } },\n ],\n },\n },\n out: [\n ['elb', { name: 'page view', data: { title: 'Home' } }],\n ['elb', { name: 'button click', data: { id: 'cta' } }],\n ],\n};\n\nexport const pixelGet: Flow.StepExample = {\n title: 'Pixel GET',\n description:\n 'A fetch GET with query parameters in the URL is parsed into an elb event payload for pixel-style tracking.',\n trigger: { type: 'GET' },\n in: {\n method: 'GET',\n url: 'http://localhost/collect?e=page+view&d=%7B%22title%22%3A%22Home%22%7D',\n },\n out: [\n [\n 'elb',\n {\n e: 'page view',\n d: '{\"title\":\"Home\"}',\n },\n ],\n ],\n};\n","import type { Trigger, Collector } from '@walkeros/core';\nimport { startFlow } from '@walkeros/collector';\n\nexport interface Content {\n method: string;\n url: string;\n body?: unknown;\n headers?: Record<string, string>;\n}\n\nexport interface Result {\n status: number;\n body: unknown;\n headers: Record<string, string>;\n}\n\nfunction findFetchSource(collector: Collector.Instance) {\n for (const source of Object.values(collector.sources || {})) {\n if ((source as { type?: string }).type === 'fetch') return source;\n }\n}\n\nconst createTrigger: Trigger.CreateFn<Content, Result> = async (\n config: Collector.InitConfig,\n) => {\n let flow: Trigger.FlowHandle | undefined;\n\n const trigger: Trigger.Fn<Content, Result> =\n () =>\n async (content: Content): Promise<Result> => {\n if (!flow) {\n const result = await startFlow(config);\n flow = { collector: result.collector, elb: result.elb };\n }\n\n const source = findFetchSource(flow.collector);\n if (!source) throw new Error('Fetch source not found in collector');\n\n // Construct real Request from content\n const init: RequestInit = {\n method: content.method,\n headers: { 'Content-Type': 'application/json', ...content.headers },\n };\n if (content.method !== 'GET' && content.body !== undefined) {\n init.body = JSON.stringify(content.body);\n }\n const request = new Request(content.url, init);\n\n // Call source.push with the real Request\n const response = await (\n source as unknown as { push: (r: Request) => Promise<Response> }\n ).push(request);\n\n // Convert Response to serializable result\n const responseHeaders: Record<string, string> = {};\n response.headers.forEach((v, k) => {\n responseHeaders[k] = v;\n });\n\n const ct = response.headers.get('content-type') || '';\n const body = ct.includes('json')\n ? await response.json()\n : await response.text();\n\n return { status: response.status, body, headers: responseHeaders };\n };\n\n return {\n get flow() {\n return flow;\n },\n trigger,\n };\n};\n\nexport { createTrigger };\n"],"mappings":"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","names":["result","batch"]}
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- var __defProp=Object.defineProperty,__export=(target,all)=>{for(var name in all)__defProp(target,name,{get:all[name],enumerable:!0})};import{requestToData,isObject,isDefined}from"@walkeros/core";function createCorsHeaders(corsConfig=!0,requestOrigin){const headers=new Headers;if(!1===corsConfig)return headers;if(!0===corsConfig)headers.set("Access-Control-Allow-Origin","*"),headers.set("Access-Control-Allow-Methods","GET, POST, OPTIONS"),headers.set("Access-Control-Allow-Headers","Content-Type");else{if(corsConfig.origin){let origin;origin=Array.isArray(corsConfig.origin)?requestOrigin&&corsConfig.origin.includes(requestOrigin)?requestOrigin:corsConfig.origin[0]:corsConfig.origin,headers.set("Access-Control-Allow-Origin",origin)}corsConfig.methods&&headers.set("Access-Control-Allow-Methods",corsConfig.methods.join(", ")),corsConfig.headers&&headers.set("Access-Control-Allow-Headers",corsConfig.headers.join(", ")),corsConfig.credentials&&headers.set("Access-Control-Allow-Credentials","true"),corsConfig.maxAge&&headers.set("Access-Control-Max-Age",String(corsConfig.maxAge))}return headers}var TRANSPARENT_GIF_BASE64="R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7";function createPixelResponse(corsHeaders){const binaryString=atob("R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"),bytes=new Uint8Array(binaryString.length);for(let i=0;i<binaryString.length;i++)bytes[i]=binaryString.charCodeAt(i);const headers=new Headers(corsHeaders);return headers.set("Content-Type","image/gif"),headers.set("Cache-Control","no-cache, no-store, must-revalidate"),new Response(bytes,{status:200,headers:headers})}function createJsonResponse(body,status=200,corsHeaders){const headers=new Headers(corsHeaders);return headers.set("Content-Type","application/json"),new Response(JSON.stringify(body),{status:status,headers:headers})}function matchPath(requestPath,pattern){if(pattern.endsWith("/*")){const prefix=pattern.slice(0,-2);return requestPath===prefix||requestPath.startsWith(prefix+"/")}return requestPath===pattern}var types_exports={},examples_exports={};__export(examples_exports,{createTrigger:()=>createTrigger,inputs:()=>inputs_exports,requests:()=>requests_exports,step:()=>step_exports});var inputs_exports={};__export(inputs_exports,{batch:()=>batch,completeEvent:()=>completeEvent,minimal:()=>minimal,pageView:()=>pageView,productAdd:()=>productAdd});var pageView={name:"page view",data:{title:"Home Page",path:"/",referrer:"https://google.com"},user:{id:"user-123",session:"session-456"},timestamp:17e11},productAdd={name:"product add",data:{id:"P-123",name:"Laptop",price:999.99,quantity:1},context:{stage:["shopping",1]},globals:{language:"en",currency:"USD"},user:{id:"user-123"},nested:[{entity:"category",data:{name:"Electronics",path:"/electronics"}}],consent:{functional:!0,marketing:!0}},completeEvent={name:"order complete",data:{id:"ORDER-123",total:999.99,currency:"USD"},context:{stage:["checkout",3],test:["variant-A",0]},globals:{language:"en",country:"US"},custom:{campaignId:"summer-sale",source:"email"},user:{id:"user-123",email:"user@example.com",session:"session-456"},nested:[{entity:"product",data:{id:"P-123",price:999.99}}],consent:{functional:!0,marketing:!0,analytics:!1},trigger:"click"},minimal={name:"ping"},batch=[pageView,productAdd,{name:"button click",data:{id:"cta"}}],requests_exports={};__export(requests_exports,{batchPostRequest:()=>batchPostRequest,healthCheckRequest:()=>healthCheckRequest,invalidJsonRequest:()=>invalidJsonRequest,optionsRequest:()=>optionsRequest,oversizedRequest:()=>oversizedRequest,pixelGetRequest:()=>pixelGetRequest,validPostRequest:()=>validPostRequest});var validPostRequest={method:"POST",url:"https://example.com/collect",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:"page view",data:{title:"Home"}})},batchPostRequest={method:"POST",url:"https://example.com/collect",headers:{"Content-Type":"application/json"},body:JSON.stringify({batch:[{name:"page view",data:{title:"Home"}},{name:"button click",data:{id:"cta"}}]})},pixelGetRequest={method:"GET",url:"https://example.com/collect?event=page%20view&data[title]=Home&user[id]=user123"},healthCheckRequest={method:"GET",url:"https://example.com/health"},optionsRequest={method:"OPTIONS",url:"https://example.com/collect",headers:{Origin:"https://example.com"}},invalidJsonRequest={method:"POST",url:"https://example.com/collect",headers:{"Content-Type":"application/json"},body:"invalid json{"},oversizedRequest={method:"POST",url:"https://example.com/collect",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:"test",data:{payload:"x".repeat(2e5)}})},step_exports={};__export(step_exports,{batchRequest:()=>batchRequest,pixelGet:()=>pixelGet,postEvent:()=>postEvent});var postEvent={title:"POST event",description:"A fetch POST request with a JSON body becomes a single walker elb event in a fetch-based server.",trigger:{type:"POST"},in:{method:"POST",url:"http://localhost/collect",body:{name:"page view",data:{title:"Docs",url:"https://example.com/docs"}}},out:[["elb",{name:"page view",data:{title:"Docs",url:"https://example.com/docs"}}]]},batchRequest={title:"Batch POST",description:"A fetch POST with a batch array produces one walker elb event per batched item preserving order.",trigger:{type:"POST"},in:{method:"POST",url:"http://localhost/collect",body:{batch:[{name:"page view",data:{title:"Home"}},{name:"button click",data:{id:"cta"}}]}},out:[["elb",{name:"page view",data:{title:"Home"}}],["elb",{name:"button click",data:{id:"cta"}}]]},pixelGet={title:"Pixel GET",description:"A fetch GET with query parameters in the URL is parsed into an elb event payload for pixel-style tracking.",trigger:{type:"GET"},in:{method:"GET",url:"http://localhost/collect?e=page+view&d=%7B%22title%22%3A%22Home%22%7D"},out:[["elb",{e:"page view",d:'{"title":"Home"}'}]]};import{startFlow}from"@walkeros/collector";var createTrigger=async config=>{let flow;return{get flow(){return flow},trigger:()=>async content=>{if(!flow){const result=await startFlow(config);flow={collector:result.collector,elb:result.elb}}const source=function(collector){for(const source of Object.values(collector.sources||{}))if("fetch"===source.type)return source}(flow.collector);if(!source)throw new Error("Fetch source not found in collector");const init={method:content.method,headers:{"Content-Type":"application/json",...content.headers}};"GET"!==content.method&&void 0!==content.body&&(init.body=JSON.stringify(content.body));const request=new Request(content.url,init),response=await source.push(request),responseHeaders={};response.headers.forEach((v,k)=>{responseHeaders[k]=v});const body=(response.headers.get("content-type")||"").includes("json")?await response.json():await response.text();return{status:response.status,body:body,headers:responseHeaders}}}},sourceFetch=async context=>{const{config:config={},env:env,setIngest:setIngest}=context,userSettings=config.settings||{},settings={...userSettings,cors:userSettings.cors??!0,maxRequestSize:userSettings.maxRequestSize??102400,maxBatchSize:userSettings.maxBatchSize??100,paths:userSettings.paths??(userSettings.path?[userSettings.path]:["/collect"])},{logger:logger}=env;return{type:"fetch",config:{...config,settings:settings},push:async request=>{Date.now();try{const url=new URL(request.url),method=request.method.toUpperCase(),origin=request.headers.get("Origin"),corsHeaders=createCorsHeaders(settings.cors,origin),matchedRoute=settings.paths.map(entry=>"string"==typeof entry?{path:entry,methods:["GET","POST"]}:{path:entry.path,methods:entry.methods||["GET","POST"]}).find(route=>matchPath(url.pathname,route.path));if(!matchedRoute)return createJsonResponse({success:!1,error:"Not found"},404,corsHeaders);if("OPTIONS"===method)return new Response(null,{status:204,headers:corsHeaders});if(!matchedRoute.methods.includes(method))return createJsonResponse({success:!1,error:"Method not allowed"},405,corsHeaders);if(await setIngest(request),"GET"===method){const parsedData=requestToData(url.search);return parsedData&&isObject(parsedData)&&await env.push(parsedData),createPixelResponse(corsHeaders)}if("POST"===method){const contentLength=request.headers.get("Content-Length");if(contentLength){const size=parseInt(contentLength,10);if(size>settings.maxRequestSize)return logger.error("Request too large",{size:size,limit:settings.maxRequestSize}),createJsonResponse({success:!1,error:`Request too large. Maximum size: ${settings.maxRequestSize} bytes`},413,corsHeaders)}let eventData,bodyText,rawBody=!1;try{if(bodyText=await request.text(),bodyText.length>settings.maxRequestSize)return logger.error("Request body too large",{size:bodyText.length,limit:settings.maxRequestSize}),createJsonResponse({success:!1,error:`Request too large. Maximum size: ${settings.maxRequestSize} bytes`},413,corsHeaders);eventData=JSON.parse(bodyText)}catch{eventData={},rawBody=!0}if(isDefined(eventData)&&isObject(eventData)||(eventData={},rawBody=!0),rawBody){const result2=await processEvent(eventData,env.push);return result2.error?(logger.error("Event processing failed",{error:result2.error}),createJsonResponse({success:!1,error:result2.error},400,corsHeaders)):createJsonResponse({success:!0,id:result2.id,timestamp:Date.now()},200,corsHeaders)}const validData=eventData;if("batch"in validData&&Array.isArray(validData.batch)){const batch2=validData.batch;if(batch2.length>settings.maxBatchSize)return logger.error("Batch too large",{size:batch2.length,limit:settings.maxBatchSize}),createJsonResponse({success:!1,error:`Batch too large. Maximum size: ${settings.maxBatchSize} events`},400,corsHeaders);const results=await async function(events,push,logger){const results={successful:0,failed:0,ids:[],errors:[]};for(let i=0;i<events.length;i++){const event=events[i];try{const result=await push(event);result?.event?.id&&results.ids.push(result.event.id),results.successful++}catch(error){results.failed++,results.errors.push({index:i,error:error instanceof Error?error.message:"Unknown error"}),logger.error(`Batch event ${i} processing failed`,error)}}return results}(batch2,env.push,logger);return results.failed>0?createJsonResponse({success:!1,processed:results.successful,failed:results.failed,errors:results.errors},207,corsHeaders):createJsonResponse({success:!0,processed:results.successful,ids:results.ids},200,corsHeaders)}const result=await processEvent(eventData,env.push);return result.error?(logger.error("Event processing failed",{error:result.error}),createJsonResponse({success:!1,error:result.error},400,corsHeaders)):createJsonResponse({success:!0,id:result.id,timestamp:Date.now()},200,corsHeaders)}return createJsonResponse({success:!1,error:"Method not allowed"},405,corsHeaders)}catch(error){logger.error("Internal server error",error);const corsHeaders=createCorsHeaders(settings.cors);return createJsonResponse({success:!1,error:error instanceof Error?error.message:"Internal server error"},500,corsHeaders)}}}};async function processEvent(event,push){try{const result=await push(event);return{id:result?.event?.id}}catch(error){return{error:error instanceof Error?error.message:"Unknown error"}}}var index_default=sourceFetch;export{types_exports as SourceFetch,TRANSPARENT_GIF_BASE64,createCorsHeaders,createJsonResponse,createPixelResponse,index_default as default,examples_exports as examples,matchPath,sourceFetch};//# sourceMappingURL=index.mjs.map
1
+ var __defProp=Object.defineProperty,__export=(target,all)=>{for(var name in all)__defProp(target,name,{get:all[name],enumerable:!0})};import{requestToData,isObject,isDefined}from"@walkeros/core";function createCorsHeaders(corsConfig=!0,requestOrigin){const headers=new Headers;if(!1===corsConfig)return headers;if(!0===corsConfig)headers.set("Access-Control-Allow-Origin","*"),headers.set("Access-Control-Allow-Methods","GET, POST, OPTIONS"),headers.set("Access-Control-Allow-Headers","Content-Type");else{if(corsConfig.origin){let origin;origin=Array.isArray(corsConfig.origin)?requestOrigin&&corsConfig.origin.includes(requestOrigin)?requestOrigin:corsConfig.origin[0]:corsConfig.origin,headers.set("Access-Control-Allow-Origin",origin)}corsConfig.methods&&headers.set("Access-Control-Allow-Methods",corsConfig.methods.join(", ")),corsConfig.headers&&headers.set("Access-Control-Allow-Headers",corsConfig.headers.join(", ")),corsConfig.credentials&&headers.set("Access-Control-Allow-Credentials","true"),corsConfig.maxAge&&headers.set("Access-Control-Max-Age",String(corsConfig.maxAge))}return headers}var TRANSPARENT_GIF_BASE64="R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7";function createPixelResponse(corsHeaders){const binaryString=atob("R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"),bytes=new Uint8Array(binaryString.length);for(let i=0;i<binaryString.length;i++)bytes[i]=binaryString.charCodeAt(i);const headers=new Headers(corsHeaders);return headers.set("Content-Type","image/gif"),headers.set("Cache-Control","no-cache, no-store, must-revalidate"),new Response(bytes,{status:200,headers:headers})}function createJsonResponse(body,status=200,corsHeaders){const headers=new Headers(corsHeaders);return headers.set("Content-Type","application/json"),new Response(JSON.stringify(body),{status:status,headers:headers})}function matchPath(requestPath,pattern){if(pattern.endsWith("/*")){const prefix=pattern.slice(0,-2);return requestPath===prefix||requestPath.startsWith(prefix+"/")}return requestPath===pattern}var types_exports={},examples_exports={};__export(examples_exports,{createTrigger:()=>createTrigger,inputs:()=>inputs_exports,requests:()=>requests_exports,step:()=>step_exports});var inputs_exports={};__export(inputs_exports,{batch:()=>batch,completeEvent:()=>completeEvent,minimal:()=>minimal,pageView:()=>pageView,productAdd:()=>productAdd});var pageView={name:"page view",data:{title:"Home Page",path:"/",referrer:"https://google.com"},user:{id:"user-123",session:"session-456"},timestamp:17e11},productAdd={name:"product add",data:{id:"P-123",name:"Laptop",price:999.99,quantity:1},context:{stage:["shopping",1]},globals:{language:"en",currency:"USD"},user:{id:"user-123"},nested:[{entity:"category",data:{name:"Electronics",path:"/electronics"}}],consent:{functional:!0,marketing:!0}},completeEvent={name:"order complete",data:{id:"ORDER-123",total:999.99,currency:"USD"},context:{stage:["checkout",3],test:["variant-A",0]},globals:{language:"en",country:"US"},custom:{campaignId:"summer-sale",source:"email"},user:{id:"user-123",email:"user@example.com",session:"session-456"},nested:[{entity:"product",data:{id:"P-123",price:999.99}}],consent:{functional:!0,marketing:!0,analytics:!1},trigger:"click"},minimal={name:"ping"},batch=[pageView,productAdd,{name:"button click",data:{id:"cta"}}],requests_exports={};__export(requests_exports,{batchPostRequest:()=>batchPostRequest,healthCheckRequest:()=>healthCheckRequest,invalidJsonRequest:()=>invalidJsonRequest,optionsRequest:()=>optionsRequest,oversizedRequest:()=>oversizedRequest,pixelGetRequest:()=>pixelGetRequest,validPostRequest:()=>validPostRequest});var validPostRequest={method:"POST",url:"https://example.com/collect",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:"page view",data:{title:"Home"}})},batchPostRequest={method:"POST",url:"https://example.com/collect",headers:{"Content-Type":"application/json"},body:JSON.stringify({batch:[{name:"page view",data:{title:"Home"}},{name:"button click",data:{id:"cta"}}]})},pixelGetRequest={method:"GET",url:"https://example.com/collect?event=page%20view&data[title]=Home&user[id]=user123"},healthCheckRequest={method:"GET",url:"https://example.com/health"},optionsRequest={method:"OPTIONS",url:"https://example.com/collect",headers:{Origin:"https://example.com"}},invalidJsonRequest={method:"POST",url:"https://example.com/collect",headers:{"Content-Type":"application/json"},body:"invalid json{"},oversizedRequest={method:"POST",url:"https://example.com/collect",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:"test",data:{payload:"x".repeat(2e5)}})},step_exports={};__export(step_exports,{batchRequest:()=>batchRequest,pixelGet:()=>pixelGet,postEvent:()=>postEvent});var postEvent={title:"POST event",description:"A fetch POST request with a JSON body becomes a single walker elb event in a fetch-based server.",trigger:{type:"POST"},in:{method:"POST",url:"http://localhost/collect",body:{name:"page view",data:{title:"Docs",url:"https://example.com/docs"}}},out:[["elb",{name:"page view",data:{title:"Docs",url:"https://example.com/docs"}}]]},batchRequest={title:"Batch POST",description:"A fetch POST with a batch array produces one walker elb event per batched item preserving order.",trigger:{type:"POST"},in:{method:"POST",url:"http://localhost/collect",body:{batch:[{name:"page view",data:{title:"Home"}},{name:"button click",data:{id:"cta"}}]}},out:[["elb",{name:"page view",data:{title:"Home"}}],["elb",{name:"button click",data:{id:"cta"}}]]},pixelGet={title:"Pixel GET",description:"A fetch GET with query parameters in the URL is parsed into an elb event payload for pixel-style tracking.",trigger:{type:"GET"},in:{method:"GET",url:"http://localhost/collect?e=page+view&d=%7B%22title%22%3A%22Home%22%7D"},out:[["elb",{e:"page view",d:'{"title":"Home"}'}]]};import{startFlow}from"@walkeros/collector";var createTrigger=async config=>{let flow;return{get flow(){return flow},trigger:()=>async content=>{if(!flow){const result=await startFlow(config);flow={collector:result.collector,elb:result.elb}}const source=function(collector){for(const source of Object.values(collector.sources||{}))if("fetch"===source.type)return source}(flow.collector);if(!source)throw new Error("Fetch source not found in collector");const init={method:content.method,headers:{"Content-Type":"application/json",...content.headers}};"GET"!==content.method&&void 0!==content.body&&(init.body=JSON.stringify(content.body));const request=new Request(content.url,init),response=await source.push(request),responseHeaders={};response.headers.forEach((v,k)=>{responseHeaders[k]=v});const body=(response.headers.get("content-type")||"").includes("json")?await response.json():await response.text();return{status:response.status,body:body,headers:responseHeaders}}}},sourceFetch=async context=>{const{config:config={},env:env}=context,userSettings=config.settings||{},settings={...userSettings,cors:userSettings.cors??!0,maxRequestSize:userSettings.maxRequestSize??102400,maxBatchSize:userSettings.maxBatchSize??100,paths:userSettings.paths??(userSettings.path?[userSettings.path]:["/collect"])},{logger:logger}=env;return{type:"fetch",config:{...config,settings:settings},push:async request=>{Date.now();try{const url=new URL(request.url),method=request.method.toUpperCase(),origin=request.headers.get("Origin"),corsHeaders=createCorsHeaders(settings.cors,origin),matchedRoute=settings.paths.map(entry=>"string"==typeof entry?{path:entry,methods:["GET","POST"]}:{path:entry.path,methods:entry.methods||["GET","POST"]}).find(route=>matchPath(url.pathname,route.path));return matchedRoute?"OPTIONS"===method?new Response(null,{status:204,headers:corsHeaders}):matchedRoute.methods.includes(method)?await context.withScope(request,void 0,async scopeEnv=>{const envPush=scopeEnv.push;if("GET"===method){const parsedData=requestToData(url.search);return parsedData&&isObject(parsedData)&&await envPush(parsedData),createPixelResponse(corsHeaders)}if("POST"===method){const contentLength=request.headers.get("Content-Length");if(contentLength){const size=parseInt(contentLength,10);if(size>settings.maxRequestSize)return logger.error("Request too large",{size:size,limit:settings.maxRequestSize}),createJsonResponse({success:!1,error:`Request too large. Maximum size: ${settings.maxRequestSize} bytes`},413,corsHeaders)}let eventData,bodyText,rawBody=!1;try{if(bodyText=await request.text(),bodyText.length>settings.maxRequestSize)return logger.error("Request body too large",{size:bodyText.length,limit:settings.maxRequestSize}),createJsonResponse({success:!1,error:`Request too large. Maximum size: ${settings.maxRequestSize} bytes`},413,corsHeaders);eventData=JSON.parse(bodyText)}catch{eventData={},rawBody=!0}if(isDefined(eventData)&&isObject(eventData)||(eventData={},rawBody=!0),rawBody){const result2=await processEvent(eventData,envPush);return result2.error?(logger.error("Event processing failed",{error:result2.error}),createJsonResponse({success:!1,error:result2.error},400,corsHeaders)):createJsonResponse({success:!0,id:result2.id,timestamp:Date.now()},200,corsHeaders)}const validData=eventData;if("batch"in validData&&Array.isArray(validData.batch)){const batch2=validData.batch;if(batch2.length>settings.maxBatchSize)return logger.error("Batch too large",{size:batch2.length,limit:settings.maxBatchSize}),createJsonResponse({success:!1,error:`Batch too large. Maximum size: ${settings.maxBatchSize} events`},400,corsHeaders);const results=await async function(events,push,logger){const results={successful:0,failed:0,ids:[],errors:[]};for(let i=0;i<events.length;i++){const event=events[i];try{const result=await push(event);result?.event?.id&&results.ids.push(result.event.id),results.successful++}catch(error){results.failed++,results.errors.push({index:i,error:error instanceof Error?error.message:"Unknown error"}),logger.error(`Batch event ${i} processing failed`,error)}}return results}(batch2,envPush,logger);return results.failed>0?createJsonResponse({success:!1,processed:results.successful,failed:results.failed,errors:results.errors},207,corsHeaders):createJsonResponse({success:!0,processed:results.successful,ids:results.ids},200,corsHeaders)}const result=await processEvent(eventData,envPush);return result.error?(logger.error("Event processing failed",{error:result.error}),createJsonResponse({success:!1,error:result.error},400,corsHeaders)):createJsonResponse({success:!0,id:result.id,timestamp:Date.now()},200,corsHeaders)}return createJsonResponse({success:!1,error:"Method not allowed"},405,corsHeaders)}):createJsonResponse({success:!1,error:"Method not allowed"},405,corsHeaders):createJsonResponse({success:!1,error:"Not found"},404,corsHeaders)}catch(error){logger.error("Internal server error",error);const corsHeaders=createCorsHeaders(settings.cors);return createJsonResponse({success:!1,error:error instanceof Error?error.message:"Internal server error"},500,corsHeaders)}}}};async function processEvent(event,push){try{const result=await push(event);return{id:result?.event?.id}}catch(error){return{error:error instanceof Error?error.message:"Unknown error"}}}var index_default=sourceFetch;export{types_exports as SourceFetch,TRANSPARENT_GIF_BASE64,createCorsHeaders,createJsonResponse,createPixelResponse,index_default as default,examples_exports as examples,matchPath,sourceFetch};//# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/utils.ts","../src/types.ts","../src/examples/index.ts","../src/examples/inputs.ts","../src/examples/requests.ts","../src/examples/step.ts","../src/examples/trigger.ts"],"sourcesContent":["import { requestToData, isObject, isDefined } from '@walkeros/core';\nimport type { WalkerOS, Collector, Source } from '@walkeros/core';\nimport type { FetchSource, Types } from './types';\nimport {\n createCorsHeaders,\n createPixelResponse,\n createJsonResponse,\n matchPath,\n} from './utils';\n\nexport const sourceFetch: Source.Init<Types> = async (context) => {\n const { config = {}, env, setIngest } = context;\n const userSettings = config.settings || {};\n const settings = {\n ...userSettings,\n cors: userSettings.cors ?? true,\n maxRequestSize: userSettings.maxRequestSize ?? 102400,\n maxBatchSize: userSettings.maxBatchSize ?? 100,\n paths:\n userSettings.paths ??\n (userSettings.path ? [userSettings.path] : ['/collect']),\n };\n const { logger } = env;\n\n const push = async (request: Request): Promise<Response> => {\n const startTime = Date.now();\n\n try {\n const url = new URL(request.url);\n const method = request.method.toUpperCase();\n const origin = request.headers.get('Origin');\n const corsHeaders = createCorsHeaders(settings.cors, origin);\n\n // Resolve route configs\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 // Match request path against configured routes\n const matchedRoute = resolvedPaths.find((route) =>\n matchPath(url.pathname, route.path),\n );\n\n if (!matchedRoute) {\n return createJsonResponse(\n { success: false, error: 'Not found' },\n 404,\n corsHeaders,\n );\n }\n\n // OPTIONS (CORS preflight - no logging, routine)\n if (method === 'OPTIONS') {\n return new Response(null, { status: 204, headers: corsHeaders });\n }\n\n // Check method is allowed for this route\n if (!matchedRoute.methods.includes(method as 'GET' | 'POST')) {\n return createJsonResponse(\n { success: false, error: 'Method not allowed' },\n 405,\n corsHeaders,\n );\n }\n\n // Extract ingest metadata from request (if config.ingest is defined)\n await setIngest(request);\n\n // GET (pixel tracking - no logging, routine)\n if (method === 'GET') {\n const parsedData = requestToData(url.search);\n if (parsedData && isObject(parsedData)) {\n await env.push(parsedData);\n }\n return createPixelResponse(corsHeaders);\n }\n\n // POST\n if (method === 'POST') {\n // Check request size\n const contentLength = request.headers.get('Content-Length');\n if (contentLength) {\n const size = parseInt(contentLength, 10);\n if (size > settings.maxRequestSize) {\n logger.error('Request too large', {\n size,\n limit: settings.maxRequestSize,\n });\n return createJsonResponse(\n {\n success: false,\n error: `Request too large. Maximum size: ${settings.maxRequestSize} bytes`,\n },\n 413,\n corsHeaders,\n );\n }\n }\n\n let eventData: unknown;\n let bodyText: string;\n let rawBody = false;\n\n try {\n bodyText = await request.text();\n\n // Check actual body size\n if (bodyText.length > settings.maxRequestSize) {\n logger.error('Request body too large', {\n size: bodyText.length,\n limit: settings.maxRequestSize,\n });\n return createJsonResponse(\n {\n success: false,\n error: `Request too large. Maximum size: ${settings.maxRequestSize} bytes`,\n },\n 413,\n corsHeaders,\n );\n }\n\n eventData = JSON.parse(bodyText);\n } catch {\n // Non-JSON body: push empty event for source.before transformers\n eventData = {};\n rawBody = true;\n }\n\n if (!isDefined(eventData) || !isObject(eventData)) {\n // Non-object body: push empty event for source.before transformers\n eventData = {};\n rawBody = true;\n }\n\n // Raw body: push empty event directly, skip validation\n if (rawBody) {\n const result = await processEvent(\n eventData as WalkerOS.DeepPartialEvent,\n env.push,\n );\n if (result.error) {\n logger.error('Event processing failed', { error: result.error });\n return createJsonResponse(\n { success: false, error: result.error },\n 400,\n corsHeaders,\n );\n }\n\n return createJsonResponse(\n { success: true, id: result.id, timestamp: Date.now() },\n 200,\n corsHeaders,\n );\n }\n\n // Check for batch (eventData is a validated object at this point)\n const validData = eventData as Record<string, unknown>;\n const isBatch = 'batch' in validData && Array.isArray(validData.batch);\n\n if (isBatch) {\n const batch = validData.batch as unknown[];\n\n if (batch.length > settings.maxBatchSize) {\n logger.error('Batch too large', {\n size: batch.length,\n limit: settings.maxBatchSize,\n });\n return createJsonResponse(\n {\n success: false,\n error: `Batch too large. Maximum size: ${settings.maxBatchSize} events`,\n },\n 400,\n corsHeaders,\n );\n }\n\n const results = await processBatch(batch, env.push, logger);\n\n if (results.failed > 0) {\n return createJsonResponse(\n {\n success: false,\n processed: results.successful,\n failed: results.failed,\n errors: results.errors,\n },\n 207,\n corsHeaders,\n );\n }\n\n return createJsonResponse(\n {\n success: true,\n processed: results.successful,\n ids: results.ids,\n },\n 200,\n corsHeaders,\n );\n }\n\n // Forward event directly — validation is not the source's responsibility.\n const result = await processEvent(\n eventData as WalkerOS.DeepPartialEvent,\n env.push,\n );\n if (result.error) {\n logger.error('Event processing failed', { error: result.error });\n return createJsonResponse(\n { success: false, error: result.error },\n 400,\n corsHeaders,\n );\n }\n\n return createJsonResponse(\n { success: true, id: result.id, timestamp: Date.now() },\n 200,\n corsHeaders,\n );\n }\n\n return createJsonResponse(\n { success: false, error: 'Method not allowed' },\n 405,\n corsHeaders,\n );\n } catch (error) {\n logger.error('Internal server error', error);\n const corsHeaders = createCorsHeaders(settings.cors);\n return createJsonResponse(\n {\n success: false,\n error:\n error instanceof Error ? error.message : 'Internal server error',\n },\n 500,\n corsHeaders,\n );\n }\n };\n\n return { type: 'fetch', config: { ...config, settings }, push };\n};\n\nasync function processEvent(\n event: WalkerOS.DeepPartialEvent,\n push: Collector.PushFn,\n): Promise<{ id?: string; error?: string }> {\n try {\n const result = await push(event);\n return { id: result?.event?.id };\n } catch (error) {\n return { error: error instanceof Error ? error.message : 'Unknown error' };\n }\n}\n\nasync function processBatch(\n events: unknown[],\n push: Collector.PushFn,\n logger: Types['env']['logger'],\n): Promise<{\n successful: number;\n failed: number;\n ids: string[];\n errors: Array<{ index: number; error: string }>;\n}> {\n const results = {\n successful: 0,\n failed: 0,\n ids: [] as string[],\n errors: [] as Array<{ index: number; error: string }>,\n };\n\n for (let i = 0; i < events.length; i++) {\n const event = events[i];\n\n try {\n const result = await push(event as WalkerOS.DeepPartialEvent);\n if (result?.event?.id) {\n results.ids.push(result.event.id);\n }\n results.successful++;\n } catch (error) {\n results.failed++;\n results.errors.push({\n index: i,\n error: error instanceof Error ? error.message : 'Unknown error',\n });\n logger.error(`Batch event ${i} processing failed`, error);\n }\n }\n\n return results;\n}\n\nexport type * from './types';\nexport * as SourceFetch from './types';\nexport * from './utils';\nexport * as examples from './examples';\n\nexport default sourceFetch;\n","import type { CorsOptions } from './schemas';\n\nexport function createCorsHeaders(\n corsConfig: boolean | CorsOptions = true,\n requestOrigin?: string | null,\n): Headers {\n const headers = new Headers();\n\n if (corsConfig === false) return headers;\n\n if (corsConfig === true) {\n headers.set('Access-Control-Allow-Origin', '*');\n headers.set('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');\n headers.set('Access-Control-Allow-Headers', 'Content-Type');\n } else {\n if (corsConfig.origin) {\n let origin: string;\n if (Array.isArray(corsConfig.origin)) {\n origin =\n requestOrigin && corsConfig.origin.includes(requestOrigin)\n ? requestOrigin\n : corsConfig.origin[0];\n } else {\n origin = corsConfig.origin;\n }\n headers.set('Access-Control-Allow-Origin', origin);\n }\n\n if (corsConfig.methods) {\n headers.set(\n 'Access-Control-Allow-Methods',\n corsConfig.methods.join(', '),\n );\n }\n\n if (corsConfig.headers) {\n headers.set(\n 'Access-Control-Allow-Headers',\n corsConfig.headers.join(', '),\n );\n }\n\n if (corsConfig.credentials) {\n headers.set('Access-Control-Allow-Credentials', 'true');\n }\n\n if (corsConfig.maxAge) {\n headers.set('Access-Control-Max-Age', String(corsConfig.maxAge));\n }\n }\n\n return headers;\n}\n\nexport const TRANSPARENT_GIF_BASE64 =\n 'R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';\n\nexport function createPixelResponse(corsHeaders?: Headers): Response {\n const binaryString = atob(TRANSPARENT_GIF_BASE64);\n const bytes = new Uint8Array(binaryString.length);\n for (let i = 0; i < binaryString.length; i++) {\n bytes[i] = binaryString.charCodeAt(i);\n }\n\n const headers = new Headers(corsHeaders);\n headers.set('Content-Type', 'image/gif');\n headers.set('Cache-Control', 'no-cache, no-store, must-revalidate');\n\n return new Response(bytes, { status: 200, headers });\n}\n\nexport function createJsonResponse(\n body: unknown,\n status = 200,\n corsHeaders?: Headers,\n): Response {\n const headers = new Headers(corsHeaders);\n headers.set('Content-Type', 'application/json');\n\n return new Response(JSON.stringify(body), { status, headers });\n}\n\n/**\n * Match a request pathname against a route pattern.\n * Supports exact matches and wildcard patterns (e.g., /api/*).\n */\nexport function matchPath(requestPath: string, pattern: string): boolean {\n if (pattern.endsWith('/*')) {\n const prefix = pattern.slice(0, -2);\n return requestPath === prefix || requestPath.startsWith(prefix + '/');\n }\n return requestPath === pattern;\n}\n","import type { WalkerOS, Source as CoreSource } from '@walkeros/core';\nimport type {\n SettingsSchema,\n CorsOptionsSchema,\n RouteConfigSchema,\n} from './schemas';\nimport type { z } from '@walkeros/core/dev';\n\ndeclare module '@walkeros/core' {\n interface SourceMap {\n fetch: { type: 'fetch'; platform: 'server' };\n }\n}\n\nexport type Settings = z.infer<typeof SettingsSchema>;\nexport type CorsOptions = z.infer<typeof CorsOptionsSchema>;\nexport type RouteConfig = z.infer<typeof RouteConfigSchema>;\nexport type RouteMethod = 'GET' | 'POST';\nexport type InitSettings = Partial<Settings>;\n\nexport interface Mapping {}\n\nexport type Push = (request: Request) => Response | Promise<Response>;\n\nexport interface Env extends CoreSource.Env {\n request?: Request;\n}\n\nexport type Types = CoreSource.Types<\n Settings,\n Mapping,\n Push,\n Env,\n InitSettings\n>;\nexport type Config = CoreSource.Config<Types>;\nexport type PartialConfig = CoreSource.PartialConfig<Types>;\n\nexport interface FetchSource extends Omit<CoreSource.Instance<Types>, 'push'> {\n push: Push;\n}\n\nexport interface EventResponse {\n success: boolean;\n id?: string;\n timestamp?: number;\n error?: string;\n}\n","export * as inputs from './inputs';\nexport * as requests from './requests';\nexport * as step from './step';\nexport { createTrigger } from './trigger';\n","import type { WalkerOS } from '@walkeros/core';\n\n/**\n * Example walkerOS events that HTTP clients send to this source.\n * These are the CONTRACT - tests verify implementation handles these inputs.\n */\n\n// Simple page view event\nexport const pageView: WalkerOS.DeepPartialEvent = {\n name: 'page view',\n data: {\n title: 'Home Page',\n path: '/',\n referrer: 'https://google.com',\n },\n user: {\n id: 'user-123',\n session: 'session-456',\n },\n timestamp: 1700000000000,\n};\n\n// E-commerce event with nested entities\nexport const productAdd: WalkerOS.DeepPartialEvent = {\n name: 'product add',\n data: {\n id: 'P-123',\n name: 'Laptop',\n price: 999.99,\n quantity: 1,\n },\n context: {\n stage: ['shopping', 1],\n },\n globals: {\n language: 'en',\n currency: 'USD',\n },\n user: {\n id: 'user-123',\n },\n nested: [\n {\n entity: 'category',\n data: {\n name: 'Electronics',\n path: '/electronics',\n },\n },\n ],\n consent: {\n functional: true,\n marketing: true,\n },\n};\n\n// Complete event with all optional fields\nexport const completeEvent: WalkerOS.DeepPartialEvent = {\n name: 'order complete',\n data: {\n id: 'ORDER-123',\n total: 999.99,\n currency: 'USD',\n },\n context: {\n stage: ['checkout', 3],\n test: ['variant-A', 0],\n },\n globals: {\n language: 'en',\n country: 'US',\n },\n custom: {\n campaignId: 'summer-sale',\n source: 'email',\n },\n user: {\n id: 'user-123',\n email: 'user@example.com',\n session: 'session-456',\n },\n nested: [\n {\n entity: 'product',\n data: {\n id: 'P-123',\n price: 999.99,\n },\n },\n ],\n consent: {\n functional: true,\n marketing: true,\n analytics: false,\n },\n trigger: 'click',\n};\n\n// Minimal valid event\nexport const minimal: WalkerOS.DeepPartialEvent = {\n name: 'ping',\n};\n\n// Batch of events\nexport const batch: WalkerOS.DeepPartialEvent[] = [\n pageView,\n productAdd,\n { name: 'button click', data: { id: 'cta' } },\n];\n","/**\n * HTTP request examples for testing the fetch source.\n * Shows what external HTTP clients will send.\n */\n\nexport const validPostRequest = {\n method: 'POST',\n url: 'https://example.com/collect',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n name: 'page view',\n data: { title: 'Home' },\n }),\n};\n\nexport const batchPostRequest = {\n method: 'POST',\n url: 'https://example.com/collect',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n batch: [\n { name: 'page view', data: { title: 'Home' } },\n { name: 'button click', data: { id: 'cta' } },\n ],\n }),\n};\n\nexport const pixelGetRequest = {\n method: 'GET',\n url: 'https://example.com/collect?event=page%20view&data[title]=Home&user[id]=user123',\n};\n\nexport const healthCheckRequest = {\n method: 'GET',\n url: 'https://example.com/health',\n};\n\nexport const optionsRequest = {\n method: 'OPTIONS',\n url: 'https://example.com/collect',\n headers: { Origin: 'https://example.com' },\n};\n\nexport const invalidJsonRequest = {\n method: 'POST',\n url: 'https://example.com/collect',\n headers: { 'Content-Type': 'application/json' },\n body: 'invalid json{',\n};\n\nexport const oversizedRequest = {\n method: 'POST',\n url: 'https://example.com/collect',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n name: 'test',\n data: { payload: 'x'.repeat(200000) }, // 200KB\n }),\n};\n","import type { Flow } from '@walkeros/core';\n\nexport const postEvent: Flow.StepExample = {\n title: 'POST event',\n description:\n 'A fetch POST request with a JSON body becomes a single walker elb event in a fetch-based server.',\n trigger: { type: 'POST' },\n in: {\n method: 'POST',\n url: 'http://localhost/collect',\n body: {\n name: 'page view',\n data: { title: 'Docs', url: 'https://example.com/docs' },\n },\n },\n out: [\n [\n 'elb',\n {\n name: 'page view',\n data: { title: 'Docs', url: 'https://example.com/docs' },\n },\n ],\n ],\n};\n\nexport const batchRequest: Flow.StepExample = {\n title: 'Batch POST',\n description:\n 'A fetch POST with a batch array produces one walker elb event per batched item preserving order.',\n trigger: { type: 'POST' },\n in: {\n method: 'POST',\n url: 'http://localhost/collect',\n body: {\n batch: [\n { name: 'page view', data: { title: 'Home' } },\n { name: 'button click', data: { id: 'cta' } },\n ],\n },\n },\n out: [\n ['elb', { name: 'page view', data: { title: 'Home' } }],\n ['elb', { name: 'button click', data: { id: 'cta' } }],\n ],\n};\n\nexport const pixelGet: Flow.StepExample = {\n title: 'Pixel GET',\n description:\n 'A fetch GET with query parameters in the URL is parsed into an elb event payload for pixel-style tracking.',\n trigger: { type: 'GET' },\n in: {\n method: 'GET',\n url: 'http://localhost/collect?e=page+view&d=%7B%22title%22%3A%22Home%22%7D',\n },\n out: [\n [\n 'elb',\n {\n e: 'page view',\n d: '{\"title\":\"Home\"}',\n },\n ],\n ],\n};\n","import type { Trigger, Collector } from '@walkeros/core';\nimport { startFlow } from '@walkeros/collector';\n\nexport interface Content {\n method: string;\n url: string;\n body?: unknown;\n headers?: Record<string, string>;\n}\n\nexport interface Result {\n status: number;\n body: unknown;\n headers: Record<string, string>;\n}\n\nfunction findFetchSource(collector: Collector.Instance) {\n for (const source of Object.values(collector.sources || {})) {\n if ((source as { type?: string }).type === 'fetch') return source;\n }\n}\n\nconst createTrigger: Trigger.CreateFn<Content, Result> = async (\n config: Collector.InitConfig,\n) => {\n let flow: Trigger.FlowHandle | undefined;\n\n const trigger: Trigger.Fn<Content, Result> =\n () =>\n async (content: Content): Promise<Result> => {\n if (!flow) {\n const result = await startFlow(config);\n flow = { collector: result.collector, elb: result.elb };\n }\n\n const source = findFetchSource(flow.collector);\n if (!source) throw new Error('Fetch source not found in collector');\n\n // Construct real Request from content\n const init: RequestInit = {\n method: content.method,\n headers: { 'Content-Type': 'application/json', ...content.headers },\n };\n if (content.method !== 'GET' && content.body !== undefined) {\n init.body = JSON.stringify(content.body);\n }\n const request = new Request(content.url, init);\n\n // Call source.push with the real Request\n const response = await (\n source as unknown as { push: (r: Request) => Promise<Response> }\n ).push(request);\n\n // Convert Response to serializable result\n const responseHeaders: Record<string, string> = {};\n response.headers.forEach((v, k) => {\n responseHeaders[k] = v;\n });\n\n const ct = response.headers.get('content-type') || '';\n const body = ct.includes('json')\n ? await response.json()\n : await response.text();\n\n return { status: response.status, body, headers: responseHeaders };\n };\n\n return {\n get flow() {\n return flow;\n },\n trigger,\n };\n};\n\nexport { createTrigger };\n"],"mappings":"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","names":["result","batch"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/utils.ts","../src/types.ts","../src/examples/index.ts","../src/examples/inputs.ts","../src/examples/requests.ts","../src/examples/step.ts","../src/examples/trigger.ts"],"sourcesContent":["import { requestToData, isObject, isDefined } from '@walkeros/core';\nimport type { WalkerOS, Collector, Source } from '@walkeros/core';\nimport type { FetchSource, Types } from './types';\nimport {\n createCorsHeaders,\n createPixelResponse,\n createJsonResponse,\n matchPath,\n} from './utils';\n\nexport const sourceFetch: Source.Init<Types> = async (context) => {\n const { config = {}, env } = context;\n const userSettings = config.settings || {};\n const settings = {\n ...userSettings,\n cors: userSettings.cors ?? true,\n maxRequestSize: userSettings.maxRequestSize ?? 102400,\n maxBatchSize: userSettings.maxBatchSize ?? 100,\n paths:\n userSettings.paths ??\n (userSettings.path ? [userSettings.path] : ['/collect']),\n };\n const { logger } = env;\n\n const push = async (request: Request): Promise<Response> => {\n const startTime = Date.now();\n void startTime;\n\n try {\n const url = new URL(request.url);\n const method = request.method.toUpperCase();\n const origin = request.headers.get('Origin');\n const corsHeaders = createCorsHeaders(settings.cors, origin);\n\n // Resolve route configs\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 // Match request path against configured routes\n const matchedRoute = resolvedPaths.find((route) =>\n matchPath(url.pathname, route.path),\n );\n\n if (!matchedRoute) {\n return createJsonResponse(\n { success: false, error: 'Not found' },\n 404,\n corsHeaders,\n );\n }\n\n // OPTIONS (CORS preflight - no logging, routine)\n if (method === 'OPTIONS') {\n return new Response(null, { status: 204, headers: corsHeaders });\n }\n\n // Check method is allowed for this route\n if (!matchedRoute.methods.includes(method as 'GET' | 'POST')) {\n return createJsonResponse(\n { success: false, error: 'Method not allowed' },\n 405,\n corsHeaders,\n );\n }\n\n // Per-request scope: each fetch invocation gets its own ingest.\n // Fetch sources return a Response directly, not via async respond.\n return await context.withScope(request, undefined, async (scopeEnv) => {\n const envPush = scopeEnv.push;\n\n // GET (pixel tracking - no logging, routine)\n if (method === 'GET') {\n const parsedData = requestToData(url.search);\n if (parsedData && isObject(parsedData)) {\n await envPush(parsedData);\n }\n return createPixelResponse(corsHeaders);\n }\n\n // POST\n if (method === 'POST') {\n // Check request size\n const contentLength = request.headers.get('Content-Length');\n if (contentLength) {\n const size = parseInt(contentLength, 10);\n if (size > settings.maxRequestSize) {\n logger.error('Request too large', {\n size,\n limit: settings.maxRequestSize,\n });\n return createJsonResponse(\n {\n success: false,\n error: `Request too large. Maximum size: ${settings.maxRequestSize} bytes`,\n },\n 413,\n corsHeaders,\n );\n }\n }\n\n let eventData: unknown;\n let bodyText: string;\n let rawBody = false;\n\n try {\n bodyText = await request.text();\n\n // Check actual body size\n if (bodyText.length > settings.maxRequestSize) {\n logger.error('Request body too large', {\n size: bodyText.length,\n limit: settings.maxRequestSize,\n });\n return createJsonResponse(\n {\n success: false,\n error: `Request too large. Maximum size: ${settings.maxRequestSize} bytes`,\n },\n 413,\n corsHeaders,\n );\n }\n\n eventData = JSON.parse(bodyText);\n } catch {\n // Non-JSON body: push empty event for source.before transformers\n eventData = {};\n rawBody = true;\n }\n\n if (!isDefined(eventData) || !isObject(eventData)) {\n // Non-object body: push empty event for source.before transformers\n eventData = {};\n rawBody = true;\n }\n\n // Raw body: push empty event directly, skip validation\n if (rawBody) {\n const result = await processEvent(\n eventData as WalkerOS.DeepPartialEvent,\n envPush,\n );\n if (result.error) {\n logger.error('Event processing failed', { error: result.error });\n return createJsonResponse(\n { success: false, error: result.error },\n 400,\n corsHeaders,\n );\n }\n\n return createJsonResponse(\n { success: true, id: result.id, timestamp: Date.now() },\n 200,\n corsHeaders,\n );\n }\n\n // Check for batch (eventData is a validated object at this point)\n const validData = eventData as Record<string, unknown>;\n const isBatch =\n 'batch' in validData && Array.isArray(validData.batch);\n\n if (isBatch) {\n const batch = validData.batch as unknown[];\n\n if (batch.length > settings.maxBatchSize) {\n logger.error('Batch too large', {\n size: batch.length,\n limit: settings.maxBatchSize,\n });\n return createJsonResponse(\n {\n success: false,\n error: `Batch too large. Maximum size: ${settings.maxBatchSize} events`,\n },\n 400,\n corsHeaders,\n );\n }\n\n const results = await processBatch(batch, envPush, logger);\n\n if (results.failed > 0) {\n return createJsonResponse(\n {\n success: false,\n processed: results.successful,\n failed: results.failed,\n errors: results.errors,\n },\n 207,\n corsHeaders,\n );\n }\n\n return createJsonResponse(\n {\n success: true,\n processed: results.successful,\n ids: results.ids,\n },\n 200,\n corsHeaders,\n );\n }\n\n // Forward event directly — validation is not the source's responsibility.\n const result = await processEvent(\n eventData as WalkerOS.DeepPartialEvent,\n envPush,\n );\n if (result.error) {\n logger.error('Event processing failed', { error: result.error });\n return createJsonResponse(\n { success: false, error: result.error },\n 400,\n corsHeaders,\n );\n }\n\n return createJsonResponse(\n { success: true, id: result.id, timestamp: Date.now() },\n 200,\n corsHeaders,\n );\n }\n\n return createJsonResponse(\n { success: false, error: 'Method not allowed' },\n 405,\n corsHeaders,\n );\n });\n } catch (error) {\n logger.error('Internal server error', error);\n const corsHeaders = createCorsHeaders(settings.cors);\n return createJsonResponse(\n {\n success: false,\n error:\n error instanceof Error ? error.message : 'Internal server error',\n },\n 500,\n corsHeaders,\n );\n }\n };\n\n return { type: 'fetch', config: { ...config, settings }, push };\n};\n\nasync function processEvent(\n event: WalkerOS.DeepPartialEvent,\n push: Collector.PushFn,\n): Promise<{ id?: string; error?: string }> {\n try {\n const result = await push(event);\n return { id: result?.event?.id };\n } catch (error) {\n return { error: error instanceof Error ? error.message : 'Unknown error' };\n }\n}\n\nasync function processBatch(\n events: unknown[],\n push: Collector.PushFn,\n logger: Types['env']['logger'],\n): Promise<{\n successful: number;\n failed: number;\n ids: string[];\n errors: Array<{ index: number; error: string }>;\n}> {\n const results = {\n successful: 0,\n failed: 0,\n ids: [] as string[],\n errors: [] as Array<{ index: number; error: string }>,\n };\n\n for (let i = 0; i < events.length; i++) {\n const event = events[i];\n\n try {\n const result = await push(event as WalkerOS.DeepPartialEvent);\n if (result?.event?.id) {\n results.ids.push(result.event.id);\n }\n results.successful++;\n } catch (error) {\n results.failed++;\n results.errors.push({\n index: i,\n error: error instanceof Error ? error.message : 'Unknown error',\n });\n logger.error(`Batch event ${i} processing failed`, error);\n }\n }\n\n return results;\n}\n\nexport type * from './types';\nexport * as SourceFetch from './types';\nexport * from './utils';\nexport * as examples from './examples';\n\nexport default sourceFetch;\n","import type { CorsOptions } from './schemas';\n\nexport function createCorsHeaders(\n corsConfig: boolean | CorsOptions = true,\n requestOrigin?: string | null,\n): Headers {\n const headers = new Headers();\n\n if (corsConfig === false) return headers;\n\n if (corsConfig === true) {\n headers.set('Access-Control-Allow-Origin', '*');\n headers.set('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');\n headers.set('Access-Control-Allow-Headers', 'Content-Type');\n } else {\n if (corsConfig.origin) {\n let origin: string;\n if (Array.isArray(corsConfig.origin)) {\n origin =\n requestOrigin && corsConfig.origin.includes(requestOrigin)\n ? requestOrigin\n : corsConfig.origin[0];\n } else {\n origin = corsConfig.origin;\n }\n headers.set('Access-Control-Allow-Origin', origin);\n }\n\n if (corsConfig.methods) {\n headers.set(\n 'Access-Control-Allow-Methods',\n corsConfig.methods.join(', '),\n );\n }\n\n if (corsConfig.headers) {\n headers.set(\n 'Access-Control-Allow-Headers',\n corsConfig.headers.join(', '),\n );\n }\n\n if (corsConfig.credentials) {\n headers.set('Access-Control-Allow-Credentials', 'true');\n }\n\n if (corsConfig.maxAge) {\n headers.set('Access-Control-Max-Age', String(corsConfig.maxAge));\n }\n }\n\n return headers;\n}\n\nexport const TRANSPARENT_GIF_BASE64 =\n 'R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';\n\nexport function createPixelResponse(corsHeaders?: Headers): Response {\n const binaryString = atob(TRANSPARENT_GIF_BASE64);\n const bytes = new Uint8Array(binaryString.length);\n for (let i = 0; i < binaryString.length; i++) {\n bytes[i] = binaryString.charCodeAt(i);\n }\n\n const headers = new Headers(corsHeaders);\n headers.set('Content-Type', 'image/gif');\n headers.set('Cache-Control', 'no-cache, no-store, must-revalidate');\n\n return new Response(bytes, { status: 200, headers });\n}\n\nexport function createJsonResponse(\n body: unknown,\n status = 200,\n corsHeaders?: Headers,\n): Response {\n const headers = new Headers(corsHeaders);\n headers.set('Content-Type', 'application/json');\n\n return new Response(JSON.stringify(body), { status, headers });\n}\n\n/**\n * Match a request pathname against a route pattern.\n * Supports exact matches and wildcard patterns (e.g., /api/*).\n */\nexport function matchPath(requestPath: string, pattern: string): boolean {\n if (pattern.endsWith('/*')) {\n const prefix = pattern.slice(0, -2);\n return requestPath === prefix || requestPath.startsWith(prefix + '/');\n }\n return requestPath === pattern;\n}\n","import type { WalkerOS, Source as CoreSource } from '@walkeros/core';\nimport type {\n SettingsSchema,\n CorsOptionsSchema,\n RouteConfigSchema,\n} from './schemas';\nimport type { z } from '@walkeros/core/dev';\n\ndeclare module '@walkeros/core' {\n interface SourceMap {\n fetch: { type: 'fetch'; platform: 'server' };\n }\n}\n\nexport type Settings = z.infer<typeof SettingsSchema>;\nexport type CorsOptions = z.infer<typeof CorsOptionsSchema>;\nexport type RouteConfig = z.infer<typeof RouteConfigSchema>;\nexport type RouteMethod = 'GET' | 'POST';\nexport type InitSettings = Partial<Settings>;\n\nexport interface Mapping {}\n\nexport type Push = (request: Request) => Response | Promise<Response>;\n\nexport interface Env extends CoreSource.Env {\n request?: Request;\n}\n\nexport type Types = CoreSource.Types<\n Settings,\n Mapping,\n Push,\n Env,\n InitSettings\n>;\nexport type Config = CoreSource.Config<Types>;\nexport type PartialConfig = CoreSource.PartialConfig<Types>;\n\nexport interface FetchSource extends Omit<CoreSource.Instance<Types>, 'push'> {\n push: Push;\n}\n\nexport interface EventResponse {\n success: boolean;\n id?: string;\n timestamp?: number;\n error?: string;\n}\n","export * as inputs from './inputs';\nexport * as requests from './requests';\nexport * as step from './step';\nexport { createTrigger } from './trigger';\n","import type { WalkerOS } from '@walkeros/core';\n\n/**\n * Example walkerOS events that HTTP clients send to this source.\n * These are the CONTRACT - tests verify implementation handles these inputs.\n */\n\n// Simple page view event\nexport const pageView: WalkerOS.DeepPartialEvent = {\n name: 'page view',\n data: {\n title: 'Home Page',\n path: '/',\n referrer: 'https://google.com',\n },\n user: {\n id: 'user-123',\n session: 'session-456',\n },\n timestamp: 1700000000000,\n};\n\n// E-commerce event with nested entities\nexport const productAdd: WalkerOS.DeepPartialEvent = {\n name: 'product add',\n data: {\n id: 'P-123',\n name: 'Laptop',\n price: 999.99,\n quantity: 1,\n },\n context: {\n stage: ['shopping', 1],\n },\n globals: {\n language: 'en',\n currency: 'USD',\n },\n user: {\n id: 'user-123',\n },\n nested: [\n {\n entity: 'category',\n data: {\n name: 'Electronics',\n path: '/electronics',\n },\n },\n ],\n consent: {\n functional: true,\n marketing: true,\n },\n};\n\n// Complete event with all optional fields\nexport const completeEvent: WalkerOS.DeepPartialEvent = {\n name: 'order complete',\n data: {\n id: 'ORDER-123',\n total: 999.99,\n currency: 'USD',\n },\n context: {\n stage: ['checkout', 3],\n test: ['variant-A', 0],\n },\n globals: {\n language: 'en',\n country: 'US',\n },\n custom: {\n campaignId: 'summer-sale',\n source: 'email',\n },\n user: {\n id: 'user-123',\n email: 'user@example.com',\n session: 'session-456',\n },\n nested: [\n {\n entity: 'product',\n data: {\n id: 'P-123',\n price: 999.99,\n },\n },\n ],\n consent: {\n functional: true,\n marketing: true,\n analytics: false,\n },\n trigger: 'click',\n};\n\n// Minimal valid event\nexport const minimal: WalkerOS.DeepPartialEvent = {\n name: 'ping',\n};\n\n// Batch of events\nexport const batch: WalkerOS.DeepPartialEvent[] = [\n pageView,\n productAdd,\n { name: 'button click', data: { id: 'cta' } },\n];\n","/**\n * HTTP request examples for testing the fetch source.\n * Shows what external HTTP clients will send.\n */\n\nexport const validPostRequest = {\n method: 'POST',\n url: 'https://example.com/collect',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n name: 'page view',\n data: { title: 'Home' },\n }),\n};\n\nexport const batchPostRequest = {\n method: 'POST',\n url: 'https://example.com/collect',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n batch: [\n { name: 'page view', data: { title: 'Home' } },\n { name: 'button click', data: { id: 'cta' } },\n ],\n }),\n};\n\nexport const pixelGetRequest = {\n method: 'GET',\n url: 'https://example.com/collect?event=page%20view&data[title]=Home&user[id]=user123',\n};\n\nexport const healthCheckRequest = {\n method: 'GET',\n url: 'https://example.com/health',\n};\n\nexport const optionsRequest = {\n method: 'OPTIONS',\n url: 'https://example.com/collect',\n headers: { Origin: 'https://example.com' },\n};\n\nexport const invalidJsonRequest = {\n method: 'POST',\n url: 'https://example.com/collect',\n headers: { 'Content-Type': 'application/json' },\n body: 'invalid json{',\n};\n\nexport const oversizedRequest = {\n method: 'POST',\n url: 'https://example.com/collect',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n name: 'test',\n data: { payload: 'x'.repeat(200000) }, // 200KB\n }),\n};\n","import type { Flow } from '@walkeros/core';\n\nexport const postEvent: Flow.StepExample = {\n title: 'POST event',\n description:\n 'A fetch POST request with a JSON body becomes a single walker elb event in a fetch-based server.',\n trigger: { type: 'POST' },\n in: {\n method: 'POST',\n url: 'http://localhost/collect',\n body: {\n name: 'page view',\n data: { title: 'Docs', url: 'https://example.com/docs' },\n },\n },\n out: [\n [\n 'elb',\n {\n name: 'page view',\n data: { title: 'Docs', url: 'https://example.com/docs' },\n },\n ],\n ],\n};\n\nexport const batchRequest: Flow.StepExample = {\n title: 'Batch POST',\n description:\n 'A fetch POST with a batch array produces one walker elb event per batched item preserving order.',\n trigger: { type: 'POST' },\n in: {\n method: 'POST',\n url: 'http://localhost/collect',\n body: {\n batch: [\n { name: 'page view', data: { title: 'Home' } },\n { name: 'button click', data: { id: 'cta' } },\n ],\n },\n },\n out: [\n ['elb', { name: 'page view', data: { title: 'Home' } }],\n ['elb', { name: 'button click', data: { id: 'cta' } }],\n ],\n};\n\nexport const pixelGet: Flow.StepExample = {\n title: 'Pixel GET',\n description:\n 'A fetch GET with query parameters in the URL is parsed into an elb event payload for pixel-style tracking.',\n trigger: { type: 'GET' },\n in: {\n method: 'GET',\n url: 'http://localhost/collect?e=page+view&d=%7B%22title%22%3A%22Home%22%7D',\n },\n out: [\n [\n 'elb',\n {\n e: 'page view',\n d: '{\"title\":\"Home\"}',\n },\n ],\n ],\n};\n","import type { Trigger, Collector } from '@walkeros/core';\nimport { startFlow } from '@walkeros/collector';\n\nexport interface Content {\n method: string;\n url: string;\n body?: unknown;\n headers?: Record<string, string>;\n}\n\nexport interface Result {\n status: number;\n body: unknown;\n headers: Record<string, string>;\n}\n\nfunction findFetchSource(collector: Collector.Instance) {\n for (const source of Object.values(collector.sources || {})) {\n if ((source as { type?: string }).type === 'fetch') return source;\n }\n}\n\nconst createTrigger: Trigger.CreateFn<Content, Result> = async (\n config: Collector.InitConfig,\n) => {\n let flow: Trigger.FlowHandle | undefined;\n\n const trigger: Trigger.Fn<Content, Result> =\n () =>\n async (content: Content): Promise<Result> => {\n if (!flow) {\n const result = await startFlow(config);\n flow = { collector: result.collector, elb: result.elb };\n }\n\n const source = findFetchSource(flow.collector);\n if (!source) throw new Error('Fetch source not found in collector');\n\n // Construct real Request from content\n const init: RequestInit = {\n method: content.method,\n headers: { 'Content-Type': 'application/json', ...content.headers },\n };\n if (content.method !== 'GET' && content.body !== undefined) {\n init.body = JSON.stringify(content.body);\n }\n const request = new Request(content.url, init);\n\n // Call source.push with the real Request\n const response = await (\n source as unknown as { push: (r: Request) => Promise<Response> }\n ).push(request);\n\n // Convert Response to serializable result\n const responseHeaders: Record<string, string> = {};\n response.headers.forEach((v, k) => {\n responseHeaders[k] = v;\n });\n\n const ct = response.headers.get('content-type') || '';\n const body = ct.includes('json')\n ? await response.json()\n : await response.text();\n\n return { status: response.status, body, headers: responseHeaders };\n };\n\n return {\n get flow() {\n return flow;\n },\n trigger,\n };\n};\n\nexport { createTrigger };\n"],"mappings":"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","names":["result","batch"]}
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$meta": {
3
3
  "package": "@walkeros/server-source-fetch",
4
- "version": "4.1.0-next-1778668930820",
4
+ "version": "4.1.0",
5
5
  "type": "source",
6
6
  "platform": [
7
7
  "server"
@@ -131,11 +131,7 @@
131
131
  "description": "Maximum events per batch request"
132
132
  }
133
133
  },
134
- "required": [
135
- "cors",
136
- "maxRequestSize",
137
- "maxBatchSize"
138
- ],
134
+ "required": [],
139
135
  "additionalProperties": false
140
136
  }
141
137
  },
package/package.json CHANGED
@@ -1,13 +1,14 @@
1
1
  {
2
2
  "name": "@walkeros/server-source-fetch",
3
3
  "description": "Web Standard Fetch API source for walkerOS (Cloudflare Workers, Vercel Edge, Deno, Bun)",
4
- "version": "4.1.0-next-1778668930820",
4
+ "version": "4.1.0",
5
5
  "license": "MIT",
6
6
  "main": "./dist/index.js",
7
7
  "module": "./dist/index.mjs",
8
8
  "types": "./dist/index.d.ts",
9
9
  "files": [
10
- "dist/**"
10
+ "dist/**",
11
+ "CHANGELOG.md"
11
12
  ],
12
13
  "scripts": {
13
14
  "build": "tsup --silent",
@@ -19,8 +20,8 @@
19
20
  "update": "npx npm-check-updates -u && npm update"
20
21
  },
21
22
  "dependencies": {
22
- "@walkeros/collector": "4.1.0-next-1778668930820",
23
- "@walkeros/core": "4.1.0-next-1778668930820"
23
+ "@walkeros/collector": "4.1.0",
24
+ "@walkeros/core": "4.1.0"
24
25
  },
25
26
  "devDependencies": {},
26
27
  "repository": {