@sanoma-ai/workflows 0.0.0-stage → 0.2.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 (176) hide show
  1. package/LICENSE +105 -0
  2. package/README.md +544 -2
  3. package/dist/apply-steps.d.ts +6 -0
  4. package/dist/apply-steps.js +93 -0
  5. package/dist/apply-steps.js.map +1 -0
  6. package/dist/apply.d.ts +197 -0
  7. package/dist/apply.js +470 -0
  8. package/dist/apply.js.map +1 -0
  9. package/dist/approvals.d.ts +46 -0
  10. package/dist/approvals.js +111 -0
  11. package/dist/approvals.js.map +1 -0
  12. package/dist/ast.d.ts +57 -0
  13. package/dist/ast.js +81 -0
  14. package/dist/ast.js.map +1 -0
  15. package/dist/call.d.ts +37 -0
  16. package/dist/call.js +417 -0
  17. package/dist/call.js.map +1 -0
  18. package/dist/client.d.ts +203 -0
  19. package/dist/client.js +457 -0
  20. package/dist/client.js.map +1 -0
  21. package/dist/config.d.ts +126 -0
  22. package/dist/config.js +264 -0
  23. package/dist/config.js.map +1 -0
  24. package/dist/credentials.d.ts +55 -0
  25. package/dist/credentials.js +261 -0
  26. package/dist/credentials.js.map +1 -0
  27. package/dist/cucumber.d.ts +64 -0
  28. package/dist/cucumber.js +158 -0
  29. package/dist/cucumber.js.map +1 -0
  30. package/dist/datafile.d.ts +71 -0
  31. package/dist/datafile.js +380 -0
  32. package/dist/datafile.js.map +1 -0
  33. package/dist/db.d.ts +58 -0
  34. package/dist/db.js +179 -0
  35. package/dist/db.js.map +1 -0
  36. package/dist/define.d.ts +205 -0
  37. package/dist/define.js +103 -0
  38. package/dist/define.js.map +1 -0
  39. package/dist/describe.d.ts +141 -0
  40. package/dist/describe.js +135 -0
  41. package/dist/describe.js.map +1 -0
  42. package/dist/drift.d.ts +127 -0
  43. package/dist/drift.js +167 -0
  44. package/dist/drift.js.map +1 -0
  45. package/dist/env.d.ts +49 -0
  46. package/dist/env.js +83 -0
  47. package/dist/env.js.map +1 -0
  48. package/dist/errors.d.ts +88 -0
  49. package/dist/errors.js +148 -0
  50. package/dist/errors.js.map +1 -0
  51. package/dist/expectations.d.ts +26 -0
  52. package/dist/expectations.js +162 -0
  53. package/dist/expectations.js.map +1 -0
  54. package/dist/fake.d.ts +55 -0
  55. package/dist/fake.js +87 -0
  56. package/dist/fake.js.map +1 -0
  57. package/dist/fill.d.ts +9 -0
  58. package/dist/fill.js +17 -0
  59. package/dist/fill.js.map +1 -0
  60. package/dist/host.d.ts +56 -0
  61. package/dist/host.js +45 -0
  62. package/dist/host.js.map +1 -0
  63. package/dist/index.d.ts +23 -0
  64. package/dist/index.js +29 -0
  65. package/dist/index.js.map +1 -0
  66. package/dist/ledger.d.ts +217 -0
  67. package/dist/ledger.js +251 -0
  68. package/dist/ledger.js.map +1 -0
  69. package/dist/lint.d.ts +32 -0
  70. package/dist/lint.js +168 -0
  71. package/dist/lint.js.map +1 -0
  72. package/dist/lockfile.d.ts +36 -0
  73. package/dist/lockfile.js +69 -0
  74. package/dist/lockfile.js.map +1 -0
  75. package/dist/log.d.ts +24 -0
  76. package/dist/log.js +83 -0
  77. package/dist/log.js.map +1 -0
  78. package/dist/op.d.ts +260 -0
  79. package/dist/op.js +188 -0
  80. package/dist/op.js.map +1 -0
  81. package/dist/outline.d.ts +179 -0
  82. package/dist/outline.js +506 -0
  83. package/dist/outline.js.map +1 -0
  84. package/dist/paths.d.ts +11 -0
  85. package/dist/paths.js +30 -0
  86. package/dist/paths.js.map +1 -0
  87. package/dist/plugin.d.ts +28 -0
  88. package/dist/plugin.js +25 -0
  89. package/dist/plugin.js.map +1 -0
  90. package/dist/policy.d.ts +114 -0
  91. package/dist/policy.js +60 -0
  92. package/dist/policy.js.map +1 -0
  93. package/dist/resource.d.ts +378 -0
  94. package/dist/resource.js +430 -0
  95. package/dist/resource.js.map +1 -0
  96. package/dist/resources.d.ts +77 -0
  97. package/dist/resources.js +244 -0
  98. package/dist/resources.js.map +1 -0
  99. package/dist/run.d.ts +101 -0
  100. package/dist/run.js +7 -0
  101. package/dist/run.js.map +1 -0
  102. package/dist/sandbox.d.ts +33 -0
  103. package/dist/sandbox.js +127 -0
  104. package/dist/sandbox.js.map +1 -0
  105. package/dist/scenario.d.ts +221 -0
  106. package/dist/scenario.js +1104 -0
  107. package/dist/scenario.js.map +1 -0
  108. package/dist/scenarios.d.ts +55 -0
  109. package/dist/scenarios.js +71 -0
  110. package/dist/scenarios.js.map +1 -0
  111. package/dist/secret.d.ts +42 -0
  112. package/dist/secret.js +58 -0
  113. package/dist/secret.js.map +1 -0
  114. package/dist/shared.d.ts +69 -0
  115. package/dist/shared.js +84 -0
  116. package/dist/shared.js.map +1 -0
  117. package/dist/source.d.ts +58 -0
  118. package/dist/source.js +54 -0
  119. package/dist/source.js.map +1 -0
  120. package/dist/steps.d.ts +76 -0
  121. package/dist/steps.js +23 -0
  122. package/dist/steps.js.map +1 -0
  123. package/dist/version.d.ts +29 -0
  124. package/dist/version.js +76 -0
  125. package/dist/version.js.map +1 -0
  126. package/dist/worker.d.ts +37 -0
  127. package/dist/worker.js +228 -0
  128. package/dist/worker.js.map +1 -0
  129. package/dist/writer.d.ts +35 -0
  130. package/dist/writer.js +201 -0
  131. package/dist/writer.js.map +1 -0
  132. package/oxlint.json +128 -0
  133. package/package.json +96 -3
  134. package/src/apply-steps.ts +110 -0
  135. package/src/apply.ts +626 -0
  136. package/src/approvals.ts +157 -0
  137. package/src/ast.ts +115 -0
  138. package/src/call.ts +483 -0
  139. package/src/client.ts +604 -0
  140. package/src/config.ts +404 -0
  141. package/src/credentials.ts +296 -0
  142. package/src/cucumber.ts +230 -0
  143. package/src/datafile.ts +481 -0
  144. package/src/db.ts +197 -0
  145. package/src/define.ts +285 -0
  146. package/src/describe.ts +282 -0
  147. package/src/drift.ts +259 -0
  148. package/src/env.ts +122 -0
  149. package/src/errors.ts +202 -0
  150. package/src/expectations.ts +191 -0
  151. package/src/fake.ts +156 -0
  152. package/src/fill.ts +24 -0
  153. package/src/host.ts +96 -0
  154. package/src/index.ts +143 -0
  155. package/src/ledger.ts +419 -0
  156. package/src/lint.ts +208 -0
  157. package/src/lockfile.ts +95 -0
  158. package/src/log.ts +82 -0
  159. package/src/op.ts +402 -0
  160. package/src/outline.ts +620 -0
  161. package/src/paths.ts +32 -0
  162. package/src/plugin.ts +37 -0
  163. package/src/policy.ts +139 -0
  164. package/src/resource.ts +670 -0
  165. package/src/resources.ts +311 -0
  166. package/src/run.ts +106 -0
  167. package/src/sandbox.ts +161 -0
  168. package/src/scenario.ts +1365 -0
  169. package/src/scenarios.ts +111 -0
  170. package/src/secret.ts +92 -0
  171. package/src/shared.ts +126 -0
  172. package/src/source.ts +82 -0
  173. package/src/steps.ts +90 -0
  174. package/src/version.ts +86 -0
  175. package/src/worker.ts +264 -0
  176. package/src/writer.ts +225 -0
