@workflow/world-local 5.0.0-beta.10 → 5.0.0-beta.11

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.
Files changed (63) hide show
  1. package/dist/config.d.ts +23 -5
  2. package/dist/config.d.ts.map +1 -1
  3. package/dist/config.js +19 -14
  4. package/dist/fs.d.ts +113 -2
  5. package/dist/fs.d.ts.map +1 -1
  6. package/dist/fs.js +321 -28
  7. package/dist/index.d.ts +16 -2
  8. package/dist/index.d.ts.map +1 -1
  9. package/dist/index.js +97 -6
  10. package/dist/init.d.ts +91 -0
  11. package/dist/init.d.ts.map +1 -0
  12. package/dist/init.js +268 -0
  13. package/dist/instrumentObject.d.ts +8 -0
  14. package/dist/instrumentObject.d.ts.map +1 -0
  15. package/dist/instrumentObject.js +66 -0
  16. package/dist/queue.d.ts +8 -1
  17. package/dist/queue.d.ts.map +1 -1
  18. package/dist/queue.js +195 -54
  19. package/dist/storage/events-storage.d.ts +7 -0
  20. package/dist/storage/events-storage.d.ts.map +1 -0
  21. package/dist/storage/events-storage.js +898 -0
  22. package/dist/storage/filters.d.ts +22 -0
  23. package/dist/storage/filters.d.ts.map +1 -0
  24. package/dist/storage/filters.js +33 -0
  25. package/dist/storage/helpers.d.ts +18 -0
  26. package/dist/storage/helpers.d.ts.map +1 -0
  27. package/dist/storage/helpers.js +44 -0
  28. package/dist/storage/hooks-storage.d.ts +12 -0
  29. package/dist/storage/hooks-storage.d.ts.map +1 -0
  30. package/dist/storage/hooks-storage.js +93 -0
  31. package/dist/storage/index.d.ts +21 -0
  32. package/dist/storage/index.d.ts.map +1 -0
  33. package/dist/storage/index.js +30 -0
  34. package/dist/storage/legacy.d.ts +13 -0
  35. package/dist/storage/legacy.d.ts.map +1 -0
  36. package/dist/storage/legacy.js +78 -0
  37. package/dist/storage/runs-storage.d.ts +33 -0
  38. package/dist/storage/runs-storage.d.ts.map +1 -0
  39. package/dist/storage/runs-storage.js +130 -0
  40. package/dist/storage/steps-storage.d.ts +7 -0
  41. package/dist/storage/steps-storage.d.ts.map +1 -0
  42. package/dist/storage/steps-storage.js +52 -0
  43. package/dist/storage.d.ts +9 -2
  44. package/dist/storage.d.ts.map +1 -1
  45. package/dist/storage.js +9 -456
  46. package/dist/streamer.d.ts +4 -2
  47. package/dist/streamer.d.ts.map +1 -1
  48. package/dist/streamer.js +467 -107
  49. package/dist/telemetry.d.ts +28 -0
  50. package/dist/telemetry.d.ts.map +1 -0
  51. package/dist/telemetry.js +71 -0
  52. package/dist/test-helpers.d.ts +54 -0
  53. package/dist/test-helpers.d.ts.map +1 -0
  54. package/dist/test-helpers.js +118 -0
  55. package/dist/util.js +1 -1
  56. package/package.json +12 -11
  57. package/dist/config.js.map +0 -1
  58. package/dist/fs.js.map +0 -1
  59. package/dist/index.js.map +0 -1
  60. package/dist/queue.js.map +0 -1
  61. package/dist/storage.js.map +0 -1
  62. package/dist/streamer.js.map +0 -1
  63. package/dist/util.js.map +0 -1
package/dist/config.d.ts CHANGED
@@ -3,17 +3,35 @@ export type Config = {
3
3
  dataDir: string;
4
4
  port?: number;
5
5
  baseUrl?: string;
6
+ /**
7
+ * Whether start() should re-enqueue pending/running runs from storage.
8
+ * Defaults to true. Test harnesses that always start from a clean slate can
9
+ * disable recovery to avoid replaying stale runs.
10
+ */
11
+ recoverActiveRuns?: boolean;
12
+ /**
13
+ * Optional tag to scope filesystem operations.
14
+ * When set, files are written as `{id}.{tag}.json` and `clear()` only deletes
15
+ * files matching this tag. Used by vitest to isolate test data in the shared
16
+ * `.workflow-data` directory.
17
+ */
18
+ tag?: string;
19
+ /**
20
+ * Override the flush interval (in ms) for buffered stream writes.
21
+ * Default is 10ms. Set to 0 for immediate flushing.
22
+ */
23
+ streamFlushIntervalMs?: number;
6
24
  };
