@akterjs/cli 0.0.0-stage → 0.1.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 (109) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +47 -2
  3. package/dist/Argument-D81dqizB.mjs +57 -0
  4. package/dist/Array-B4kuTQeW.mjs +2323 -0
  5. package/dist/Boolean-kILIvmhE.mjs +26 -0
  6. package/dist/ChildProcess-BCIwxPGc.mjs +577 -0
  7. package/dist/CliError-Cf5xqkkj.mjs +633 -0
  8. package/dist/Command-Dzq9KM-h.mjs +5135 -0
  9. package/dist/Config-B6OND9WR.mjs +854 -0
  10. package/dist/Console-BKHUkH6a.mjs +141 -0
  11. package/dist/Data-CeCULr0-.mjs +251 -0
  12. package/dist/Digest-CBd3uv5B.mjs +348 -0
  13. package/dist/Duration-EH9Vy4U6.mjs +791 -0
  14. package/dist/Effect-CKFpqbmw.mjs +12911 -0
  15. package/dist/FileSystem-4pPcEb_i.mjs +1366 -0
  16. package/dist/HttpClientError-BUeMWx70.mjs +303 -0
  17. package/dist/HttpClientResponse-D5ZKICVV.mjs +855 -0
  18. package/dist/Match-CGPLZYrV.mjs +434 -0
  19. package/dist/MutableHashMap-f8nW8AJR.mjs +376 -0
  20. package/dist/MutableHashSet-_HI572Ya.mjs +155 -0
  21. package/dist/MutableRef-D4Qv592C.mjs +107 -0
  22. package/dist/Number-BvkRkfc-.mjs +137 -0
  23. package/dist/Option-DkxSnBhp.mjs +3967 -0
  24. package/dist/Order-C1JC991I.mjs +481 -0
  25. package/dist/Path-Djdv_eF5.mjs +130 -0
  26. package/dist/Queue-CO5UQ6os.mjs +1394 -0
  27. package/dist/Redacted-RkJrG5Me.mjs +160 -0
  28. package/dist/Ref-BIPOxJNH.mjs +267 -0
  29. package/dist/Runtime-BInIAwK3.mjs +297 -0
  30. package/dist/Schema-MiKt5K1v.mjs +10999 -0
  31. package/dist/SecureRandom-B_U4ysO3.mjs +279 -0
  32. package/dist/Semaphore-DOVJ4ZGS.mjs +177 -0
  33. package/dist/Stdio-KylmOBX_.mjs +74 -0
  34. package/dist/Stream-bK9QIETN.mjs +4012 -0
  35. package/dist/String-q5dcsVe4.mjs +351 -0
  36. package/dist/TerminalCapabilities-w_44MAca.mjs +1769 -0
  37. package/dist/WebCrypto-ZI_GNVlw.mjs +33 -0
  38. package/dist/actor-call.service-CGM_vD9u.mjs +1269 -0
  39. package/dist/actor-client.adapter-Coem7gF1.mjs +3691 -0
  40. package/dist/akter-program.config-D8yb9xQP.mjs +7034 -0
  41. package/dist/akter.cli.mjs +5 -0
  42. package/dist/app-cli.config.mjs +49 -0
  43. package/dist/app-entry.pure.mjs +31 -0
  44. package/dist/archive/akter-archive.schema.mjs +65 -0
  45. package/dist/archive/akter-archive.service.mjs +309 -0
  46. package/dist/archive/archive-cli.config.mjs +45 -0
  47. package/dist/archive/archive-invalid.errors.mjs +5 -0
  48. package/dist/archive/archived-lineage.pure.mjs +13 -0
  49. package/dist/archive/tar.pure.mjs +291 -0
  50. package/dist/archive/zstd.adapter.mjs +46 -0
  51. package/dist/bench/bench-report.pure.mjs +120 -0
  52. package/dist/bench/bench-runner.pure.mjs +89 -0
  53. package/dist/bench/bench.service.mjs +301 -0
  54. package/dist/cli-runtime.layer-BqK2mmVL.mjs +1191 -0
  55. package/dist/cli-runtime.layer.mjs +1 -0
  56. package/dist/cloud-client.adapter-Cy1BjDbG.mjs +3186 -0
  57. package/dist/cloud-client.adapter-DOVMoYAj.mjs +304 -0
  58. package/dist/command/akter-commands.config.mjs +32 -0
  59. package/dist/command/akter-program.config.mjs +1 -0
  60. package/dist/credentials/credentials.service.mjs +226 -0
  61. package/dist/credentials/keychain.adapter.mjs +92 -0
  62. package/dist/credentials/login.config.mjs +251 -0
  63. package/dist/deploy/auth/api-attempt.service.mjs +30 -0
  64. package/dist/deploy/auth/token-refresh.errors.mjs +4 -0
  65. package/dist/deploy/build-bundle.adapter.mjs +133 -0
  66. package/dist/deploy/build-manifest.pure.mjs +44 -0
  67. package/dist/deploy/cloud-client.adapter.mjs +1 -0
  68. package/dist/deploy/cloud-url.pure.mjs +17 -0
  69. package/dist/deploy/deploy-failed.errors.mjs +17 -0
  70. package/dist/deploy/deploy.service.mjs +156 -0
  71. package/dist/deploy/request-failure.pure.mjs +87 -0
  72. package/dist/dev-runner.pure.mjs +30 -0
  73. package/dist/docs/doc-topics.pure.mjs +21 -0
  74. package/dist/docs/docs.config.mjs +1 -0
  75. package/dist/docs.config-D2amjsje.mjs +190 -0
  76. package/dist/docs.config-D3zzLzLR.mjs +190 -0
  77. package/dist/export/actor-export.service.mjs +267 -0
  78. package/dist/export/export-failed.errors.mjs +4 -0
  79. package/dist/export/export-failure.pure.mjs +18 -0
  80. package/dist/export/ordered-lines.pure.mjs +43 -0
  81. package/dist/export/ranged-download.pure.mjs +66 -0
  82. package/dist/export/snapshot-download.pure.mjs +86 -0
  83. package/dist/history-runner.pure.mjs +186 -0
  84. package/dist/history-since.pure.mjs +17 -0
  85. package/dist/hosted-runtime.layer-Cx3IPsEd.mjs +16358 -0
  86. package/dist/local/environment-cli.config.mjs +90 -0
  87. package/dist/local/environment-runner.pure.mjs +75 -0
  88. package/dist/local/local-cli.config.mjs +159 -0
  89. package/dist/logs/log-follow.config.mjs +21 -0
  90. package/dist/logs/log-follow.service.mjs +87 -0
  91. package/dist/logs/log-lines.pure.mjs +44 -0
  92. package/dist/migrate-runner.pure.mjs +28 -0
  93. package/dist/operation-input.pure-CS9iUhqK.mjs +1383 -0
  94. package/dist/operation-registry.pure-DVC8EDgj.mjs +283 -0
  95. package/dist/registry/actor-call.service.mjs +1 -0
  96. package/dist/registry/actor-commands.config.mjs +127 -0
  97. package/dist/registry/actor-refusal.pure.mjs +34 -0
  98. package/dist/registry/approval.service.mjs +80 -0
  99. package/dist/registry/cloud-commands.config.mjs +151 -0
  100. package/dist/registry/cloud-served.pure.mjs +31 -0
  101. package/dist/registry/operation-call.service.mjs +262 -0
  102. package/dist/registry/operation-input.pure.mjs +1 -0
  103. package/dist/registry/operation-output.pure.mjs +91 -0
  104. package/dist/registry/served-command.config.mjs +57 -0
  105. package/dist/runner-exited.errors.mjs +10 -0
  106. package/dist/terminal/cli-exit.errors.mjs +38 -0
  107. package/dist/terminal/cli-failure.pure.mjs +31 -0
  108. package/dist/terminal/confirm.adapter.mjs +27 -0
  109. package/package.json +61 -3
