@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 +335 -0
- package/README.md +33 -306
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/dist/walkerOS.json +2 -6
- package/package.json +5 -4
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
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
>
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
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) •
|
|
15
|
+
[NPM Package](https://www.npmjs.com/package/@walkeros/server-source-fetch)
|
|
16
|
+
•
|
|
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
|
|
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
|
-
##
|
|
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
|
-
"
|
|
261
|
-
"
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
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
|
-
|
|
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
|
-
|
|
43
|
+
Full configuration, mapping, and examples live in the docs:
|
|
44
|
+
**https://www.walkeros.io/docs/sources/server/fetch**
|
|
320
45
|
|
|
321
|
-
##
|
|
46
|
+
## Contribute
|
|
322
47
|
|
|
323
|
-
|
|
324
|
-
|
|
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
|
package/dist/index.mjs.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/walkerOS.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$meta": {
|
|
3
3
|
"package": "@walkeros/server-source-fetch",
|
|
4
|
-
"version": "4.1.0
|
|
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
|
|
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
|
|
23
|
-
"@walkeros/core": "4.1.0
|
|
23
|
+
"@walkeros/collector": "4.1.0",
|
|
24
|
+
"@walkeros/core": "4.1.0"
|
|
24
25
|
},
|
|
25
26
|
"devDependencies": {},
|
|
26
27
|
"repository": {
|