7
25
  export declare const config: {
8
26
  readonly value: Config;
9
27
  };
10
28
  /**
11
29
  * Resolves the base URL for queue requests following the priority order:
12
- * 1. config.baseUrl (highest priority - full override from args or WORKFLOW_EMBEDDED_BASE_URL env var)
13
- * 2. config.port (explicit port override from args)
14
- * 3. Auto-detected port via pid-port (primary approach)
15
- * 4. PORT env var (fallback)
16
- * 5. Fallback to 3000
30
+ * 1. config.baseUrl (highest priority - full override from args)
31
+ * 2. WORKFLOW_LOCAL_BASE_URL env var (checked directly to handle late env var setting)
32
+ * 3. config.port (explicit port override from args)
33
+ * 4. PORT env var (explicit configuration)
34
+ * 5. Auto-detected port via getPort (detect actual listening port)
17
35
  */
18
36
  export declare function resolveBaseUrl(config: Partial<Config>): Promise<string>;
19
37
  //# sourceMappingURL=config.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,2BAA2B,QAAQ,CAAC;AAMjD,MAAM,MAAM,MAAM,GAAG;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,eAAO,MAAM,MAAM;;CAKjB,CAAC;AAEH;;;;;;;GAOG;AACH,wBAAsB,cAAc,CAAC,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CAmB7E"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,2BAA2B,QAAQ,CAAC;AAMjD,MAAM,MAAM,MAAM,GAAG;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B;;;;;OAKG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;;;OAGG;IACH,qBAAqB,CAAC,EAAE,MAAM,CAAC;CAChC,CAAC;AAEF,eAAO,MAAM,MAAM;;CAKjB,CAAC;AAEH;;;;;;;GAOG;AACH,wBAAsB,cAAc,CAAC,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CAyB7E"}
package/dist/config.js CHANGED
@@ -1,11 +1,11 @@
1
- import { getPort } from '@workflow/utils/get-port';
1
+ import { getWorkflowPort } from '@workflow/utils/get-port';
2
2
  import { once } from './util.js';
3
3
  const getDataDirFromEnv = () => {
4
- return process.env.WORKFLOW_EMBEDDED_DATA_DIR || '.workflow-data';
4
+ return process.env.WORKFLOW_LOCAL_DATA_DIR || '.workflow-data';
5
5
  };
6
6
  export const DEFAULT_RESOLVE_DATA_OPTION = 'all';
7
7
  const getBaseUrlFromEnv = () => {
8
- return process.env.WORKFLOW_EMBEDDED_BASE_URL;
8
+ return process.env.WORKFLOW_LOCAL_BASE_URL;
9
9
  };
