@offsida/cli 0.3.0 → 0.4.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.
- package/dist/bundle.d.ts +1 -0
- package/dist/bundle.js +1 -1
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +26 -7
- package/dist/compile-workflow.d.ts +11 -0
- package/dist/compile-workflow.js +122 -0
- package/dist/push-directory.d.ts +1 -1
- package/dist/push-directory.js +4 -2
- package/dist/resolve-package.d.ts +3 -1
- package/dist/resolve-package.js +6 -4
- package/dist/workflow-file.d.ts +3 -1
- package/dist/workflow-file.js +4 -0
- package/package.json +2 -2
package/dist/bundle.d.ts
CHANGED
package/dist/bundle.js
CHANGED
package/dist/cli.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { type PushDirectoryDeps } from './push-directory.js';
|
|
3
|
-
export declare const USAGE = "usage:\n offsida push [dir] [--publish] [--url <u>] [--org <id>] [--allow-remote]\n offsida build [dir] [--out-dir <dir>]\n\ndir defaults to the current directory and must contain a package.json.\n\nEvery file below dir is one artifact, named after the file:\n <name>.action.ts default-exports defineAction(\u2026); uploaded as a package holding that\n one action, also called <name>. Names are kebab-case (a-z, 0-9, -).\n <name>.package.ts default-exports definePackage(\u2026) \u2014 for connections, triggers, config,\n or several actions sharing one revision. Letters, digits, . _ -.\nNames are per org: two packages pushing the same name overwrite each other's artifact.\nA package file may not import an action file (that action would be published twice).\n\npush uploads every package file, then every action file (so an action requiring a\npackage's connection gets the one just pushed), then every *.workflow.json as that
|
|
3
|
+
export declare const USAGE = "usage:\n offsida push [dir] [--publish] [--url <u>] [--org <id>] [--allow-remote]\n offsida build [dir] [--out-dir <dir>]\n\ndir defaults to the current directory and must contain a package.json.\n\nEvery file below dir is one artifact, named after the file:\n <name>.action.ts default-exports defineAction(\u2026); uploaded as a package holding that\n one action, also called <name>. Names are kebab-case (a-z, 0-9, -).\n <name>.package.ts default-exports definePackage(\u2026) \u2014 for connections, triggers, config,\n or several actions sharing one revision. Letters, digits, . _ -.\nNames are per org: two packages pushing the same name overwrite each other's artifact.\nA package file may not import an action file (that action would be published twice).\n\npush uploads every package file, then every action file (so an action requiring a\npackage's connection gets the one just pushed), then every *.workflow.json \u2014 and every\n*.workflow.ts, compiled \u2014 as that workflow's draft, replacing edits made in the Offsida\neditor. A failed upload skips\nthe workflows. Subfolders with their own package.json are separate packages and are\nskipped, as are node_modules, dist and dot-folders. A workflow file's optional \"id\"\npins one workflow in one org; without it the workflow is matched by name or created.\n--publish also publishes each workflow; \"latest\" steps lock to the code just pushed.\n\nA *.workflow.ts default-exports defineWorkflow(\u2026) from @offsida/sdk/workflow. It is\nbundled and run in Node at push (author code, like any build script); an import of a\n*.action.ts becomes that action's name, so the action's own code never runs.\n\nbuild bundles every artifact and compiles every *.workflow.ts without uploading: with\n--out-dir it writes <name>.js per artifact and <file>.json per typed workflow; without,\nit prints each artifact's size against the cap and each typed workflow's name.\n\nA first publish goes live with no capability confirmation (offsida.web#14). A later\npublish that adds access is left for confirming in Offsida (exit 2). Every push mints\na new revision of every artifact, so --publish republishes \"latest\" workflows\n(offsida.web#15).\n\nAuth (environment only): OFFSIDA_TOKEN, or OFFSIDA_EMAIL + OFFSIDA_CODE.\nScopes: code:publish; workflows:list, :get, :create, :update; workflows:publish with --publish.\nAlso: OFFSIDA_URL (default http://localhost:3808), OFFSIDA_ORG, OFFSIDA_ALLOW_REMOTE=1.\n\nLimits: name matching reads a list that lags a few seconds, so two quick pushes of a\nnew workflow can create two. Same-named workflows in different packages overwrite\neach other without \"id\". Deleting a *.workflow.json leaves its workflow live.\n\nBundles are minified and must stay under the platform's 1 MiB cap. A rate-limited\nrequest (429) waits out its Retry-After, up to a minute, and is retried.\n\nExit codes: 0 done, 1 something failed, 2 something needs confirming in Offsida.";
|
|
4
4
|
type RunDeps = PushDirectoryDeps & {
|
|
5
5
|
out?: (s: string) => void;
|
|
6
6
|
err?: (s: string) => void;
|
package/dist/cli.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { realpathSync } from 'node:fs';
|
|
3
3
|
import { mkdir, writeFile } from 'node:fs/promises';
|
|
4
|
-
import { join, relative } from 'node:path';
|
|
4
|
+
import { basename, join, relative } from 'node:path';
|
|
5
5
|
import { fileURLToPath } from 'node:url';
|
|
6
|
+
import { compileWorkflowFiles } from './compile-workflow.js';
|
|
6
7
|
import { prepareArtifacts } from './prepare.js';
|
|
7
8
|
import { CODE_SIZE_LIMIT } from './push.js';
|
|
8
9
|
import { pushDirectory } from './push-directory.js';
|
|
@@ -22,15 +23,21 @@ Names are per org: two packages pushing the same name overwrite each other's art
|
|
|
22
23
|
A package file may not import an action file (that action would be published twice).
|
|
23
24
|
|
|
24
25
|
push uploads every package file, then every action file (so an action requiring a
|
|
25
|
-
package's connection gets the one just pushed), then every *.workflow.json
|
|
26
|
-
workflow's draft, replacing edits made in the Offsida
|
|
26
|
+
package's connection gets the one just pushed), then every *.workflow.json — and every
|
|
27
|
+
*.workflow.ts, compiled — as that workflow's draft, replacing edits made in the Offsida
|
|
28
|
+
editor. A failed upload skips
|
|
27
29
|
the workflows. Subfolders with their own package.json are separate packages and are
|
|
28
30
|
skipped, as are node_modules, dist and dot-folders. A workflow file's optional "id"
|
|
29
31
|
pins one workflow in one org; without it the workflow is matched by name or created.
|
|
30
32
|
--publish also publishes each workflow; "latest" steps lock to the code just pushed.
|
|
31
33
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
+
A *.workflow.ts default-exports defineWorkflow(…) from @offsida/sdk/workflow. It is
|
|
35
|
+
bundled and run in Node at push (author code, like any build script); an import of a
|
|
36
|
+
*.action.ts becomes that action's name, so the action's own code never runs.
|
|
37
|
+
|
|
38
|
+
build bundles every artifact and compiles every *.workflow.ts without uploading: with
|
|
39
|
+
--out-dir it writes <name>.js per artifact and <file>.json per typed workflow; without,
|
|
40
|
+
it prints each artifact's size against the cap and each typed workflow's name.
|
|
34
41
|
|
|
35
42
|
A first publish goes live with no capability confirmation (offsida.web#14). A later
|
|
36
43
|
publish that adds access is left for confirming in Offsida (exit 2). Every push mints
|
|
@@ -109,9 +116,11 @@ export async function run(argv, env, deps = {}) {
|
|
|
109
116
|
const pkg = await resolvePackage(dir);
|
|
110
117
|
for (const w of pkg.warnings)
|
|
111
118
|
err(`warning: ${w}`);
|
|
112
|
-
if (pkg.artifacts.length === 0)
|
|
113
|
-
throw new Error(`${dir}: no *.action.ts or *.
|
|
119
|
+
if (pkg.artifacts.length === 0 && pkg.workflowTsFiles.length === 0) {
|
|
120
|
+
throw new Error(`${dir}: no *.action.ts, *.package.ts or *.workflow.ts files to build`);
|
|
121
|
+
}
|
|
114
122
|
const artifacts = await prepareArtifacts(pkg);
|
|
123
|
+
const workflows = await compileWorkflowFiles(pkg);
|
|
115
124
|
const outDir = flags.get('--out-dir');
|
|
116
125
|
if (typeof outDir === 'string') {
|
|
117
126
|
await mkdir(outDir, { recursive: true });
|
|
@@ -120,9 +129,19 @@ export async function run(argv, env, deps = {}) {
|
|
|
120
129
|
await writeFile(file, a.code);
|
|
121
130
|
out(`wrote ${file}`);
|
|
122
131
|
}
|
|
132
|
+
for (const w of workflows) {
|
|
133
|
+
const file = join(outDir, `${basename(w.path, '.ts')}.json`);
|
|
134
|
+
const { path: _path, ...json } = w;
|
|
135
|
+
await writeFile(file, `${JSON.stringify(json, null, 2)}\n`);
|
|
136
|
+
out(`wrote ${file}`);
|
|
137
|
+
}
|
|
123
138
|
}
|
|
124
139
|
else {
|
|
140
|
+
for (const w of workflows)
|
|
141
|
+
out(`workflow "${w.name}" ${relative(pkg.dir, w.path)}`);
|
|
125
142
|
const rows = artifacts.map((a) => [a.name, relative(pkg.dir, a.file), a.code.length]);
|
|
143
|
+
if (rows.length === 0)
|
|
144
|
+
return 0;
|
|
126
145
|
const w0 = Math.max(...rows.map((r) => r[0].length));
|
|
127
146
|
const w1 = Math.max(...rows.map((r) => r[1].length));
|
|
128
147
|
for (const [name, file, size] of rows) {
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type ResolvedPackage } from './resolve-package.js';
|
|
2
|
+
import { type WorkflowFile } from './workflow-file.js';
|
|
3
|
+
/**
|
|
4
|
+
* Compile one `*.workflow.ts`: bundle it for Node (packages stay external, so `@offsida/sdk` resolves from
|
|
5
|
+
* the package's own install), import it, and call its default export's `compile()`. The bundle is written
|
|
6
|
+
* under the package's `node_modules/.cache/offsida/` so bare imports resolve, and removed afterwards.
|
|
7
|
+
* Running the file is running author code — the same trust as any build script.
|
|
8
|
+
*/
|
|
9
|
+
export declare function compileWorkflowFile(pkg: ResolvedPackage, file: string): Promise<WorkflowFile>;
|
|
10
|
+
/** Compile every `*.workflow.ts` in the package, reporting every failure in one error. */
|
|
11
|
+
export declare function compileWorkflowFiles(pkg: ResolvedPackage): Promise<WorkflowFile[]>;
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import * as esbuild from 'esbuild-wasm';
|
|
2
|
+
import { realpathSync } from 'node:fs';
|
|
3
|
+
import { mkdir, rm, writeFile } from 'node:fs/promises';
|
|
4
|
+
import { basename, join, relative } from 'node:path';
|
|
5
|
+
import { pathToFileURL } from 'node:url';
|
|
6
|
+
import { ensureInit } from './bundle.js';
|
|
7
|
+
import { ACTION_NAME } from './resolve-package.js';
|
|
8
|
+
import { parseWorkflowFile } from './workflow-file.js';
|
|
9
|
+
const ACTION_SUFFIX = '.action.ts';
|
|
10
|
+
/**
|
|
11
|
+
* The plugin that makes a typed workflow cheap to compile: an import of a `*.action.ts` becomes a marker
|
|
12
|
+
* carrying the action's name (its file name), which `step.action` reads. TypeScript still checks the
|
|
13
|
+
* workflow against the real action; the compiled workflow never loads the action's code or dependencies.
|
|
14
|
+
*/
|
|
15
|
+
function actionMarkers(pkg) {
|
|
16
|
+
// esbuild reports real paths, so compare real paths (a temp dir or a checkout may sit behind a symlink).
|
|
17
|
+
const real = (p) => realpathSync(p);
|
|
18
|
+
const root = real(pkg.dir);
|
|
19
|
+
const actions = new Set(pkg.artifacts.filter((a) => a.kind === 'action').map((a) => real(a.file)));
|
|
20
|
+
return {
|
|
21
|
+
name: 'offsida-action-markers',
|
|
22
|
+
setup(build) {
|
|
23
|
+
build.onResolve({ filter: /\.action(\.ts)?$/ }, async (args) => {
|
|
24
|
+
if (args.pluginData === 'offsida-resolving')
|
|
25
|
+
return undefined;
|
|
26
|
+
const r = await build.resolve(args.path, { resolveDir: args.resolveDir, kind: args.kind, pluginData: 'offsida-resolving' });
|
|
27
|
+
if (r.errors.length > 0 || !r.path.endsWith(ACTION_SUFFIX))
|
|
28
|
+
return undefined;
|
|
29
|
+
return { path: r.path, namespace: 'offsida-action' };
|
|
30
|
+
});
|
|
31
|
+
build.onLoad({ filter: /.*/, namespace: 'offsida-action' }, (args) => {
|
|
32
|
+
const rel = relative(root, args.path);
|
|
33
|
+
const name = basename(args.path).slice(0, -ACTION_SUFFIX.length);
|
|
34
|
+
if (!actions.has(args.path)) {
|
|
35
|
+
return { errors: [{ text: `${rel} is not an action of this package — a workflow can only call actions pushed with it` }] };
|
|
36
|
+
}
|
|
37
|
+
if (!ACTION_NAME.test(name))
|
|
38
|
+
return { errors: [{ text: `${rel}: an action file name must be kebab-case` }] };
|
|
39
|
+
return { contents: `export default { [Symbol.for('offsida.action')]: { name: ${JSON.stringify(name)} } };`, loader: 'js' };
|
|
40
|
+
});
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
function buildMessage(e) {
|
|
45
|
+
const errors = e.errors;
|
|
46
|
+
if (!errors?.length)
|
|
47
|
+
return e.message;
|
|
48
|
+
return errors.map((x) => (x.location ? `${x.text} (${x.location.file}:${x.location.line})` : x.text)).join('; ');
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Compile one `*.workflow.ts`: bundle it for Node (packages stay external, so `@offsida/sdk` resolves from
|
|
52
|
+
* the package's own install), import it, and call its default export's `compile()`. The bundle is written
|
|
53
|
+
* under the package's `node_modules/.cache/offsida/` so bare imports resolve, and removed afterwards.
|
|
54
|
+
* Running the file is running author code — the same trust as any build script.
|
|
55
|
+
*/
|
|
56
|
+
export async function compileWorkflowFile(pkg, file) {
|
|
57
|
+
const rel = relative(pkg.dir, file);
|
|
58
|
+
await ensureInit();
|
|
59
|
+
let code;
|
|
60
|
+
try {
|
|
61
|
+
const result = await esbuild.build({
|
|
62
|
+
entryPoints: [file],
|
|
63
|
+
bundle: true,
|
|
64
|
+
format: 'esm',
|
|
65
|
+
platform: 'node',
|
|
66
|
+
target: 'node20',
|
|
67
|
+
packages: 'external',
|
|
68
|
+
absWorkingDir: pkg.dir,
|
|
69
|
+
write: false,
|
|
70
|
+
logLevel: 'silent',
|
|
71
|
+
plugins: [actionMarkers(pkg)],
|
|
72
|
+
});
|
|
73
|
+
code = result.outputFiles[0].text;
|
|
74
|
+
}
|
|
75
|
+
catch (e) {
|
|
76
|
+
throw new Error(`${rel}: ${buildMessage(e)}`);
|
|
77
|
+
}
|
|
78
|
+
const cacheDir = join(pkg.dir, 'node_modules', '.cache', 'offsida');
|
|
79
|
+
await mkdir(cacheDir, { recursive: true });
|
|
80
|
+
const out = join(cacheDir, `${basename(file, '.ts')}-${process.pid}-${Date.now()}.mjs`);
|
|
81
|
+
await writeFile(out, code);
|
|
82
|
+
try {
|
|
83
|
+
let mod;
|
|
84
|
+
try {
|
|
85
|
+
mod = (await import(pathToFileURL(out).href));
|
|
86
|
+
}
|
|
87
|
+
catch (e) {
|
|
88
|
+
throw new Error(`${rel}: ${e.message}`);
|
|
89
|
+
}
|
|
90
|
+
const workflow = mod.default;
|
|
91
|
+
if (!workflow || typeof workflow.compile !== 'function') {
|
|
92
|
+
throw new Error(`${rel}: must default-export defineWorkflow({ … }) from @offsida/sdk/workflow`);
|
|
93
|
+
}
|
|
94
|
+
let compiled;
|
|
95
|
+
try {
|
|
96
|
+
compiled = workflow.compile();
|
|
97
|
+
}
|
|
98
|
+
catch (e) {
|
|
99
|
+
throw new Error(`${rel}: ${e.message}`);
|
|
100
|
+
}
|
|
101
|
+
return parseWorkflowFile(file, compiled);
|
|
102
|
+
}
|
|
103
|
+
finally {
|
|
104
|
+
await rm(out, { force: true });
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
/** Compile every `*.workflow.ts` in the package, reporting every failure in one error. */
|
|
108
|
+
export async function compileWorkflowFiles(pkg) {
|
|
109
|
+
const out = [];
|
|
110
|
+
const problems = [];
|
|
111
|
+
for (const file of pkg.workflowTsFiles) {
|
|
112
|
+
try {
|
|
113
|
+
out.push(await compileWorkflowFile(pkg, file));
|
|
114
|
+
}
|
|
115
|
+
catch (e) {
|
|
116
|
+
problems.push(e.message);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
if (problems.length > 0)
|
|
120
|
+
throw new Error(problems.join('\n'));
|
|
121
|
+
return out;
|
|
122
|
+
}
|
package/dist/push-directory.d.ts
CHANGED
|
@@ -11,7 +11,7 @@ export type PushDirectoryDeps = {
|
|
|
11
11
|
};
|
|
12
12
|
/**
|
|
13
13
|
* `offsida push [dir]`: each *.package.ts / *.action.ts as its own artifact, then each *.workflow.json
|
|
14
|
-
* as its workflow's draft (and, with `publish`, published — `latest` steps lock to the code just pushed). Throws only before anything
|
|
14
|
+
* and compiled *.workflow.ts as its workflow's draft (and, with `publish`, published — `latest` steps lock to the code just pushed). Throws only before anything
|
|
15
15
|
* is pushed (pre-flight, target, auth). After that every problem is reported and the result is the worst
|
|
16
16
|
* outcome: 1 failed, 2 needs confirming in Offsida, 0 done.
|
|
17
17
|
*/
|
package/dist/push-directory.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { relative } from 'node:path';
|
|
2
2
|
import { connect } from './api.js';
|
|
3
|
+
import { compileWorkflowFiles } from './compile-workflow.js';
|
|
3
4
|
import { prepareArtifacts } from './prepare.js';
|
|
4
5
|
import { pushCode } from './push.js';
|
|
5
6
|
import { resolvePackage } from './resolve-package.js';
|
|
@@ -14,7 +15,7 @@ const SUMMARY = [
|
|
|
14
15
|
];
|
|
15
16
|
/**
|
|
16
17
|
* `offsida push [dir]`: each *.package.ts / *.action.ts as its own artifact, then each *.workflow.json
|
|
17
|
-
* as its workflow's draft (and, with `publish`, published — `latest` steps lock to the code just pushed). Throws only before anything
|
|
18
|
+
* and compiled *.workflow.ts as its workflow's draft (and, with `publish`, published — `latest` steps lock to the code just pushed). Throws only before anything
|
|
18
19
|
* is pushed (pre-flight, target, auth). After that every problem is reported and the result is the worst
|
|
19
20
|
* outcome: 1 failed, 2 needs confirming in Offsida, 0 done.
|
|
20
21
|
*/
|
|
@@ -32,12 +33,13 @@ export async function pushDirectory(opts, deps = {}) {
|
|
|
32
33
|
const files = [];
|
|
33
34
|
for (const path of pkg.workflowFiles)
|
|
34
35
|
files.push(await readWorkflowFile(path));
|
|
36
|
+
files.push(...(await compileWorkflowFiles(pkg)));
|
|
35
37
|
assertNoDuplicates(files);
|
|
36
38
|
for (const f of files)
|
|
37
39
|
if (f.id !== undefined)
|
|
38
40
|
workflowDeps.pinned.add(f.id);
|
|
39
41
|
if (pkg.artifacts.length === 0 && files.length === 0) {
|
|
40
|
-
throw new Error(`${opts.dir}: nothing to push — no *.action.ts, *.package.ts or *.workflow.
|
|
42
|
+
throw new Error(`${opts.dir}: nothing to push — no *.action.ts, *.package.ts, *.workflow.json or *.workflow.ts files`);
|
|
41
43
|
}
|
|
42
44
|
const artifacts = await prepareArtifacts(pkg);
|
|
43
45
|
const api = await connect(opts, deps.fetch, workflowDeps.sleep);
|
|
@@ -9,12 +9,14 @@ export type ResolvedPackage = {
|
|
|
9
9
|
dir: string;
|
|
10
10
|
artifacts: ArtifactFile[];
|
|
11
11
|
workflowFiles: string[];
|
|
12
|
+
workflowTsFiles: string[];
|
|
12
13
|
warnings: string[];
|
|
13
14
|
};
|
|
15
|
+
export declare const ACTION_NAME: RegExp;
|
|
14
16
|
/**
|
|
15
17
|
* A package directory → what `offsida push` uploads. Artifacts: every `<name>.action.ts` and
|
|
16
18
|
* `<name>.package.ts` below, each named after its file, packages first (an action may require a
|
|
17
|
-
* package's connection) then by name. Workflows: every *.workflow.json below. Both skip node_modules,
|
|
19
|
+
* package's connection) then by name. Workflows: every *.workflow.json and *.workflow.ts below. Both skip node_modules,
|
|
18
20
|
* dist, dot-dirs and nested packages. Every naming problem is reported in one error.
|
|
19
21
|
*/
|
|
20
22
|
export declare function resolvePackage(dirArg: string): Promise<ResolvedPackage>;
|
package/dist/resolve-package.js
CHANGED
|
@@ -4,7 +4,7 @@ import { join, relative, resolve } from 'node:path';
|
|
|
4
4
|
const ARTIFACT_NAME = /^[a-zA-Z0-9._-]{1,64}$/;
|
|
5
5
|
// An action file's name is also its action's name, which the manifest schema holds to kebab-case
|
|
6
6
|
// (lib/contracts/src/schemas/connections.ts actionDefinitionSchema).
|
|
7
|
-
const ACTION_NAME = /^[a-z][a-z0-9-]{0,63}$/;
|
|
7
|
+
export const ACTION_NAME = /^[a-z][a-z0-9-]{0,63}$/;
|
|
8
8
|
const SUFFIXES = [
|
|
9
9
|
['.action.ts', 'action'],
|
|
10
10
|
['.package.ts', 'package'],
|
|
@@ -31,6 +31,8 @@ async function walk(dir, out) {
|
|
|
31
31
|
else if (e.isFile()) {
|
|
32
32
|
if (e.name.endsWith('.workflow.json'))
|
|
33
33
|
out.workflowFiles.push(path);
|
|
34
|
+
if (e.name.endsWith('.workflow.ts'))
|
|
35
|
+
out.workflowTsFiles.push(path);
|
|
34
36
|
const match = SUFFIXES.find(([suffix]) => e.name.endsWith(suffix));
|
|
35
37
|
if (match)
|
|
36
38
|
out.artifacts.push({ name: e.name.slice(0, -match[0].length), kind: match[1], file: path });
|
|
@@ -49,7 +51,7 @@ const byKindThenName = (a, b) => (a.kind === b.kind ? 0 : a.kind === 'package' ?
|
|
|
49
51
|
/**
|
|
50
52
|
* A package directory → what `offsida push` uploads. Artifacts: every `<name>.action.ts` and
|
|
51
53
|
* `<name>.package.ts` below, each named after its file, packages first (an action may require a
|
|
52
|
-
* package's connection) then by name. Workflows: every *.workflow.json below. Both skip node_modules,
|
|
54
|
+
* package's connection) then by name. Workflows: every *.workflow.json and *.workflow.ts below. Both skip node_modules,
|
|
53
55
|
* dist, dot-dirs and nested packages. Every naming problem is reported in one error.
|
|
54
56
|
*/
|
|
55
57
|
export async function resolvePackage(dirArg) {
|
|
@@ -73,7 +75,7 @@ export async function resolvePackage(dirArg) {
|
|
|
73
75
|
if (pkg.offsida?.name !== undefined) {
|
|
74
76
|
warnings.push('package.json: "offsida.name" is ignored — artifacts are named after their *.action.ts / *.package.ts files');
|
|
75
77
|
}
|
|
76
|
-
const found = { artifacts: [], workflowFiles: [] };
|
|
78
|
+
const found = { artifacts: [], workflowFiles: [], workflowTsFiles: [] };
|
|
77
79
|
await walk(dir, found);
|
|
78
80
|
const artifacts = found.artifacts.sort(byKindThenName);
|
|
79
81
|
const problems = [];
|
|
@@ -94,5 +96,5 @@ export async function resolvePackage(dirArg) {
|
|
|
94
96
|
}
|
|
95
97
|
if (problems.length > 0)
|
|
96
98
|
throw new Error(problems.join('\n'));
|
|
97
|
-
return { dir, artifacts, workflowFiles: found.workflowFiles.sort(), warnings };
|
|
99
|
+
return { dir, artifacts, workflowFiles: found.workflowFiles.sort(), workflowTsFiles: found.workflowTsFiles.sort(), warnings };
|
|
98
100
|
}
|
package/dist/workflow-file.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** A `*.workflow.json` file. `id` pins one workflow in one org; only `name` + `definition` are sent. */
|
|
1
|
+
/** A `*.workflow.json` file, or a compiled `*.workflow.ts`. `id` pins one workflow in one org; only `name` + `definition` are sent. */
|
|
2
2
|
export type WorkflowFile = {
|
|
3
3
|
path: string;
|
|
4
4
|
id?: string;
|
|
@@ -6,4 +6,6 @@ export type WorkflowFile = {
|
|
|
6
6
|
definition: Record<string, unknown>;
|
|
7
7
|
};
|
|
8
8
|
export declare function readWorkflowFile(path: string): Promise<WorkflowFile>;
|
|
9
|
+
/** The shape checks, on an already-parsed value — shared by `*.workflow.json` and compiled `*.workflow.ts`. */
|
|
10
|
+
export declare function parseWorkflowFile(path: string, v: unknown): WorkflowFile;
|
|
9
11
|
export declare function assertNoDuplicates(files: WorkflowFile[]): void;
|
package/dist/workflow-file.js
CHANGED
|
@@ -17,6 +17,10 @@ export async function readWorkflowFile(path) {
|
|
|
17
17
|
catch {
|
|
18
18
|
throw new Error(`${path}: not valid JSON`);
|
|
19
19
|
}
|
|
20
|
+
return parseWorkflowFile(path, v);
|
|
21
|
+
}
|
|
22
|
+
/** The shape checks, on an already-parsed value — shared by `*.workflow.json` and compiled `*.workflow.ts`. */
|
|
23
|
+
export function parseWorkflowFile(path, v) {
|
|
20
24
|
if (!isObject(v))
|
|
21
25
|
throw new Error(`${path}: expected a JSON object`);
|
|
22
26
|
if (typeof v.name !== 'string' || !v.name.trim())
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@offsida/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "The `offsida` CLI — bundle an integration package and publish it to a running Offsida environment.",
|
|
6
6
|
"license": "MIT",
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
39
|
"esbuild-wasm": "^0.25.12",
|
|
40
|
-
"@offsida/types": "0.
|
|
40
|
+
"@offsida/types": "0.3.0"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"@types/node": "^25.9.3",
|