@nuetzliches/croniq-runner 0.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.
Files changed (67) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +172 -0
  3. package/dist/abort.d.ts +7 -0
  4. package/dist/abort.d.ts.map +1 -0
  5. package/dist/abort.js +31 -0
  6. package/dist/abort.js.map +1 -0
  7. package/dist/client.d.ts +32 -0
  8. package/dist/client.d.ts.map +1 -0
  9. package/dist/client.js +147 -0
  10. package/dist/client.js.map +1 -0
  11. package/dist/context.d.ts +82 -0
  12. package/dist/context.d.ts.map +1 -0
  13. package/dist/context.js +52 -0
  14. package/dist/context.js.map +1 -0
  15. package/dist/deferred.d.ts +18 -0
  16. package/dist/deferred.d.ts.map +1 -0
  17. package/dist/deferred.js +40 -0
  18. package/dist/deferred.js.map +1 -0
  19. package/dist/dispatcher.d.ts +33 -0
  20. package/dist/dispatcher.d.ts.map +1 -0
  21. package/dist/dispatcher.js +159 -0
  22. package/dist/dispatcher.js.map +1 -0
  23. package/dist/duration.d.ts +2 -0
  24. package/dist/duration.d.ts.map +1 -0
  25. package/dist/duration.js +23 -0
  26. package/dist/duration.js.map +1 -0
  27. package/dist/enrichment.d.ts +15 -0
  28. package/dist/enrichment.d.ts.map +1 -0
  29. package/dist/enrichment.js +30 -0
  30. package/dist/enrichment.js.map +1 -0
  31. package/dist/handler.d.ts +35 -0
  32. package/dist/handler.d.ts.map +1 -0
  33. package/dist/handler.js +47 -0
  34. package/dist/handler.js.map +1 -0
  35. package/dist/identity.d.ts +23 -0
  36. package/dist/identity.d.ts.map +1 -0
  37. package/dist/identity.js +64 -0
  38. package/dist/identity.js.map +1 -0
  39. package/dist/index.d.ts +11 -0
  40. package/dist/index.d.ts.map +1 -0
  41. package/dist/index.js +6 -0
  42. package/dist/index.js.map +1 -0
  43. package/dist/log-writer.d.ts +38 -0
  44. package/dist/log-writer.d.ts.map +1 -0
  45. package/dist/log-writer.js +153 -0
  46. package/dist/log-writer.js.map +1 -0
  47. package/dist/logger.d.ts +27 -0
  48. package/dist/logger.d.ts.map +1 -0
  49. package/dist/logger.js +65 -0
  50. package/dist/logger.js.map +1 -0
  51. package/dist/options.d.ts +89 -0
  52. package/dist/options.d.ts.map +1 -0
  53. package/dist/options.js +50 -0
  54. package/dist/options.js.map +1 -0
  55. package/dist/protocol.d.ts +54 -0
  56. package/dist/protocol.d.ts.map +1 -0
  57. package/dist/protocol.js +8 -0
  58. package/dist/protocol.js.map +1 -0
  59. package/dist/runner.d.ts +40 -0
  60. package/dist/runner.d.ts.map +1 -0
  61. package/dist/runner.js +226 -0
  62. package/dist/runner.js.map +1 -0
  63. package/dist/url.d.ts +10 -0
  64. package/dist/url.d.ts.map +1 -0
  65. package/dist/url.js +20 -0
  66. package/dist/url.js.map +1 -0
  67. package/package.json +63 -0