package/dist/lint.js ADDED
@@ -0,0 +1,168 @@
1
+ import { basename, dirname, join } from "node:path";
2
+ import { byPosition, childrenOf, parsed } from "./ast.js";
3
+ import { readDataFile } from "./datafile.js";
4
+ import { constsOf, outlineBody, workflowLiterals } from "./outline.js";
5
+ import { inside, nearestDir, RELATIVE } from "./paths.js";
6
+ // From src/ and from dist/ alike, the package's own oxlint.json: the one list of allowed names.
7
+ import oxlint from "../oxlint.json" with { type: "json" };
8
+ /**
9
+ * A workflow must call vendors through `ctx`, so the policy sees every call. These are the
10
+ * import rules oxlint's built-in rules cannot express; the clock, randomness, the network
11
+ * and the environment are oxlint's (the package's `oxlint.json`).
12
+ */
13
+ const THROUGH_CTX = "a workflow must call vendors through ctx, so the policy sees every call";
14
+ /**
15
+ * The packages the author surface is imported from, each allowing the same names: `sanoma`
16
+ * re-exports what `@sanoma-ai/workflows` allows (and `z`). Adding one here accepts it.
17
+ */
18
+ const AUTHOR_PACKAGES = ["@sanoma-ai/workflows", "sanoma"];
19
+ /** The packages a workflow may import from at all: the author packages, connectors and zod. */
20
+ const ALLOWED_PACKAGE = new RegExp(`^(${[...AUTHOR_PACKAGES, "@sanoma-ai/connector-[a-z0-9-]+", "zod"].join("|")})$`);
21
+ /** Packages refused by name, with the reason. */
22
+ const REFUSED_PACKAGES = [
23
+ [/^@sanoma-ai\/testing(\/|$)/, `fakes and test helpers belong in tests; ${THROUGH_CTX}`],
24
+ [/^@sanoma-ai\/app(\/|$)/, "the app starts runs and decides approvals, so a workflow could approve itself"],
25
+ [/^@sanoma-ai\/connector-[^/]+\/(fake|driver)(\/|$)/, `${THROUGH_CTX}; import the connector itself`],
26
+ [/^sanoma\//, "`sanoma` has no entry points for a workflow: import its names from `sanoma` itself"],
27
+ ];
28
+ /**
29
+ * What a workflow or policy may import from an author package, besides types: the one list,
30
+ * `allowImportNames` of oxlint.json's `@sanoma-ai/workflows` entry (`sanoma`'s generated
31
+ * `oxlint.json` derives its own entry from it). Everything else is
32
+ * refused: the client, the worker and the app could start runs or approve the run's own
33
+ * approvals, a ledger store could forge the audit record (a store keeps the first record per
34
+ * id), and config helpers can read credentials.
35
+ */
36
+ const WORKFLOW_IMPORTS = restrictedImports(oxlint).find((p) => p.name === "@sanoma-ai/workflows")?.allowImportNames ?? [];
37
+ const ALLOWED_NAMES = new Set(WORKFLOW_IMPORTS);
38
+ const NOT_ALLOWED = `a workflow or policy imports only ${WORKFLOW_IMPORTS.join(", ")} and types from ` +
39
+ `${AUTHOR_PACKAGES.join(" or ")}: the rest could start runs, approve its own approvals, forge the ledger or read credentials`;
40
+ /**
41
+ * Error classes a run must not test with `instanceof`: on a replay DBOS rethrows a serialized
42
+ * copy, which is no instance of them, so a branch on it goes another way than the first time
43
+ * and the run's steps fall out of step. Read the code with `errorCode(err)` instead.
44
+ */
45
+ const ERROR_CLASSES = new Set(["DriverError", "SanomaError", "PolicyDeniedError", "RejectedError"]);
46
+ export function lintWorkflow(input, path) {
47
+ const filename = typeof input === "string" ? path : input.file;
48
+ const read = typeof input === "string" ? parsed(input, filename ?? "workflow.ts") : input;
49
+ const { program, at } = read;
50
+ const problems = [...read.problems];
51
+ const root = filename === undefined ? undefined : nearestDir(filename, ["workflows", "policies"]);
52
+ const checkSource = (node) => {
53
+ const spec = node.source.value;
54
+ const refusal = whyRefused(spec, filename, root);
55
+ if (refusal) {
56
+ problems.push({ ...at(node.source.start), message: `import "${spec}" is not allowed in a workflow: ${refusal}` });
57
+ return;
58
+ }
59
+ if (!AUTHOR_PACKAGES.includes(spec))
60
+ return;
61
+ if (node.type === "ExportAllDeclaration") {
62
+ problems.push({
63
+ ...at(node.start),
64
+ message: `export * from "${spec}" is not allowed in a workflow: it would re-export what a workflow may not import`,
65
+ });
66
+ }
67
+ for (const s of node.specifiers ?? []) {
68
+ if (s.type === "ImportNamespaceSpecifier") {
69
+ problems.push({
70
+ ...at(s.start),
71
+ message: `import * from "${spec}" is not allowed in a workflow: import the names you use, so the rest stays out`,
72
+ });
73
+ continue;
74
+ }
75
+ // `import type { X }`, `import { type X }` and `export type { X }` bring in no values.
76
+ if (node.importKind === "type" ||
77
+ node.exportKind === "type" ||
78
+ s.importKind === "type" ||
79
+ s.exportKind === "type") {
80
+ continue;
81
+ }
82
+ // What the module exports under: `imported` for an import, `local` for a re-export.
83
+ const named = s.imported ?? s.local;
84
+ const imported = s.type === "ImportDefaultSpecifier" ? "default" : (named?.name ?? named?.value);
85
+ if (!ALLOWED_NAMES.has(imported)) {
86
+ problems.push({ ...at(s.start), message: `${imported} is not allowed in a workflow: ${NOT_ALLOWED}` });
87
+ }
88
+ }
89
+ };
90
+ const visit = (node) => {
91
+ if (!node)
92
+ return;
93
+ if ((node.type === "ImportDeclaration" ||
94
+ node.type === "ExportNamedDeclaration" ||
95
+ node.type === "ExportAllDeclaration") &&
96
+ node.source) {
97
+ checkSource(node);
98
+ }
99
+ else if (node.type === "ImportExpression") {
100
+ problems.push({ ...at(node.start), message: "dynamic import is not allowed in a workflow" });
101
+ }
102
+ else if (node.type === "BinaryExpression" && node.operator === "instanceof") {
103
+ checkInstanceof(node);
104
+ }
105
+ for (const child of childrenOf(node))
106
+ visit(child);
107
+ };
108
+ // A workflow imports none of these classes, so they are refused by the name they have.
109
+ const checkInstanceof = (node) => {
110
+ const right = node.right;
111
+ const name = right?.type === "Identifier"
112
+ ? right.name
113
+ : right?.type === "MemberExpression" && !right.computed
114
+ ? right.property?.name
115
+ : undefined;
116
+ if (name !== undefined && ERROR_CLASSES.has(name)) {
117
+ problems.push({
118
+ ...at(node.start),
119
+ message: `instanceof ${name} is not allowed in a workflow: on a replay DBOS rethrows a copy of the error, ` +
120
+ "which is no instance of it, so the run would take another branch; read `errorCode(err)`",
121
+ });
122
+ }
123
+ };
124
+ visit(program);
125
+ // Each workflow's `run` as the worker reads it when it starts: what the outline cannot draw,
126
+ // the worker refuses to start with. One reading, so the lint and the worker agree.
127
+ const outlined = { consts: constsOf(program), source: typeof input === "string" ? input : input.source };
128
+ for (const { run } of workflowLiterals(program))
129
+ for (const { start, message } of outlineBody(run, outlined).problems)
130
+ problems.push({ ...at(start), message });
131
+ return byPosition(problems);
132
+ }
133
+ /**
134
+ * Checks a data file under `resources/`: only named imports (a connector's constructors from its
135
+ * `…/resources` entry, and resources from other data files inside the same `resources/`
136
+ * directory), `export const <name> = <vendor>.<type>({ … })` with literal fields and names of
137
+ * declared resources, and `export default [ … ]`. Each message says what to write instead.
138
+ * It is the subset `readResources` reads (`readDataFile`), without the config: whether the
139
+ * connector, the type and the values are known is the reader's to say.
140
+ */
141
+ export function lintResources(source, filename) {
142
+ const { program, problems, at } = parsed(source, filename);
143
+ for (const p of readDataFile(program, filename).problems)
144
+ problems.push({ ...at(p.start), message: p.message });
145
+ return byPosition(problems);
146
+ }
147
+ /** The `paths` of oxlint.json's `no-restricted-imports` rule. */
148
+ function restrictedImports(config) {
149
+ // JSON types the rule's [severity, options] as an array of either.
150
+ return config.overrides.flatMap((o) => "no-restricted-imports" in o.rules
151
+ ? o.rules["no-restricted-imports"][1].paths
152
+ : []);
153
+ }
154
+ function whyRefused(spec, filename, root) {
155
+ if (RELATIVE.test(spec)) {
156
+ if (filename === undefined || root === undefined || inside(root, join(dirname(filename), spec)))
157
+ return undefined;
158
+ const where = basename(root) === "workflows" || basename(root) === "policies" ? `${basename(root)}/` : "this directory";
159
+ return `it reaches outside ${where}, toward the config and its drivers; ${THROUGH_CTX}`;
160
+ }
161
+ for (const [pattern, reason] of REFUSED_PACKAGES)
162
+ if (pattern.test(spec))
163
+ return reason;
164
+ if (ALLOWED_PACKAGE.test(spec))
165
+ return undefined;
166
+ return "import only from `sanoma` (or `@sanoma-ai/workflows`), a `@sanoma-ai/connector-*` package, zod, or a file beside this one";
167
+ }
168
+ //# sourceMappingURL=lint.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lint.js","sourceRoot":"","sources":["../src/lint.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ import type { ResourceProblem } from "./resources.ts";
2
+ /** Where the lockfile is, relative to the config's root. */
3
+ export declare const LOCKFILE = "resources/sanoma.lock.json";
4
+ /** Which vendor object a declaration means: its `<vendor>.<type>` and the vendor's stable id for it. */
5
+ export interface Binding {
6
+ type: string;
7
+ id: string;
8
+ }
9
+ /** The lockfile's content: by declaration key, `<file>#<export>` (the file relative to the config's root, with `/`). */
10
+ export type Bindings = Record<string, Binding>;
11
+ /**
12
+ * The lockfile under `root`: no bindings when there is none, and no bindings with a problem when
13
+ * it is not JSON or not a map of `<file>#<export>` to `{ type, id }`.
14
+ */
15
+ export declare function readLockfile(root: string): {
16
+ bindings: Bindings;
17
+ problems: ResourceProblem[];
18
+ };
19
+ /** The lockfile's text for `bindings`: keys sorted, two-space JSON, a trailing newline, so a diff shows only what changed. */
20
+ export declare function serializeLockfile(bindings: Bindings): string;
21
+ /** Writes the lockfile under `root` whole or not at all: to a file beside it, then renamed over it. Apply only. */
22
+ export declare function writeLockfile(root: string, bindings: Bindings): void;
23
+ /**
24
+ * One change to the lockfile: a declaration bound for the first time (`bind`, `to`), pointed at
25
+ * another object (`rebind`, `from` and `to`), or no longer bound (`unbind`, `from`). `type` is
26
+ * the binding's `<vendor>.<type>`, the new one's for a rebind.
27
+ */
28
+ export interface Rebind {
29
+ key: string;
30
+ type: string;
31
+ kind: "bind" | "rebind" | "unbind";
32
+ from?: string;
33
+ to?: string;
34
+ }
35
+ /** What changed from `before` to `after`, by key, sorted. */
36
+ export declare function diffLockfiles(before: Bindings, after: Bindings): Rebind[];
@@ -0,0 +1,69 @@
1
+ import { existsSync, readFileSync, renameSync, rmSync, writeFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { z } from "zod";
4
+ // The lockfile: which vendor object each declaration means, kept apart from the data files (which
5
+ // hold intent only), as `package-lock.json` is from `package.json`. Only apply writes it.
6
+ /** Where the lockfile is, relative to the config's root. */
7
+ export const LOCKFILE = "resources/sanoma.lock.json";
8
+ const lockfile = z.record(z.string().regex(/^resources\/[^#]+#[^#]+$/), z.strictObject({ type: z.string().regex(/^[^.\s]+\.[^.\s]+$/), id: z.string().min(1) }));
9
+ /**
10
+ * The lockfile under `root`: no bindings when there is none, and no bindings with a problem when
11
+ * it is not JSON or not a map of `<file>#<export>` to `{ type, id }`.
12
+ */
13
+ export function readLockfile(root) {
14
+ const path = join(root, LOCKFILE);
15
+ if (!existsSync(path))
16
+ return { bindings: {}, problems: [] };
17
+ let json;
18
+ try {
19
+ json = JSON.parse(readFileSync(path, "utf8"));
20
+ }
21
+ catch (e) {
22
+ return { bindings: {}, problems: [{ file: LOCKFILE, message: `not JSON: ${e.message}` }] };
23
+ }
24
+ const parsed = lockfile.safeParse(json);
25
+ if (!parsed.success) {
26
+ // One line: zod's own spans lines.
27
+ return {
28
+ bindings: {},
29
+ problems: [{ file: LOCKFILE, message: z.prettifyError(parsed.error).replaceAll(/\s*\n\s*/g, " ") }],
30
+ };
31
+ }
32
+ return { bindings: parsed.data, problems: [] };
33
+ }
34
+ /** The lockfile's text for `bindings`: keys sorted, two-space JSON, a trailing newline, so a diff shows only what changed. */
35
+ export function serializeLockfile(bindings) {
36
+ const sorted = Object.entries(bindings)
37
+ .toSorted(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))
38
+ .map(([key, { type, id }]) => [key, { type, id }]);
39
+ return `${JSON.stringify(Object.fromEntries(sorted), null, 2)}\n`;
40
+ }
41
+ /** Writes the lockfile under `root` whole or not at all: to a file beside it, then renamed over it. Apply only. */
42
+ export function writeLockfile(root, bindings) {
43
+ const path = join(root, LOCKFILE);
44
+ const temporary = `${path}.${process.pid}.tmp`;
45
+ try {
46
+ writeFileSync(temporary, serializeLockfile(bindings));
47
+ renameSync(temporary, path);
48
+ }
49
+ catch (err) {
50
+ rmSync(temporary, { force: true });
51
+ throw err;
52
+ }
53
+ }
54
+ /** What changed from `before` to `after`, by key, sorted. */
55
+ export function diffLockfiles(before, after) {
56
+ const keys = [...new Set([...Object.keys(before), ...Object.keys(after)])].toSorted();
57
+ return keys.flatMap((key) => {
58
+ const was = before[key];
59
+ const now = after[key];
60
+ if (!now)
61
+ return was ? [{ key, type: was.type, kind: "unbind", from: was.id }] : [];
62
+ if (!was)
63
+ return [{ key, type: now.type, kind: "bind", to: now.id }];
64
+ if (was.id === now.id && was.type === now.type)
65
+ return [];
66
+ return [{ key, type: now.type, kind: "rebind", from: was.id, to: now.id }];
67
+ });
68
+ }
69
+ //# sourceMappingURL=lockfile.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lockfile.js","sourceRoot":"","sources":["../src/lockfile.ts"],"names":[],"mappings":"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"}
package/dist/log.d.ts ADDED
@@ -0,0 +1,24 @@
1
+ import type { DLogger } from "@dbos-inc/dbos-sdk";
2
+ /** Shows the messages at `level` and above from now on; an unknown level as `warn`. */
3
+ export declare function setLogLevel(level?: string): void;
4
+ /** Tells the operator what the runtime did, such as loading credentials (never their values); shown at `info`. */
5
+ export declare const info: (message: string) => void;
6
+ /** Tells the operator something went wrong or was skipped, without failing anything; shown at `warn`. */
7
+ export declare const warn: (message: string) => void;
8
+ /**
9
+ * Runs a workflow's body, as a sandbox run's when `sandbox`: `dbosLogger` then shows none of DBOS's
10
+ * warnings from inside it (its steps' failed tries among them), nor the error it fails with. A
11
+ * scenario's fakes fail on purpose; the run's ledger and its status say what happened. The run
12
+ * fails with a copy of its error (same prototype and properties), made for it, so the same error
13
+ * object thrown by a live run is still shown.
14
+ */
15
+ export declare function quietIfSandbox<T>(sandbox: boolean, body: () => Promise<T>): Promise<T>;
16
+ /**
17
+ * DBOS's logger (`DBOS.setConfig`'s `logger`): its lines at the last `startWorker`'s `logLevel`,
18
+ * printed as DBOS's own console logger (`DBOSConsoleLogger`) prints them, except a sandbox run's
19
+ * (`quietIfSandbox`). A live run's failed tries and failure show as they always did. Installed
20
+ * only while DBOS exports no logs over OTLP: a custom logger replaces that transport.
21
+ */
22
+ export declare const dbosLogger: DLogger;
23
+ /** A value as JSON, or as a string when it isn't JSON, cut to `max` characters, for a message. */
24
+ export declare function shown(value: unknown, max?: number): string;
package/dist/log.js ADDED
@@ -0,0 +1,83 @@
1
+ import { AsyncLocalStorage } from "node:async_hooks";
2
+ // DBOS's levels (winston's), most severe first. A message shows when its level is at or above the
3
+ // last `startWorker`'s `logLevel`, as DBOS's own do: `warn` by default. One threshold for the
4
+ // process, as DBOS's own logger is one per process.
5
+ const LEVELS = ["error", "warn", "info", "http", "verbose", "debug", "silly"];
6
+ const levelsUpTo = (level) => new Set(LEVELS.slice(0, LEVELS.indexOf(level) + 1));
7
+ let visible = levelsUpTo("warn");
8
+ /** Shows the messages at `level` and above from now on; an unknown level as `warn`. */
9
+ export function setLogLevel(level = "warn") {
10
+ visible = levelsUpTo(LEVELS.includes(level) ? level : "warn");
11
+ }
12
+ const shows = (level) => visible.has(level);
13
+ /** Tells the operator what the runtime did, such as loading credentials (never their values); shown at `info`. */
14
+ export const info = (message) => {
15
+ if (shows("info"))
16
+ console.info(`sanoma: ${message}`);
17
+ };
18
+ /** Tells the operator something went wrong or was skipped, without failing anything; shown at `warn`. */
19
+ export const warn = (message) => {
20
+ if (shows("warn"))
21
+ console.warn(`sanoma: ${message}`);
22
+ };
23
+ /** Set while a sandbox run's body runs. */
24
+ const sandboxRun = new AsyncLocalStorage();
25
+ /** What sandbox runs failed with: each a copy made for its run (`quietIfSandbox`). */
26
+ const sandboxErrors = new WeakSet();
27
+ /**
28
+ * Runs a workflow's body, as a sandbox run's when `sandbox`: `dbosLogger` then shows none of DBOS's
29
+ * warnings from inside it (its steps' failed tries among them), nor the error it fails with. A
30
+ * scenario's fakes fail on purpose; the run's ledger and its status say what happened. The run
31
+ * fails with a copy of its error (same prototype and properties), made for it, so the same error
32
+ * object thrown by a live run is still shown.
33
+ */
34
+ export function quietIfSandbox(sandbox, body) {
35
+ if (!sandbox)
36
+ return body();
37
+ return sandboxRun.run(true, body).catch((err) => {
38
+ if (typeof err !== "object" || err === null)
39
+ throw err;
40
+ const copy = Object.create(Object.getPrototypeOf(err), Object.getOwnPropertyDescriptors(err));
41
+ // V8's `stack` accessor reads the original's internal slot, which the copy lacks.
42
+ if ("stack" in err)
43
+ Object.defineProperty(copy, "stack", { value: err.stack, writable: true, configurable: true });
44
+ sandboxErrors.add(copy);
45
+ throw copy;
46
+ });
47
+ }
48
+ /**
49
+ * DBOS's logger (`DBOS.setConfig`'s `logger`): its lines at the last `startWorker`'s `logLevel`,
50
+ * printed as DBOS's own console logger (`DBOSConsoleLogger`) prints them, except a sandbox run's
51
+ * (`quietIfSandbox`). A live run's failed tries and failure show as they always did. Installed
52
+ * only while DBOS exports no logs over OTLP: a custom logger replaces that transport.
53
+ */
54
+ export const dbosLogger = {
55
+ info: (entry) => void (shows("info") && console.log(entry)),
56
+ debug: (entry) => void (shows("debug") && console.debug(entry)),
57
+ warn(entry) {
58
+ if (shows("warn") && !sandboxRun.getStore())
59
+ console.warn(entry);
60
+ },
61
+ // DBOS's GlobalLogger passes a string, with the stack in `metadata.stack` and an error in `metadata.error`.
62
+ error(entry, metadata) {
63
+ const error = metadata?.error;
64
+ if (!shows("error") || (typeof error === "object" && error !== null && sandboxErrors.has(error)))
65
+ return;
66
+ if (metadata?.stack)
67
+ console.error(entry, "\n", metadata.stack);
68
+ else
69
+ console.error(entry);
70
+ },
71
+ };
72
+ /** A value as JSON, or as a string when it isn't JSON, cut to `max` characters, for a message. */
73
+ export function shown(value, max = Number.POSITIVE_INFINITY) {
74
+ let text;
75
+ try {
76
+ text = JSON.stringify(value) ?? String(value);
77
+ }
78
+ catch {
79
+ text = String(value);
80
+ }
81
+ return text.length > max ? `${text.slice(0, max)}…` : text;
82
+ }
83
+ //# sourceMappingURL=log.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"log.js","sourceRoot":"","sources":["../src/log.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAGrD,kGAAkG;AAClG,8FAA8F;AAC9F,oDAAoD;AACpD,MAAM,MAAM,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;AAC9E,MAAM,UAAU,GAAG,CAAC,KAAa,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AAC1F,IAAI,OAAO,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC;AAEjC,uFAAuF;AACvF,MAAM,UAAU,WAAW,CAAC,KAAK,GAAG,MAAM;IACxC,OAAO,GAAG,UAAU,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;AAChE,CAAC;AAED,MAAM,KAAK,GAAG,CAAC,KAAa,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AAEpD,kHAAkH;AAClH,MAAM,CAAC,MAAM,IAAI,GAAG,CAAC,OAAe,EAAE,EAAE;IACtC,IAAI,KAAK,CAAC,MAAM,CAAC;QAAE,OAAO,CAAC,IAAI,CAAC,WAAW,OAAO,EAAE,CAAC,CAAC;AACxD,CAAC,CAAC;AAEF,yGAAyG;AACzG,MAAM,CAAC,MAAM,IAAI,GAAG,CAAC,OAAe,EAAE,EAAE;IACtC,IAAI,KAAK,CAAC,MAAM,CAAC;QAAE,OAAO,CAAC,IAAI,CAAC,WAAW,OAAO,EAAE,CAAC,CAAC;AACxD,CAAC,CAAC;AAEF,2CAA2C;AAC3C,MAAM,UAAU,GAAG,IAAI,iBAAiB,EAAQ,CAAC;AACjD,sFAAsF;AACtF,MAAM,aAAa,GAAG,IAAI,OAAO,EAAU,CAAC;AAE5C;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAAI,OAAgB,EAAE,IAAsB;IACxE,IAAI,CAAC,OAAO;QAAE,OAAO,IAAI,EAAE,CAAC;IAC5B,OAAO,UAAU,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;QACvD,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI;YAAE,MAAM,GAAG,CAAC;QACvD,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,cAAc,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,yBAAyB,CAAC,GAAG,CAAC,CAAW,CAAC;QACxG,kFAAkF;QAClF,IAAI,OAAO,IAAI,GAAG;YAAE,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC;QACnH,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACxB,MAAM,IAAI,CAAC;IACb,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,MAAM,UAAU,GAAY;IACjC,IAAI,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAC3D,KAAK,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAC/D,IAAI,CAAC,KAAK;QACR,IAAI,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,EAAE;YAAE,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACnE,CAAC;IACD,4GAA4G;IAC5G,KAAK,CAAC,KAAK,EAAE,QAAQ;QACnB,MAAM,KAAK,GAAG,QAAQ,EAAE,KAAK,CAAC;QAC9B,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,aAAa,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;YAAE,OAAO;QACzG,IAAI,QAAQ,EAAE,KAAK;YAAE,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,IAAI,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC;;YAC3D,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAC5B,CAAC;CACF,CAAC;AAEF,kGAAkG;AAClG,MAAM,UAAU,KAAK,CAAC,KAAc,EAAE,GAAG,GAAG,MAAM,CAAC,iBAAiB;IAClE,IAAI,IAAY,CAAC;IACjB,IAAI,CAAC;QACH,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC;IAChD,CAAC;IAAC,MAAM,CAAC;QACP,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IACvB,CAAC;IACD,OAAO,IAAI,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;AAC7D,CAAC"}