@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,1269 @@
1
+ import { R as some, T as join, j as map, k as makeBy, l as filter, r as contains, s as ensure, y as head } from "./Array-B4kuTQeW.mjs";
2
+ import { t as match } from "./Boolean-kILIvmhE.mjs";
3
+ import { a as option, i as String$1 } from "./Config-B6OND9WR.mjs";
4
+ import { t as error } from "./Console-BKHUkH6a.mjs";
5
+ import { $t as suspend, A as ensuring, An as spaced, At as provideContext, B as flatMap, Bn as build, Dt as orElseSucceed, En as exponential, Et as orDie, Ft as repeat, Gt as scoped, Jn as succeed, K as forEach, Kn as provide, Lt as retry, M as fail, Nt as raceFirst, Q as fromOption, T as context, Vn as effect, W as fnUntraced, Wn as merge, X as forkScoped, Xt as succeed$1, Yt as sleep, _n as when, a as all, aa as Service, d as asVoid, dt as map$1, en as sync, et as gen, ft as mapBoth, g as catchDefect, gn as void_, ht as mapError, in as timeout, l as as, ln as try_, n as acquireRelease, o as andThen, q as forever, qn as provideMerge, sn as transposeOption, tt as ignore, x as catchTag, yt as matchEffect } from "./Effect-CKFpqbmw.mjs";
6
+ import { t as FileSystem } from "./FileSystem-4pPcEb_i.mjs";
7
+ import { C as orElse, S as none, T as toArray, _ as isSome, b as map$2, c as flatten, cn as isString, d as fromUndefinedOr, f as getOrElse, h as isNone, i as filter$1, o as flatMap$1, p as getOrNull, t as all$1, u as fromNullishOr, un as isTagged, v as liftPredicate, w as some$1, x as match$1 } from "./Option-DkxSnBhp.mjs";
8
+ import { B as TaggedStruct, F as String$2, I as Struct, J as UndefinedOr, T as NonEmptyArray, U as Tuple, X as Unknown, Y as Union, an as optionalKey, ar as filter$2, at as decodeUnknownEffect, cr as getSomes, ct as encodeOption, ft as encodeUnknownOption, g as Finite, hr as toEntries, mt as is, n as ArraySchema, nt as decodeOption, or as fromEntries, ot as decodeUnknownOption, pt as fromJsonString, q as Uint8ArrayFromBase64, sr as get, st as encodeEffect, tt as decodeEffect, un as toEncoded, v as Int, y as Json } from "./Schema-MiKt5K1v.mjs";
9
+ import { i as value } from "./Redacted-RkJrG5Me.mjs";
10
+ import { n as getUnsafe, o as set, r as make, t as get$1 } from "./Ref-BIPOxJNH.mjs";
11
+ import { t as Stdio } from "./Stdio-KylmOBX_.mjs";
12
+ import { H as runFold, I as provideContext$1, T as make$2, U as runFoldEffect, W as runForEach, Y as take, dt as make$1, k as mapError$1, m as flatMap$2, nt as unwrap, p as filter$3, pt as open, y as fromIterable, z as run } from "./Stream-bK9QIETN.mjs";
13
+ import { d as replace, g as toLowerCase, h as startsWith, m as split, p as slice, r as endsWith } from "./String-q5dcsVe4.mjs";
14
+ import { D as uploadChunkBytes$1, E as fileTag, It as make$6, Lt as remove, Ot as fromWebSocket, Rt as run$1, T as fileRpcsOf, X as ActorUnavailableError, et as Protocol, ft as isTerminalResponse, mt as RpcClientError, n as ActorFileClients, nt as makeProtocolHttp, o as Authentication, ot as layerNdjson, pt as RpcClientDefect, t as ActorClients, tt as make$4, ut as constPing, wt as make$3, yt as make$5 } from "./actor-client.adapter-Coem7gF1.mjs";
15
+ import { n as layerWebCrypto, t as SecureRandom } from "./SecureRandom-B_U4ysO3.mjs";
16
+ import { n as Fetch, r as layer, t as CloudClient } from "./cloud-client.adapter-DOVMoYAj.mjs";
17
+ import { f as HttpClient, g as mapRequest } from "./cloud-client.adapter-Cy1BjDbG.mjs";
18
+ import { P as currentTimeMillis, S as prependUrl, w as setHeaders } from "./HttpClientResponse-D5ZKICVV.mjs";
19
+ import { l as millis } from "./Duration-EH9Vy4U6.mjs";
20
+ import { a as tags, r as orElse$1, s as value$1 } from "./Match-CGPLZYrV.mjs";
21
+ import { Credentials } from "./credentials/credentials.service.mjs";
22
+ import { refusalCode, rejectedRequest, unansweredOf } from "./registry/actor-refusal.pure.mjs";
23
+ import { compactJson, printJson, reported, signInFailure } from "./registry/operation-output.pure.mjs";
24
+ import { RunnerExitedError } from "./runner-exited.errors.mjs";
25
+ import { CliExitError } from "./terminal/cli-exit.errors.mjs";
26
+ // ../client/src/actor-rpc.pure.ts
27
+ const commandFields = {
28
+ commandId: String$2,
29
+ key: Json,
30
+ payload: Json
31
+ };
32
+ const queryFields = {
33
+ key: Json,
34
+ payload: Json
35
+ };
36
+ const keyFields = { key: Json };
37
+ const computerFields = {
38
+ computer: Json,
39
+ key: Json
40
+ };
41
+ const listFields = {
42
+ cursor: optionalKey(Json),
43
+ key: Json,
44
+ limit: optionalKey(Json),
45
+ prefix: optionalKey(Json)
46
+ };
47
+ const fieldsOf = {
48
+ call: commandFields,
49
+ "computers/cp": {
50
+ ...computerFields,
51
+ computerPath: Json,
52
+ direction: Json,
53
+ path: Json
54
+ },
55
+ "computers/delete": computerFields,
56
+ "computers/get": computerFields,
57
+ "computers/list": keyFields,
58
+ "computers/logs": {
59
+ ...computerFields,
60
+ after: optionalKey(Json),
61
+ limit: optionalKey(Json)
62
+ },
63
+ "computers/pause": computerFields,
64
+ "computers/resume": computerFields,
65
+ "computers/stop": computerFields,
66
+ create: commandFields,
67
+ ensure: commandFields,
68
+ "files/download": {
69
+ key: Json,
70
+ length: optionalKey(Json),
71
+ offset: optionalKey(Json),
72
+ path: Json
73
+ },
74
+ "files/list": listFields,
75
+ "files/upload": keyFields,
76
+ "files/upload/append": {
77
+ bytes: Json,
78
+ key: Json,
79
+ offset: Json,
80
+ upload: Json
81
+ },
82
+ "files/upload/close": {
83
+ bytes: Json,
84
+ key: Json,
85
+ upload: Json
86
+ },
87
+ "files/upload/open": keyFields,
88
+ "files/usage": listFields,
89
+ fork: {
90
+ commandId: String$2,
91
+ into: Json,
92
+ key: Json
93
+ },
94
+ query: queryFields,
95
+ state: keyFields,
96
+ "steps/get": {
97
+ key: Json,
98
+ step: Json
99
+ },
100
+ "steps/list": {
101
+ key: Json,
102
+ limit: optionalKey(Json)
103
+ },
104
+ warm: keyFields,
105
+ watch: queryFields
106
+ };
107
+ function unaryClient({ kind, tag }) {
108
+ const rpc = make$3(tag, {
109
+ error: Json,
110
+ payload: Struct(fieldsOf[kind]),
111
+ success: UndefinedOr(Json)
112
+ });
113
+ return make$4(make$5(rpc), { flatten: true });
114
+ }
115
+ function streamClient({ kind, tag }) {
116
+ const rpc = make$3(tag, {
117
+ error: Json,
118
+ payload: Struct(fieldsOf[kind]),
119
+ stream: true,
120
+ success: Json
121
+ });
122
+ return make$4(make$5(rpc), { flatten: true });
123
+ }
124
+ const uploadChunkBytes = 1048576;
125
+ const Base64$1 = Uint8ArrayFromBase64;
126
+ const Opened = Struct({ upload: String$2 });
127
+ const appended = fnUntraced(function* appended({ content, request, upload, wait }) {
128
+ const tag = `${request.tag}/append`;
129
+ const append = yield* unaryClient({
130
+ kind: "files/upload/append",
131
+ tag
132
+ });
133
+ const count = Math.ceil(content.length / uploadChunkBytes);
134
+ const chunks = makeBy(count, (index) => ({
135
+ bytes: content.subarray(index * uploadChunkBytes, index * uploadChunkBytes + uploadChunkBytes),
136
+ offset: index * uploadChunkBytes
137
+ }));
138
+ yield* forEach(chunks, ({ bytes, offset }) => flatMap(orDie(encodeEffect(Base64$1)(bytes)), (encoded) => timeout(append(tag, {
139
+ ...request.payload,
140
+ bytes: encoded,
141
+ offset,
142
+ upload
143
+ }), wait)));
144
+ });
145
+ const uploadSession = (upload) => gen(function* runUploadSession() {
146
+ const { content, request, wait } = upload;
147
+ const open = yield* unaryClient({
148
+ kind: "files/upload/open",
149
+ tag: `${request.tag}/open`
150
+ });
151
+ const close = yield* unaryClient({
152
+ kind: "files/upload/close",
153
+ tag: `${request.tag}/close`
154
+ });
155
+ const opened = yield* timeout(open(`${request.tag}/open`, request.payload), wait);
156
+ const session = yield* orDie(decodeUnknownEffect(Opened)(opened));
157
+ yield* appended({
158
+ content,
159
+ request,
160
+ upload: session.upload,
161
+ wait
162
+ });
163
+ const closing = {
164
+ ...request.payload,
165
+ bytes: content.length,
166
+ upload: session.upload
167
+ };
168
+ return yield* timeout(close(`${request.tag}/close`, closing), wait);
169
+ });
170
+ // ../effect/src/contract/file/rpc/rpc-file-clients.layer.ts
171
+ const retryMillis = 50;
172
+ const retryLimit = 5;
173
+ const firstByte = 0;
174
+ const one = 1;
175
+ function wireOf(actor) {
176
+ const group = make$5(...fileRpcsOf(actor)).middleware(Authentication);
177
+ return map$1(make$4(group, { flatten: true }), (client) => ({
178
+ send: client,
179
+ watch: client
180
+ }));
181
+ }
182
+ const unavailable = (actor, message) => ActorUnavailableError.make({
183
+ actor,
184
+ message
185
+ });
186
+ /**
187
+ * What a network file client answers for a failure: a lost reply, after its retries, means the actor is unavailable,
188
+ * and the actor RPC failures a file request can't cause fold into the same retryable answer.
189
+ */
190
+ const clientFailure = (actor) => (failure) => value$1(failure).pipe(tags({
191
+ ActorNotCreatedError: () => unavailable(actor, "the actor's files are unavailable"),
192
+ CommandIdExpiredError: () => unavailable(actor, "the actor's files are unavailable"),
193
+ HandlerFailedError: () => unavailable(actor, "the actor's files are unavailable"),
194
+ RpcClientError: () => unavailable(actor, "the server didn't answer. Retry shortly.")
195
+ }), orElse$1((other) => other));
196
+ const tagOf$1 = (address, operation) => fileTag({
197
+ actor: address.actor,
198
+ operation
199
+ });
200
+ /** One unary file RPC. A lost reply is retried, which every file RPC allows: reads, and appends by their offset. */
201
+ const call = ({ address, protocol }, operation, payload) => {
202
+ const sent = flatMap(wireOf(address.actor), (wire) => wire.send(tagOf$1(address, operation), {
203
+ ...payload,
204
+ key: address.key
205
+ }));
206
+ const retried = retry(scoped(sent), {
207
+ schedule: exponential(millis(retryMillis)),
208
+ times: retryLimit,
209
+ while: (failure) => isTagged(failure, "RpcClientError")
210
+ });
211
+ return provideContext(mapError(retried, clientFailure(address.actor)), protocol);
212
+ };
213
+ const listingOf = ({ cursor, limit, prefix }) => ({
214
+ ...getSomes({
215
+ cursor: fromNullishOr(cursor),
216
+ prefix: fromNullishOr(prefix)
217
+ }),
218
+ ...getSomes({ limit: fromNullishOr(limit) })
219
+ });
220
+ const slices = (bytes) => makeBy(Math.max(one, Math.ceil(bytes.length / uploadChunkBytes$1)), (index) => bytes.subarray(index * uploadChunkBytes$1, (index + one) * uploadChunkBytes$1));
221
+ const appendAll = (bound, upload, source) => source.pipe(flatMap$2((chunk) => fromIterable(slices(chunk))), filter$3((chunk) => chunk.length > firstByte), runFoldEffect(() => firstByte, (offset, bytes) => as(call(bound, "upload/append", {
222
+ bytes,
223
+ offset,
224
+ upload
225
+ }), offset + bytes.length)));
226
+ /** An upload is a session: `upload/open`, the source's bytes as ordered `upload/append` chunks, then `upload/close`. */
227
+ const uploadWith = (bound) => (source) => gen(function* upload() {
228
+ const opened = yield* call(bound, "upload/open", {});
229
+ const bytes = yield* appendAll(bound, opened.upload, source);
230
+ return (yield* call(bound, "upload/close", {
231
+ bytes,
232
+ upload: opened.upload
233
+ })).receipt;
234
+ });
235
+ const downloadWith = ({ address, protocol }) => (path, range) => {
236
+ const bytes = unwrap(map$1(wireOf(address.actor), (wire) => wire.watch(tagOf$1(address, "download"), {
237
+ key: address.key,
238
+ path,
239
+ ...range
240
+ })));
241
+ return provideContext$1(mapError$1(bytes, clientFailure(address.actor)), protocol);
242
+ };
243
+ const clientWith = (bound) => ({
244
+ download: downloadWith(bound),
245
+ fileUsage: (listing = {}) => call(bound, "usage", listingOf(listing)),
246
+ list: (listing = {}) => call(bound, "list", listingOf(listing)),
247
+ upload: uploadWith(bound)
248
+ });
249
+ /**
250
+ * File clients that reach an actor's files over its `<Actor>/files/<operation>` RPCs, for `@akterjs/client` and the
251
+ * in-process client. They give the same `FileClient` an actor's own host gives, so customer code is the same either
252
+ * way.
253
+ */
254
+ const rpcFileClients = effect(ActorFileClients, map$1(context(), (protocol) => ({ connect: (address) => clientWith({
255
+ address,
256
+ protocol
257
+ }) })));
258
+ // ../client/src/read-floors.pure.ts
259
+ const floorHeader = "akter-floor";
260
+ const Keyed = Struct({ key: Unknown });
261
+ const Versioned = Struct({
262
+ requestId: Union([String$2, Finite]),
263
+ version: Int
264
+ });
265
+ const KeyText = fromJsonString(Unknown);
266
+ const keyedOf = decodeUnknownOption(Keyed);
267
+ const versionedOf = decodeUnknownOption(Versioned);
268
+ const keyTextOf = encodeUnknownOption(KeyText);
269
+ const actorKeyOf = ({ payload, tag }) => flatMap$1(keyedOf(payload), ({ key }) => map$2(keyTextOf(key), (keyText) => `${getOrElse(head(split(tag, "/")), () => tag)}\n${keyText}`));
270
+ const pendingOf = (clientId, requestId) => `${clientId}/${requestId}`;
271
+ const trackedFloors = () => {
272
+ const floors = /* @__PURE__ */ new Map();
273
+ const pending = /* @__PURE__ */ new Map();
274
+ const floored = (clientId, request) => match$1(actorKeyOf(request), {
275
+ onNone: () => request,
276
+ onSome: (actorKey) => {
277
+ pending.set(pendingOf(clientId, request.id), actorKey);
278
+ return match$1(fromNullishOr(floors.get(actorKey)), {
279
+ onNone: () => request,
280
+ onSome: (floor) => ({
281
+ ...request,
282
+ headers: [...request.headers, [floorHeader, String(floor)]]
283
+ })
284
+ });
285
+ }
286
+ });
287
+ const sent = (clientId, message) => {
288
+ if (isTagged(message, "Request")) return floored(clientId, message);
289
+ return message;
290
+ };
291
+ const received = (clientId, response) => {
292
+ if (!isTagged(response, "Exit")) return;
293
+ const id = pendingOf(clientId, response.requestId);
294
+ const actorKey = pending.get(id);
295
+ pending.delete(id);
296
+ map$2(all$1([fromNullishOr(actorKey), versionedOf(response)]), ([key, { version }]) => {
297
+ floors.set(key, Math.max(version, floors.get(key) ?? version));
298
+ });
299
+ };
300
+ return {
301
+ received,
302
+ sent
303
+ };
304
+ };
305
+ // ../client/src/remote-interrupt.pure.ts
306
+ const InterruptReasons = NonEmptyArray(TaggedStruct("Interrupt", {}));
307
+ const InterruptedOnly = Struct({ exit: TaggedStruct("Failure", { cause: InterruptReasons }) });
308
+ const UnavailableWire = toEncoded(ActorUnavailableError);
309
+ const FailReason = TaggedStruct("Fail", { error: UnavailableWire });
310
+ /** An encoded exit that failed with one error, as Effect RPC writes it. */
311
+ const FailedExit = TaggedStruct("Failure", { cause: Tuple([FailReason]) });
312
+ const isInterruptedOnly = is(InterruptedOnly);
313
+ const encodeUnavailable = encodeOption(ActorUnavailableError);
314
+ const message = "the server stopped this request before it answered. Retry shortly.";
315
+ const requestOf$1 = (clientId, requestId) => `${clientId}/${requestId}`;
316
+ /** `Room/files/list` and `Room/post` are both Room's. */
317
+ const actorOf = (tag) => getOrElse(head(split(tag, "/")), () => tag);
318
+ const failedWith = (error) => FailedExit.make({ cause: [FailReason.make({ error })] });
319
+ const answered$1 = (actor, response) => match$1(encodeUnavailable(ActorUnavailableError.make({
320
+ actor,
321
+ message
322
+ })), {
323
+ onNone: () => response,
324
+ onSome: (error) => ({
325
+ ...response,
326
+ exit: failedWith(error)
327
+ })
328
+ });
329
+ const remoteInterrupts = () => {
330
+ const actors = /* @__PURE__ */ new Map();
331
+ const sent = (clientId, outgoing) => {
332
+ if (isTagged(outgoing, "Request")) actors.set(requestOf$1(clientId, outgoing.id), actorOf(outgoing.tag));
333
+ };
334
+ const received = (clientId, response) => {
335
+ if (!isTagged(response, "Exit")) return response;
336
+ const id = requestOf$1(clientId, response.requestId);
337
+ const actor = fromNullishOr(actors.get(id));
338
+ actors.delete(id);
339
+ if (isNone(actor) || !isInterruptedOnly(response)) return response;
340
+ return answered$1(actor.value, response);
341
+ };
342
+ return {
343
+ received,
344
+ sent
345
+ };
346
+ };
347
+ // ../client/src/actor-protocol.layer.ts
348
+ const streamSuffix = "/subscribe";
349
+ const liveProtocol = "akter-rpc";
350
+ const authProtocol = "akter-auth.";
351
+ const authorizationHeader = "authorization";
352
+ const bearerPrefix = "Bearer ";
353
+ const pingEvery = "10 seconds";
354
+ const silentMillis = 25e3;
355
+ const openTimeout = "10 seconds";
356
+ const normalClose = 1e3;
357
+ const ClientProtocolError = TaggedStruct("ClientProtocolError", {
358
+ error: RpcClientError,
359
+ requestIds: ArraySchema(Union([String$2, Finite]))
360
+ });
361
+ const JsonText$1 = fromJsonString(Unknown);
362
+ const encodeJson = encodeEffect(JsonText$1);
363
+ const decodeJson = decodeEffect(JsonText$1);
364
+ const utf8 = new globalThis.TextDecoder();
365
+ function serverMessages(values) {
366
+ return values;
367
+ }
368
+ const textOf = (message) => orDie(encodeJson(message));
369
+ const tokenOf = (headers) => map$2(filter$1(get(headers, authorizationHeader), startsWith(bearerPrefix)), slice(7));
370
+ const withoutAuthorization = (headers) => filter(toEntries(headers), ([name]) => toLowerCase(name) !== authorizationHeader);
371
+ const socketUrl = (url, request) => map$1(textOf({
372
+ ...request,
373
+ headers: []
374
+ }), (text) => {
375
+ const target = new globalThis.URL(url);
376
+ target.protocol = replace(/^http/u, "ws")(target.protocol);
377
+ target.searchParams.set("request", text);
378
+ return target.href;
379
+ });
380
+ const lost = (message, cause) => RpcClientError.make({ reason: RpcClientDefect.make({
381
+ cause,
382
+ message
383
+ }) });
384
+ const textFrom = (frame) => {
385
+ if (isString(frame)) return frame;
386
+ return utf8.decode(frame);
387
+ };
388
+ const decodeFrame = (frame) => mapBoth(decodeJson(textFrom(frame)), {
389
+ onFailure: (cause) => lost("the live socket sent a frame that isn't RPC JSON", cause),
390
+ onSuccess: (decoded) => serverMessages(ensure(decoded))
391
+ });
392
+ const opened = ({ headers, url, webSocket }, request) => gen(function* openLiveSocket() {
393
+ const sent = headers();
394
+ const credentials = map$2(tokenOf(sent), (token) => `${authProtocol}${token}`);
395
+ const protocols = [liveProtocol, ...toArray(credentials)];
396
+ const target = yield* socketUrl(url, request);
397
+ const socket = yield* fromWebSocket(acquireRelease(sync(() => new webSocket(target, protocols)), (native) => sync(() => {
398
+ native.close(normalClose);
399
+ })), { openTimeout });
400
+ const reader = yield* socket.reader;
401
+ const writer = yield* socket.writer;
402
+ const opening = yield* textOf({
403
+ ...request,
404
+ headers: [...request.headers, ...withoutAuthorization(sent)]
405
+ });
406
+ yield* writer.write(opening);
407
+ return {
408
+ reader,
409
+ writer
410
+ };
411
+ });
412
+ const received = ({ deliver, ended }) => (response) => {
413
+ if (isTagged(response, "Pong")) return void_;
414
+ if (isTerminalResponse(response)) return andThen(deliver(response), open(ended));
415
+ return deliver(response);
416
+ };
417
+ const receiving = (live) => {
418
+ const onFrame = (frame) => flatMap(decodeFrame(frame), (responses) => andThen(flatMap(currentTimeMillis, (now) => set(live.seen, now)), forEach(responses, received(live), { discard: true })));
419
+ return forever(flatMap(live.reader.pull, (frames) => forEach(frames, onFrame)));
420
+ };
421
+ const pinging = ({ seen, writer }) => forever(gen(function* pingLiveSocket() {
422
+ yield* sleep(pingEvery);
423
+ const now = yield* currentTimeMillis;
424
+ const last = yield* get$1(seen);
425
+ if (now - last > silentMillis) return yield* lost("the live socket went silent", now - last);
426
+ const frame = yield* textOf(constPing);
427
+ return yield* writer.write(frame);
428
+ }));
429
+ const transportFailure = (failure) => {
430
+ if (isTagged(failure, "RpcClientError")) return failure;
431
+ return RpcClientError.make({ reason: failure.reason });
432
+ };
433
+ const liveStream = (options, writers) => ({ deliver, request }) => {
434
+ const served = gen(function* serveLiveRequest() {
435
+ const { reader, writer } = yield* opened(options, request);
436
+ const ended = yield* make$1();
437
+ const now = yield* currentTimeMillis;
438
+ const live = {
439
+ deliver,
440
+ ended,
441
+ reader,
442
+ seen: yield* make(now),
443
+ writer
444
+ };
445
+ yield* acquireRelease(sync(() => writers.set(request.id, writer)), () => sync(() => writers.delete(request.id)));
446
+ yield* raceFirst(raceFirst(receiving(live), pinging(live)), ended.await);
447
+ });
448
+ return matchEffect(scoped(served), {
449
+ onFailure: (failure) => deliver(ClientProtocolError.make({
450
+ error: transportFailure(failure),
451
+ requestIds: [request.id]
452
+ })),
453
+ onSuccess: () => void_
454
+ });
455
+ };
456
+ const liveRequestOf = (message) => {
457
+ if (isTagged(message, "Request") && endsWith(streamSuffix)(message.tag)) return some$1(message);
458
+ return none();
459
+ };
460
+ const deliveries = (http) => {
461
+ const delivers = /* @__PURE__ */ new Map();
462
+ const floors = trackedFloors();
463
+ const interrupts = remoteInterrupts();
464
+ const deliverTo = (clientId) => (response) => match$1(fromNullishOr(delivers.get(clientId)), {
465
+ onNone: () => void_,
466
+ onSome: (deliver) => deliver(interrupts.received(clientId, response))
467
+ });
468
+ const run = (clientId, deliver) => ensuring(suspend(() => {
469
+ delivers.set(clientId, deliver);
470
+ return http.run(clientId, (response) => andThen(sync(() => {
471
+ floors.received(clientId, response);
472
+ }), suspend(() => deliver(interrupts.received(clientId, response)))));
473
+ }), sync(() => delivers.delete(clientId)));
474
+ return {
475
+ deliverTo,
476
+ floors,
477
+ interrupts,
478
+ run
479
+ };
480
+ };
481
+ const actorProtocol = fnUntraced(function* actorProtocol(options) {
482
+ const http = yield* makeProtocolHttp(options.http);
483
+ const lives = yield* make$6();
484
+ const writers = /* @__PURE__ */ new Map();
485
+ const { deliverTo, floors, interrupts, run } = deliveries(http);
486
+ const serve = liveStream(options, writers);
487
+ const writeTo = (requestId, message) => match$1(fromNullishOr(writers.get(requestId)), {
488
+ onNone: () => void_,
489
+ onSome: (writer) => ignore(flatMap(textOf(message), (frame) => writer.write(frame)))
490
+ });
491
+ const send = (clientId, message, transferables) => {
492
+ const live = liveRequestOf(message);
493
+ interrupts.sent(clientId, message);
494
+ if (isSome(live)) {
495
+ const streamed = serve({
496
+ deliver: deliverTo(clientId),
497
+ request: live.value
498
+ });
499
+ return asVoid(run$1(lives, live.value.id, streamed));
500
+ }
501
+ if (isTagged(message, "Ack")) return writeTo(message.requestId, message);
502
+ if (isTagged(message, "Interrupt")) return andThen(writeTo(message.requestId, message), remove(lives, message.requestId));
503
+ return http.send(clientId, floors.sent(clientId, message), transferables);
504
+ };
505
+ return Protocol.of({
506
+ codecFor: http.codecFor,
507
+ run,
508
+ send,
509
+ supportsAck: true,
510
+ supportsTransferables: false
511
+ });
512
+ });
513
+ // ../client/src/akter-client.layer.ts
514
+ const noHeaders$1 = () => ({});
515
+ const rpcPath = "/rpc";
516
+ const akterClient = ({ fetch = globalThis.fetch, headers = noHeaders$1, url, webSocket = globalThis.WebSocket }) => {
517
+ const rpcUrl = new globalThis.URL(rpcPath, url).href;
518
+ const httpClient = effect(HttpClient, gen(function* withHeaders() {
519
+ const client = yield* HttpClient;
520
+ return mapRequest(client, (request) => setHeaders(prependUrl(request, rpcUrl), headers()));
521
+ })).pipe(provide(layer), provide(succeed(Fetch)(fetch)));
522
+ const protocol = effect(Protocol, flatMap(HttpClient, (http) => actorProtocol({
523
+ headers,
524
+ http,
525
+ url: rpcUrl,
526
+ webSocket
527
+ }))).pipe(provide([httpClient, layerNdjson]));
528
+ const clients = merge(ActorClients.layer.pipe(provide(layerWebCrypto)), rpcFileClients);
529
+ return provideMerge(clients, protocol);
530
+ };
531
+ // ../client/src/actor-fields.pure.ts
532
+ const fieldSchemas = {
533
+ actor: {
534
+ description: "The actor's name in the app, such as Sale.",
535
+ type: "string"
536
+ },
537
+ after: {
538
+ description: "Only log lines after this seq, the last one a page before printed, to read on from there.",
539
+ type: "integer"
540
+ },
541
+ commandId: {
542
+ description: "An id for this call, so a retry with the same id runs it once. A new one is made when it is missing.",
543
+ type: "string"
544
+ },
545
+ computer: {
546
+ description: "The computer's name, as the actor named it.",
547
+ type: "string"
548
+ },
549
+ computerPath: {
550
+ description: "Relative path in the computer's files directory.",
551
+ type: "string"
552
+ },
553
+ content: {
554
+ description: "The file's bytes, as base64.",
555
+ type: "string"
556
+ },
557
+ cursor: {
558
+ description: "Where the page to read starts, from the cursor of the page before.",
559
+ type: "string"
560
+ },
561
+ direction: {
562
+ description: "toComputer or fromComputer; copy-back returns an upload receipt.",
563
+ enum: ["toComputer", "fromComputer"],
564
+ type: "string"
565
+ },
566
+ into: { description: "The new actor's key, as JSON. A bare word is taken as a string key." },
567
+ key: { description: "The actor's key, as JSON. A bare word is taken as a string key." },
568
+ length: {
569
+ description: "How many bytes to read, from offset; give both or neither.",
570
+ type: "integer"
571
+ },
572
+ limit: {
573
+ description: "The most entries to return.",
574
+ type: "integer"
575
+ },
576
+ member: {
577
+ description: "The command or query to run.",
578
+ type: "string"
579
+ },
580
+ offset: {
581
+ description: "The byte to start reading at, with length; give both or neither.",
582
+ type: "integer"
583
+ },
584
+ path: {
585
+ description: "The file's path in the actor, such as photos/cat.png.",
586
+ type: "string"
587
+ },
588
+ payload: { description: "The command's, query's or create input's payload, as JSON." },
589
+ prefix: {
590
+ description: "Only paths that start with this.",
591
+ type: "string"
592
+ },
593
+ step: {
594
+ description: "The step's id, as steps list prints it.",
595
+ type: "string"
596
+ }
597
+ };
598
+ const optional = [
599
+ "after",
600
+ "commandId",
601
+ "cursor",
602
+ "length",
603
+ "limit",
604
+ "offset",
605
+ "payload",
606
+ "prefix"
607
+ ];
608
+ const inputOf = (fields) => ({
609
+ additionalProperties: false,
610
+ properties: fromEntries(map(fields, (name) => [name, fieldSchemas[name]])),
611
+ required: filter(fields, (name) => !contains(optional, name)),
612
+ type: "object"
613
+ });
614
+ // ../client/src/actor-operations.pure.ts
615
+ const group = "actors";
616
+ const commandOfKind = (kind) => {
617
+ const [owner, name] = split("/")(kind);
618
+ return match$1(fromUndefinedOr(name), {
619
+ onNone: () => [group, kind],
620
+ onSome: (found) => [owner, found]
621
+ });
622
+ };
623
+ const subscribe = "/subscribe";
624
+ const declared = [
625
+ {
626
+ description: "Run one of an actor's commands and print its reply.",
627
+ fields: [
628
+ "actor",
629
+ "key",
630
+ "member",
631
+ "payload",
632
+ "commandId"
633
+ ],
634
+ idempotent: false,
635
+ kind: "call",
636
+ readOnly: false
637
+ },
638
+ {
639
+ description: "Run one of an actor's queries and print its reply.",
640
+ fields: [
641
+ "actor",
642
+ "key",
643
+ "member",
644
+ "payload"
645
+ ],
646
+ idempotent: true,
647
+ kind: "query",
648
+ readOnly: true
649
+ },
650
+ {
651
+ description: "Print an actor's state once.",
652
+ fields: ["actor", "key"],
653
+ idempotent: true,
654
+ kind: "state",
655
+ readOnly: true
656
+ },
657
+ {
658
+ description: "Print a query's reply, then each new reply as the actor changes, one JSON line each.",
659
+ fields: [
660
+ "actor",
661
+ "key",
662
+ "member",
663
+ "payload"
664
+ ],
665
+ idempotent: true,
666
+ kind: "watch",
667
+ readOnly: true
668
+ },
669
+ {
670
+ description: "Create an actor from its create input; fails when it already exists.",
671
+ fields: [
672
+ "actor",
673
+ "key",
674
+ "payload",
675
+ "commandId"
676
+ ],
677
+ idempotent: false,
678
+ kind: "create",
679
+ readOnly: false
680
+ },
681
+ {
682
+ description: "Create an actor from its create input unless it already exists.",
683
+ fields: [
684
+ "actor",
685
+ "key",
686
+ "payload",
687
+ "commandId"
688
+ ],
689
+ idempotent: true,
690
+ kind: "ensure",
691
+ readOnly: false
692
+ },
693
+ {
694
+ description: "List an actor's files a page at a time, with each path, size, digest and write time.",
695
+ fields: [
696
+ "actor",
697
+ "key",
698
+ "prefix",
699
+ "cursor",
700
+ "limit"
701
+ ],
702
+ idempotent: true,
703
+ kind: "files/list",
704
+ readOnly: true
705
+ },
706
+ {
707
+ description: "List an actor's files a page at a time, with the total bytes they hold.",
708
+ fields: [
709
+ "actor",
710
+ "key",
711
+ "prefix",
712
+ "cursor",
713
+ "limit"
714
+ ],
715
+ idempotent: true,
716
+ kind: "files/usage",
717
+ readOnly: true
718
+ },
719
+ {
720
+ description: "Download one of an actor's files, whole or the byte range offset and length give.",
721
+ fields: [
722
+ "actor",
723
+ "key",
724
+ "path",
725
+ "offset",
726
+ "length"
727
+ ],
728
+ idempotent: true,
729
+ kind: "files/download",
730
+ readOnly: true
731
+ },
732
+ {
733
+ description: "Upload a file for an actor and print its receipt, which a command attaches at a path.",
734
+ fields: [
735
+ "actor",
736
+ "key",
737
+ "content"
738
+ ],
739
+ idempotent: false,
740
+ kind: "files/upload",
741
+ readOnly: false
742
+ },
743
+ {
744
+ description: "Fork an actor into a new actor at another key: a copy of its state and files at one moment, with none of its work in flight (its jobs, timers and undelivered messages stay with the original). A retry with the same commandId makes one copy.",
745
+ fields: [
746
+ "actor",
747
+ "key",
748
+ "into",
749
+ "commandId"
750
+ ],
751
+ idempotent: false,
752
+ kind: "fork",
753
+ readOnly: false
754
+ },
755
+ {
756
+ description: "List an actor's computers, each with its image, size, egress and state.",
757
+ fields: ["actor", "key"],
758
+ idempotent: true,
759
+ kind: "computers/list",
760
+ readOnly: true
761
+ },
762
+ {
763
+ description: "Copy one file (at most 1 MiB) between an actor and its computer. fromComputer returns a receipt; attach it with an actor command.",
764
+ fields: [
765
+ "actor",
766
+ "key",
767
+ "computer",
768
+ "direction",
769
+ "path",
770
+ "computerPath"
771
+ ],
772
+ flag: "computerFiles",
773
+ idempotent: false,
774
+ kind: "computers/cp",
775
+ readOnly: false
776
+ },
777
+ {
778
+ description: "Show one of an actor's computers: its image, size, egress and state.",
779
+ fields: [
780
+ "actor",
781
+ "key",
782
+ "computer"
783
+ ],
784
+ idempotent: true,
785
+ kind: "computers/get",
786
+ readOnly: true
787
+ },
788
+ {
789
+ description: "Read a page of a computer's log, oldest first; pass the last seq printed as after to read on.",
790
+ fields: [
791
+ "actor",
792
+ "key",
793
+ "computer",
794
+ "after",
795
+ "limit"
796
+ ],
797
+ idempotent: true,
798
+ kind: "computers/logs",
799
+ readOnly: true
800
+ },
801
+ {
802
+ description: "Pause a computer, keeping its memory and disk, and print it.",
803
+ fields: [
804
+ "actor",
805
+ "key",
806
+ "computer"
807
+ ],
808
+ idempotent: true,
809
+ kind: "computers/pause",
810
+ readOnly: false
811
+ },
812
+ {
813
+ description: "Resume a paused computer and print it; fails while a fork holds it.",
814
+ fields: [
815
+ "actor",
816
+ "key",
817
+ "computer"
818
+ ],
819
+ idempotent: true,
820
+ kind: "computers/resume",
821
+ readOnly: false
822
+ },
823
+ {
824
+ description: "Stop a computer, keeping its disk, and print it.",
825
+ fields: [
826
+ "actor",
827
+ "key",
828
+ "computer"
829
+ ],
830
+ idempotent: true,
831
+ kind: "computers/stop",
832
+ readOnly: false
833
+ },
834
+ {
835
+ description: "Delete a computer and its disk. The actor's own jobs make computers; this only removes one.",
836
+ fields: [
837
+ "actor",
838
+ "key",
839
+ "computer"
840
+ ],
841
+ idempotent: true,
842
+ kind: "computers/delete",
843
+ readOnly: false
844
+ },
845
+ {
846
+ description: "List an actor's durable computer steps, newest first: each one's job, name, computer, command and state, and its exit code once it ran.",
847
+ fields: [
848
+ "actor",
849
+ "key",
850
+ "limit"
851
+ ],
852
+ flag: "computerSteps",
853
+ idempotent: true,
854
+ kind: "steps/list",
855
+ readOnly: true
856
+ },
857
+ {
858
+ description: "Show one of an actor's durable computer steps with its output. A step in state unknown may have done its work; reconcile it by its id.",
859
+ fields: [
860
+ "actor",
861
+ "key",
862
+ "step"
863
+ ],
864
+ flag: "computerSteps",
865
+ idempotent: true,
866
+ kind: "steps/get",
867
+ readOnly: true
868
+ },
869
+ {
870
+ description: "Load an actor ahead of its first call, so that call answers sooner.",
871
+ fields: ["actor", "key"],
872
+ idempotent: true,
873
+ kind: "warm",
874
+ readOnly: true
875
+ }
876
+ ];
877
+ const streams = [
878
+ "files/download",
879
+ "state",
880
+ "watch"
881
+ ];
882
+ const dangerous = ["computers/delete"];
883
+ const operationOf = ({ description, fields, flag, idempotent, kind, readOnly }) => {
884
+ const [owner, name] = commandOfKind(kind);
885
+ const confirm = contains(dangerous, kind);
886
+ const operation = {
887
+ annotations: {
888
+ confirm,
889
+ destructive: confirm,
890
+ idempotent,
891
+ openWorld: false,
892
+ readOnly
893
+ },
894
+ command: [owner, name],
895
+ description,
896
+ fields,
897
+ flag: fromUndefinedOr(flag),
898
+ id: `${owner}.${name}`,
899
+ input: inputOf(fields),
900
+ kind,
901
+ stream: contains(streams, kind),
902
+ tool: `${owner}_${name}`
903
+ };
904
+ if (kind === "computers/cp") return {
905
+ ...operation,
906
+ tool: "computers_files"
907
+ };
908
+ return operation;
909
+ };
910
+ const unexposedKinds = ["warm"];
911
+ const actorOperations = map(filter(declared, ({ kind }) => !contains(unexposedKinds, kind)), operationOf);
912
+ const tagOf = ({ actor, kind, member }) => {
913
+ return {
914
+ call: `${actor}/${member}`,
915
+ "computers/cp": `${actor}/computer/files`,
916
+ "computers/delete": `${actor}/computer/delete`,
917
+ "computers/get": `${actor}/computer/get`,
918
+ "computers/list": `${actor}/computer/list`,
919
+ "computers/logs": `${actor}/computer/logs`,
920
+ "computers/pause": `${actor}/computer/pause`,
921
+ "computers/resume": `${actor}/computer/resume`,
922
+ "computers/stop": `${actor}/computer/stop`,
923
+ create: `${actor}/create`,
924
+ ensure: `${actor}/ensure`,
925
+ "files/download": `${actor}/files/download`,
926
+ "files/list": `${actor}/files/list`,
927
+ "files/upload": `${actor}/files/upload`,
928
+ "files/usage": `${actor}/files/usage`,
929
+ fork: `${actor}/fork`,
930
+ query: `${actor}/${member}`,
931
+ state: `${actor}/state${subscribe}`,
932
+ "steps/get": `${actor}/computer/step`,
933
+ "steps/list": `${actor}/computer/steps`,
934
+ warm: `${actor}/warm`,
935
+ watch: `${actor}/${member}${subscribe}`
936
+ }[kind];
937
+ };
938
+ const fileRpcs = {
939
+ "files/download": {
940
+ fields: "key,length,offset,path",
941
+ kind: "files/download",
942
+ stream: true
943
+ },
944
+ "files/list": {
945
+ fields: "cursor,key,limit,prefix",
946
+ kind: "files/list",
947
+ stream: false
948
+ },
949
+ "files/upload/append": {
950
+ fields: "bytes,key,offset,upload",
951
+ kind: "files/upload",
952
+ stream: false
953
+ },
954
+ "files/upload/close": {
955
+ fields: "bytes,key,upload",
956
+ kind: "files/upload",
957
+ stream: false
958
+ },
959
+ "files/upload/open": {
960
+ fields: "key",
961
+ kind: "files/upload",
962
+ stream: false
963
+ },
964
+ "files/usage": {
965
+ fields: "cursor,key,limit,prefix",
966
+ kind: "files/usage",
967
+ stream: false
968
+ }
969
+ };
970
+ const computerRpcs = {
971
+ "computer/delete": {
972
+ fields: "computer,key",
973
+ kind: "computers/delete",
974
+ stream: false
975
+ },
976
+ "computer/files": {
977
+ fields: "computer,computerPath,direction,key,path",
978
+ kind: "computers/cp",
979
+ stream: false
980
+ },
981
+ "computer/get": {
982
+ fields: "computer,key",
983
+ kind: "computers/get",
984
+ stream: false
985
+ },
986
+ "computer/list": {
987
+ fields: "key",
988
+ kind: "computers/list",
989
+ stream: false
990
+ },
991
+ "computer/logs": {
992
+ fields: "after,computer,key,limit",
993
+ kind: "computers/logs",
994
+ stream: false
995
+ },
996
+ "computer/pause": {
997
+ fields: "computer,key",
998
+ kind: "computers/pause",
999
+ stream: false
1000
+ },
1001
+ "computer/resume": {
1002
+ fields: "computer,key",
1003
+ kind: "computers/resume",
1004
+ stream: false
1005
+ },
1006
+ "computer/step": {
1007
+ fields: "key,step",
1008
+ kind: "steps/get",
1009
+ stream: false
1010
+ },
1011
+ "computer/steps": {
1012
+ fields: "key,limit",
1013
+ kind: "steps/list",
1014
+ stream: false
1015
+ },
1016
+ "computer/stop": {
1017
+ fields: "computer,key",
1018
+ kind: "computers/stop",
1019
+ stream: false
1020
+ }
1021
+ };
1022
+ ({
1023
+ ...fileRpcs,
1024
+ ...computerRpcs
1025
+ });
1026
+ const someField = (name, value) => match$1(value, {
1027
+ onNone: () => ({}),
1028
+ onSome: (found) => ({ [name]: found })
1029
+ });
1030
+ const actorRequestOf = (operation) => (input) => gen(function* buildRequest() {
1031
+ const takes = (name) => contains(operation.fields, name);
1032
+ const minted = SecureRandom.use((random) => random.uuidV7());
1033
+ const fresh = yield* when(minted, succeed$1(takes("commandId") && isNone(input.commandId)));
1034
+ const commandId = filter$1(orElse(input.commandId, () => fresh), () => takes("commandId"));
1035
+ const payload = liftPredicate(getOrNull(input.payload), () => takes("payload"));
1036
+ return {
1037
+ payload: {
1038
+ ...filter$2(input.fileFields, (_value, name) => some(operation.fields, (field) => field === name)),
1039
+ ...someField("commandId", commandId),
1040
+ ...someField("into", filter$1(input.into, () => takes("into"))),
1041
+ ...someField("payload", payload),
1042
+ key: input.key
1043
+ },
1044
+ tag: tagOf({
1045
+ actor: input.actor,
1046
+ kind: operation.kind,
1047
+ member: input.member
1048
+ })
1049
+ };
1050
+ });
1051
+ // src/registry/actor-call.service.ts
1052
+ const callWait = "2 minutes";
1053
+ const firstOnly = 1;
1054
+ const fromFile = "@";
1055
+ const fromStdin = "-";
1056
+ const Base64 = Uint8ArrayFromBase64;
1057
+ const textFields = [
1058
+ "computer",
1059
+ "computerPath",
1060
+ "direction",
1061
+ "cursor",
1062
+ "path",
1063
+ "prefix",
1064
+ "step"
1065
+ ];
1066
+ const numberFields = [
1067
+ "after",
1068
+ "length",
1069
+ "limit",
1070
+ "offset"
1071
+ ];
1072
+ const loopbackHosts = /* @__PURE__ */ new Set([
1073
+ "localhost",
1074
+ "127.0.0.1",
1075
+ "[::1]"
1076
+ ]);
1077
+ const JsonText = fromJsonString(Json);
1078
+ const usage = (message) => CliExitError.make({
1079
+ code: CliExitError.codes.usage,
1080
+ message,
1081
+ reason: "InvalidInput"
1082
+ });
1083
+ const appUrl = fnUntraced(function* appUrl(flag) {
1084
+ const configured = yield* option(String$1("AKTER_APP_URL")).pipe(orElseSucceed(() => none()));
1085
+ const given = yield* fromOption(orElse(flag, () => configured)).pipe(mapError(() => usage("Pass --url with the app's URL, such as the one akter dev prints, or set AKTER_APP_URL.")));
1086
+ return yield* try_({
1087
+ catch: () => usage(`${given} is not a URL.`),
1088
+ try: () => new globalThis.URL(given)
1089
+ });
1090
+ });
1091
+ const noHeaders = { current: succeed$1({}) };
1092
+ const headersFor = fnUntraced(function* headersFor(url) {
1093
+ if (loopbackHosts.has(url.hostname)) return noHeaders;
1094
+ const credentials = yield* Credentials;
1095
+ const cloudUrl = yield* credentials.url(none());
1096
+ const credential = yield* credentials.credentialFor(cloudUrl);
1097
+ const cloud = yield* CloudClient.use((factory) => factory.connect({
1098
+ apiKey: credential.secret,
1099
+ url: cloudUrl
1100
+ }));
1101
+ return { current: mapBoth(cloud.bearer, {
1102
+ onFailure: signInFailure,
1103
+ onSuccess: (token) => ({ authorization: `Bearer ${value(token)}` })
1104
+ }) };
1105
+ });
1106
+ /** How often a call that outlives its token, such as a watch, reads the current headers. */
1107
+ const headerCheck = "10 seconds";
1108
+ const keyOf = (text) => getOrElse(decodeOption(JsonText)(text), () => text);
1109
+ const payloadOf = (text) => transposeOption(map$2(text, (raw) => mapError(decodeEffect(JsonText)(raw), () => usage("--payload is not JSON."))));
1110
+ const given = (options, name) => flatten(get(options.values, name));
1111
+ const required = (operation, options) => (name) => {
1112
+ if (!contains(operation.fields, name)) return succeed$1("");
1113
+ const value = given(options, name);
1114
+ return mapError(fromOption(value), () => usage(`akter ${join(operation.command, " ")} needs --${name}.`));
1115
+ };
1116
+ const wholeNumber = (name) => (text) => mapError(decodeEffect(fromJsonString(Int))(text), () => usage(`--${name} must be a whole number.`));
1117
+ const fileFieldsOf = (operation, options) => {
1118
+ const taken = (names) => filter(names, (name) => contains(operation.fields, name) && isSome(given(options, name)));
1119
+ const flag = (name) => getOrElse(given(options, name), () => "");
1120
+ const texts = map(taken(textFields), (name) => succeed$1([name, flag(name)]));
1121
+ const numbers = map(taken(numberFields), (name) => map$1(wholeNumber(name)(flag(name)), (value) => [name, value]));
1122
+ return map$1(all([...texts, ...numbers]), fromEntries);
1123
+ };
1124
+ const unreadable = (message) => () => usage(message);
1125
+ const concatBytes = (before, chunk) => {
1126
+ const joined = new Uint8Array(before.length + chunk.length);
1127
+ joined.set(before);
1128
+ joined.set(chunk, before.length);
1129
+ return joined;
1130
+ };
1131
+ const contentOf = fnUntraced(function* contentOf(raw) {
1132
+ if (raw === fromStdin) {
1133
+ const stdio = yield* Stdio;
1134
+ return yield* runFold(stdio.stdin, () => /* @__PURE__ */ new Uint8Array(), concatBytes).pipe(mapError(unreadable("Could not read --content from stdin.")));
1135
+ }
1136
+ if (startsWith(fromFile)(raw)) {
1137
+ const file = slice(1)(raw);
1138
+ return yield* (yield* FileSystem).readFile(file).pipe(mapError(unreadable(`Could not read --content from ${file}.`)));
1139
+ }
1140
+ return yield* decodeEffect(Base64)(raw).pipe(mapError(unreadable("--content is not base64; pass @<file> or - to read the file's bytes.")));
1141
+ });
1142
+ const transferOf = fnUntraced(function* transferOf(operation, options) {
1143
+ const fields = yield* fileFieldsOf(operation, options);
1144
+ const flag = yield* required(operation, options)("content");
1145
+ const raw = liftPredicate(flag, () => contains(operation.fields, "content"));
1146
+ return {
1147
+ content: yield* transposeOption(map$2(raw, contentOf)),
1148
+ fields
1149
+ };
1150
+ });
1151
+ const requestOf = fnUntraced(function* requestOf(operation, options) {
1152
+ const url = yield* appUrl(options.url);
1153
+ const need = required(operation, options);
1154
+ const actor = yield* need("actor");
1155
+ const key = yield* need("key");
1156
+ const member = yield* need("member");
1157
+ const payload = yield* payloadOf(given(options, "payload"));
1158
+ const commandId = given(options, "commandId");
1159
+ const { content, fields } = yield* transferOf(operation, options);
1160
+ return {
1161
+ ...yield* actorRequestOf(operation)({
1162
+ actor,
1163
+ commandId,
1164
+ fileFields: fields,
1165
+ into: map$2(given(options, "into"), keyOf),
1166
+ key: keyOf(key),
1167
+ member,
1168
+ payload
1169
+ }),
1170
+ content,
1171
+ operation,
1172
+ options,
1173
+ url
1174
+ };
1175
+ });
1176
+ const refused = fnUntraced(function* refused({ options, tag }, failure) {
1177
+ const unanswered = unansweredOf(tag)(failure);
1178
+ if (isSome(unanswered)) return yield* unanswered.value;
1179
+ const body = yield* orDie(decodeUnknownEffect(Json)(failure));
1180
+ if (options.json) yield* printJson(true)(body);
1181
+ else yield* flatMap(compactJson(body), (line) => error(`${tag} failed: ${line}`));
1182
+ return yield* RunnerExitedError.make({ code: refusalCode(failure) });
1183
+ });
1184
+ const printed = (json) => (reply) => printJson(json)(getOrNull(fromUndefinedOr(reply)));
1185
+ const unary = fnUntraced(function* unary(request) {
1186
+ const send = yield* unaryClient({
1187
+ kind: request.operation.kind,
1188
+ tag: request.tag
1189
+ });
1190
+ const reply = yield* timeout(send(request.tag, request.payload), callWait);
1191
+ return yield* printed(request.options.json)(reply);
1192
+ });
1193
+ const downloaded = fnUntraced(function* downloaded(request) {
1194
+ const chunks = (yield* streamClient({
1195
+ kind: "files/download",
1196
+ tag: request.tag
1197
+ }))(request.tag, request.payload);
1198
+ if (request.options.json) return yield* runForEach(chunks, printed(true));
1199
+ const stdout = (yield* Stdio).stdout({ endOnDone: false });
1200
+ return yield* runForEach(chunks, (chunk) => orDie(flatMap(decodeUnknownEffect(Base64)(chunk), (bytes) => run(make$2(bytes), stdout))));
1201
+ });
1202
+ const uploaded = fnUntraced(function* uploaded(request) {
1203
+ const content = getOrElse(request.content, () => /* @__PURE__ */ new Uint8Array());
1204
+ const receipt = yield* uploadSession({
1205
+ content,
1206
+ request,
1207
+ wait: callWait
1208
+ });
1209
+ return yield* printed(request.options.json)(receipt);
1210
+ });
1211
+ const streamed = fnUntraced(function* streamed(request) {
1212
+ const updates = (yield* streamClient({
1213
+ kind: request.operation.kind,
1214
+ tag: request.tag
1215
+ }))(request.tag, request.payload);
1216
+ const once = liftPredicate(firstOnly, () => request.operation.kind === "state");
1217
+ const count = orElse(once, () => request.options.count);
1218
+ const limited = match$1(count, {
1219
+ onNone: () => updates,
1220
+ onSome: (most) => take(updates, most)
1221
+ });
1222
+ return yield* runForEach(limited, printed(true));
1223
+ });
1224
+ const answered = fnUntraced(function* answered(request, headers) {
1225
+ const protocol = yield* build(akterClient({
1226
+ headers,
1227
+ url: request.url.href
1228
+ }));
1229
+ const { kind } = request.operation;
1230
+ if (kind === "files/download" || kind === "files/upload") {
1231
+ const transfer = match(kind === "files/download", {
1232
+ onFalse: () => uploaded(request),
1233
+ onTrue: () => downloaded(request)
1234
+ });
1235
+ return yield* provideContext(transfer, protocol);
1236
+ }
1237
+ if (request.operation.stream) return yield* provideContext(streamed(request), protocol);
1238
+ return yield* provideContext(unary(request), protocol);
1239
+ }, scoped, (effect, request) => matchEffect(effect, {
1240
+ onFailure: (failure) => refused(request, failure),
1241
+ onSuccess: succeed$1
1242
+ }), (effect, request) => catchDefect(effect, (defect) => fail(rejectedRequest(request.tag)(String(defect)))));
1243
+ const sent = fnUntraced(function* sent(request) {
1244
+ const { current } = yield* headersFor(request.url);
1245
+ const first = yield* current;
1246
+ const headers = yield* make(first);
1247
+ const refresh = ignore(flatMap(current, (fresh) => set(headers, fresh)));
1248
+ yield* forkScoped(repeat(refresh, spaced(headerCheck)));
1249
+ return yield* answered(request, () => getUnsafe(headers));
1250
+ }, scoped);
1251
+ const plan = (request) => printJson(request.options.json)({
1252
+ dryRun: true,
1253
+ operation: request.operation.id,
1254
+ payload: request.payload,
1255
+ tag: request.tag,
1256
+ url: request.url.href
1257
+ });
1258
+ const callActor = fnUntraced(function* callActor(operation, options) {
1259
+ const request = yield* requestOf(operation, options);
1260
+ if (options.dryRun) return yield* plan(request);
1261
+ return yield* sent(request);
1262
+ });
1263
+ var ActorCall = class extends Service()("@akterjs/cli/registry/actor-call.service/ActorCall", { make: gen(function* makeActorCall() {
1264
+ const context$1 = yield* context();
1265
+ return { call: (operation, options) => callActor(operation, options).pipe(catchTag("CliExitError", reported(options.json)), provideContext(context$1)) };
1266
+ }) }) {
1267
+ static layer = effect(this, this.make);
1268
+ };
1269
+ export { actorOperations as n, ActorCall as t };