@@ -0,0 +1,33 @@
1
+ import type { CroniqClient } from './client.js';
2
+ import { type HandlerRegistry } from './handler.js';
3
+ import { type Logger } from './logger.js';
4
+ import type { ResolvedRunnerOptions } from './options.js';
5
+ import type { WorkAssignment } from './protocol.js';
6
+ export interface DispatcherDeps {
7
+ client: CroniqClient;
8
+ registry: HandlerRegistry;
9
+ options: ResolvedRunnerOptions;
10
+ runnerId: string;
11
+ runnerTags: readonly string[];
12
+ logger: Logger;
13
+ }
14
+ /**
15
+ * Owns the lifecycle of a single in-flight execution: builds the
16
+ * {@link ExecutionContext}, runs the handler under a per-execution
17
+ * AbortSignal, periodically renews the work-item lease, drains the
18
+ * streaming log writer (if used), and acks the outcome.
19
+ */
20
+ export declare class ExecutionDispatcher {
21
+ #private;
22
+ constructor(deps: DispatcherDeps);
23
+ /**
24
+ * Dispatch a single work assignment.
25
+ *
26
+ * @param executionAC – AbortController owned by the runner; aborted on
27
+ * server-initiated cancel or drain-timeout.
28
+ * @param outerSignal – host shutdown signal. Used to distinguish "draining"
29
+ * from "server-cancelled" when classifying errors.
30
+ */
31
+ dispatch(assignment: WorkAssignment, executionAC: AbortController, outerSignal: AbortSignal): Promise<void>;
32
+ }
33
+ //# sourceMappingURL=dispatcher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dispatcher.d.ts","sourceRoot":"","sources":["../src/dispatcher.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAKhD,OAAO,EAAE,KAAK,eAAe,EAA4B,MAAM,cAAc,CAAC;AAC9E,OAAO,EAAgB,KAAK,MAAM,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAC1D,OAAO,KAAK,EAAyB,cAAc,EAAE,MAAM,eAAe,CAAC;AAE3E,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,YAAY,CAAC;IACrB,QAAQ,EAAE,eAAe,CAAC;IAC1B,OAAO,EAAE,qBAAqB,CAAC;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;IAC9B,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;;GAKG;AACH,qBAAa,mBAAmB;;gBAGlB,IAAI,EAAE,cAAc;IAIhC;;;;;;;OAOG;IACG,QAAQ,CACZ,UAAU,EAAE,cAAc,EAC1B,WAAW,EAAE,eAAe,EAC5B,WAAW,EAAE,WAAW,GACvB,OAAO,CAAC,IAAI,CAAC;CA+HjB"}
@@ -0,0 +1,159 @@
1
+ import { anySignal } from './abort.js';
2
+ import { ExecutionContextImpl } from './context.js';
3
+ import { sleep } from './deferred.js';
4
+ import { parseTimeoutMs } from './duration.js';
5
+ import { LogEnrichment } from './enrichment.js';
6
+ import { NoHandlerRegisteredError } from './handler.js';
7
+ import { scopedLogger } from './logger.js';
8
+ /**
9
+ * Owns the lifecycle of a single in-flight execution: builds the
10
+ * {@link ExecutionContext}, runs the handler under a per-execution
11
+ * AbortSignal, periodically renews the work-item lease, drains the
12
+ * streaming log writer (if used), and acks the outcome.
13
+ */
14
+ export class ExecutionDispatcher {
15
+ #deps;
16
+ constructor(deps) {
17
+ this.#deps = deps;
18
+ }
19
+ /**
20
+ * Dispatch a single work assignment.
21
+ *
22
+ * @param executionAC – AbortController owned by the runner; aborted on
23
+ * server-initiated cancel or drain-timeout.
24
+ * @param outerSignal – host shutdown signal. Used to distinguish "draining"
25
+ * from "server-cancelled" when classifying errors.
26
+ */
27
+ async dispatch(assignment, executionAC, outerSignal) {
28
+ const { client, registry, options, runnerId, runnerTags, logger } = this.#deps;
29
+ const executionId = assignment.execution_id;
30
+ const jobKey = assignment.job_key;
31
+ const attempt = assignment.attempt;
32
+ const timeoutMs = parseTimeoutMs(assignment.timeout) ?? 5 * 60_000;
33
+ const handlerLogger = scopedLogger(logger, {
34
+ execution_id: executionId,
35
+ job_key: jobKey,
36
+ runner_id: runnerId,
37
+ attempt,
38
+ });
39
+ const enrichment = new LogEnrichment(jobKey, runnerId, runnerTags);
40
+ const ctx = new ExecutionContextImpl({
41
+ executionId,
42
+ jobKey,
43
+ attempt,
44
+ metadata: assignment.metadata,
45
+ timeoutMs,
46
+ runnerId,
47
+ runnerTags,
48
+ signal: executionAC.signal,
49
+ logger: handlerLogger,
50
+ client,
51
+ enrichment,
52
+ logWriterOptions: options.logWriter,
53
+ sdkLogger: logger,
54
+ });
55
+ // Lease-renewal loop runs alongside the handler. Linked to the
56
+ // execution's abort signal so server-cancel/drain stops it.
57
+ const renewAC = new AbortController();
58
+ const renewSignal = anySignal(executionAC.signal, renewAC.signal);
59
+ const renewTask = this.#renewLoop(executionId, runnerId, renewSignal);
60
+ const startedAt = Date.now();
61
+ let status;
62
+ let error;
63
+ try {
64
+ const handler = registry.resolve(jobKey);
65
+ if (!handler)
66
+ throw new NoHandlerRegisteredError(jobKey);
67
+ await handler(ctx);
68
+ status = 'success';
69
+ }
70
+ catch (err) {
71
+ if (executionAC.signal.aborted && outerSignal.aborted) {
72
+ status = 'failure';
73
+ error = 'runner draining';
74
+ }
75
+ else if (executionAC.signal.aborted) {
76
+ status = 'failure';
77
+ error = 'cancelled by server';
78
+ }
79
+ else {
80
+ const ex = err instanceof Error ? err : new Error(String(err));
81
+ logger.warn(`handler for ${jobKey} (execution ${executionId}) threw`, {
82
+ error: ex.message,
83
+ job_key: jobKey,
84
+ execution_id: executionId,
85
+ });
86
+ status = 'failure';
87
+ error = ex.message;
88
+ }
89
+ }
90
+ finally {
91
+ renewAC.abort();
92
+ try {
93
+ await renewTask;
94
+ }
95
+ catch {
96
+ // expected on cancellation
97
+ }
98
+ }
99
+ const durationMs = Date.now() - startedAt;
100
+ const writer = ctx.logWriterIfCreated;
101
+ if (writer) {
102
+ try {
103
+ await writer.dispose();
104
+ }
105
+ catch (err) {
106
+ logger.warn(`log_writer drain failed for execution ${executionId}`, {
107
+ error: String(err),
108
+ execution_id: executionId,
109
+ });
110
+ }
111
+ }
112
+ // Ack uses a fresh AbortController so a draining outer signal cannot
113
+ // cancel the final ack POST. Match the .NET SDK's `CancellationToken.None`.
114
+ const ackAC = new AbortController();
115
+ try {
116
+ const payload = {
117
+ runner_id: runnerId,
118
+ execution_id: executionId,
119
+ status,
120
+ attempt,
121
+ duration_ms: durationMs,
122
+ };
123
+ if (error !== undefined)
124
+ payload.error = error;
125
+ await client.ack(payload, ackAC.signal);
126
+ }
127
+ catch (err) {
128
+ logger.error(`failed to ack execution ${executionId}`, {
129
+ error: String(err),
130
+ execution_id: executionId,
131
+ });
132
+ }
133
+ }
134
+ async #renewLoop(executionId, runnerId, signal) {
135
+ const { client, options, logger } = this.#deps;
136
+ while (!signal.aborted) {
137
+ try {
138
+ await sleep(options.renewIntervalMs, signal);
139
+ }
140
+ catch {
141
+ return;
142
+ }
143
+ if (signal.aborted)
144
+ return;
145
+ try {
146
+ await client.renew({ runner_id: runnerId, execution_id: executionId }, signal);
147
+ }
148
+ catch (err) {
149
+ if (signal.aborted)
150
+ return;
151
+ logger.debug(`lease renew failed for execution ${executionId}`, {
152
+ error: String(err),
153
+ execution_id: executionId,
154
+ });
155
+ }
156
+ }
157
+ }
158
+ }
159
+ //# sourceMappingURL=dispatcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dispatcher.js","sourceRoot":"","sources":["../src/dispatcher.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAEvC,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AACtC,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAwB,wBAAwB,EAAE,MAAM,cAAc,CAAC;AAC9E,OAAO,EAAE,YAAY,EAAe,MAAM,aAAa,CAAC;AAaxD;;;;;GAKG;AACH,MAAM,OAAO,mBAAmB;IACrB,KAAK,CAAiB;IAE/B,YAAY,IAAoB;QAC9B,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;IACpB,CAAC;IAED;;;;;;;OAOG;IACH,KAAK,CAAC,QAAQ,CACZ,UAA0B,EAC1B,WAA4B,EAC5B,WAAwB;QAExB,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC;QAC/E,MAAM,WAAW,GAAG,UAAU,CAAC,YAAY,CAAC;QAC5C,MAAM,MAAM,GAAG,UAAU,CAAC,OAAO,CAAC;QAClC,MAAM,OAAO,GAAG,UAAU,CAAC,OAAO,CAAC;QACnC,MAAM,SAAS,GAAG,cAAc,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC;QAEnE,MAAM,aAAa,GAAG,YAAY,CAAC,MAAM,EAAE;YACzC,YAAY,EAAE,WAAW;YACzB,OAAO,EAAE,MAAM;YACf,SAAS,EAAE,QAAQ;YACnB,OAAO;SACR,CAAC,CAAC;QACH,MAAM,UAAU,GAAG,IAAI,aAAa,CAAC,MAAM,EAAE,QAAQ,EAAE,UAAU,CAAC,CAAC;QAEnE,MAAM,GAAG,GAAG,IAAI,oBAAoB,CAAC;YACnC,WAAW;YACX,MAAM;YACN,OAAO;YACP,QAAQ,EAAE,UAAU,CAAC,QAAQ;YAC7B,SAAS;YACT,QAAQ;YACR,UAAU;YACV,MAAM,EAAE,WAAW,CAAC,MAAM;YAC1B,MAAM,EAAE,aAAa;YACrB,MAAM;YACN,UAAU;YACV,gBAAgB,EAAE,OAAO,CAAC,SAAS;YACnC,SAAS,EAAE,MAAM;SAClB,CAAC,CAAC;QAEH,+DAA+D;QAC/D,4DAA4D;QAC5D,MAAM,OAAO,GAAG,IAAI,eAAe,EAAE,CAAC;QACtC,MAAM,WAAW,GAAG,SAAS,CAAC,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;QAClE,MAAM,SAAS,GAAG,IAAI,CAAC,UAAU,CAAC,WAAW,EAAE,QAAQ,EAAE,WAAW,CAAC,CAAC;QAEtE,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC7B,IAAI,MAAiB,CAAC;QACtB,IAAI,KAAyB,CAAC;QAE9B,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;YACzC,IAAI,CAAC,OAAO;gBAAE,MAAM,IAAI,wBAAwB,CAAC,MAAM,CAAC,CAAC;YACzD,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC;YACnB,MAAM,GAAG,SAAS,CAAC;QACrB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,WAAW,CAAC,MAAM,CAAC,OAAO,IAAI,WAAW,CAAC,OAAO,EAAE,CAAC;gBACtD,MAAM,GAAG,SAAS,CAAC;gBACnB,KAAK,GAAG,iBAAiB,CAAC;YAC5B,CAAC;iBAAM,IAAI,WAAW,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;gBACtC,MAAM,GAAG,SAAS,CAAC;gBACnB,KAAK,GAAG,qBAAqB,CAAC;YAChC,CAAC;iBAAM,CAAC;gBACN,MAAM,EAAE,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;gBAC/D,MAAM,CAAC,IAAI,CAAC,eAAe,MAAM,eAAe,WAAW,SAAS,EAAE;oBACpE,KAAK,EAAE,EAAE,CAAC,OAAO;oBACjB,OAAO,EAAE,MAAM;oBACf,YAAY,EAAE,WAAW;iBAC1B,CAAC,CAAC;gBACH,MAAM,GAAG,SAAS,CAAC;gBACnB,KAAK,GAAG,EAAE,CAAC,OAAO,CAAC;YACrB,CAAC;QACH,CAAC;gBAAS,CAAC;YACT,OAAO,CAAC,KAAK,EAAE,CAAC;YAChB,IAAI,CAAC;gBACH,MAAM,SAAS,CAAC;YAClB,CAAC;YAAC,MAAM,CAAC;gBACP,2BAA2B;YAC7B,CAAC;QACH,CAAC;QAED,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;QAE1C,MAAM,MAAM,GAAG,GAAG,CAAC,kBAAkB,CAAC;QACtC,IAAI,MAAM,EAAE,CAAC;YACX,IAAI,CAAC;gBACH,MAAM,MAAM,CAAC,OAAO,EAAE,CAAC;YACzB,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,MAAM,CAAC,IAAI,CAAC,yCAAyC,WAAW,EAAE,EAAE;oBAClE,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC;oBAClB,YAAY,EAAE,WAAW;iBAC1B,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,qEAAqE;QACrE,4EAA4E;QAC5E,MAAM,KAAK,GAAG,IAAI,eAAe,EAAE,CAAC;QACpC,IAAI,CAAC;YACH,MAAM,OAAO,GAAe;gBAC1B,SAAS,EAAE,QAAQ;gBACnB,YAAY,EAAE,WAAW;gBACzB,MAAM;gBACN,OAAO;gBACP,WAAW,EAAE,UAAU;aACxB,CAAC;YACF,IAAI,KAAK,KAAK,SAAS;gBAAE,OAAO,CAAC,KAAK,GAAG,KAAK,CAAC;YAC/C,MAAM,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;QAC1C,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,CAAC,KAAK,CAAC,2BAA2B,WAAW,EAAE,EAAE;gBACrD,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC;gBAClB,YAAY,EAAE,WAAW;aAC1B,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,WAAmB,EAAE,QAAgB,EAAE,MAAmB;QACzE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC;QAC/C,OAAO,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACvB,IAAI,CAAC;gBACH,MAAM,KAAK,CAAC,OAAO,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC;YAC/C,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO;YACT,CAAC;YACD,IAAI,MAAM,CAAC,OAAO;gBAAE,OAAO;YAC3B,IAAI,CAAC;gBACH,MAAM,MAAM,CAAC,KAAK,CAAC,EAAE,SAAS,EAAE,QAAQ,EAAE,YAAY,EAAE,WAAW,EAAE,EAAE,MAAM,CAAC,CAAC;YACjF,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,IAAI,MAAM,CAAC,OAAO;oBAAE,OAAO;gBAC3B,MAAM,CAAC,KAAK,CAAC,oCAAoC,WAAW,EAAE,EAAE;oBAC9D,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC;oBAClB,YAAY,EAAE,WAAW;iBAC1B,CAAC,CAAC;YACL,CAAC;QACH,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1,2 @@
1
+ export declare function parseTimeoutMs(raw: string | undefined | null): number | undefined;
2
+ //# sourceMappingURL=duration.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"duration.d.ts","sourceRoot":"","sources":["../src/duration.ts"],"names":[],"mappings":"AAIA,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,MAAM,GAAG,SAAS,CAejF"}
@@ -0,0 +1,23 @@
1
+ // Humane duration strings (e.g. "5m", "30s", "1h") emitted by the Croniq
2
+ // server in `WorkAssignment.timeout`. The .NET SDK supports `s/m/h/d`; we
3
+ // match that vocabulary here so the same server output parses identically.
4
+ export function parseTimeoutMs(raw) {
5
+ if (raw == null)
6
+ return undefined;
7
+ const text = String(raw).trim().toLowerCase();
8
+ if (text.length < 2)
9
+ return undefined;
10
+ const unit = text[text.length - 1];
11
+ const valueStr = text.slice(0, -1);
12
+ const value = Number(valueStr);
13
+ if (!Number.isFinite(value))
14
+ return undefined;
15
+ switch (unit) {
16
+ case 's': return value * 1_000;
17
+ case 'm': return value * 60_000;
18
+ case 'h': return value * 3_600_000;
19
+ case 'd': return value * 86_400_000;
20
+ default: return undefined;
21
+ }
22
+ }
23
+ //# sourceMappingURL=duration.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"duration.js","sourceRoot":"","sources":["../src/duration.ts"],"names":[],"mappings":"AAAA,yEAAyE;AACzE,0EAA0E;AAC1E,2EAA2E;AAE3E,MAAM,UAAU,cAAc,CAAC,GAA8B;IAC3D,IAAI,GAAG,IAAI,IAAI;QAAE,OAAO,SAAS,CAAC;IAClC,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC9C,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,SAAS,CAAC;IACtC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACnC,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACnC,MAAM,KAAK,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC;IAC/B,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IAC9C,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,GAAG,CAAC,CAAC,OAAO,KAAK,GAAG,KAAK,CAAC;QAC/B,KAAK,GAAG,CAAC,CAAC,OAAO,KAAK,GAAG,MAAM,CAAC;QAChC,KAAK,GAAG,CAAC,CAAC,OAAO,KAAK,GAAG,SAAS,CAAC;QACnC,KAAK,GAAG,CAAC,CAAC,OAAO,KAAK,GAAG,UAAU,CAAC;QACpC,OAAO,CAAC,CAAC,OAAO,SAAS,CAAC;IAC5B,CAAC;AACH,CAAC"}
@@ -0,0 +1,15 @@
1
+ import type { WorkEvent } from './protocol.js';
2
+ /**
3
+ * Per-execution helper that injects `job_key`, `runner_id`, and (when set)
4
+ * `runner_tags` into every event's `fields` map. Explicit caller values win
5
+ * — the enricher uses `TryAdd` semantics, so a handler that puts an
6
+ * `runner_id` in its own fields keeps that override.
7
+ *
8
+ * Mirrors `LogEnrichment` from the .NET SDK.
9
+ */
10
+ export declare class LogEnrichment {
11
+ #private;
12
+ constructor(jobKey: string, runnerId: string, runnerTags: readonly string[]);
13
+ enrich(source: WorkEvent): WorkEvent;
14
+ }
15
+ //# sourceMappingURL=enrichment.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"enrichment.d.ts","sourceRoot":"","sources":["../src/enrichment.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAE/C;;;;;;;GAOG;AACH,qBAAa,aAAa;;gBAKZ,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,MAAM,EAAE;IAM3E,MAAM,CAAC,MAAM,EAAE,SAAS,GAAG,SAAS;CASrC"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Per-execution helper that injects `job_key`, `runner_id`, and (when set)
3
+ * `runner_tags` into every event's `fields` map. Explicit caller values win
4
+ * — the enricher uses `TryAdd` semantics, so a handler that puts an
5
+ * `runner_id` in its own fields keeps that override.
6
+ *
7
+ * Mirrors `LogEnrichment` from the .NET SDK.
8
+ */
9
+ export class LogEnrichment {
10
+ #jobKey;
11
+ #runnerId;
12
+ #serializedTags;
13
+ constructor(jobKey, runnerId, runnerTags) {
14
+ this.#jobKey = jobKey;
15
+ this.#runnerId = runnerId;
16
+ this.#serializedTags = runnerTags.length === 0 ? undefined : JSON.stringify(runnerTags);
17
+ }
18
+ enrich(source) {
19
+ const fields = { ...(source.fields ?? {}) };
20
+ if (!('job_key' in fields))
21
+ fields.job_key = this.#jobKey;
22
+ if (!('runner_id' in fields))
23
+ fields.runner_id = this.#runnerId;
24
+ if (this.#serializedTags !== undefined && !('runner_tags' in fields)) {
25
+ fields.runner_tags = this.#serializedTags;
26
+ }
27
+ return { ...source, fields };
28
+ }
29
+ }
30
+ //# sourceMappingURL=enrichment.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"enrichment.js","sourceRoot":"","sources":["../src/enrichment.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AACH,MAAM,OAAO,aAAa;IACf,OAAO,CAAS;IAChB,SAAS,CAAS;IAClB,eAAe,CAAqB;IAE7C,YAAY,MAAc,EAAE,QAAgB,EAAE,UAA6B;QACzE,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC;QACtB,IAAI,CAAC,SAAS,GAAG,QAAQ,CAAC;QAC1B,IAAI,CAAC,eAAe,GAAG,UAAU,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;IAC1F,CAAC;IAED,MAAM,CAAC,MAAiB;QACtB,MAAM,MAAM,GAA2B,EAAE,GAAG,CAAC,MAAM,CAAC,MAAM,IAAI,EAAE,CAAC,EAAE,CAAC;QACpE,IAAI,CAAC,CAAC,SAAS,IAAI,MAAM,CAAC;YAAE,MAAM,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;QAC1D,IAAI,CAAC,CAAC,WAAW,IAAI,MAAM,CAAC;YAAE,MAAM,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC;QAChE,IAAI,IAAI,CAAC,eAAe,KAAK,SAAS,IAAI,CAAC,CAAC,aAAa,IAAI,MAAM,CAAC,EAAE,CAAC;YACrE,MAAM,CAAC,WAAW,GAAG,IAAI,CAAC,eAAe,CAAC;QAC5C,CAAC;QACD,OAAO,EAAE,GAAG,MAAM,EAAE,MAAM,EAAE,CAAC;IAC/B,CAAC;CACF"}
@@ -0,0 +1,35 @@
1
+ import type { ExecutionContext } from './context.js';
2
+ export type JobHandler = (ctx: ExecutionContext) => void | Promise<void>;
3
+ export interface JobRegistrationOptions {
4
+ /**
5
+ * If set, the runner calls `POST /v1/jobs/register` with this schedule
6
+ * string at startup. Format follows the Croniqfile interval/cron syntax,
7
+ * e.g. `"5m"`, `"1h"`, or a 5-field crontab expression.
8
+ */
9
+ schedule?: string;
10
+ /** Server-side timeout to register with the schedule (e.g. `"10m"`). */
11
+ timeout?: string;
12
+ /** Human-readable description for the registered job. */
13
+ description?: string;
14
+ }
15
+ export interface SelfRegisterEntry {
16
+ jobKey: string;
17
+ schedule: string;
18
+ timeout: string | undefined;
19
+ description: string | undefined;
20
+ }
21
+ /** Map of `job_key` → handler, plus an optional default handler. */
22
+ export declare class HandlerRegistry {
23
+ #private;
24
+ register(jobKey: string, handler: JobHandler, opts?: JobRegistrationOptions): void;
25
+ registerDefault(handler: JobHandler): void;
26
+ resolve(jobKey: string): JobHandler | undefined;
27
+ get selfRegister(): readonly SelfRegisterEntry[];
28
+ get hasDefault(): boolean;
29
+ get keys(): readonly string[];
30
+ }
31
+ export declare class NoHandlerRegisteredError extends Error {
32
+ readonly jobKey: string;
33
+ constructor(jobKey: string);
34
+ }
35
+ //# sourceMappingURL=handler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../src/handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAErD,MAAM,MAAM,UAAU,GAAG,CAAC,GAAG,EAAE,gBAAgB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAEzE,MAAM,WAAW,sBAAsB;IACrC;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,wEAAwE;IACxE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,yDAAyD;IACzD,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;CACjC;AAED,oEAAoE;AACpE,qBAAa,eAAe;;IAK1B,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,IAAI,CAAC,EAAE,sBAAsB,GAAG,IAAI;IAclF,eAAe,CAAC,OAAO,EAAE,UAAU,GAAG,IAAI;IAK1C,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS;IAI/C,IAAI,YAAY,IAAI,SAAS,iBAAiB,EAAE,CAE/C;IAED,IAAI,UAAU,IAAI,OAAO,CAExB;IAED,IAAI,IAAI,IAAI,SAAS,MAAM,EAAE,CAE5B;CACF;AAED,qBAAa,wBAAyB,SAAQ,KAAK;aACrB,MAAM,EAAE,MAAM;gBAAd,MAAM,EAAE,MAAM;CAI3C"}
@@ -0,0 +1,47 @@
1
+ /** Map of `job_key` → handler, plus an optional default handler. */
2
+ export class HandlerRegistry {
3
+ #handlers = new Map();
4
+ #selfRegister = [];
5
+ #default;
6
+ register(jobKey, handler, opts) {
7
+ if (!jobKey)
8
+ throw new TypeError('jobKey is required');
9
+ if (typeof handler !== 'function')
10
+ throw new TypeError('handler must be a function');
11
+ this.#handlers.set(jobKey, handler);
12
+ if (opts?.schedule) {
13
+ this.#selfRegister.push({
14
+ jobKey,
15
+ schedule: opts.schedule,
16
+ timeout: opts.timeout,
17
+ description: opts.description,
18
+ });
19
+ }
20
+ }
21
+ registerDefault(handler) {
22
+ if (typeof handler !== 'function')
23
+ throw new TypeError('handler must be a function');
24
+ this.#default = handler;
25
+ }
26
+ resolve(jobKey) {
27
+ return this.#handlers.get(jobKey) ?? this.#default;
28
+ }
29
+ get selfRegister() {
30
+ return this.#selfRegister;
31
+ }
32
+ get hasDefault() {
33
+ return this.#default !== undefined;
34
+ }
35
+ get keys() {
36
+ return [...this.#handlers.keys()];
37
+ }
38
+ }
39
+ export class NoHandlerRegisteredError extends Error {
40
+ jobKey;
41
+ constructor(jobKey) {
42
+ super(`No handler registered for job '${jobKey}' and no default handler configured`);
43
+ this.jobKey = jobKey;
44
+ this.name = 'NoHandlerRegisteredError';
45
+ }
46
+ }
47
+ //# sourceMappingURL=handler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handler.js","sourceRoot":"","sources":["../src/handler.ts"],"names":[],"mappings":"AAwBA,oEAAoE;AACpE,MAAM,OAAO,eAAe;IACjB,SAAS,GAAG,IAAI,GAAG,EAAsB,CAAC;IAC1C,aAAa,GAAwB,EAAE,CAAC;IACjD,QAAQ,CAAyB;IAEjC,QAAQ,CAAC,MAAc,EAAE,OAAmB,EAAE,IAA6B;QACzE,IAAI,CAAC,MAAM;YAAE,MAAM,IAAI,SAAS,CAAC,oBAAoB,CAAC,CAAC;QACvD,IAAI,OAAO,OAAO,KAAK,UAAU;YAAE,MAAM,IAAI,SAAS,CAAC,4BAA4B,CAAC,CAAC;QACrF,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACpC,IAAI,IAAI,EAAE,QAAQ,EAAE,CAAC;YACnB,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC;gBACtB,MAAM;gBACN,QAAQ,EAAE,IAAI,CAAC,QAAQ;gBACvB,OAAO,EAAE,IAAI,CAAC,OAAO;gBACrB,WAAW,EAAE,IAAI,CAAC,WAAW;aAC9B,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,eAAe,CAAC,OAAmB;QACjC,IAAI,OAAO,OAAO,KAAK,UAAU;YAAE,MAAM,IAAI,SAAS,CAAC,4BAA4B,CAAC,CAAC;QACrF,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC;IAC1B,CAAC;IAED,OAAO,CAAC,MAAc;QACpB,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC;IACrD,CAAC;IAED,IAAI,YAAY;QACd,OAAO,IAAI,CAAC,aAAa,CAAC;IAC5B,CAAC;IAED,IAAI,UAAU;QACZ,OAAO,IAAI,CAAC,QAAQ,KAAK,SAAS,CAAC;IACrC,CAAC;IAED,IAAI,IAAI;QACN,OAAO,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,CAAC;IACpC,CAAC;CACF;AAED,MAAM,OAAO,wBAAyB,SAAQ,KAAK;IACrB;IAA5B,YAA4B,MAAc;QACxC,KAAK,CAAC,kCAAkC,MAAM,qCAAqC,CAAC,CAAC;QAD3D,WAAM,GAAN,MAAM,CAAQ;QAExC,IAAI,CAAC,IAAI,GAAG,0BAA0B,CAAC;IACzC,CAAC;CACF"}
@@ -0,0 +1,23 @@
1
+ import type { Logger } from './logger.js';
2
+ export interface IdentityResolverInput {
3
+ /** Explicit runner-id from configuration. */
4
+ runnerId?: string | undefined;
5
+ /** Prefix used when generating a fresh id. */
6
+ runnerIdPrefix: string;
7
+ /** Optional data dir override. Falls back to env var, then platform default. */
8
+ runnerDataDir?: string | undefined;
9
+ }
10
+ /**
11
+ * Resolves the runner ID with the same precedence as the .NET / Rust SDKs:
12
+ *
13
+ * 1. Explicit option
14
+ * 2. `RUNNER_ID` env var
15
+ * 3. Persisted `runner-id` state file under {@link IdentityResolverInput.runnerDataDir}
16
+ * (or `CRONIQ_RUNNER_DATA_DIR`, or the platform default)
17
+ * 4. Newly generated `{prefix}-{hex8}`, persisted to the state file
18
+ *
19
+ * If persistence fails (filesystem read-only etc.), returns a deterministic
20
+ * `{prefix}-{hostname}` fallback so the runner can still start.
21
+ */
22
+ export declare function resolveRunnerId(input: IdentityResolverInput, logger: Logger): string;
23
+ //# sourceMappingURL=identity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"identity.d.ts","sourceRoot":"","sources":["../src/identity.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C,MAAM,WAAW,qBAAqB;IACpC,6CAA6C;IAC7C,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,8CAA8C;IAC9C,cAAc,EAAE,MAAM,CAAC;IACvB,gFAAgF;IAChF,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACpC;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,qBAAqB,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CA4BpF"}
@@ -0,0 +1,64 @@
1
+ import { randomBytes } from 'node:crypto';
2
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
3
+ import { homedir, hostname } from 'node:os';
4
+ import { join } from 'node:path';
5
+ /**
6
+ * Resolves the runner ID with the same precedence as the .NET / Rust SDKs:
7
+ *
8
+ * 1. Explicit option
9
+ * 2. `RUNNER_ID` env var
10
+ * 3. Persisted `runner-id` state file under {@link IdentityResolverInput.runnerDataDir}
11
+ * (or `CRONIQ_RUNNER_DATA_DIR`, or the platform default)
12
+ * 4. Newly generated `{prefix}-{hex8}`, persisted to the state file
13
+ *
14
+ * If persistence fails (filesystem read-only etc.), returns a deterministic
15
+ * `{prefix}-{hostname}` fallback so the runner can still start.
16
+ */
17
+ export function resolveRunnerId(input, logger) {
18
+ if (input.runnerId && input.runnerId.length > 0)
19
+ return input.runnerId;
20
+ const fromEnv = process.env.RUNNER_ID;
21
+ if (fromEnv && fromEnv.length > 0)
22
+ return fromEnv;
23
+ const dataDir = resolveDataDir(input.runnerDataDir);
24
+ const idFile = join(dataDir, 'runner-id');
25
+ try {
26
+ if (existsSync(idFile)) {
27
+ const persisted = readFileSync(idFile, 'utf8').trim();
28
+ if (persisted.length > 0)
29
+ return persisted;
30
+ }
31
+ }
32
+ catch (err) {
33
+ logger.warn(`could not read persisted runner ID from ${idFile}`, { error: String(err) });
34
+ }
35
+ const generated = `${input.runnerIdPrefix}-${randomBytes(4).toString('hex')}`;
36
+ try {
37
+ mkdirSync(dataDir, { recursive: true });
38
+ writeFileSync(idFile, generated, 'utf8');
39
+ }
40
+ catch (err) {
41
+ logger.warn(`could not persist generated runner ID to ${idFile}`, { error: String(err) });
42
+ return `${input.runnerIdPrefix}-${hostname().toLowerCase()}`;
43
+ }
44
+ return generated;
45
+ }
46
+ function resolveDataDir(override) {
47
+ if (override && override.length > 0)
48
+ return override;
49
+ const fromEnv = process.env.CRONIQ_RUNNER_DATA_DIR;
50
+ if (fromEnv && fromEnv.length > 0)
51
+ return fromEnv;
52
+ // Platform-appropriate state directory.
53
+ // On Linux/macOS use $XDG_STATE_HOME or ~/.local/state; on Windows use %LOCALAPPDATA%.
54
+ if (process.platform === 'win32') {
55
+ const localAppData = process.env.LOCALAPPDATA ?? join(homedir(), 'AppData', 'Local');
56
+ return join(localAppData, 'croniq-runner');
57
+ }
58
+ const xdgStateHome = process.env.XDG_STATE_HOME;
59
+ const base = xdgStateHome && xdgStateHome.length > 0
60
+ ? xdgStateHome
61
+ : join(homedir(), '.local', 'state');
62
+ return join(base, 'croniq-runner');
63
+ }
64
+ //# sourceMappingURL=identity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"identity.js","sourceRoot":"","sources":["../src/identity.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ export { CroniqRunner, createRunner } from './runner.js';
2
+ export type { CroniqRunnerOptions, LogWriterOptions, ResolvedRunnerOptions, ResolvedLogWriterOptions, } from './options.js';
3
+ export type { ExecutionContext } from './context.js';
4
+ export type { JobHandler, JobRegistrationOptions } from './handler.js';
5
+ export { NoHandlerRegisteredError } from './handler.js';
6
+ export type { Logger, LogLevel } from './logger.js';
7
+ export { consoleLogger, noopLogger } from './logger.js';
8
+ export type { LogWriter } from './log-writer.js';
9
+ export type { AckRequest, AckStatus, PollRequest, PollResponse, RegisterJobRequest, RegisterJobResponse, RenewRequest, WorkAssignment, WorkEvent, WorkEventLevel, } from './protocol.js';
10
+ export { HttpError } from './client.js';
11
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AACzD,YAAY,EACV,mBAAmB,EACnB,gBAAgB,EAChB,qBAAqB,EACrB,wBAAwB,GACzB,MAAM,cAAc,CAAC;AACtB,YAAY,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACrD,YAAY,EAAE,UAAU,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;AACvE,OAAO,EAAE,wBAAwB,EAAE,MAAM,cAAc,CAAC;AACxD,YAAY,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACxD,YAAY,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,YAAY,EACV,UAAU,EACV,SAAS,EACT,WAAW,EACX,YAAY,EACZ,kBAAkB,EAClB,mBAAmB,EACnB,YAAY,EACZ,cAAc,EACd,SAAS,EACT,cAAc,GACf,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,6 @@
1
+ // Public API surface for `@nuetzliches/croniq-runner`.
2
+ export { CroniqRunner, createRunner } from './runner.js';
3
+ export { NoHandlerRegisteredError } from './handler.js';
4
+ export { consoleLogger, noopLogger } from './logger.js';
5
+ export { HttpError } from './client.js';
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,uDAAuD;AAEvD,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AASzD,OAAO,EAAE,wBAAwB,EAAE,MAAM,cAAc,CAAC;AAExD,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAcxD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,38 @@
1
+ import type { CroniqClient } from './client.js';
2
+ import type { LogEnrichment } from './enrichment.js';
3
+ import type { Logger } from './logger.js';
4
+ import type { ResolvedLogWriterOptions } from './options.js';
5
+ import type { WorkEvent, WorkEventLevel } from './protocol.js';
6
+ export interface LogWriter {
7
+ /** Append an event. Awaits a slot if the bounded buffer is full. */
8
+ write(level: WorkEventLevel, message: string, fields?: Record<string, string>): Promise<void>;
9
+ /** Append a pre-built event. */
10
+ writeEvent(event: WorkEvent): Promise<void>;
11
+ /** Block until every queued event has been POSTed. */
12
+ flush(): Promise<void>;
13
+ /**
14
+ * Close the writer and wait for the background flusher to drain, bounded
15
+ * by `shutdownTimeoutMs`. Safe to call multiple times.
16
+ */
17
+ dispose(): Promise<void>;
18
+ }
19
+ /**
20
+ * Streaming log writer. Backed by a bounded in-memory buffer and a single
21
+ * background flusher coroutine; mirrors the .NET / Rust SDKs:
22
+ *
23
+ * - Batch by count: flush when {@link ResolvedLogWriterOptions.batchSizeThreshold} events accumulate.
24
+ * - Batch by time: flush at least every {@link ResolvedLogWriterOptions.batchTimeThresholdMs} ms.
25
+ * - Drain-before-ack: {@link dispose} waits up to `shutdownTimeoutMs` for the buffer to flush.
26
+ * - Backpressure: {@link write} awaits when the buffer is at capacity.
27
+ *
28
+ * Enrichment runs at POST time (`job_key`, `runner_id`, `runner_tags`).
29
+ */
30
+ export declare class StreamingLogWriter implements LogWriter {
31
+ #private;
32
+ constructor(client: CroniqClient, executionId: string, enrichment: LogEnrichment, opts: ResolvedLogWriterOptions, logger: Logger);
33
+ write(level: WorkEventLevel, message: string, fields?: Record<string, string>): Promise<void>;
34
+ writeEvent(event: WorkEvent): Promise<void>;
35
+ flush(): Promise<void>;
36
+ dispose(): Promise<void>;
37
+ }
38
+ //# sourceMappingURL=log-writer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"log-writer.d.ts","sourceRoot":"","sources":["../src/log-writer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,cAAc,CAAC;AAC7D,OAAO,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAE/D,MAAM,WAAW,SAAS;IACxB,oEAAoE;IACpE,KAAK,CAAC,KAAK,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9F,gCAAgC;IAChC,UAAU,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5C,sDAAsD;IACtD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB;;;OAGG;IACH,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1B;AAED;;;;;;;;;;GAUG;AACH,qBAAa,kBAAmB,YAAW,SAAS;;gBAkBhD,MAAM,EAAE,YAAY,EACpB,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,aAAa,EACzB,IAAI,EAAE,wBAAwB,EAC9B,MAAM,EAAE,MAAM;IAUV,KAAK,CAAC,KAAK,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAK7F,UAAU,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IAUjD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAQhB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CAyG/B"}