@walkeros/server-destination-file 3.4.0-next-1776749829492

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.
@@ -0,0 +1,113 @@
1
+ import { DestinationServer } from '@walkeros/server-core';
2
+ import { WriteStream } from 'node:fs';
3
+ import { Flow } from '@walkeros/core';
4
+
5
+ type Format = 'jsonl' | 'tsv' | 'csv';
6
+ /**
7
+ * Minimal write-stream interface used by the destination. Matches the
8
+ * subset of node:fs WriteStream needed for append-only writes. Tests
9
+ * inject a fake implementation via env.fs.
10
+ */
11
+ interface FileWriteStream {
12
+ write: (chunk: string) => boolean;
13
+ end: () => void;
14
+ }
15
+ interface Env extends DestinationServer.Env {
16
+ /**
17
+ * Override the file system primitives. Tests inject a fake here so
18
+ * disk writes are captured in memory.
19
+ */
20
+ fs?: {
21
+ createWriteStream: (path: string, options: {
22
+ flags: string;
23
+ }) => FileWriteStream | WriteStream;
24
+ mkdir: (path: string, options: {
25
+ recursive: boolean;
26
+ }) => Promise<void>;
27
+ };
28
+ }
29
+
30
+ /**
31
+ * Captured file state for assertions in tests.
32
+ */
33
+ interface CapturedFile {
34
+ filename: string;
35
+ lines: string[];
36
+ ended: boolean;
37
+ }
38
+ interface SpyState {
39
+ captured: Map<string, CapturedFile>;
40
+ mkdirCalls: string[];
41
+ }
42
+ interface SpyEnv extends Env {
43
+ _spy: SpyState;
44
+ }
45
+ declare const init: SpyEnv;
46
+ declare const push: SpyEnv;
47
+
48
+ type env_CapturedFile = CapturedFile;
49
+ type env_SpyEnv = SpyEnv;
50
+ type env_SpyState = SpyState;
51
+ declare const env_init: typeof init;
52
+ declare const env_push: typeof push;
53
+ declare namespace env {
54
+ export { type env_CapturedFile as CapturedFile, type env_SpyEnv as SpyEnv, type env_SpyState as SpyState, env_init as init, env_push as push };
55
+ }
56
+
57
+ /**
58
+ * Raw filename-config shape accepted in step examples and flow.json.
59
+ * Mirrors the runtime Settings.filename but types `fn` as string so
60
+ * `$code:` tags (resolved at bundle time by walkerOS) are expressible
61
+ * here without casting to a function type.
62
+ */
63
+ interface FileSettingsJson {
64
+ filename: string | {
65
+ key?: string;
66
+ fn?: string | ((value: unknown) => unknown);
67
+ value?: unknown;
68
+ };
69
+ format?: Format;
70
+ fields?: string[];
71
+ }
72
+ /**
73
+ * Extended step example that carries destination-level settings for the
74
+ * file destination.
75
+ *
76
+ * `out` is modeled at intent level as a single `['fs.writeFile', path, line]`
77
+ * tuple per event (even though the destination internally uses a persistent
78
+ * createWriteStream + write). This matches the design doc's preference for
79
+ * readable intent-level callable tuples over stream-chain fidelity.
80
+ *
81
+ * Dropped / ignored events produce `out: []`.
82
+ */
83
+ type FileStepExample = Flow.StepExample & {
84
+ settings: FileSettingsJson;
85
+ };
86
+ /** Default JSONL append. Static filename, all defaults. */
87
+ declare const jsonlDefault: FileStepExample;
88
+ /** Baersch-style TSV log: PHP parity case. */
89
+ declare const tsvBaerschLog: FileStepExample;
90
+ /** Tenant sharding via plain key extraction. */
91
+ declare const jsonlTenantShardKey: FileStepExample;
92
+ /**
93
+ * Daily rotation via a mapping fn. In flow.json this is authored as a
94
+ * `$code:` string; walkerOS compiles it to a function at bundle time. For
95
+ * in-process tests we pass the already-compiled function directly so the
96
+ * example exercises the same code path without needing the bundler.
97
+ */
98
+ declare const jsonlDailyRotation: FileStepExample;
99
+ /** CSV with an object cell. data is JSON-stringified, properly quoted. */
100
+ declare const csvObjectCell: FileStepExample;
101
+
102
+ type step_FileSettingsJson = FileSettingsJson;
103
+ type step_FileStepExample = FileStepExample;
104
+ declare const step_csvObjectCell: typeof csvObjectCell;
105
+ declare const step_jsonlDailyRotation: typeof jsonlDailyRotation;
106
+ declare const step_jsonlDefault: typeof jsonlDefault;
107
+ declare const step_jsonlTenantShardKey: typeof jsonlTenantShardKey;
108
+ declare const step_tsvBaerschLog: typeof tsvBaerschLog;
109
+ declare namespace step {
110
+ export { type step_FileSettingsJson as FileSettingsJson, type step_FileStepExample as FileStepExample, step_csvObjectCell as csvObjectCell, step_jsonlDailyRotation as jsonlDailyRotation, step_jsonlDefault as jsonlDefault, step_jsonlTenantShardKey as jsonlTenantShardKey, step_tsvBaerschLog as tsvBaerschLog };
111
+ }
112
+
113
+ export { env, step };
@@ -0,0 +1,178 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/examples/index.ts
21
+ var examples_exports = {};
22
+ __export(examples_exports, {
23
+ env: () => env_exports,
24
+ step: () => step_exports
25
+ });
26
+ module.exports = __toCommonJS(examples_exports);
27
+
28
+ // src/examples/env.ts
29
+ var env_exports = {};
30
+ __export(env_exports, {
31
+ init: () => init,
32
+ push: () => push
33
+ });
34
+ function makeSpyEnv() {
35
+ const state = {
36
+ captured: /* @__PURE__ */ new Map(),
37
+ mkdirCalls: []
38
+ };
39
+ const createWriteStream = (path) => {
40
+ const existing = state.captured.get(path);
41
+ const file = existing != null ? existing : {
42
+ filename: path,
43
+ lines: [],
44
+ ended: false
45
+ };
46
+ if (!existing) state.captured.set(path, file);
47
+ const stream = {
48
+ write(chunk) {
49
+ file.lines.push(chunk);
50
+ return true;
51
+ },
52
+ end() {
53
+ file.ended = true;
54
+ }
55
+ };
56
+ return stream;
57
+ };
58
+ const mkdir = async (path) => {
59
+ state.mkdirCalls.push(path);
60
+ };
61
+ return {
62
+ _spy: state,
63
+ fs: {
64
+ createWriteStream,
65
+ mkdir
66
+ }
67
+ };
68
+ }
69
+ var init = makeSpyEnv();
70
+ var push = makeSpyEnv();
71
+
72
+ // src/examples/step.ts
73
+ var step_exports = {};
74
+ __export(step_exports, {
75
+ csvObjectCell: () => csvObjectCell,
76
+ jsonlDailyRotation: () => jsonlDailyRotation,
77
+ jsonlDefault: () => jsonlDefault,
78
+ jsonlTenantShardKey: () => jsonlTenantShardKey,
79
+ tsvBaerschLog: () => tsvBaerschLog
80
+ });
81
+ var import_core = require("@walkeros/core");
82
+ var jsonlDefault = {
83
+ in: (0, import_core.getEvent)("page view", { timestamp: 17e11 }),
84
+ settings: { filename: "events.jsonl" },
85
+ out: [
86
+ [
87
+ "fs.writeFile",
88
+ "events.jsonl",
89
+ // JSONL framework contract: JSON.stringify(event) + '\n'.
90
+ // The test recomputes this from example.in for the jsonl default to
91
+ // avoid duplicating the full event shape here.
92
+ "jsonl:event"
93
+ ]
94
+ ]
95
+ };
96
+ var tsvBaerschLog = {
97
+ in: (0, import_core.getEvent)("page view", {
98
+ timestamp: 17e11,
99
+ data: { title: "Docs" },
100
+ user: { session: "sess-1" },
101
+ source: {
102
+ id: "https://example.com/docs",
103
+ type: "server",
104
+ previous_id: "https://example.com/"
105
+ }
106
+ }),
107
+ settings: {
108
+ filename: "storage/mblog.txt",
109
+ format: "tsv",
110
+ fields: [
111
+ "timestamp",
112
+ "user.session",
113
+ "name",
114
+ "source.id",
115
+ "data.title",
116
+ "source.previous_id"
117
+ ]
118
+ },
119
+ out: [
120
+ [
121
+ "fs.writeFile",
122
+ "storage/mblog.txt",
123
+ "1700000000000 sess-1 page view https://example.com/docs Docs https://example.com/\n"
124
+ ]
125
+ ]
126
+ };
127
+ var jsonlTenantShardKey = {
128
+ in: (0, import_core.getEvent)("custom event", {
129
+ timestamp: 17e11,
130
+ data: { tenant: "acme" }
131
+ }),
132
+ settings: {
133
+ filename: { key: "data.tenant" },
134
+ format: "jsonl"
135
+ },
136
+ out: [["fs.writeFile", "acme", "jsonl:event"]]
137
+ };
138
+ var jsonlDailyRotation = {
139
+ in: (0, import_core.getEvent)("order complete", {
140
+ timestamp: Date.UTC(2026, 3, 15, 12, 34, 56),
141
+ data: { id: "ORD-1" }
142
+ }),
143
+ settings: {
144
+ filename: {
145
+ fn: (value) => {
146
+ var _a;
147
+ const event = value;
148
+ const ts = (_a = event.timestamp) != null ? _a : 0;
149
+ return `events-${new Date(ts).toISOString().slice(0, 10)}.jsonl`;
150
+ }
151
+ },
152
+ format: "jsonl"
153
+ },
154
+ out: [["fs.writeFile", "events-2026-04-15.jsonl", "jsonl:event"]]
155
+ };
156
+ var csvObjectCell = {
157
+ in: (0, import_core.getEvent)("page view", {
158
+ timestamp: 17e11,
159
+ data: { title: 'Hello, "World"', count: 3 }
160
+ }),
161
+ settings: {
162
+ filename: "events.csv",
163
+ format: "csv",
164
+ fields: ["timestamp", "name", "data"]
165
+ },
166
+ out: [
167
+ [
168
+ "fs.writeFile",
169
+ "events.csv",
170
+ '1700000000000,page view,"{""title"":""Hello, \\""World\\"""",""count"":3}"\n'
171
+ ]
172
+ ]
173
+ };
174
+ // Annotate the CommonJS export names for ESM import in node:
175
+ 0 && (module.exports = {
176
+ env,
177
+ step
178
+ });
@@ -0,0 +1,156 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __export = (target, all) => {
3
+ for (var name in all)
4
+ __defProp(target, name, { get: all[name], enumerable: true });
5
+ };
6
+
7
+ // src/examples/env.ts
8
+ var env_exports = {};
9
+ __export(env_exports, {
10
+ init: () => init,
11
+ push: () => push
12
+ });
13
+ function makeSpyEnv() {
14
+ const state = {
15
+ captured: /* @__PURE__ */ new Map(),
16
+ mkdirCalls: []
17
+ };
18
+ const createWriteStream = (path) => {
19
+ const existing = state.captured.get(path);
20
+ const file = existing != null ? existing : {
21
+ filename: path,
22
+ lines: [],
23
+ ended: false
24
+ };
25
+ if (!existing) state.captured.set(path, file);
26
+ const stream = {
27
+ write(chunk) {
28
+ file.lines.push(chunk);
29
+ return true;
30
+ },
31
+ end() {
32
+ file.ended = true;
33
+ }
34
+ };
35
+ return stream;
36
+ };
37
+ const mkdir = async (path) => {
38
+ state.mkdirCalls.push(path);
39
+ };
40
+ return {
41
+ _spy: state,
42
+ fs: {
43
+ createWriteStream,
44
+ mkdir
45
+ }
46
+ };
47
+ }
48
+ var init = makeSpyEnv();
49
+ var push = makeSpyEnv();
50
+
51
+ // src/examples/step.ts
52
+ var step_exports = {};
53
+ __export(step_exports, {
54
+ csvObjectCell: () => csvObjectCell,
55
+ jsonlDailyRotation: () => jsonlDailyRotation,
56
+ jsonlDefault: () => jsonlDefault,
57
+ jsonlTenantShardKey: () => jsonlTenantShardKey,
58
+ tsvBaerschLog: () => tsvBaerschLog
59
+ });
60
+ import { getEvent } from "@walkeros/core";
61
+ var jsonlDefault = {
62
+ in: getEvent("page view", { timestamp: 17e11 }),
63
+ settings: { filename: "events.jsonl" },
64
+ out: [
65
+ [
66
+ "fs.writeFile",
67
+ "events.jsonl",
68
+ // JSONL framework contract: JSON.stringify(event) + '\n'.
69
+ // The test recomputes this from example.in for the jsonl default to
70
+ // avoid duplicating the full event shape here.
71
+ "jsonl:event"
72
+ ]
73
+ ]
74
+ };
75
+ var tsvBaerschLog = {
76
+ in: getEvent("page view", {
77
+ timestamp: 17e11,
78
+ data: { title: "Docs" },
79
+ user: { session: "sess-1" },
80
+ source: {
81
+ id: "https://example.com/docs",
82
+ type: "server",
83
+ previous_id: "https://example.com/"
84
+ }
85
+ }),
86
+ settings: {
87
+ filename: "storage/mblog.txt",
88
+ format: "tsv",
89
+ fields: [
90
+ "timestamp",
91
+ "user.session",
92
+ "name",
93
+ "source.id",
94
+ "data.title",
95
+ "source.previous_id"
96
+ ]
97
+ },
98
+ out: [
99
+ [
100
+ "fs.writeFile",
101
+ "storage/mblog.txt",
102
+ "1700000000000 sess-1 page view https://example.com/docs Docs https://example.com/\n"
103
+ ]
104
+ ]
105
+ };
106
+ var jsonlTenantShardKey = {
107
+ in: getEvent("custom event", {
108
+ timestamp: 17e11,
109
+ data: { tenant: "acme" }
110
+ }),
111
+ settings: {
112
+ filename: { key: "data.tenant" },
113
+ format: "jsonl"
114
+ },
115
+ out: [["fs.writeFile", "acme", "jsonl:event"]]
116
+ };
117
+ var jsonlDailyRotation = {
118
+ in: getEvent("order complete", {
119
+ timestamp: Date.UTC(2026, 3, 15, 12, 34, 56),
120
+ data: { id: "ORD-1" }
121
+ }),
122
+ settings: {
123
+ filename: {
124
+ fn: (value) => {
125
+ var _a;
126
+ const event = value;
127
+ const ts = (_a = event.timestamp) != null ? _a : 0;
128
+ return `events-${new Date(ts).toISOString().slice(0, 10)}.jsonl`;
129
+ }
130
+ },
131
+ format: "jsonl"
132
+ },
133
+ out: [["fs.writeFile", "events-2026-04-15.jsonl", "jsonl:event"]]
134
+ };
135
+ var csvObjectCell = {
136
+ in: getEvent("page view", {
137
+ timestamp: 17e11,
138
+ data: { title: 'Hello, "World"', count: 3 }
139
+ }),
140
+ settings: {
141
+ filename: "events.csv",
142
+ format: "csv",
143
+ fields: ["timestamp", "name", "data"]
144
+ },
145
+ out: [
146
+ [
147
+ "fs.writeFile",
148
+ "events.csv",
149
+ '1700000000000,page view,"{""title"":""Hello, \\""World\\"""",""count"":3}"\n'
150
+ ]
151
+ ]
152
+ };
153
+ export {
154
+ env_exports as env,
155
+ step_exports as step
156
+ };
@@ -0,0 +1,78 @@
1
+ import { Mapping as Mapping$1, Destination as Destination$1 } from '@walkeros/core';
2
+ import { DestinationServer } from '@walkeros/server-core';
3
+ import { WriteStream } from 'node:fs';
4
+
5
+ type Format = 'jsonl' | 'tsv' | 'csv';
6
+ interface Settings {
7
+ /**
8
+ * Output filename. Either a static string or a Mapping.Value resolved
9
+ * per event (e.g. tenant sharding via `key`, daily rotation via `$code:` fn).
10
+ * Static filenames are validated and opened at flow startup;
11
+ * dynamic ones at first matching event.
12
+ */
13
+ filename: string | Mapping$1.Value;
14
+ /** Serialisation format. Defaults to 'jsonl'. */
15
+ format?: Format;
16
+ /**
17
+ * Event paths used as columns for tsv/csv formats. Order preserved.
18
+ * Object values are JSON-stringified into a single cell.
19
+ * Required when format is 'tsv' or 'csv'.
20
+ */
21
+ fields?: string[];
22
+ }
23
+ type InitSettings = Partial<Settings>;
24
+ interface Mapping {
25
+ }
26
+ /**
27
+ * Minimal write-stream interface used by the destination. Matches the
28
+ * subset of node:fs WriteStream needed for append-only writes. Tests
29
+ * inject a fake implementation via env.fs.
30
+ */
31
+ interface FileWriteStream {
32
+ write: (chunk: string) => boolean;
33
+ end: () => void;
34
+ }
35
+ interface Env extends DestinationServer.Env {
36
+ /**
37
+ * Override the file system primitives. Tests inject a fake here so
38
+ * disk writes are captured in memory.
39
+ */
40
+ fs?: {
41
+ createWriteStream: (path: string, options: {
42
+ flags: string;
43
+ }) => FileWriteStream | WriteStream;
44
+ mkdir: (path: string, options: {
45
+ recursive: boolean;
46
+ }) => Promise<void>;
47
+ };
48
+ }
49
+ type Types = Destination$1.Types<Settings, Mapping, Env, InitSettings>;
50
+ interface Destination extends DestinationServer.Destination<Types> {
51
+ init: DestinationServer.InitFn<Types>;
52
+ }
53
+ type Config = {
54
+ settings: Settings;
55
+ } & DestinationServer.Config<Types>;
56
+ type PartialConfig = DestinationServer.PartialConfig<Types>;
57
+ type InitFn = DestinationServer.InitFn<Types>;
58
+ type PushFn = DestinationServer.PushFn<Types>;
59
+
60
+ type index_Config = Config;
61
+ type index_Destination = Destination;
62
+ type index_Env = Env;
63
+ type index_FileWriteStream = FileWriteStream;
64
+ type index_Format = Format;
65
+ type index_InitFn = InitFn;
66
+ type index_InitSettings = InitSettings;
67
+ type index_Mapping = Mapping;
68
+ type index_PartialConfig = PartialConfig;
69
+ type index_PushFn = PushFn;
70
+ type index_Settings = Settings;
71
+ type index_Types = Types;
72
+ declare namespace index {
73
+ export type { index_Config as Config, index_Destination as Destination, index_Env as Env, index_FileWriteStream as FileWriteStream, index_Format as Format, index_InitFn as InitFn, index_InitSettings as InitSettings, index_Mapping as Mapping, index_PartialConfig as PartialConfig, index_PushFn as PushFn, index_Settings as Settings, index_Types as Types };
74
+ }
75
+
76
+ declare const destinationFile: Destination;
77
+
78
+ export { index as DestinationFile, destinationFile as default, destinationFile };
@@ -0,0 +1,78 @@
1
+ import { Mapping as Mapping$1, Destination as Destination$1 } from '@walkeros/core';
2
+ import { DestinationServer } from '@walkeros/server-core';
3
+ import { WriteStream } from 'node:fs';
4
+
5
+ type Format = 'jsonl' | 'tsv' | 'csv';
6
+ interface Settings {
7
+ /**
8
+ * Output filename. Either a static string or a Mapping.Value resolved
9
+ * per event (e.g. tenant sharding via `key`, daily rotation via `$code:` fn).
10
+ * Static filenames are validated and opened at flow startup;
11
+ * dynamic ones at first matching event.
12
+ */
13
+ filename: string | Mapping$1.Value;
14
+ /** Serialisation format. Defaults to 'jsonl'. */
15
+ format?: Format;
16
+ /**
17
+ * Event paths used as columns for tsv/csv formats. Order preserved.
18
+ * Object values are JSON-stringified into a single cell.
19
+ * Required when format is 'tsv' or 'csv'.
20
+ */
21
+ fields?: string[];
22
+ }
23
+ type InitSettings = Partial<Settings>;
24
+ interface Mapping {
25
+ }
26
+ /**
27
+ * Minimal write-stream interface used by the destination. Matches the
28
+ * subset of node:fs WriteStream needed for append-only writes. Tests
29
+ * inject a fake implementation via env.fs.
30
+ */
31
+ interface FileWriteStream {
32
+ write: (chunk: string) => boolean;
33
+ end: () => void;
34
+ }
35
+ interface Env extends DestinationServer.Env {
36
+ /**
37
+ * Override the file system primitives. Tests inject a fake here so
38
+ * disk writes are captured in memory.
39
+ */
40
+ fs?: {
41
+ createWriteStream: (path: string, options: {
42
+ flags: string;
43
+ }) => FileWriteStream | WriteStream;
44
+ mkdir: (path: string, options: {
45
+ recursive: boolean;
46
+ }) => Promise<void>;
47
+ };
48
+ }
49
+ type Types = Destination$1.Types<Settings, Mapping, Env, InitSettings>;
50
+ interface Destination extends DestinationServer.Destination<Types> {
51
+ init: DestinationServer.InitFn<Types>;
52
+ }
53
+ type Config = {
54
+ settings: Settings;
55
+ } & DestinationServer.Config<Types>;
56
+ type PartialConfig = DestinationServer.PartialConfig<Types>;
57
+ type InitFn = DestinationServer.InitFn<Types>;
58
+ type PushFn = DestinationServer.PushFn<Types>;
59
+
60
+ type index_Config = Config;
61
+ type index_Destination = Destination;
62
+ type index_Env = Env;
63
+ type index_FileWriteStream = FileWriteStream;
64
+ type index_Format = Format;
65
+ type index_InitFn = InitFn;
66
+ type index_InitSettings = InitSettings;
67
+ type index_Mapping = Mapping;
68
+ type index_PartialConfig = PartialConfig;
69
+ type index_PushFn = PushFn;
70
+ type index_Settings = Settings;
71
+ type index_Types = Types;
72
+ declare namespace index {
73
+ export type { index_Config as Config, index_Destination as Destination, index_Env as Env, index_FileWriteStream as FileWriteStream, index_Format as Format, index_InitFn as InitFn, index_InitSettings as InitSettings, index_Mapping as Mapping, index_PartialConfig as PartialConfig, index_PushFn as PushFn, index_Settings as Settings, index_Types as Types };
74
+ }
75
+
76
+ declare const destinationFile: Destination;
77
+
78
+ export { index as DestinationFile, destinationFile as default, destinationFile };
package/dist/index.js ADDED
@@ -0,0 +1 @@
1
+ "use strict";var mod,__defProp=Object.defineProperty,__getOwnPropDesc=Object.getOwnPropertyDescriptor,__getOwnPropNames=Object.getOwnPropertyNames,__hasOwnProp=Object.prototype.hasOwnProperty,index_exports={};((target,all)=>{for(var name in all)__defProp(target,name,{get:all[name],enumerable:!0})})(index_exports,{DestinationFile:()=>types_exports,default:()=>index_default,destinationFile:()=>destinationFile}),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_core2=require("@walkeros/core"),import_node_fs=require("fs"),import_promises=require("fs/promises"),import_node_path=require("path"),import_core=require("@walkeros/core");async function ensureHandle(state,filename){const cached=state.handles.get(filename);if(cached)return cached;await state.fs.mkdir((0,import_node_path.dirname)(filename)||".",{recursive:!0});const handle=state.fs.createWriteStream(filename,{flags:"a"});return state.handles.set(filename,handle),handle}function serialize(event,format,fields){if("jsonl"===format)return JSON.stringify(event)+"\n";if(!fields||0===fields.length)throw new Error(`file destination: format '${format}' requires non-empty 'fields' setting`);const cells=fields.map(path=>{return null==(value=(0,import_core.getByPath)(event,path))?"":(0,import_core.isObject)(value)||Array.isArray(value)?JSON.stringify(value):"string"==typeof value?value:"number"==typeof value||"boolean"==typeof value?String(value):JSON.stringify(value);var value});return"tsv"===format?cells.join("\t")+"\n":cells.map(csvEscape).join(",")+"\n"}function csvEscape(value){return/[",\r\n]/.test(value)?`"${value.replace(/"/g,'""')}"`:value}var states=new Map;function getState(id){return states.get(id)}var types_exports={},destinationFile={type:"file",config:{},init:async({id:id,config:config,env:env,logger:logger})=>{var _a,_b;const partial=null!=(_a=null==config?void 0:config.settings)?_a:{};if(void 0===partial.filename||null===partial.filename)return logger.throw("file destination: 'filename' is required (string or Mapping.Value)"),!1;if(!(0,import_core2.isString)(partial.filename)&&!(0,import_core2.isObject)(partial.filename)&&!Array.isArray(partial.filename))return logger.throw("file destination: 'filename' must be a string or a Mapping.Value"),!1;const format=null!=(_b=partial.format)?_b:"jsonl";if(!("tsv"!==format&&"csv"!==format||partial.fields&&0!==partial.fields.length))return logger.throw(`file destination: format '${format}' requires non-empty 'fields'`),!1;const settings={filename:partial.filename,format:format,fields:partial.fields},state=function(env){const fsOverride=null==env?void 0:env.fs,defaultFs={createWriteStream:(path,options)=>(0,import_node_fs.createWriteStream)(path,options),mkdir:async(path,options)=>{await(0,import_promises.mkdir)(path,options)}};return{handles:new Map,fs:null!=fsOverride?fsOverride:defaultFs}}(env);if((0,import_core2.isString)(settings.filename))try{await ensureHandle(state,settings.filename)}catch(err){return logger.throw(`file destination: failed to open '${settings.filename}': ${err instanceof Error?err.message:String(err)}`),!1}return function(id,state){states.set(id,state)}(id,state),{...config,settings:settings}},push:async(event,{id:id,config:config,collector:collector,logger:logger})=>{var _a;const settings=config.settings;if(!settings)return void logger.warn("file destination: settings missing");const state=getState(id);if(!state)return void logger.warn("file destination: state missing, init may have failed");let filename;if((0,import_core2.isString)(settings.filename))filename=settings.filename;else{const resolved=await(0,import_core2.getMappingValue)(event,settings.filename,{collector:collector});if(!(0,import_core2.isString)(resolved)||0===resolved.length)return void logger.warn("file destination: dynamic filename resolved to empty or non-string, dropping event");filename=resolved}try{(await ensureHandle(state,filename)).write(serialize(event,null!=(_a=settings.format)?_a:"jsonl",settings.fields))}catch(err){logger.warn(`file destination: write failed for ${filename}: ${err instanceof Error?err.message:String(err)}`)}},async destroy({id:id}){const state=getState(id);if(state){for(const handle of state.handles.values())try{handle.end()}catch(e){}state.handles.clear(),function(id){states.delete(id)}(id)}}},index_default=destinationFile;//# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/helpers.ts","../src/types/index.ts"],"sourcesContent":["import { getMappingValue, isString, isObject } from '@walkeros/core';\nimport type { Destination, InitFn, PushFn, Settings } from './types';\nimport {\n createState,\n ensureHandle,\n getState,\n registerState,\n removeState,\n serialize,\n} from './helpers';\n\nexport * as DestinationFile from './types';\n\nconst init: InitFn = async ({ id, config, env, logger }) => {\n const partial = (config?.settings ?? {}) as Partial<Settings>;\n if (partial.filename === undefined || partial.filename === null) {\n logger.throw(\n \"file destination: 'filename' is required (string or Mapping.Value)\",\n );\n return false;\n }\n if (\n !isString(partial.filename) &&\n !(isObject(partial.filename) || Array.isArray(partial.filename))\n ) {\n logger.throw(\n \"file destination: 'filename' must be a string or a Mapping.Value\",\n );\n return false;\n }\n\n const format = partial.format ?? 'jsonl';\n if (\n (format === 'tsv' || format === 'csv') &&\n (!partial.fields || partial.fields.length === 0)\n ) {\n logger.throw(\n `file destination: format '${format}' requires non-empty 'fields'`,\n );\n return false;\n }\n\n const settings: Settings = {\n filename: partial.filename,\n format,\n fields: partial.fields,\n };\n\n const state = createState(env);\n\n // Eager open for static filename — fail-fast on bad path.\n if (isString(settings.filename)) {\n try {\n await ensureHandle(state, settings.filename);\n } catch (err) {\n logger.throw(\n `file destination: failed to open '${settings.filename}': ${\n err instanceof Error ? err.message : String(err)\n }`,\n );\n return false;\n }\n }\n\n registerState(id, state);\n\n return {\n ...config,\n settings,\n };\n};\n\nconst push: PushFn = async (event, { id, config, collector, logger }) => {\n const settings = config.settings as Settings | undefined;\n if (!settings) {\n logger.warn('file destination: settings missing');\n return;\n }\n const state = getState(id);\n if (!state) {\n logger.warn('file destination: state missing, init may have failed');\n return;\n }\n\n let filename: string;\n if (isString(settings.filename)) {\n filename = settings.filename;\n } else {\n const resolved = await getMappingValue(event, settings.filename, {\n collector,\n });\n if (!isString(resolved) || resolved.length === 0) {\n logger.warn(\n 'file destination: dynamic filename resolved to empty or non-string, dropping event',\n );\n return;\n }\n filename = resolved;\n }\n\n try {\n const handle = await ensureHandle(state, filename);\n handle.write(serialize(event, settings.format ?? 'jsonl', settings.fields));\n } catch (err) {\n logger.warn(\n `file destination: write failed for ${filename}: ${\n err instanceof Error ? err.message : String(err)\n }`,\n );\n }\n};\n\nexport const destinationFile: Destination = {\n type: 'file',\n\n config: {},\n\n init,\n\n push,\n\n async destroy({ id }) {\n const state = getState(id);\n if (!state) return;\n for (const handle of state.handles.values()) {\n try {\n handle.end();\n } catch {\n // idempotent — ignore end errors on already-closed streams\n }\n }\n state.handles.clear();\n removeState(id);\n },\n};\n\nexport default destinationFile;\n","import {\n createWriteStream as nodeCreateWriteStream,\n type WriteStream,\n} from 'node:fs';\nimport { mkdir as nodeMkdir } from 'node:fs/promises';\nimport { dirname } from 'node:path';\nimport { getByPath, isObject } from '@walkeros/core';\nimport type { WalkerOS } from '@walkeros/core';\nimport type { Env, FileWriteStream, Format } from './types';\n\n/**\n * State held per destination instance. Created in init(), reused by\n * push() and destroy(). Keyed by a stable instance id so tests and\n * hot-swap do not share handles across instances.\n */\nexport interface State {\n handles: Map<string, FileWriteStream>;\n fs: NonNullable<Env['fs']>;\n}\n\nexport function createState(env: Env | undefined): State {\n const fsOverride = env?.fs;\n const defaultFs: NonNullable<Env['fs']> = {\n createWriteStream: (path: string, options: { flags: string }) =>\n nodeCreateWriteStream(path, options),\n mkdir: async (path: string, options: { recursive: boolean }) => {\n await nodeMkdir(path, options);\n },\n };\n return {\n handles: new Map(),\n fs: fsOverride ?? defaultFs,\n };\n}\n\n/**\n * Idempotent open-or-cache. Ensures the parent directory exists and\n * appends to the file via flag 'a' (creates the file if missing).\n * Used by both init() (eager static open) and push() (lazy per-event open).\n */\nexport async function ensureHandle(\n state: State,\n filename: string,\n): Promise<FileWriteStream> {\n const cached = state.handles.get(filename);\n if (cached) return cached;\n await state.fs.mkdir(dirname(filename) || '.', { recursive: true });\n const handle = state.fs.createWriteStream(filename, {\n flags: 'a',\n }) as FileWriteStream | WriteStream;\n state.handles.set(filename, handle);\n return handle;\n}\n\n/**\n * Format an event into a single output line (with trailing newline).\n * One implementation, used by push() for all three formats.\n */\nexport function serialize(\n event: WalkerOS.Event,\n format: Format,\n fields: string[] | undefined,\n): string {\n if (format === 'jsonl') {\n return JSON.stringify(event) + '\\n';\n }\n if (!fields || fields.length === 0) {\n throw new Error(\n `file destination: format '${format}' requires non-empty 'fields' setting`,\n );\n }\n const cells = fields.map((path) =>\n formatCell(getByPath(event as unknown as WalkerOS.Properties, path)),\n );\n if (format === 'tsv') {\n return cells.join('\\t') + '\\n';\n }\n // csv\n return cells.map(csvEscape).join(',') + '\\n';\n}\n\nfunction formatCell(value: unknown): string {\n if (value === null || value === undefined) return '';\n if (isObject(value) || Array.isArray(value)) return JSON.stringify(value);\n if (typeof value === 'string') return value;\n if (typeof value === 'number' || typeof value === 'boolean')\n return String(value);\n return JSON.stringify(value);\n}\n\n/**\n * RFC 4180 CSV escaping: wrap in quotes if the value contains\n * comma, quote, CR, or LF; double up internal quotes.\n */\nfunction csvEscape(value: string): string {\n if (/[\",\\r\\n]/.test(value)) {\n return `\"${value.replace(/\"/g, '\"\"')}\"`;\n }\n return value;\n}\n\n/**\n * Module-level state map keyed by destination instance id. Plan Task 5\n * documents this as the fallback to config-attached symbols. Each\n * destination instance has a unique id; destroy() removes its entry.\n */\nconst states = new Map<string, State>();\n\nexport function registerState(id: string, state: State): void {\n states.set(id, state);\n}\n\nexport function getState(id: string): State | undefined {\n return states.get(id);\n}\n\nexport function removeState(id: string): void {\n states.delete(id);\n}\n","import type {\n Destination as CoreDestination,\n Mapping as CoreMapping,\n} from '@walkeros/core';\nimport type { DestinationServer } from '@walkeros/server-core';\nimport type { WriteStream } from 'node:fs';\n\nexport type Format = 'jsonl' | 'tsv' | 'csv';\n\nexport interface Settings {\n /**\n * Output filename. Either a static string or a Mapping.Value resolved\n * per event (e.g. tenant sharding via `key`, daily rotation via `$code:` fn).\n * Static filenames are validated and opened at flow startup;\n * dynamic ones at first matching event.\n */\n filename: string | CoreMapping.Value;\n\n /** Serialisation format. Defaults to 'jsonl'. */\n format?: Format;\n\n /**\n * Event paths used as columns for tsv/csv formats. Order preserved.\n * Object values are JSON-stringified into a single cell.\n * Required when format is 'tsv' or 'csv'.\n */\n fields?: string[];\n}\n\nexport type InitSettings = Partial<Settings>;\n\nexport interface Mapping {}\n\n/**\n * Minimal write-stream interface used by the destination. Matches the\n * subset of node:fs WriteStream needed for append-only writes. Tests\n * inject a fake implementation via env.fs.\n */\nexport interface FileWriteStream {\n write: (chunk: string) => boolean;\n end: () => void;\n}\n\nexport interface Env extends DestinationServer.Env {\n /**\n * Override the file system primitives. Tests inject a fake here so\n * disk writes are captured in memory.\n */\n fs?: {\n createWriteStream: (\n path: string,\n options: { flags: string },\n ) => FileWriteStream | WriteStream;\n mkdir: (path: string, options: { recursive: boolean }) => Promise<void>;\n };\n}\n\nexport type Types = CoreDestination.Types<Settings, Mapping, Env, InitSettings>;\n\nexport interface Destination extends DestinationServer.Destination<Types> {\n init: DestinationServer.InitFn<Types>;\n}\n\nexport type Config = {\n settings: Settings;\n} & DestinationServer.Config<Types>;\n\nexport type PartialConfig = DestinationServer.PartialConfig<Types>;\nexport type InitFn = DestinationServer.InitFn<Types>;\nexport type PushFn = DestinationServer.PushFn<Types>;\n"],"mappings":"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","names":["import_core","nodeCreateWriteStream","nodeMkdir"]}
package/dist/index.mjs ADDED
@@ -0,0 +1 @@
1
+ import{getMappingValue,isString,isObject as isObject2}from"@walkeros/core";import{createWriteStream as nodeCreateWriteStream}from"fs";import{mkdir as nodeMkdir}from"fs/promises";import{dirname}from"path";import{getByPath,isObject}from"@walkeros/core";async function ensureHandle(state,filename){const cached=state.handles.get(filename);if(cached)return cached;await state.fs.mkdir(dirname(filename)||".",{recursive:!0});const handle=state.fs.createWriteStream(filename,{flags:"a"});return state.handles.set(filename,handle),handle}function serialize(event,format,fields){if("jsonl"===format)return JSON.stringify(event)+"\n";if(!fields||0===fields.length)throw new Error(`file destination: format '${format}' requires non-empty 'fields' setting`);const cells=fields.map(path=>{return null==(value=getByPath(event,path))?"":isObject(value)||Array.isArray(value)?JSON.stringify(value):"string"==typeof value?value:"number"==typeof value||"boolean"==typeof value?String(value):JSON.stringify(value);var value});return"tsv"===format?cells.join("\t")+"\n":cells.map(csvEscape).join(",")+"\n"}function csvEscape(value){return/[",\r\n]/.test(value)?`"${value.replace(/"/g,'""')}"`:value}var states=new Map;function getState(id){return states.get(id)}var types_exports={},destinationFile={type:"file",config:{},init:async({id:id,config:config,env:env,logger:logger})=>{var _a,_b;const partial=null!=(_a=null==config?void 0:config.settings)?_a:{};if(void 0===partial.filename||null===partial.filename)return logger.throw("file destination: 'filename' is required (string or Mapping.Value)"),!1;if(!isString(partial.filename)&&!isObject2(partial.filename)&&!Array.isArray(partial.filename))return logger.throw("file destination: 'filename' must be a string or a Mapping.Value"),!1;const format=null!=(_b=partial.format)?_b:"jsonl";if(!("tsv"!==format&&"csv"!==format||partial.fields&&0!==partial.fields.length))return logger.throw(`file destination: format '${format}' requires non-empty 'fields'`),!1;const settings={filename:partial.filename,format:format,fields:partial.fields},state=function(env){const fsOverride=null==env?void 0:env.fs,defaultFs={createWriteStream:(path,options)=>nodeCreateWriteStream(path,options),mkdir:async(path,options)=>{await nodeMkdir(path,options)}};return{handles:new Map,fs:null!=fsOverride?fsOverride:defaultFs}}(env);if(isString(settings.filename))try{await ensureHandle(state,settings.filename)}catch(err){return logger.throw(`file destination: failed to open '${settings.filename}': ${err instanceof Error?err.message:String(err)}`),!1}return function(id,state){states.set(id,state)}(id,state),{...config,settings:settings}},push:async(event,{id:id,config:config,collector:collector,logger:logger})=>{var _a;const settings=config.settings;if(!settings)return void logger.warn("file destination: settings missing");const state=getState(id);if(!state)return void logger.warn("file destination: state missing, init may have failed");let filename;if(isString(settings.filename))filename=settings.filename;else{const resolved=await getMappingValue(event,settings.filename,{collector:collector});if(!isString(resolved)||0===resolved.length)return void logger.warn("file destination: dynamic filename resolved to empty or non-string, dropping event");filename=resolved}try{(await ensureHandle(state,filename)).write(serialize(event,null!=(_a=settings.format)?_a:"jsonl",settings.fields))}catch(err){logger.warn(`file destination: write failed for ${filename}: ${err instanceof Error?err.message:String(err)}`)}},async destroy({id:id}){const state=getState(id);if(state){for(const handle of state.handles.values())try{handle.end()}catch(e){}state.handles.clear(),function(id){states.delete(id)}(id)}}},index_default=destinationFile;export{types_exports as DestinationFile,index_default as default,destinationFile};//# sourceMappingURL=index.mjs.map