@sanoma-ai/workflows 0.6.0 → 0.7.1

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 (166) hide show
  1. package/README.md +52 -14
  2. package/dist/apply.d.ts +2 -1
  3. package/dist/apply.js +29 -7
  4. package/dist/apply.js.map +1 -1
  5. package/dist/approvals.d.ts +27 -2
  6. package/dist/approvals.js +73 -9
  7. package/dist/approvals.js.map +1 -1
  8. package/dist/call.d.ts +3 -2
  9. package/dist/call.js +38 -30
  10. package/dist/call.js.map +1 -1
  11. package/dist/cedar.js +24 -9
  12. package/dist/cedar.js.map +1 -1
  13. package/dist/change.d.ts +219 -0
  14. package/dist/change.js +150 -0
  15. package/dist/change.js.map +1 -0
  16. package/dist/chats.d.ts +43 -0
  17. package/dist/chats.js +48 -0
  18. package/dist/chats.js.map +1 -0
  19. package/dist/client.d.ts +52 -6
  20. package/dist/client.js +88 -47
  21. package/dist/client.js.map +1 -1
  22. package/dist/config.d.ts +75 -8
  23. package/dist/config.js +103 -13
  24. package/dist/config.js.map +1 -1
  25. package/dist/constructors.d.ts +37 -1
  26. package/dist/constructors.js +6 -2
  27. package/dist/constructors.js.map +1 -1
  28. package/dist/database.d.ts +83 -0
  29. package/dist/database.js +92 -0
  30. package/dist/database.js.map +1 -0
  31. package/dist/db.d.ts +19 -1
  32. package/dist/db.js +51 -7
  33. package/dist/db.js.map +1 -1
  34. package/dist/deadlines.d.ts +91 -0
  35. package/dist/deadlines.js +165 -0
  36. package/dist/deadlines.js.map +1 -0
  37. package/dist/define.d.ts +25 -4
  38. package/dist/define.js +40 -0
  39. package/dist/define.js.map +1 -1
  40. package/dist/demo.d.ts +28 -0
  41. package/dist/demo.js +72 -0
  42. package/dist/demo.js.map +1 -0
  43. package/dist/describe.d.ts +5 -2
  44. package/dist/describe.js +10 -6
  45. package/dist/describe.js.map +1 -1
  46. package/dist/errors.d.ts +10 -1
  47. package/dist/errors.js +13 -0
  48. package/dist/errors.js.map +1 -1
  49. package/dist/fake.d.ts +34 -0
  50. package/dist/fake.js +134 -1
  51. package/dist/fake.js.map +1 -1
  52. package/dist/grid.d.ts +34 -0
  53. package/dist/grid.js +62 -0
  54. package/dist/grid.js.map +1 -0
  55. package/dist/host.d.ts +12 -2
  56. package/dist/host.js +2 -2
  57. package/dist/host.js.map +1 -1
  58. package/dist/index.d.ts +15 -8
  59. package/dist/index.js +10 -5
  60. package/dist/index.js.map +1 -1
  61. package/dist/ledger.d.ts +11 -2
  62. package/dist/ledger.js.map +1 -1
  63. package/dist/lint.js +2 -2
  64. package/dist/lint.js.map +1 -1
  65. package/dist/op.d.ts +21 -2
  66. package/dist/op.js.map +1 -1
  67. package/dist/person.d.ts +5 -0
  68. package/dist/person.js +3 -1
  69. package/dist/person.js.map +1 -1
  70. package/dist/policy.d.ts +7 -1
  71. package/dist/policy.js +2 -1
  72. package/dist/policy.js.map +1 -1
  73. package/dist/resource.d.ts +13 -1
  74. package/dist/resource.js +9 -1
  75. package/dist/resource.js.map +1 -1
  76. package/dist/resources.d.ts +2 -0
  77. package/dist/resources.js +15 -4
  78. package/dist/resources.js.map +1 -1
  79. package/dist/run.d.ts +5 -0
  80. package/dist/run.js.map +1 -1
  81. package/dist/sandbox.d.ts +38 -10
  82. package/dist/sandbox.js +66 -35
  83. package/dist/sandbox.js.map +1 -1
  84. package/dist/scenario.d.ts +18 -1
  85. package/dist/scenario.js +77 -27
  86. package/dist/scenario.js.map +1 -1
  87. package/dist/scenarios.d.ts +10 -1
  88. package/dist/scenarios.js +19 -4
  89. package/dist/scenarios.js.map +1 -1
  90. package/dist/schedules.d.ts +66 -0
  91. package/dist/schedules.js +158 -0
  92. package/dist/schedules.js.map +1 -0
  93. package/dist/schema.d.ts +6 -0
  94. package/dist/schema.js +13 -3
  95. package/dist/schema.js.map +1 -1
  96. package/dist/shared.d.ts +30 -2
  97. package/dist/shared.js +42 -4
  98. package/dist/shared.js.map +1 -1
  99. package/dist/source.d.ts +185 -2
  100. package/dist/source.js +9 -0
  101. package/dist/source.js.map +1 -1
  102. package/dist/supervisor.d.ts +39 -0
  103. package/dist/supervisor.js +68 -0
  104. package/dist/supervisor.js.map +1 -0
  105. package/dist/version.d.ts +3 -1
  106. package/dist/version.js +3 -1
  107. package/dist/version.js.map +1 -1
  108. package/dist/wakeup-driver.d.ts +128 -0
  109. package/dist/wakeup-driver.js +216 -0
  110. package/dist/wakeup-driver.js.map +1 -0
  111. package/dist/wakeup-service.d.ts +83 -0
  112. package/dist/wakeup-service.js +415 -0
  113. package/dist/wakeup-service.js.map +1 -0
  114. package/dist/wakeup-type.d.ts +43 -0
  115. package/dist/wakeup-type.js +80 -0
  116. package/dist/wakeup-type.js.map +1 -0
  117. package/dist/wakeup.d.ts +77 -0
  118. package/dist/wakeup.js +78 -0
  119. package/dist/wakeup.js.map +1 -0
  120. package/dist/worker.d.ts +39 -1
  121. package/dist/worker.js +125 -38
  122. package/dist/worker.js.map +1 -1
  123. package/oxlint.json +3 -1
  124. package/package.json +10 -2
  125. package/src/apply.ts +25 -6
  126. package/src/approvals.ts +89 -16
  127. package/src/call.ts +40 -29
  128. package/src/cedar.ts +24 -6
  129. package/src/change.ts +222 -0
  130. package/src/chats.ts +114 -0
  131. package/src/client.ts +145 -55
  132. package/src/config.ts +149 -21
  133. package/src/constructors.ts +8 -2
  134. package/src/database.ts +152 -0
  135. package/src/db.ts +58 -9
  136. package/src/deadlines.ts +228 -0
  137. package/src/define.ts +71 -4
  138. package/src/demo.ts +87 -0
  139. package/src/describe.ts +18 -6
  140. package/src/errors.ts +14 -0
  141. package/src/fake.ts +149 -0
  142. package/src/grid.ts +100 -0
  143. package/src/host.ts +12 -4
  144. package/src/index.ts +66 -3
  145. package/src/ledger.ts +15 -3
  146. package/src/lint.ts +2 -2
  147. package/src/op.ts +22 -2
  148. package/src/person.ts +4 -1
  149. package/src/policy.ts +7 -1
  150. package/src/resource.ts +22 -3
  151. package/src/resources.ts +17 -4
  152. package/src/run.ts +5 -0
  153. package/src/sandbox.ts +97 -37
  154. package/src/scenario.ts +97 -28
  155. package/src/scenarios.ts +21 -5
  156. package/src/schedules.ts +206 -0
  157. package/src/schema.ts +16 -3
  158. package/src/shared.ts +51 -4
  159. package/src/source.ts +176 -3
  160. package/src/supervisor.ts +102 -0
  161. package/src/version.ts +3 -1
  162. package/src/wakeup-driver.ts +270 -0
  163. package/src/wakeup-service.ts +504 -0
  164. package/src/wakeup-type.ts +90 -0
  165. package/src/wakeup.ts +139 -0
  166. package/src/worker.ts +176 -43