10
10
  export const config = once(() => {
11
11
  const dataDir = getDataDirFromEnv();
@@ -14,26 +14,31 @@ export const config = once(() => {
14
14
  });
15
15
  /**
16
16
  * Resolves the base URL for queue requests following the priority order:
17
- * 1. config.baseUrl (highest priority - full override from args or WORKFLOW_EMBEDDED_BASE_URL env var)
18
- * 2. config.port (explicit port override from args)
19
- * 3. Auto-detected port via pid-port (primary approach)
20
- * 4. PORT env var (fallback)
21
- * 5. Fallback to 3000
17
+ * 1. config.baseUrl (highest priority - full override from args)
18
+ * 2. WORKFLOW_LOCAL_BASE_URL env var (checked directly to handle late env var setting)
19
+ * 3. config.port (explicit port override from args)
20
+ * 4. PORT env var (explicit configuration)
21
+ * 5. Auto-detected port via getPort (detect actual listening port)
22
22
  */
23
23
  export async function resolveBaseUrl(config) {
24
24
  if (config.baseUrl) {
25
25
  return config.baseUrl;
26
26
  }
27
+ // Check env var directly in case it was set after the config was cached
28
+ // This is important for CLI tools that set the env var after module import
29
+ if (process.env.WORKFLOW_LOCAL_BASE_URL) {
30
+ return process.env.WORKFLOW_LOCAL_BASE_URL;
31
+ }
27
32
  if (typeof config.port === 'number') {
28
33
  return `http://localhost:${config.port}`;
29
34
  }
30
- const detectedPort = await getPort();
31
- if (detectedPort) {
32
- return `http://localhost:${detectedPort}`;
33
- }
34
35
  if (process.env.PORT) {
35
36
  return `http://localhost:${process.env.PORT}`;
36
37
  }
37
- return 'http://localhost:3000';
38
+ const detectedPort = await getWorkflowPort();
39
+ if (detectedPort) {
40
+ return `http://localhost:${detectedPort}`;
41
+ }
42
+ throw new Error('Unable to resolve base URL for workflow queue.');
38
43
  }
39
- //# sourceMappingURL=config.js.map
44
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29uZmlnLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL2NvbmZpZy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFDM0QsT0FBTyxFQUFFLElBQUksRUFBRSxNQUFNLFdBQVcsQ0FBQztBQUVqQyxNQUFNLGlCQUFpQixHQUFHLEdBQUcsRUFBRTtJQUM3QixPQUFPLE9BQU8sQ0FBQyxHQUFHLENBQUMsdUJBQXVCLElBQUksZ0JBQWdCLENBQUM7QUFDakUsQ0FBQyxDQUFDO0FBRUYsTUFBTSxDQUFDLE1BQU0sMkJBQTJCLEdBQUcsS0FBSyxDQUFDO0FBRWpELE1BQU0saUJBQWlCLEdBQUcsR0FBRyxFQUFFO0lBQzdCLE9BQU8sT0FBTyxDQUFDLEdBQUcsQ0FBQyx1QkFBdUIsQ0FBQztBQUM3QyxDQUFDLENBQUM7QUEwQkYsTUFBTSxDQUFDLE1BQU0sTUFBTSxHQUFHLElBQUksQ0FBUyxHQUFHLEVBQUU7SUFDdEMsTUFBTSxPQUFPLEdBQUcsaUJBQWlCLEVBQUUsQ0FBQztJQUNwQyxNQUFNLE9BQU8sR0FBRyxpQkFBaUIsRUFBRSxDQUFDO0lBRXBDLE9BQU8sRUFBRSxPQUFPLEVBQUUsT0FBTyxFQUFFLENBQUM7QUFDOUIsQ0FBQyxDQUFDLENBQUM7QUFFSDs7Ozs7OztHQU9HO0FBQ0gsTUFBTSxDQUFDLEtBQUssVUFBVSxjQUFjLENBQUMsTUFBdUI7SUFDMUQsSUFBSSxNQUFNLENBQUMsT0FBTyxFQUFFLENBQUM7UUFDbkIsT0FBTyxNQUFNLENBQUMsT0FBTyxDQUFDO0lBQ3hCLENBQUM7SUFFRCx3RUFBd0U7SUFDeEUsMkVBQTJFO0lBQzNFLElBQUksT0FBTyxDQUFDLEdBQUcsQ0FBQyx1QkFBdUIsRUFBRSxDQUFDO1FBQ3hDLE9BQU8sT0FBTyxDQUFDLEdBQUcsQ0FBQyx1QkFBdUIsQ0FBQztJQUM3QyxDQUFDO0lBRUQsSUFBSSxPQUFPLE1BQU0sQ0FBQyxJQUFJLEtBQUssUUFBUSxFQUFFLENBQUM7UUFDcEMsT0FBTyxvQkFBb0IsTUFBTSxDQUFDLElBQUksRUFBRSxDQUFDO0lBQzNDLENBQUM7SUFFRCxJQUFJLE9BQU8sQ0FBQyxHQUFHLENBQUMsSUFBSSxFQUFFLENBQUM7UUFDckIsT0FBTyxvQkFBb0IsT0FBTyxDQUFDLEdBQUcsQ0FBQyxJQUFJLEVBQUUsQ0FBQztJQUNoRCxDQUFDO0lBRUQsTUFBTSxZQUFZLEdBQUcsTUFBTSxlQUFlLEVBQUUsQ0FBQztJQUM3QyxJQUFJLFlBQVksRUFBRSxDQUFDO1FBQ2pCLE9BQU8sb0JBQW9CLFlBQVksRUFBRSxDQUFDO0lBQzVDLENBQUM7SUFFRCxNQUFNLElBQUksS0FBSyxDQUFDLGdEQUFnRCxDQUFDLENBQUM7QUFDcEUsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IGdldFdvcmtmbG93UG9ydCB9IGZyb20gJ0B3b3JrZmxvdy91dGlscy9nZXQtcG9ydCc7XG5pbXBvcnQgeyBvbmNlIH0gZnJvbSAnLi91dGlsLmpzJztcblxuY29uc3QgZ2V0RGF0YURpckZyb21FbnYgPSAoKSA9PiB7XG4gIHJldHVybiBwcm9jZXNzLmVudi5XT1JLRkxPV19MT0NBTF9EQVRBX0RJUiB8fCAnLndvcmtmbG93LWRhdGEnO1xufTtcblxuZXhwb3J0IGNvbnN0IERFRkFVTFRfUkVTT0xWRV9EQVRBX09QVElPTiA9ICdhbGwnO1xuXG5jb25zdCBnZXRCYXNlVXJsRnJvbUVudiA9ICgpID0+IHtcbiAgcmV0dXJuIHByb2Nlc3MuZW52LldPUktGTE9XX0xPQ0FMX0JBU0VfVVJMO1xufTtcblxuZXhwb3J0IHR5cGUgQ29uZmlnID0ge1xuICBkYXRhRGlyOiBzdHJpbmc7XG4gIHBvcnQ/OiBudW1iZXI7XG4gIGJhc2VVcmw/OiBzdHJpbmc7XG4gIC8qKlxuICAgKiBXaGV0aGVyIHN0YXJ0KCkgc2hvdWxkIHJlLWVucXVldWUgcGVuZGluZy9ydW5uaW5nIHJ1bnMgZnJvbSBzdG9yYWdlLlxuICAgKiBEZWZhdWx0cyB0byB0cnVlLiBUZXN0IGhhcm5lc3NlcyB0aGF0IGFsd2F5cyBzdGFydCBmcm9tIGEgY2xlYW4gc2xhdGUgY2FuXG4gICAqIGRpc2FibGUgcmVjb3ZlcnkgdG8gYXZvaWQgcmVwbGF5aW5nIHN0YWxlIHJ1bnMuXG4gICAqL1xuICByZWNvdmVyQWN0aXZlUnVucz86IGJvb2xlYW47XG4gIC8qKlxuICAgKiBPcHRpb25hbCB0YWcgdG8gc2NvcGUgZmlsZXN5c3RlbSBvcGVyYXRpb25zLlxuICAgKiBXaGVuIHNldCwgZmlsZXMgYXJlIHdyaXR0ZW4gYXMgYHtpZH0ue3RhZ30uanNvbmAgYW5kIGBjbGVhcigpYCBvbmx5IGRlbGV0ZXNcbiAgICogZmlsZXMgbWF0Y2hpbmcgdGhpcyB0YWcuIFVzZWQgYnkgdml0ZXN0IHRvIGlzb2xhdGUgdGVzdCBkYXRhIGluIHRoZSBzaGFyZWRcbiAgICogYC53b3JrZmxvdy1kYXRhYCBkaXJlY3RvcnkuXG4gICAqL1xuICB0YWc/OiBzdHJpbmc7XG4gIC8qKlxuICAgKiBPdmVycmlkZSB0aGUgZmx1c2ggaW50ZXJ2YWwgKGluIG1zKSBmb3IgYnVmZmVyZWQgc3RyZWFtIHdyaXRlcy5cbiAgICogRGVmYXVsdCBpcyAxMG1zLiBTZXQgdG8gMCBmb3IgaW1tZWRpYXRlIGZsdXNoaW5nLlxuICAgKi9cbiAgc3RyZWFtRmx1c2hJbnRlcnZhbE1zPzogbnVtYmVyO1xufTtcblxuZXhwb3J0IGNvbnN0IGNvbmZpZyA9IG9uY2U8Q29uZmlnPigoKSA9PiB7XG4gIGNvbnN0IGRhdGFEaXIgPSBnZXREYXRhRGlyRnJvbUVudigpO1xuICBjb25zdCBiYXNlVXJsID0gZ2V0QmFzZVVybEZyb21FbnYoKTtcblxuICByZXR1cm4geyBkYXRhRGlyLCBiYXNlVXJsIH07XG59KTtcblxuLyoqXG4gKiBSZXNvbHZlcyB0aGUgYmFzZSBVUkwgZm9yIHF1ZXVlIHJlcXVlc3RzIGZvbGxvd2luZyB0aGUgcHJpb3JpdHkgb3JkZXI6XG4gKiAxLiBjb25maWcuYmFzZVVybCAoaGlnaGVzdCBwcmlvcml0eSAtIGZ1bGwgb3ZlcnJpZGUgZnJvbSBhcmdzKVxuICogMi4gV09SS0ZMT1dfTE9DQUxfQkFTRV9VUkwgZW52IHZhciAoY2hlY2tlZCBkaXJlY3RseSB0byBoYW5kbGUgbGF0ZSBlbnYgdmFyIHNldHRpbmcpXG4gKiAzLiBjb25maWcucG9ydCAoZXhwbGljaXQgcG9ydCBvdmVycmlkZSBmcm9tIGFyZ3MpXG4gKiA0LiBQT1JUIGVudiB2YXIgKGV4cGxpY2l0IGNvbmZpZ3VyYXRpb24pXG4gKiA1LiBBdXRvLWRldGVjdGVkIHBvcnQgdmlhIGdldFBvcnQgKGRldGVjdCBhY3R1YWwgbGlzdGVuaW5nIHBvcnQpXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiByZXNvbHZlQmFzZVVybChjb25maWc6IFBhcnRpYWw8Q29uZmlnPik6IFByb21pc2U8c3RyaW5nPiB7XG4gIGlmIChjb25maWcuYmFzZVVybCkge1xuICAgIHJldHVybiBjb25maWcuYmFzZVVybDtcbiAgfVxuXG4gIC8vIENoZWNrIGVudiB2YXIgZGlyZWN0bHkgaW4gY2FzZSBpdCB3YXMgc2V0IGFmdGVyIHRoZSBjb25maWcgd2FzIGNhY2hlZFxuICAvLyBUaGlzIGlzIGltcG9ydGFudCBmb3IgQ0xJIHRvb2xzIHRoYXQgc2V0IHRoZSBlbnYgdmFyIGFmdGVyIG1vZHVsZSBpbXBvcnRcbiAgaWYgKHByb2Nlc3MuZW52LldPUktGTE9XX0xPQ0FMX0JBU0VfVVJMKSB7XG4gICAgcmV0dXJuIHByb2Nlc3MuZW52LldPUktGTE9XX0xPQ0FMX0JBU0VfVVJMO1xuICB9XG5cbiAgaWYgKHR5cGVvZiBjb25maWcucG9ydCA9PT0gJ251bWJlcicpIHtcbiAgICByZXR1cm4gYGh0dHA6Ly9sb2NhbGhvc3Q6JHtjb25maWcucG9ydH1gO1xuICB9XG5cbiAgaWYgKHByb2Nlc3MuZW52LlBPUlQpIHtcbiAgICByZXR1cm4gYGh0dHA6Ly9sb2NhbGhvc3Q6JHtwcm9jZXNzLmVudi5QT1JUfWA7XG4gIH1cblxuICBjb25zdCBkZXRlY3RlZFBvcnQgPSBhd2FpdCBnZXRXb3JrZmxvd1BvcnQoKTtcbiAgaWYgKGRldGVjdGVkUG9ydCkge1xuICAgIHJldHVybiBgaHR0cDovL2xvY2FsaG9zdDoke2RldGVjdGVkUG9ydH1gO1xuICB9XG5cbiAgdGhyb3cgbmV3IEVycm9yKCdVbmFibGUgdG8gcmVzb2x2ZSBiYXNlIFVSTCBmb3Igd29ya2Zsb3cgcXVldWUuJyk7XG59XG4iXX0=
package/dist/fs.d.ts CHANGED
@@ -1,20 +1,132 @@
1
+ import { WorkflowWorldError } from '@workflow/errors';
1
2
  import type { PaginatedResponse } from '@workflow/world';
2
3
  import { z } from 'zod';
3
- export declare function ulidToDate(maybeUlid: string): Date | null;
4
+ /**
5
+ * Thrown when a caller-supplied entity ID contains characters that would
6
+ * escape the storage root (path traversal) or otherwise produce an unsafe
7
+ * filename. Extends {@link WorkflowWorldError} so the platform's standard
8
+ * error-to-HTTP mapping handles it alongside other world-layer errors.
9
+ */
10
+ export declare class UnsafeEntityIdError extends WorkflowWorldError {
11
+ constructor(kind: string, value: string);
12
+ static is(value: unknown): value is UnsafeEntityIdError;
13
+ }
14
+ /**
15
+ * Validate that a string is safe to embed in a filesystem path as a single
16
+ * path component. Rejects values that are:
17
+ * - empty
18
+ * - starting with `.` (blocks `.`, `..`, `.locks`, `.tmp`, and other
19
+ * hidden or reserved filenames)
20
+ * - containing `.` (would collide with the `.tag` / `.json` suffix the
21
+ * tagging logic strips from filenames; see {@link stripTag} /
22
+ * {@link getObjectCreatedAt})
23
+ * - containing `/`, `\`, or a NUL byte
24
+ *
25
+ * This is the primary defense against path-traversal attacks where a
26
+ * request body supplies a `runId` / `stepId` / `correlationId` containing
27
+ * `../` sequences to read or write files outside the storage root.
28
+ * {@link resolveWithinBase} provides a belt-and-suspenders containment
29
+ * check at the point of `path.join` for defense in depth.
30
+ *
31
+ * @param kind - Human-readable label used in the error message (e.g. "runId")
32
+ * @param value - The value to validate; throws {@link UnsafeEntityIdError}
33
+ * if the value is not safe.
34
+ */
35
+ export declare function assertSafeEntityId(kind: string, value: string): void;
36
+ /**
37
+ * Join `basedir` with an entity-relative path and assert the result stays
38
+ * inside `basedir`. Complements {@link assertSafeEntityId}: per-entry-point
39
+ * validation is the primary defense, and this final check catches any path
40
+ * escape that slipped past (e.g. a new call site that forgot to validate,
41
+ * or an unusual character combination on a future filesystem). Throws
42
+ * {@link UnsafeEntityIdError} if the joined path escapes `basedir`.
43
+ */
44
+ export declare function resolveWithinBase(basedir: string, ...segments: string[]): string;
45
+ /**
46
+ * Clear the created files cache. Useful for testing or when files are deleted externally.
47
+ */
48
+ export declare function clearCreatedFilesCache(): void;
49
+ export { ulidToDate } from '@workflow/world';
50
+ /**
51
+ * Strip a tag suffix from a fileId.
52
+ * `wrun_ABC.vitest-0` → `wrun_ABC`
53
+ * `wrun_ABC` → `wrun_ABC` (no-op if no tag)
54
+ */
55
+ export declare function stripTag(fileId: string): string;
56
+ /**
57
+ * Check whether a fileId belongs to a specific tag.
58
+ * `wrun_ABC.vitest-0` belongs to `vitest-0`.
59
+ * Untagged fileIds never match a tag-scoped lookup.
60
+ */
61
+ export declare function hasTag(fileId: string, tag: string): boolean;
62
+ /**
63
+ * Build the file path for an entity, with optional tag embedded in the filename.
64
+ * `taggedPath('/data', 'runs', 'wrun_ABC', 'vitest-0')` → `/data/runs/wrun_ABC.vitest-0.json`
65
+ * `taggedPath('/data', 'runs', 'wrun_ABC')` → `/data/runs/wrun_ABC.json`
66
+ *
67
+ * The `fileId` and `tag` are validated with {@link assertSafeEntityId} and
68
+ * the result is containment-checked with {@link resolveWithinBase} to
69
+ * prevent path-traversal attacks when values are derived from untrusted
70
+ * request input.
71
+ */
72
+ export declare function taggedPath(basedir: string, entityDir: string, fileId: string, tag?: string): string;
73
+ /**
74
+ * Read a JSON entity with tagged fallback.
75
+ * When a tag is set, tries the tagged path first, then falls back to the
76
+ * untagged path (so a tagged world can read entities written without a tag).
77
+ */
78
+ export declare function readJSONWithFallback<T>(basedir: string, entityDir: string, fileId: string, schema: z.ZodType<T>, tag?: string): Promise<T | null>;
79
+ /**
80
+ * List all filenames in a directory that have a specific tag.
81
+ * Returns full filenames (e.g., `wrun_ABC.vitest-0.json`).
82
+ */
83
+ export declare function listTaggedFiles(dirPath: string, tag: string): Promise<string[]>;
84
+ /**
85
+ * List all filenames in a directory that have a specific tag and extension.
86
+ * Returns full filenames (e.g., `stream-chnk_ABC.vitest-0.bin`).
87
+ */
88
+ export declare function listTaggedFilesByExtension(dirPath: string, tag: string, extension: string): Promise<string[]>;
4
89
  export declare function ensureDir(dirPath: string): Promise<void>;
5
90
  interface WriteOptions {
6
91
  overwrite?: boolean;
7
92
  }
93
+ /**
94
+ * Custom JSON replacer that encodes Uint8Array as base64 strings.
95
+ * Format: { __type: 'Uint8Array', data: '<base64>' }
96
+ */
97
+ export declare function jsonReplacer(_key: string, value: unknown): unknown;
98
+ /**
99
+ * Custom JSON reviver that decodes base64 strings back to Uint8Array.
100
+ */
101
+ export declare function jsonReviver(_key: string, value: unknown): unknown;
8
102
  export declare function writeJSON(filePath: string, data: any, opts?: WriteOptions): Promise<void>;
103
+ /**
104
+ * Writes data to a file using atomic write-rename pattern.
105
+ *
106
+ * Note: While this function uses temp files to avoid partial writes,
107
+ * it does not provide protection against concurrent writes from multiple
108
+ * processes. In a multi-writer scenario, the last writer wins.
109
+ * For production use with multiple writers, consider using a proper
110
+ * database or locking mechanism.
111
+ */
9
112
  export declare function write(filePath: string, data: string | Buffer, opts?: WriteOptions): Promise<void>;
10
113
  export declare function readJSON<T>(filePath: string, decoder: z.ZodType<T>): Promise<T | null>;
11
114
  export declare function readBuffer(filePath: string): Promise<Buffer>;
115
+ export declare function readFirstByte(filePath: string): Promise<number | undefined>;
12
116
  export declare function deleteJSON(filePath: string): Promise<void>;
117
+ /**
118
+ * Atomically create a file using O_CREAT | O_EXCL flags.
119
+ * Returns true if the file was created, false if it already exists.
120
+ * This is atomic at the OS level, safe for concurrent access.
121
+ */
122
+ export declare function writeExclusive(filePath: string, data: string): Promise<boolean>;
13
123
  export declare function listJSONFiles(dirPath: string): Promise<string[]>;
124
+ export declare function listFilesByExtension(dirPath: string, extension: string): Promise<string[]>;
14
125
  interface PaginatedFileSystemQueryConfig<T> {
15
126
  directory: string;
16
127
  schema: z.ZodType<T>;
17
128
  filePrefix?: string;
129
+ fileIdFilter?: (fileId: string) => boolean;
18
130
  filter?: (item: T) => boolean;
19
131
  sortOrder?: 'asc' | 'desc';
20
132
  limit?: number;
@@ -25,5 +137,4 @@ interface PaginatedFileSystemQueryConfig<T> {
25
137
  export declare function paginatedFileSystemQuery<T extends {
26
138
  createdAt: Date;
27
139
  }>(config: PaginatedFileSystemQueryConfig<T>): Promise<PaginatedResponse<T>>;
28
- export {};
29
140
  //# sourceMappingURL=fs.d.ts.map
package/dist/fs.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"fs.d.ts","sourceRoot":"","sources":["../src/fs.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAEzD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAMxB,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAOzD;AAED,wBAAsB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAM9D;AAED,UAAU,YAAY;IACpB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,wBAAsB,SAAS,CAC7B,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,GAAG,EACT,IAAI,CAAC,EAAE,YAAY,GAClB,OAAO,CAAC,IAAI,CAAC,CAEf;AAED,wBAAsB,KAAK,CACzB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,GAAG,MAAM,EACrB,IAAI,CAAC,EAAE,YAAY,GAClB,OAAO,CAAC,IAAI,CAAC,CAyBf;AAED,wBAAsB,QAAQ,CAAC,CAAC,EAC9B,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GACpB,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAQnB;AAED,wBAAsB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAGlE;AAED,wBAAsB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAMhE;AAED,wBAAsB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAUtE;AAED,UAAU,8BAA8B,CAAC,CAAC;IACxC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC;IAC9B,SAAS,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAAC;IAC5C,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC,GAAG,MAAM,CAAC;CACzB;AAqBD,wBAAsB,wBAAwB,CAAC,CAAC,SAAS;IAAE,SAAS,EAAE,IAAI,CAAA;CAAE,EAC1E,MAAM,EAAE,8BAA8B,CAAC,CAAC,CAAC,GACxC,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAoI/B"}
1
+ {"version":3,"file":"fs.d.ts","sourceRoot":"","sources":["../src/fs.ts"],"names":[],"mappings":"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"}