@@ -0,0 +1,301 @@
1
+ import { C as isReadonlyArrayEmpty, T as join, j as map, r as contains, y as head } from "../Array-B4kuTQeW.mjs";
2
+ import { P as currentTimeMillis } from "../HttpClientResponse-D5ZKICVV.mjs";
3
+ import { n as log, t as error } from "../Console-BKHUkH6a.mjs";
4
+ import { At as provideContext, B as flatMap, Dt as orElseSucceed, Et as orDie, K as forEach, Q as fromOption, R as filterOrFail, T as context, Tt as option, U as fn, Vn as effect, X as forkScoped, Xt as succeed, _r as succeed$1, a as all, aa as Service, dt as map$1, et as gen, hr as make, o as andThen, on as timeoutOrElse, sn as transposeOption, sr as _await, tn as tap, z as findFirst } from "../Effect-CKFpqbmw.mjs";
5
+ import { t as FileSystem } from "../FileSystem-4pPcEb_i.mjs";
6
+ import { S as none, _ as isSome, f as getOrElse, h as isNone, u as fromNullishOr, w as some, x as match } from "../Option-DkxSnBhp.mjs";
7
+ import { t as Path } from "../Path-Djdv_eF5.mjs";
8
+ import { g as take, l as offer, v as unbounded } from "../Queue-CO5UQ6os.mjs";
9
+ import { F as String, I as Struct, S as Literals, X as Unknown, an as optionalKey, cr as getSomes, or as fromEntries, pt as fromJsonString, st as encodeEffect, tt as decodeEffect } from "../Schema-MiKt5K1v.mjs";
10
+ import { i as value } from "../Redacted-RkJrG5Me.mjs";
11
+ import { K as splitLines, O as mapEffect, Q as tick, W as runForEach, c as drop, i as decodeText, l as empty, nt as unwrap, r as concat, u as encodeText, v as fromEffect } from "../Stream-bK9QIETN.mjs";
12
+ import { i as sha256, t as Digest } from "../Digest-CBd3uv5B.mjs";
13
+ import { a as ChildProcessSpawner, n as make$1 } from "../ChildProcess-BCIwxPGc.mjs";
14
+ import { BenchSamples, benchReport, reportLines } from "./bench-report.pure.mjs";
15
+ import { benchRunner } from "./bench-runner.pure.mjs";
16
+ import { Credentials } from "../credentials/credentials.service.mjs";
17
+ import { t as CloudClient } from "../cloud-client.adapter-DOVMoYAj.mjs";
18
+ import { devRunner } from "../dev-runner.pure.mjs";
19
+ import { millisOf } from "../history-since.pure.mjs";
20
+ import { RunnerExitedError } from "../runner-exited.errors.mjs";
21
+ // src/bench/bench.service.ts
22
+ const anyPort = 0;
23
+ const exitedCleanly = 0;
24
+ const usageError = 2;
25
+ const fewestWorkers = 1;
26
+ const loopbackHosts = [
27
+ "localhost",
28
+ "127.0.0.1",
29
+ "[::1]"
30
+ ];
31
+ /**
32
+ * How often the runner gets the Cloud session's current token. The session refreshes within 30 s of its one-minute
33
+ * expiry, so a check more often than that hands the runner the new token before the old one lapses.
34
+ */
35
+ const tokenCheck = "10 seconds";
36
+ const devUrlLine = /akter dev: (?<url>http:\/\/127\.0\.0\.1:\d+),/u;
37
+ const jsonText = encodeEffect(fromJsonString(Unknown));
38
+ const samplesOf = decodeEffect(fromJsonString(BenchSamples));
39
+ const unknown = "unknown";
40
+ const packages = [
41
+ "@akterjs/cli",
42
+ "@akterjs/client",
43
+ "@akterjs/effect",
44
+ "effect"
45
+ ];
46
+ const lockfiles = [
47
+ "pnpm-lock.yaml",
48
+ "bun.lock",
49
+ "package-lock.json"
50
+ ];
51
+ const Manifest = fromJsonString(Struct({ version: String }));
52
+ const gitLines = fn("gitLines")(function* gitLines(args) {
53
+ const spawner = yield* ChildProcessSpawner;
54
+ const lines = yield* option(spawner.lines(make$1("git", args)));
55
+ return getOrElse(lines, () => []);
56
+ });
57
+ const nearest = fn("nearest")(function* nearest(directory, names) {
58
+ const fileSystem = yield* FileSystem;
59
+ const path = yield* Path;
60
+ const candidates = map(names, (name) => path.join(directory, name));
61
+ const found = yield* findFirst(candidates, (candidate) => orElseSucceed(fileSystem.exists(candidate), () => false));
62
+ const parent = path.dirname(directory);
63
+ if (isSome(found) || parent === directory) return found;
64
+ return yield* nearest(parent, names);
65
+ });
66
+ const versionOf = fn("versionOf")(function* versionOf(name) {
67
+ const fileSystem = yield* FileSystem;
68
+ const path = yield* Path;
69
+ const manifestPath = yield* nearest(path.resolve("."), [path.join("node_modules", name, "package.json")]);
70
+ const manifest = yield* flatMap(fromOption(manifestPath), (found) => flatMap(fileSystem.readFileString(found), decodeEffect(Manifest))).pipe(option);
71
+ return [name, match(manifest, {
72
+ onNone: () => unknown,
73
+ onSome: ({ version }) => version
74
+ })];
75
+ });
76
+ const lockfilePin = fn("lockfilePin")(function* lockfilePin() {
77
+ const fileSystem = yield* FileSystem;
78
+ const path = yield* Path;
79
+ const lockfile = yield* nearest(path.resolve("."), lockfiles);
80
+ if (isNone(lockfile)) return {
81
+ lockfile: "no lockfile",
82
+ lockfileSha256: unknown
83
+ };
84
+ const bytes = yield* fileSystem.readFile(lockfile.value);
85
+ const lockfileSha256 = yield* Digest.use((digest) => digest.digestHex(sha256, bytes));
86
+ return {
87
+ lockfile: path.relative(path.resolve("."), lockfile.value),
88
+ lockfileSha256
89
+ };
90
+ });
91
+ const worktreeOf = (changed) => {
92
+ if (isReadonlyArrayEmpty(changed)) return "clean";
93
+ return `${changed.length} uncommitted changes`;
94
+ };
95
+ const benchEnvironment = gen(function* benchEnvironment() {
96
+ const versions = yield* forEach(packages, versionOf);
97
+ const commit = yield* map$1(gitLines(["rev-parse", "HEAD"]), head);
98
+ const changed = yield* gitLines(["status", "--porcelain"]);
99
+ const lockfile = yield* lockfilePin();
100
+ return {
101
+ pins: {
102
+ commit: getOrElse(commit, () => unknown),
103
+ ...lockfile,
104
+ worktree: worktreeOf(changed)
105
+ },
106
+ versions: fromEntries(versions)
107
+ };
108
+ });
109
+ const usage = fn("usage")(function* usage(message) {
110
+ yield* error(`akter bench: ${message}`);
111
+ return yield* RunnerExitedError.make({ code: usageError });
112
+ });
113
+ const devUrlOf = (lines) => flatMap(take(lines), (line) => match(fromNullishOr(devUrlLine.exec(line)?.groups?.url), {
114
+ onNone: () => andThen(error(line), devUrlOf(lines)),
115
+ onSome: succeed
116
+ }));
117
+ const devSource = devRunner({
118
+ allowedHosts: "[]",
119
+ directory: "process.argv[2]",
120
+ entry: "process.argv[3]",
121
+ environment: "null",
122
+ inspectorPort: anyPort,
123
+ port: anyPort
124
+ });
125
+ const writeRunner = fn("writeRunner")(function* writeRunner(name, source) {
126
+ const fileSystem = yield* FileSystem;
127
+ const path = yield* Path;
128
+ const runner = path.resolve("node_modules", ".akter", name);
129
+ yield* fileSystem.makeDirectory(path.dirname(runner), { recursive: true });
130
+ yield* fileSystem.writeFileString(runner, source);
131
+ return runner;
132
+ });
133
+ const startDev = fn("startDev")(function* startDev(entry, directory) {
134
+ const spawner = yield* ChildProcessSpawner;
135
+ const path = yield* Path;
136
+ const runner = yield* writeRunner("bench-dev.mjs", devSource);
137
+ const app = yield* path.toFileUrl(path.resolve(entry));
138
+ const handle = yield* spawner.spawn(make$1(globalThis.process.execPath, [
139
+ runner,
140
+ directory,
141
+ app.href
142
+ ]));
143
+ const output = splitLines(decodeText(handle.all));
144
+ const lines = yield* unbounded();
145
+ yield* forkScoped(runForEach(output, (line) => offer(lines, line)));
146
+ return yield* devUrlOf(lines).pipe(timeoutOrElse({
147
+ duration: "60 seconds",
148
+ orElse: () => usage("akter dev didn't print its URL within 60 seconds.")
149
+ }));
150
+ });
151
+ /**
152
+ * Signs in with the CLI's credential (AKTER_API_KEY or akter login) and returns how to read the session's current
153
+ * bearer header, so a run longer than the one-minute token keeps signing its steps.
154
+ */
155
+ const cloudAuthorization = fn("cloudAuthorization")(function* cloudAuthorization() {
156
+ const credentials = yield* Credentials;
157
+ const url = yield* credentials.url(none());
158
+ const credential = yield* credentials.credentialFor(url);
159
+ const cloud = yield* CloudClient.use((factory) => factory.connect({
160
+ apiKey: credential.secret,
161
+ url
162
+ }));
163
+ const current = map$1(cloud.bearer, (token) => `Bearer ${value(token)}`);
164
+ yield* cloud.signIn;
165
+ return some(orDie(current));
166
+ });
167
+ const givenTarget = fn("givenTarget")(function* givenTarget(url) {
168
+ const host = fromNullishOr(globalThis.URL.parse(url)?.hostname);
169
+ if (isNone(host)) return yield* usage(`--url ${url} is not a URL.`);
170
+ if (contains(loopbackHosts, host.value)) return {
171
+ connection: {
172
+ authorization: none(),
173
+ kind: "local",
174
+ url
175
+ },
176
+ target: `akter dev at ${url}`
177
+ };
178
+ return {
179
+ connection: {
180
+ authorization: yield* cloudAuthorization(),
181
+ kind: "cloud",
182
+ url
183
+ },
184
+ target: `the Akter Cloud app at ${url}`
185
+ };
186
+ });
187
+ const comparedTarget = (system, url) => match(url, {
188
+ onNone: () => usage(`--system ${system} needs --url, where the workload reaches it.`),
189
+ onSome: (given) => succeed({
190
+ connection: {
191
+ authorization: none(),
192
+ kind: "comparison",
193
+ url: given
194
+ },
195
+ target: `${system} at ${given}, for comparison`
196
+ })
197
+ });
198
+ const targetOf = fn("targetOf")(function* targetOf(options, scratch) {
199
+ const path = yield* Path;
200
+ if (isSome(options.system)) return yield* comparedTarget(options.system.value, options.url);
201
+ if (isSome(options.url)) return yield* givenTarget(options.url.value);
202
+ const url = yield* startDev(options.entry, path.join(scratch, "data"));
203
+ return {
204
+ connection: {
205
+ authorization: none(),
206
+ kind: "local",
207
+ url
208
+ },
209
+ target: `akter dev at ${url}, started by akter bench on an empty folder`
210
+ };
211
+ });
212
+ const RunnerLine = Struct({
213
+ authorization: optionalKey(String),
214
+ kind: optionalKey(Literals([
215
+ "cloud",
216
+ "comparison",
217
+ "local"
218
+ ])),
219
+ url: optionalKey(String)
220
+ });
221
+ const encodeLine = encodeEffect(fromJsonString(RunnerLine));
222
+ const lineOf = (line) => map$1(orDie(encodeLine(line)), (json) => `${json}\n`);
223
+ const sentFirst = 1;
224
+ const runnerInput = ({ authorization, kind, url }) => {
225
+ const first = flatMap(transposeOption(authorization), (header) => lineOf({
226
+ kind,
227
+ url,
228
+ ...getSomes({ authorization: header })
229
+ }));
230
+ const refreshed = match(authorization, {
231
+ onNone: () => empty,
232
+ onSome: (current) => tick(tokenCheck).pipe(drop(sentFirst), mapEffect(() => flatMap(current, (header) => lineOf({ authorization: header }))))
233
+ });
234
+ return concat(fromEffect(first), refreshed);
235
+ };
236
+ const runRunner = fn("runRunner")(function* runRunner(config, connection) {
237
+ const spawner = yield* ChildProcessSpawner;
238
+ const runner = yield* writeRunner("bench.mjs", benchRunner);
239
+ const input = unwrap(map$1(_await(connection), runnerInput));
240
+ const io = {
241
+ stderr: "inherit",
242
+ stdin: encodeText(input),
243
+ stdout: "inherit"
244
+ };
245
+ const command = make$1(globalThis.process.execPath, [runner, config], io);
246
+ return yield* spawner.exitCode(command).pipe(filterOrFail((code) => code === exitedCleanly, (code) => RunnerExitedError.make({ code })));
247
+ });
248
+ const sampled = fn("sampled")(function* sampled(options, timing, scratch) {
249
+ const fileSystem = yield* FileSystem;
250
+ const path = yield* Path;
251
+ const now = yield* currentTimeMillis;
252
+ const workload = yield* path.toFileUrl(path.resolve(options.workload));
253
+ const config = {
254
+ concurrency: options.concurrency,
255
+ durationMillis: timing.durationMillis,
256
+ id: `bench-${now}`,
257
+ out: path.join(scratch, "samples.json"),
258
+ stepTimeoutMillis: timing.stepTimeoutMillis,
259
+ workload: workload.href
260
+ };
261
+ const connection = yield* make();
262
+ const [targeted] = yield* all([tap(targetOf(options, scratch), (started) => succeed$1(connection, started.connection)), flatMap(jsonText(config), (json) => runRunner(json, connection))], { concurrency: 2 });
263
+ const run = yield* flatMap(fileSystem.readFileString(config.out), samplesOf);
264
+ return {
265
+ kind: targeted.connection.kind,
266
+ run,
267
+ target: targeted.target
268
+ };
269
+ });
270
+ const printed = (report, json) => {
271
+ if (json) return flatMap(jsonText(report), log);
272
+ return log(join(reportLines(report), "\n"));
273
+ };
274
+ const runBench = fn("runBench")(function* runBench(options) {
275
+ const durationMillis = getOrElse(millisOf(options.duration), () => anyPort);
276
+ const stepTimeoutMillis = getOrElse(millisOf(options.stepTimeout), () => anyPort);
277
+ if (durationMillis <= anyPort || stepTimeoutMillis <= anyPort || options.concurrency < fewestWorkers) return yield* usage("--duration and --step-timeout take a whole number and a unit, like 30s or 5m, and --concurrency at least 1.");
278
+ const scratch = yield* (yield* FileSystem).makeTempDirectoryScoped({ prefix: "akter-bench-" });
279
+ const [{ kind, run, target }, environment] = yield* all([sampled(options, {
280
+ durationMillis,
281
+ stepTimeoutMillis
282
+ }, scratch), benchEnvironment], { concurrency: 2 });
283
+ const report = benchReport({
284
+ environment,
285
+ run,
286
+ settings: {
287
+ concurrency: options.concurrency,
288
+ durationMillis,
289
+ kind,
290
+ target
291
+ }
292
+ });
293
+ return yield* printed(report, options.json);
294
+ });
295
+ var Bench = class extends Service()("@akterjs/cli/bench/bench.service/Bench", { make: gen(function* makeBench() {
296
+ const context$1 = yield* context();
297
+ return { run: (options) => provideContext(runBench(options), context$1) };
298
+ }) }) {
299
+ static layer = effect(this, this.make);
300
+ };
301
+ export { Bench };