@@ -0,0 +1,68 @@
1
+ import { warn } from "./log.js";
2
+ import { errorMessage } from "./shared.js";
3
+ import { startWorker } from "./worker.js";
4
+ /**
5
+ * Starts a worker on `config` that stops itself when idle with a wakeup declared (`onStopped`
6
+ * in `WorkerOptions`), and a fresh one each time `resume` or `wake` asks after it did. Throws
7
+ * when the first does not start. A write heard while a worker starts or runs may land after its last check
8
+ * for being idle, so a worker that stops itself after one is started again at once: it stops
9
+ * again on its own when nothing came of it.
10
+ */
11
+ export async function superviseWorker(config, options = {}) {
12
+ const { onStopped, selfStop = true, ...workerOptions } = options;
13
+ let worker;
14
+ let starting;
15
+ let closed = false;
16
+ // A write while the worker starts or runs, since it began starting.
17
+ let heard = false;
18
+ const launch = async () => {
19
+ heard = false;
20
+ const started = await startWorker(config, { ...workerOptions, ...(selfStop && { onStopped: selfStopped }) });
21
+ if (closed)
22
+ await started.stop();
23
+ else
24
+ worker = started;
25
+ };
26
+ const selfStopped = (stopped) => {
27
+ worker = undefined;
28
+ if (closed)
29
+ return;
30
+ // Resumed first, so `stopped` is false when `onStopped` looks.
31
+ if (heard)
32
+ void supervisor.resume();
33
+ onStopped?.(stopped);
34
+ };
35
+ const supervisor = {
36
+ get stopped() {
37
+ return !closed && !worker && !starting;
38
+ },
39
+ resume() {
40
+ if (closed)
41
+ return Promise.resolve();
42
+ if (worker) {
43
+ heard = true;
44
+ return Promise.resolve();
45
+ }
46
+ if (starting) {
47
+ heard = true;
48
+ return starting;
49
+ }
50
+ return (starting = launch()
51
+ .catch((err) => warn(`the worker could not start again: ${errorMessage(err)}`))
52
+ .finally(() => {
53
+ starting = undefined;
54
+ }));
55
+ },
56
+ wake: () => (supervisor.stopped ? supervisor.resume() : Promise.resolve()),
57
+ async stop() {
58
+ closed = true;
59
+ await starting;
60
+ const running = worker;
61
+ worker = undefined;
62
+ await running?.stop();
63
+ },
64
+ };
65
+ await launch();
66
+ return supervisor;
67
+ }
68
+ //# sourceMappingURL=supervisor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"supervisor.js","sourceRoot":"","sources":["../src/supervisor.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AAChC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,WAAW,EAAmC,MAAM,aAAa,CAAC;AAqC3E;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,MAAoB,EAAE,OAAO,GAAsB,EAAE;IACzF,MAAM,EAAE,SAAS,EAAE,QAAQ,GAAG,IAAI,EAAE,GAAG,aAAa,EAAE,GAAG,OAAO,CAAC;IACjE,IAAI,MAA0B,CAAC;IAC/B,IAAI,QAAmC,CAAC;IACxC,IAAI,MAAM,GAAG,KAAK,CAAC;IACnB,oEAAoE;IACpE,IAAI,KAAK,GAAG,KAAK,CAAC;IAElB,MAAM,MAAM,GAAG,KAAK,IAAI,EAAE;QACxB,KAAK,GAAG,KAAK,CAAC;QACd,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,MAAM,EAAE,EAAE,GAAG,aAAa,EAAE,GAAG,CAAC,QAAQ,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,CAAC,EAAE,CAAC,CAAC;QAC7G,IAAI,MAAM;YAAE,MAAM,OAAO,CAAC,IAAI,EAAE,CAAC;;YAC5B,MAAM,GAAG,OAAO,CAAC;IACxB,CAAC,CAAC;IACF,MAAM,WAAW,GAAG,CAAC,OAAiB,EAAE,EAAE;QACxC,MAAM,GAAG,SAAS,CAAC;QACnB,IAAI,MAAM;YAAE,OAAO;QACnB,+DAA+D;QAC/D,IAAI,KAAK;YAAE,KAAK,UAAU,CAAC,MAAM,EAAE,CAAC;QACpC,SAAS,EAAE,CAAC,OAAO,CAAC,CAAC;IACvB,CAAC,CAAC;IAEF,MAAM,UAAU,GAAe;QAC7B,IAAI,OAAO;YACT,OAAO,CAAC,MAAM,IAAI,CAAC,MAAM,IAAI,CAAC,QAAQ,CAAC;QACzC,CAAC;QACD,MAAM;YACJ,IAAI,MAAM;gBAAE,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;YACrC,IAAI,MAAM,EAAE,CAAC;gBACX,KAAK,GAAG,IAAI,CAAC;gBACb,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;YAC3B,CAAC;YACD,IAAI,QAAQ,EAAE,CAAC;gBACb,KAAK,GAAG,IAAI,CAAC;gBACb,OAAO,QAAQ,CAAC;YAClB,CAAC;YACD,OAAO,CAAC,QAAQ,GAAG,MAAM,EAAE;iBACxB,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE,CAAC,IAAI,CAAC,qCAAqC,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;iBACvF,OAAO,CAAC,GAAG,EAAE;gBACZ,QAAQ,GAAG,SAAS,CAAC;YACvB,CAAC,CAAC,CAAC,CAAC;QACR,CAAC;QACD,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;QAC1E,KAAK,CAAC,IAAI;YACR,MAAM,GAAG,IAAI,CAAC;YACd,MAAM,QAAQ,CAAC;YACf,MAAM,OAAO,GAAG,MAAM,CAAC;YACvB,MAAM,GAAG,SAAS,CAAC;YACnB,MAAM,OAAO,EAAE,IAAI,EAAE,CAAC;QACxB,CAAC;KACF,CAAC;IACF,MAAM,MAAM,EAAE,CAAC;IACf,OAAO,UAAU,CAAC;AACpB,CAAC"}
package/dist/version.d.ts CHANGED
@@ -7,8 +7,10 @@ export declare const RUNTIME_VERSION: string;
7
7
  * package release, so a run in flight on the old layout is not replayed against the new one.
8
8
  * 2: calls run in program order; a decision event per approval (2026-10-07).
9
9
  * 3: a start the policy holds waits on its approval before the body (2026-10-21).
10
+ * 4: a sleep for a duration reads DBOS's clock for its start (2026-10-25).
11
+ * 5: a scheduled run admits its starter and asks the policy in two steps before the body (2026-10-25).
10
12
  */
11
- export declare const STEP_LAYOUT = 3;
13
+ export declare const STEP_LAYOUT = 5;
12
14
  /**
13
15
  * The application version DBOS stamps on every run, always `<appName>@…`: DBOS version names
14
16
  * are unique per system database across apps. A worker recovers and dequeues only runs of its
package/dist/version.js CHANGED
@@ -12,8 +12,10 @@ export const RUNTIME_VERSION = JSON.parse(readFileSync(new URL("../package.json"
12
12
  * package release, so a run in flight on the old layout is not replayed against the new one.
13
13
  * 2: calls run in program order; a decision event per approval (2026-10-07).
14
14
  * 3: a start the policy holds waits on its approval before the body (2026-10-21).
15
+ * 4: a sleep for a duration reads DBOS's clock for its start (2026-10-25).
16
+ * 5: a scheduled run admits its starter and asks the policy in two steps before the body (2026-10-25).
15
17
  */
16
- export const STEP_LAYOUT = 3;
18
+ export const STEP_LAYOUT = 5;
17
19
  let dbosVersion;
18
20
  /** The installed DBOS SDK's version, read from its package.json (which its exports don't expose). */
19
21
  function installedDbosVersion() {
@@ -1 +1 @@
1
- {"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,128 @@
1
+ import { z } from "zod";
2
+ import { type CallContext, DriverError } from "./op.ts";
3
+ import type { PlanAction } from "./resource.ts";
4
+ import type { WakeupRegistration } from "./wakeup.ts";
5
+ /** An instance as the service shows it (`GET /wakeup/instances/{id}`): the fields read here. */
6
+ declare const instanceSchema: z.ZodObject<{
7
+ id: z.ZodString;
8
+ url: z.ZodString;
9
+ at: z.ZodNullable<z.ZodString>;
10
+ lastError: z.ZodNullable<z.ZodString>;
11
+ }, z.core.$strip>;
12
+ export type Instance = z.output<typeof instanceSchema>;
13
+ /** The wakeup service, as the operations use it. Each call fails with a `DriverError`. */
14
+ export interface WakeupApi {
15
+ /**
16
+ * `POST /wakeup/instances { url, token }` with the account's token: the instance the token
17
+ * names, made, or moved to `url` when the account registered it before.
18
+ */
19
+ put(url: string, token: string): Promise<{
20
+ id: string;
21
+ }>;
22
+ /** `GET /wakeup/instances/{id}` with the account's token; undefined when there is none (404). */
23
+ get(id: string): Promise<Instance | undefined>;
24
+ /** `DELETE /wakeup/instances/{id}` with the account's token; nothing when there is none. */
25
+ remove(id: string): Promise<void>;
26
+ /** `PUT /wakeup/wake { at }` with the instance's token, which names the instance. */
27
+ wake(registration: WakeupRegistration, token: string): Promise<void>;
28
+ }
29
+ /** What the service holds of an instance that registered no wake: a new one's, and one moved to a new URL. */
30
+ export declare const UNREGISTERED: {
31
+ readonly at: null;
32
+ readonly lastError: null;
33
+ };
34
+ export declare const fail: (message: string, status: number) => DriverError;
35
+ /**
36
+ * The wakeup type's operations and `wakeup.register` over `api()`, made on each call. The
37
+ * instance's token, `SANOMA_WAKEUP_TOKEN`, names the instance: `create` and `update` both post it
38
+ * with the host's URL (minted and stored first when none is, as for a data file written by hand),
39
+ * so a new host is the same instance moved, never a replace; `register` sends it.
40
+ */
41
+ export declare function wakeupCalls(api: () => WakeupApi): {
42
+ import: ({ id }: {
43
+ id: string;
44
+ }) => Promise<{
45
+ id: string;
46
+ gone: boolean;
47
+ state: {
48
+ id: string;
49
+ host: string;
50
+ at: string | null;
51
+ lastError: string | null;
52
+ };
53
+ } | {
54
+ state?: undefined;
55
+ id: string;
56
+ gone: boolean;
57
+ }>;
58
+ read: ({ id }: {
59
+ id: string;
60
+ }) => Promise<{
61
+ id: string;
62
+ gone: boolean;
63
+ state: {
64
+ id: string;
65
+ host: string;
66
+ at: string | null;
67
+ lastError: string | null;
68
+ };
69
+ } | {
70
+ state?: undefined;
71
+ id: string;
72
+ gone: boolean;
73
+ }>;
74
+ plan: (input: {
75
+ id?: string;
76
+ desired?: Record<string, unknown>;
77
+ }) => Promise<{
78
+ action: PlanAction;
79
+ planned?: Record<string, unknown>;
80
+ unknown: string[];
81
+ replace: string[];
82
+ }>;
83
+ create: ({ desired }: {
84
+ desired: Record<string, unknown>;
85
+ }, call: CallContext) => Promise<{
86
+ id: string;
87
+ state: {
88
+ id: string;
89
+ host: string;
90
+ at: string | null;
91
+ lastError: string | null;
92
+ };
93
+ }>;
94
+ update: ({ id, desired, expect, }: {
95
+ id: string;
96
+ desired: Record<string, unknown>;
97
+ expect?: {
98
+ action: PlanAction;
99
+ replace: string[];
100
+ };
101
+ }, call: CallContext) => Promise<{
102
+ id: string;
103
+ state: {
104
+ id: string;
105
+ host: string;
106
+ at: string | null;
107
+ lastError: string | null;
108
+ };
109
+ }>;
110
+ delete: ({ id }: {
111
+ id: string;
112
+ }) => Promise<{
113
+ id: string;
114
+ gone: true;
115
+ }>;
116
+ register: (registration: WakeupRegistration, { secrets }: CallContext) => Promise<{}>;
117
+ };
118
+ /**
119
+ * The real wakeup service at `SANOMA_WAKEUP_URL`: instances created, read and deleted with
120
+ * `SANOMA_WAKEUP_ACCOUNT_TOKEN`, each named by its `SANOMA_WAKEUP_TOKEN` (which `create` and
121
+ * `register` send). `timeoutMs` is how long one request may take: 10 s by default.
122
+ */
123
+ export declare function sanomaWakeupDriver({ timeoutMs }?: {
124
+ timeoutMs?: number;
125
+ }): import("./op.ts").Driver;
126
+ /** The wakeup's step for Gherkin tests: an instance at the service before the run, named `wakeup` (`$wakeup.id`). */
127
+ export declare const wakeupSteps: import("./steps.ts").Steps;
128
+ export {};
@@ -0,0 +1,216 @@
1
+ import { z } from "zod";
2
+ import { defineDriver, DriverError, retryableStatus } from "./op.js";
3
+ import { defineSteps } from "./steps.js";
4
+ import { instanceUrl, mintInstanceToken, WAKEUP_TOKEN } from "./wakeup-service.js";
5
+ import { wakeupOps } from "./wakeup-type.js";
6
+ // `sanoma.wakeup`'s operations over a wakeup service (`WakeupApi`): the driver's call it over
7
+ // HTTP (plain `fetch`, the service has no SDK), the fake's (`fakeSanomaWakeup` in `fake.ts`)
8
+ // answer from its state. Both go through `wakeupCalls`, so they plan, post the token and refuse
9
+ // alike. `config.ts` puts the two together as the built-in `sanomaWakeup`.
10
+ /** An instance as the service shows it (`GET /wakeup/instances/{id}`): the fields read here. */
11
+ const instanceSchema = z.object({
12
+ id: z.string(),
13
+ url: z.string(),
14
+ at: z.string().nullable(),
15
+ lastError: z.string().nullable(),
16
+ });
17
+ /** What the service holds of an instance that registered no wake: a new one's, and one moved to a new URL. */
18
+ export const UNREGISTERED = { at: null, lastError: null };
19
+ export const fail = (message, status) => new DriverError(`sanoma.wakeup: ${message}`, { retryable: retryableStatus(status), status });
20
+ /** The driver's own refusal, before or instead of a call: never retried. */
21
+ const refused = (message, vendorCode) => new DriverError(`sanoma.wakeup: ${message}`, { retryable: false, ...(vendorCode && { vendorCode }) });
22
+ /** A wakeup's state: the service's instance, its URL as `host`. */
23
+ const stateOf = ({ id, url, at, lastError }) => ({ id, host: url, at, lastError });
24
+ /** A URL as the service keeps it (`instanceUrl`, the service's own rule), or as given when the service would refuse it. */
25
+ const normalUrl = (url) => {
26
+ const checked = instanceUrl(url);
27
+ return "url" in checked ? checked.url : String(url);
28
+ };
29
+ /**
30
+ * The wakeup type's operations and `wakeup.register` over `api()`, made on each call. The
31
+ * instance's token, `SANOMA_WAKEUP_TOKEN`, names the instance: `create` and `update` both post it
32
+ * with the host's URL (minted and stored first when none is, as for a data file written by hand),
33
+ * so a new host is the same instance moved, never a replace; `register` sends it.
34
+ */
35
+ export function wakeupCalls(api) {
36
+ const read = async ({ id }) => {
37
+ const found = await api().get(id);
38
+ return found ? { id, gone: false, state: stateOf(found) } : { id, gone: true };
39
+ };
40
+ /**
41
+ * The instance the stored token names, at the desired host: made or moved, its state as a new
42
+ * one's (a repeat after a lost reply keeps the wake the service holds, which the next read shows).
43
+ */
44
+ const put = async (desired, { secrets }) => {
45
+ const host = normalUrl(desired.host);
46
+ const token = await secrets.ensure(WAKEUP_TOKEN, mintInstanceToken);
47
+ const { id } = await api().put(host, token);
48
+ const state = { id, host, ...UNREGISTERED };
49
+ return { id, state };
50
+ };
51
+ const plan = async ({ id, desired }) => {
52
+ const state = id === undefined ? undefined : (await read({ id })).state;
53
+ const none = { unknown: [], replace: [] };
54
+ if (!desired)
55
+ return { action: state ? "delete" : "none", state, ...none };
56
+ const planned = { host: normalUrl(desired.host) };
57
+ if (!state)
58
+ return { action: "create", planned, unknown: ["id"], replace: [] };
59
+ if (planned.host === state.host)
60
+ return { action: "none", planned: state, state, ...none };
61
+ // A move forgets the wake registered at the old URL, as the service does.
62
+ return { action: "update", planned: { ...state, ...planned, ...UNREGISTERED }, state, ...none };
63
+ };
64
+ return {
65
+ import: read,
66
+ read,
67
+ plan: async (input) => {
68
+ const { state: _, ...out } = await plan(input);
69
+ return out;
70
+ },
71
+ create: ({ desired }, call) => put(desired, call),
72
+ update: async ({ id, desired, expect, }, call) => {
73
+ const fresh = await plan({ id, desired });
74
+ if (expect && (expect.action !== fresh.action || expect.replace.join() !== fresh.replace.join())) {
75
+ throw refused(`update: the plan changed (${expect.action}, now ${fresh.action})`, "plan_changed");
76
+ }
77
+ if (fresh.state && fresh.action === "none")
78
+ return { id, state: fresh.state };
79
+ return put(desired, call);
80
+ },
81
+ delete: async ({ id }) => {
82
+ await api().remove(id);
83
+ return { id, gone: true };
84
+ },
85
+ register: async (registration, { secrets }) => {
86
+ const token = await secrets.get(WAKEUP_TOKEN);
87
+ if (!token)
88
+ throw refused(`register: ${WAKEUP_TOKEN} is not set: connect a wakeup service in /setup, then apply the wakeup`);
89
+ await api().wake(registration, token);
90
+ return {};
91
+ },
92
+ };
93
+ }
94
+ /** The environment variables the driver reads, on every call. */
95
+ const env = z.object({
96
+ SANOMA_WAKEUP_URL: z.url().optional().describe("the wakeup service's URL: Sanoma's, or your own `sanoma wakeup`"),
97
+ SANOMA_WAKEUP_ACCOUNT_TOKEN: z
98
+ .string()
99
+ .startsWith("swa_", "an account's token starts swa_")
100
+ .optional()
101
+ .describe("an account's token at the wakeup service (swa_…), which creates and deletes the instances"),
102
+ // No check of its form: a host's own wakeup (Cloudflare's alarm) takes this variable too, and
103
+ // the service refuses a token that is not an instance's.
104
+ [WAKEUP_TOKEN]: z
105
+ .string()
106
+ .optional()
107
+ .describe("this instance's token at the wakeup service (swi_…), which /setup mints and the wakeup's create registers"),
108
+ });
109
+ /** The variable `name`, read when an operation is called, or the driver's refusal. */
110
+ function required(name) {
111
+ const value = process.env[name];
112
+ if (!value)
113
+ throw refused(`${name} is not set (${env.shape[name].description})`);
114
+ return value;
115
+ }
116
+ const Posted = z.object({ id: z.string() });
117
+ /** The service's error body. */
118
+ const Problem = z.object({ error: z.string() });
119
+ const instance = (id) => `/wakeup/instances/${encodeURIComponent(id)}`;
120
+ /** The service at `SANOMA_WAKEUP_URL`, read when an operation is called: each request's failure a `DriverError`. */
121
+ function serviceApi(timeoutMs) {
122
+ const base = required("SANOMA_WAKEUP_URL").replace(/\/+$/, "");
123
+ if (!URL.canParse(base))
124
+ throw refused("SANOMA_WAKEUP_URL is not a URL");
125
+ const account = () => required("SANOMA_WAKEUP_ACCOUNT_TOKEN");
126
+ /**
127
+ * One request: its reply parsed by `reply` (none: not read), a 404 `undefined` where `absent`
128
+ * says it means no such instance, and any other answer but a 2xx a `DriverError`.
129
+ */
130
+ const send = async (method, path, token, { reply, body, absent = false } = {}) => {
131
+ const where = `${method} ${path}`;
132
+ let res;
133
+ let text;
134
+ try {
135
+ res = await fetch(`${base}${path}`, {
136
+ method,
137
+ signal: AbortSignal.timeout(timeoutMs),
138
+ // A redirect is no answer of the service's, and would carry the token elsewhere.
139
+ redirect: "manual",
140
+ headers: {
141
+ authorization: `Bearer ${token}`,
142
+ accept: "application/json",
143
+ ...(body !== undefined && { "content-type": "application/json" }),
144
+ },
145
+ ...(body !== undefined && { body: JSON.stringify(body) }),
146
+ });
147
+ text = await res.text();
148
+ }
149
+ catch (cause) {
150
+ // No answer: the request may or may not have reached the service.
151
+ const why = cause.name === "TimeoutError" ? `no reply in ${timeoutMs} ms` : "the request failed";
152
+ throw new DriverError(`sanoma.wakeup: ${where}: ${why}`, { retryable: true, cause });
153
+ }
154
+ const { status } = res;
155
+ let json;
156
+ try {
157
+ json = text ? JSON.parse(text) : undefined;
158
+ }
159
+ catch {
160
+ // A proxy's HTML page, say: no body to read.
161
+ }
162
+ // The service's own 404 (its `{ error }`), not another server's at that URL.
163
+ if (status === 404 && absent && Problem.safeParse(json).success)
164
+ return undefined;
165
+ if (status < 200 || status >= 300)
166
+ throw fail(`${where}: ${Problem.safeParse(json).data?.error ?? `HTTP ${status}`}`, status);
167
+ if (!reply)
168
+ return undefined;
169
+ const parsed = reply.safeParse(json);
170
+ if (!parsed.success) {
171
+ throw new DriverError(`sanoma.wakeup: ${where}: the reply is not a wakeup service's; is SANOMA_WAKEUP_URL right?`, {
172
+ retryable: false,
173
+ status,
174
+ cause: parsed.error,
175
+ });
176
+ }
177
+ return parsed.data;
178
+ };
179
+ return {
180
+ put: async (url, token) => {
181
+ try {
182
+ return (await send("POST", "/wakeup/instances", account(), { reply: Posted, body: { url, token } }));
183
+ }
184
+ catch (error) {
185
+ // Another account's instance's token: the advice is the company's, so it is here, not the service's.
186
+ if (!(error instanceof DriverError) || error.status !== 409)
187
+ throw error;
188
+ throw new DriverError(`${error.message}: a new account needs a new instance token (store the new account's token in /setup, which mints one)`, { retryable: false, status: 409, cause: error });
189
+ }
190
+ },
191
+ get: (id) => send("GET", instance(id), account(), { reply: instanceSchema, absent: true }),
192
+ async remove(id) {
193
+ await send("DELETE", instance(id), account(), { absent: true });
194
+ },
195
+ async wake({ at }, token) {
196
+ await send("PUT", "/wakeup/wake", token, { body: { at } });
197
+ },
198
+ };
199
+ }
200
+ /**
201
+ * The real wakeup service at `SANOMA_WAKEUP_URL`: instances created, read and deleted with
202
+ * `SANOMA_WAKEUP_ACCOUNT_TOKEN`, each named by its `SANOMA_WAKEUP_TOKEN` (which `create` and
203
+ * `register` send). `timeoutMs` is how long one request may take: 10 s by default.
204
+ */
205
+ export function sanomaWakeupDriver({ timeoutMs = 10_000 } = {}) {
206
+ return defineDriver(wakeupOps, { wakeup: wakeupCalls(() => serviceApi(timeoutMs)) }, { env });
207
+ }
208
+ /** The wakeup's step for Gherkin tests: an instance at the service before the run, named `wakeup` (`$wakeup.id`). */
209
+ export const wakeupSteps = defineSteps("sanoma", ({ given }) => {
210
+ given("a sanoma wakeup for {string}", (host) => ({
211
+ op: wakeupOps.wakeup.create,
212
+ input: { desired: { host } },
213
+ as: "wakeup",
214
+ }));
215
+ });
216
+ //# sourceMappingURL=wakeup-driver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wakeup-driver.js","sourceRoot":"","sources":["../src/wakeup-driver.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,83 @@
1
+ /** Where the accounts live: one per party that registers instances, its token's hash alone. */
2
+ export declare const WAKEUP_ACCOUNTS_TABLE = "sanoma_wakeup_accounts";
3
+ /** Where the instances live: each one's URL, its token's hash and its registered wake. */
4
+ export declare const WAKEUP_INSTANCES_TABLE = "sanoma_wakeup_instances";
5
+ /** The shape of `@sanoma-ai/app`'s `IngressRoute`, which `startApp`'s `ingress` takes. */
6
+ export interface WakeupRoute {
7
+ method?: "GET" | "POST" | "PUT" | "DELETE";
8
+ /** `/wakeup`, with every path under it (`prefix`). */
9
+ path: string;
10
+ prefix: true;
11
+ handle(request: Request): Promise<Response>;
12
+ }
13
+ export interface WakeupServiceOptions {
14
+ /** The service's own Postgres: its tables are made there when missing (the database too). */
15
+ databaseUrl: string;
16
+ /** The clock: what is due, and what `called_at` and `next_attempt_at` are set from. */
17
+ now?: () => Date;
18
+ /** How the instances are called. */
19
+ fetch?: typeof globalThis.fetch;
20
+ /** One `info` line per call, a `warn` per failure; the runtime's logger by default. */
21
+ log?: {
22
+ info(line: string): void;
23
+ warn(line: string): void;
24
+ };
25
+ }
26
+ export interface WakeupService {
27
+ /** One route answering everything under `/wakeup`, for `startApp`'s `ingress` or a server of its own. */
28
+ routes: WakeupRoute[];
29
+ /** An account that may register instances: its id, and its token, shown this once. */
30
+ mintAccount(label: string): Promise<{
31
+ id: string;
32
+ token: string;
33
+ }>;
34
+ /** Refuses the account's token and its instances' from now on, and wakes its instances no more. */
35
+ revokeAccount(id: string): Promise<void>;
36
+ /** Ends the loop, abandoning the calls in flight (called again once their claim lapses), and closes the pool. */
37
+ stop(): Promise<void>;
38
+ }
39
+ /**
40
+ * A new instance token (`swi_…`), which the company mints and stores as `SANOMA_WAKEUP_TOKEN`
41
+ * before anything is applied, so its host is given it from the first apply; the wakeup's create
42
+ * then registers it with the service. The service never mints one.
43
+ */
44
+ export declare const mintInstanceToken: () => string;
45
+ /** The secret a company keeps its instance token in: what its host's `secrets` name and its wakeup's driver reads. */
46
+ export declare const WAKEUP_TOKEN = "SANOMA_WAKEUP_TOKEN";
47
+ /** An instance token the service takes: `swi_`, then at least as many base64url characters as a minted one has. */
48
+ export declare const INSTANCE_TOKEN: RegExp;
49
+ /**
50
+ * An instance's URL as it is stored, without a trailing slash, or why it is refused: `http(s)`, no
51
+ * user or password, no query, no fragment (`/wake` is added to it).
52
+ */
53
+ export declare function instanceUrl(value: unknown): {
54
+ url: string;
55
+ } | {
56
+ error: string;
57
+ };
58
+ /**
59
+ * An account of the wakeup service on `databaseUrl`, minted without starting the service (its
60
+ * tables made when missing): what `sanoma wakeup account <label>` prints.
61
+ */
62
+ export declare function mintWakeupAccount(databaseUrl: string, label: string): Promise<{
63
+ id: string;
64
+ token: string;
65
+ }>;
66
+ /**
67
+ * Starts the wakeup service on its own database: its two tables made when missing, its one loop
68
+ * running, and `routes` for whoever serves it (`sanoma wakeup`, or `sanoma serve` with
69
+ * `wakeup: true`). Routes, each JSON and `no-store`:
70
+ *
71
+ * - `POST /wakeup/instances { url, token }`, an account's token → 201 `{ id }` for a new instance
72
+ * token, 200 `{ id }` for one the account registered already, its URL now the given one (a lost
73
+ * reply, or a host that moved; its registered wake kept only when the URL is the same), 409 for
74
+ * another account's
75
+ * - `GET /wakeup/instances/{id}`, its account's token → `{ id, url, at, calledAt, attempts, lastError }`
76
+ * - `DELETE /wakeup/instances/{id}`, its account's token → 204
77
+ * - `PUT /wakeup/wake { at }`, an instance's own token, which names the instance → 204, replacing
78
+ * the wake it had, and waking the loop
79
+ *
80
+ * 401 without a token or with an unknown one, 403 for another account's instance, 400 for a bad
81
+ * body, 404 for an unknown id or path.
82
+ */
83
+ export declare function startWakeupService({ databaseUrl, now, fetch, log, }: WakeupServiceOptions): Promise<WakeupService>;