effect-cf 0.25.3 → 0.27.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/CHANGELOG.md +16 -0
- package/README.md +213 -1
- package/dist/Artifacts-BhWrdyqX.mjs +241 -0
- package/dist/Artifacts-DcoXcRP5.d.mts +231 -0
- package/dist/ComputerArtifacts.d.mts +55 -0
- package/dist/ComputerArtifacts.mjs +95 -0
- package/dist/ComputerWorkspace.d.mts +279 -0
- package/dist/ComputerWorkspace.mjs +545 -0
- package/dist/ComputerWorkspaceHost.d.mts +71 -0
- package/dist/ComputerWorkspaceHost.mjs +74 -0
- package/dist/ComputerWorkspaceHostRegistry-CY5Fv4Ng.mjs +8 -0
- package/dist/{DurableObjectState-CEh0DVw7.mjs → DurableObjectState-Dux8KfjG.mjs} +3 -48
- package/dist/{WorkflowBinding-D5iWzCUa.d.mts → DurableObjectState-biHrHwrh.d.mts} +7 -81
- package/dist/ErrorMessage-_lg53p3W.mjs +49 -0
- package/dist/Vitest.d.mts +2 -1
- package/dist/Vitest.mjs +2 -1
- package/dist/WorkflowBinding-zlRPCXVf.d.mts +79 -0
- package/dist/index.d.mts +80 -2
- package/dist/index.mjs +72 -123
- package/package.json +23 -1
- package/src/Artifacts.ts +519 -0
- package/src/ComputerArtifacts.ts +255 -0
- package/src/ComputerWorkspace.ts +1098 -0
- package/src/ComputerWorkspaceHost.ts +216 -0
- package/src/WebTransport.ts +123 -0
- package/src/index.ts +2 -0
- package/src/internal/ComputerWorkspaceHostRegistry.ts +10 -0
package/src/Artifacts.ts
ADDED
|
@@ -0,0 +1,519 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ArtifactsCreateRepoResult as CloudflareArtifactsCreateRepoResult,
|
|
3
|
+
ArtifactsCreateTokenResult as CloudflareArtifactsCreateTokenResult,
|
|
4
|
+
ArtifactsErrorCode as CloudflareArtifactsErrorCode,
|
|
5
|
+
ArtifactsRepoInfo as CloudflareArtifactsRepoInfo,
|
|
6
|
+
ArtifactsTokenInfo as CloudflareArtifactsTokenInfo,
|
|
7
|
+
ArtifactsTokenListResult as CloudflareArtifactsTokenListResult,
|
|
8
|
+
} from "@cloudflare/workers-types";
|
|
9
|
+
import { Context, Data, Effect, type Layer } from "effect";
|
|
10
|
+
|
|
11
|
+
import * as Binding from "./Binding";
|
|
12
|
+
import type { WorkerEnvironment } from "./Environment";
|
|
13
|
+
import * as ErrorMessage from "./internal/ErrorMessage";
|
|
14
|
+
|
|
15
|
+
const expectedArtifactsBinding =
|
|
16
|
+
"Artifacts binding with create(), get(), import(), list(), and delete()";
|
|
17
|
+
|
|
18
|
+
const expectedArtifactsRepo =
|
|
19
|
+
"Artifacts repo handle with createToken(), listTokens(), revokeToken(), fork(), log(), readCommit(), and readTree()";
|
|
20
|
+
|
|
21
|
+
/** Artifacts operation represented by {@link ArtifactsOperationError}. */
|
|
22
|
+
export type ArtifactsOperation =
|
|
23
|
+
| "createClient"
|
|
24
|
+
| "create"
|
|
25
|
+
| "get"
|
|
26
|
+
| "import"
|
|
27
|
+
| "list"
|
|
28
|
+
| "delete"
|
|
29
|
+
| "createToken"
|
|
30
|
+
| "listTokens"
|
|
31
|
+
| "getToken"
|
|
32
|
+
| "revokeToken"
|
|
33
|
+
| "fork"
|
|
34
|
+
| "log"
|
|
35
|
+
| "readCommit"
|
|
36
|
+
| "readTree"
|
|
37
|
+
| "cli";
|
|
38
|
+
|
|
39
|
+
/** Documented string error codes returned by Cloudflare Artifacts. */
|
|
40
|
+
export const artifactsErrorCodes = [
|
|
41
|
+
"ALREADY_EXISTS",
|
|
42
|
+
"NOT_FOUND",
|
|
43
|
+
"IMPORT_IN_PROGRESS",
|
|
44
|
+
"FORK_IN_PROGRESS",
|
|
45
|
+
"INVALID_INPUT",
|
|
46
|
+
"INVALID_REPO_NAME",
|
|
47
|
+
"INVALID_TTL",
|
|
48
|
+
"INVALID_URL",
|
|
49
|
+
"REMOTE_AUTH_REQUIRED",
|
|
50
|
+
"UPSTREAM_UNAVAILABLE",
|
|
51
|
+
"MEMORY_LIMIT",
|
|
52
|
+
"INTERNAL_ERROR",
|
|
53
|
+
] as const satisfies ReadonlyArray<CloudflareArtifactsErrorCode>;
|
|
54
|
+
|
|
55
|
+
/** Documented numeric error codes returned by Cloudflare Artifacts. */
|
|
56
|
+
export const artifactsErrorNumericCodes = {
|
|
57
|
+
ALREADY_EXISTS: 10201,
|
|
58
|
+
NOT_FOUND: 10200,
|
|
59
|
+
IMPORT_IN_PROGRESS: 10302,
|
|
60
|
+
FORK_IN_PROGRESS: 10303,
|
|
61
|
+
INVALID_INPUT: 10100,
|
|
62
|
+
INVALID_REPO_NAME: 10101,
|
|
63
|
+
INVALID_TTL: 10103,
|
|
64
|
+
INVALID_URL: 10104,
|
|
65
|
+
REMOTE_AUTH_REQUIRED: 10106,
|
|
66
|
+
UPSTREAM_UNAVAILABLE: 10401,
|
|
67
|
+
MEMORY_LIMIT: 10402,
|
|
68
|
+
INTERNAL_ERROR: 10400,
|
|
69
|
+
} as const satisfies Readonly<Record<CloudflareArtifactsErrorCode, number>>;
|
|
70
|
+
|
|
71
|
+
/** A documented Cloudflare Artifacts string error code. */
|
|
72
|
+
export type ArtifactsErrorCode = CloudflareArtifactsErrorCode;
|
|
73
|
+
|
|
74
|
+
/** Error raised when a Cloudflare Artifacts operation fails. */
|
|
75
|
+
export class ArtifactsOperationError extends Data.TaggedError("ArtifactsOperationError")<{
|
|
76
|
+
readonly binding: string;
|
|
77
|
+
readonly operation: ArtifactsOperation;
|
|
78
|
+
readonly cause: unknown;
|
|
79
|
+
/** Cloudflare string error code, when retained by the runtime. */
|
|
80
|
+
readonly code?: ArtifactsErrorCode | (string & {});
|
|
81
|
+
/** Cloudflare REST-compatible numeric error code, when retained by the runtime. */
|
|
82
|
+
readonly numericCode?: number;
|
|
83
|
+
}> {
|
|
84
|
+
override get message(): string {
|
|
85
|
+
const code = this.code === undefined ? "" : ` (${this.code})`;
|
|
86
|
+
|
|
87
|
+
return `Artifacts ${this.operation} failed for binding "${this.binding}"${code}: ${ErrorMessage.causeMessage(this.cause)}`;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** Typed Cloudflare Artifacts binding definition. */
|
|
92
|
+
export interface ArtifactsDefinition {
|
|
93
|
+
/** Binding name from an `artifacts` entry in `wrangler.jsonc`. */
|
|
94
|
+
readonly binding: string;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/** Repository name containing alphanumeric characters, dots, hyphens, or underscores. */
|
|
98
|
+
export type RepoName = string;
|
|
99
|
+
|
|
100
|
+
/** Cursor used by repository list pagination. */
|
|
101
|
+
export type Cursor = string;
|
|
102
|
+
|
|
103
|
+
/** Scope granted to a repository token. */
|
|
104
|
+
export type ArtifactsTokenScope = "read" | "write";
|
|
105
|
+
|
|
106
|
+
/** Lifecycle state of a repository token. */
|
|
107
|
+
export type ArtifactsTokenState = "active" | "expired" | "revoked";
|
|
108
|
+
|
|
109
|
+
/** Lifecycle state included with repositories returned by `list()`. */
|
|
110
|
+
export type ArtifactsRepoStatus = "ready" | "importing" | "forking";
|
|
111
|
+
|
|
112
|
+
/** Stable repository metadata returned by Cloudflare Artifacts. */
|
|
113
|
+
export type ArtifactsRepoInfo = CloudflareArtifactsRepoInfo;
|
|
114
|
+
|
|
115
|
+
/** Result of creating, importing, or forking a repository. */
|
|
116
|
+
export type ArtifactsCreateRepoResult = Readonly<CloudflareArtifactsCreateRepoResult>;
|
|
117
|
+
|
|
118
|
+
/** Repository metadata returned by `list()`. */
|
|
119
|
+
export interface ArtifactsRepoListEntry extends ArtifactsRepoInfo {
|
|
120
|
+
readonly status: ArtifactsRepoStatus;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/** Cursor-paginated repository list result. */
|
|
124
|
+
export interface ArtifactsRepoListResult {
|
|
125
|
+
readonly repos: ReadonlyArray<ArtifactsRepoListEntry>;
|
|
126
|
+
readonly total: number;
|
|
127
|
+
readonly cursor?: Cursor;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/** Result of creating a repository token. */
|
|
131
|
+
export type ArtifactsCreateTokenResult = CloudflareArtifactsCreateTokenResult;
|
|
132
|
+
|
|
133
|
+
/** Repository token metadata, excluding its plaintext secret. */
|
|
134
|
+
export type ArtifactsTokenInfo = CloudflareArtifactsTokenInfo;
|
|
135
|
+
|
|
136
|
+
/** Repository token list result. */
|
|
137
|
+
export type ArtifactsTokenListResult = CloudflareArtifactsTokenListResult;
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Commit history returned by `log()`.
|
|
141
|
+
*
|
|
142
|
+
* Cloudflare currently documents this generated type by name but does not
|
|
143
|
+
* publish its fields in the binding reference or Workers type declarations.
|
|
144
|
+
*/
|
|
145
|
+
export interface ArtifactsLogResult {
|
|
146
|
+
readonly [field: string]: unknown;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Parsed Git commit returned by `readCommit()`.
|
|
151
|
+
*
|
|
152
|
+
* Cloudflare currently documents this generated type by name but does not
|
|
153
|
+
* publish its fields in the binding reference or Workers type declarations.
|
|
154
|
+
*/
|
|
155
|
+
export interface ArtifactsCommit {
|
|
156
|
+
readonly [field: string]: unknown;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Parsed Git tree returned by `readTree()`.
|
|
161
|
+
*
|
|
162
|
+
* Cloudflare currently documents this generated type by name but does not
|
|
163
|
+
* publish its fields in the binding reference or Workers type declarations.
|
|
164
|
+
*/
|
|
165
|
+
export interface ArtifactsTree {
|
|
166
|
+
readonly [field: string]: unknown;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/** Options for `Artifacts.create()`. */
|
|
170
|
+
export interface ArtifactsCreateOptions {
|
|
171
|
+
/** Prevent pushes to the repository. */
|
|
172
|
+
readonly readOnly?: boolean;
|
|
173
|
+
readonly description?: string;
|
|
174
|
+
/** Initial default branch name. */
|
|
175
|
+
readonly setDefaultBranch?: string;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/** Options for cursor-paginating `Artifacts.list()`. */
|
|
179
|
+
export interface ArtifactsListOptions {
|
|
180
|
+
/** Page size from 1 through 200. Defaults to 50. */
|
|
181
|
+
readonly limit?: number;
|
|
182
|
+
/** Cursor returned by a previous list result. */
|
|
183
|
+
readonly cursor?: Cursor;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/** External Git source used by `Artifacts.import()`. */
|
|
187
|
+
export interface ArtifactsImportSource {
|
|
188
|
+
/** Full HTTPS URL of the Git repository. */
|
|
189
|
+
readonly url: string;
|
|
190
|
+
/** Source branch. Defaults to the remote's default branch. */
|
|
191
|
+
readonly branch?: string;
|
|
192
|
+
/** Shallow clone depth. */
|
|
193
|
+
readonly depth?: number;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/** Options for the target of `Artifacts.import()`. */
|
|
197
|
+
export interface ArtifactsImportTargetOptions {
|
|
198
|
+
readonly description?: string;
|
|
199
|
+
readonly readOnly?: boolean;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/** Target repository used by `Artifacts.import()`. */
|
|
203
|
+
export interface ArtifactsImportTarget {
|
|
204
|
+
readonly name: RepoName;
|
|
205
|
+
readonly opts?: ArtifactsImportTargetOptions;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/** Parameters for `Artifacts.import()`. */
|
|
209
|
+
export interface ArtifactsImportParams {
|
|
210
|
+
readonly source: ArtifactsImportSource;
|
|
211
|
+
readonly target: ArtifactsImportTarget;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/** Options for `ArtifactsRepoClient.fork()`. */
|
|
215
|
+
export interface ArtifactsForkOptions {
|
|
216
|
+
readonly description?: string;
|
|
217
|
+
readonly readOnly?: boolean;
|
|
218
|
+
/** Only copy the default branch. Defaults to `true`. */
|
|
219
|
+
readonly defaultBranchOnly?: boolean;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/** Options for `ArtifactsRepoClient.log()`. */
|
|
223
|
+
export interface ArtifactsLogOptions {
|
|
224
|
+
/** Branch, tag, or commit hash. */
|
|
225
|
+
readonly ref?: string;
|
|
226
|
+
readonly limit?: number;
|
|
227
|
+
readonly offset?: number;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/** Runtime repository handle, including methods absent from current shipped Workers types. */
|
|
231
|
+
export interface ArtifactsRepoBinding extends ArtifactsRepoInfo {
|
|
232
|
+
/**
|
|
233
|
+
* Create a Git token for the repository.
|
|
234
|
+
*
|
|
235
|
+
* Scope defaults to `"write"`. TTL is measured in seconds, defaults to
|
|
236
|
+
* 86,400, and must be between 60 and 31,536,000.
|
|
237
|
+
*/
|
|
238
|
+
readonly createToken: (
|
|
239
|
+
scope?: ArtifactsTokenScope,
|
|
240
|
+
ttl?: number,
|
|
241
|
+
) => Promise<ArtifactsCreateTokenResult>;
|
|
242
|
+
readonly listTokens: () => Promise<ArtifactsTokenListResult>;
|
|
243
|
+
readonly revokeToken: (tokenOrId: string) => Promise<boolean>;
|
|
244
|
+
readonly fork: (
|
|
245
|
+
name: RepoName,
|
|
246
|
+
options?: ArtifactsForkOptions,
|
|
247
|
+
) => Promise<ArtifactsCreateRepoResult>;
|
|
248
|
+
readonly log: (options?: ArtifactsLogOptions) => Promise<ArtifactsLogResult>;
|
|
249
|
+
readonly readCommit: (hash: string) => Promise<ArtifactsCommit>;
|
|
250
|
+
readonly readTree: (hash: string) => Promise<ArtifactsTree>;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/** Cloudflare Artifacts namespace binding. */
|
|
254
|
+
export interface ArtifactsBinding {
|
|
255
|
+
readonly create: (
|
|
256
|
+
name: RepoName,
|
|
257
|
+
options?: ArtifactsCreateOptions,
|
|
258
|
+
) => Promise<ArtifactsCreateRepoResult>;
|
|
259
|
+
readonly get: (name: RepoName) => Promise<ArtifactsRepoBinding>;
|
|
260
|
+
readonly import: (params: ArtifactsImportParams) => Promise<ArtifactsCreateRepoResult>;
|
|
261
|
+
readonly list: (options?: ArtifactsListOptions) => Promise<ArtifactsRepoListResult>;
|
|
262
|
+
readonly delete: (name: RepoName) => Promise<boolean>;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/** Effect wrapper around a repository handle returned by `Artifacts.get()`. */
|
|
266
|
+
export interface ArtifactsRepoClient extends ArtifactsRepoInfo {
|
|
267
|
+
/**
|
|
268
|
+
* Create a Git token for the repository.
|
|
269
|
+
*
|
|
270
|
+
* Scope defaults to `"write"`. TTL is measured in seconds, defaults to
|
|
271
|
+
* 86,400, and must be between 60 and 31,536,000.
|
|
272
|
+
*/
|
|
273
|
+
readonly createToken: (
|
|
274
|
+
scope?: ArtifactsTokenScope,
|
|
275
|
+
ttl?: number,
|
|
276
|
+
) => Effect.Effect<ArtifactsCreateTokenResult, ArtifactsOperationError>;
|
|
277
|
+
readonly listTokens: Effect.Effect<ArtifactsTokenListResult, ArtifactsOperationError>;
|
|
278
|
+
readonly revokeToken: (tokenOrId: string) => Effect.Effect<boolean, ArtifactsOperationError>;
|
|
279
|
+
readonly fork: (
|
|
280
|
+
name: RepoName,
|
|
281
|
+
options?: ArtifactsForkOptions,
|
|
282
|
+
) => Effect.Effect<ArtifactsCreateRepoResult, ArtifactsOperationError>;
|
|
283
|
+
readonly log: (
|
|
284
|
+
options?: ArtifactsLogOptions,
|
|
285
|
+
) => Effect.Effect<ArtifactsLogResult, ArtifactsOperationError>;
|
|
286
|
+
readonly readCommit: (hash: string) => Effect.Effect<ArtifactsCommit, ArtifactsOperationError>;
|
|
287
|
+
readonly readTree: (hash: string) => Effect.Effect<ArtifactsTree, ArtifactsOperationError>;
|
|
288
|
+
readonly raw: ArtifactsRepoBinding;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/** Effect wrapper around a Cloudflare Artifacts namespace binding. */
|
|
292
|
+
export interface ArtifactsClient {
|
|
293
|
+
readonly create: (
|
|
294
|
+
name: RepoName,
|
|
295
|
+
options?: ArtifactsCreateOptions,
|
|
296
|
+
) => Effect.Effect<ArtifactsCreateRepoResult, ArtifactsOperationError>;
|
|
297
|
+
readonly get: (name: RepoName) => Effect.Effect<ArtifactsRepoClient, ArtifactsOperationError>;
|
|
298
|
+
readonly import: (
|
|
299
|
+
params: ArtifactsImportParams,
|
|
300
|
+
) => Effect.Effect<ArtifactsCreateRepoResult, ArtifactsOperationError>;
|
|
301
|
+
readonly list: (
|
|
302
|
+
options?: ArtifactsListOptions,
|
|
303
|
+
) => Effect.Effect<ArtifactsRepoListResult, ArtifactsOperationError>;
|
|
304
|
+
readonly delete: (name: RepoName) => Effect.Effect<boolean, ArtifactsOperationError>;
|
|
305
|
+
readonly rawUnsafe: Effect.Effect<ArtifactsBinding>;
|
|
306
|
+
readonly definition: ArtifactsDefinition;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
declare const ArtifactsServiceTypeId: unique symbol;
|
|
310
|
+
|
|
311
|
+
/** Nominal service marker for Artifacts services created with {@link make}. */
|
|
312
|
+
export interface ArtifactsService<Id extends string> {
|
|
313
|
+
readonly [ArtifactsServiceTypeId]: {
|
|
314
|
+
readonly id: Id;
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
export type LayerOptions = {
|
|
319
|
+
readonly binding: string;
|
|
320
|
+
};
|
|
321
|
+
|
|
322
|
+
export interface TagClass<Self, Id extends string> extends Context.ServiceClass<
|
|
323
|
+
Self,
|
|
324
|
+
Id,
|
|
325
|
+
ArtifactsClient
|
|
326
|
+
> {
|
|
327
|
+
readonly id: Id;
|
|
328
|
+
readonly layer: (
|
|
329
|
+
options: LayerOptions,
|
|
330
|
+
) => Layer.Layer<
|
|
331
|
+
Self,
|
|
332
|
+
Binding.BindingNotFoundError | Binding.BindingValidationError,
|
|
333
|
+
WorkerEnvironment
|
|
334
|
+
>;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
const artifactsErrorDetails = (
|
|
338
|
+
cause: unknown,
|
|
339
|
+
): Pick<ArtifactsOperationError, "code" | "numericCode"> => {
|
|
340
|
+
if (typeof cause !== "object" || cause === null) {
|
|
341
|
+
return {};
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
const code = Reflect.get(cause, "code");
|
|
345
|
+
const numericCode = Reflect.get(cause, "numericCode");
|
|
346
|
+
|
|
347
|
+
return {
|
|
348
|
+
...(typeof code === "string" ? { code } : {}),
|
|
349
|
+
...(typeof numericCode === "number" ? { numericCode } : {}),
|
|
350
|
+
};
|
|
351
|
+
};
|
|
352
|
+
|
|
353
|
+
const artifactsError = (binding: string, operation: ArtifactsOperation, cause: unknown) =>
|
|
354
|
+
new ArtifactsOperationError({
|
|
355
|
+
binding,
|
|
356
|
+
operation,
|
|
357
|
+
cause,
|
|
358
|
+
...artifactsErrorDetails(cause),
|
|
359
|
+
});
|
|
360
|
+
|
|
361
|
+
const tryArtifactsPromise = <A>(
|
|
362
|
+
binding: string,
|
|
363
|
+
operation: ArtifactsOperation,
|
|
364
|
+
evaluate: () => Promise<A>,
|
|
365
|
+
): Effect.Effect<A, ArtifactsOperationError> =>
|
|
366
|
+
Effect.tryPromise({
|
|
367
|
+
try: evaluate,
|
|
368
|
+
catch: (cause) => artifactsError(binding, operation, cause),
|
|
369
|
+
});
|
|
370
|
+
|
|
371
|
+
const spanOptions = (binding: string, operation: ArtifactsOperation) => ({
|
|
372
|
+
attributes: { binding, operation },
|
|
373
|
+
});
|
|
374
|
+
|
|
375
|
+
const hasFunction = (value: object, key: string): boolean =>
|
|
376
|
+
typeof Reflect.get(value, key) === "function";
|
|
377
|
+
|
|
378
|
+
/** Tests whether a value exposes the complete documented Artifacts repo handle API. */
|
|
379
|
+
export const isArtifactsRepoBinding = (value: unknown): value is ArtifactsRepoBinding =>
|
|
380
|
+
typeof value === "object" &&
|
|
381
|
+
value !== null &&
|
|
382
|
+
hasFunction(value, "createToken") &&
|
|
383
|
+
hasFunction(value, "listTokens") &&
|
|
384
|
+
hasFunction(value, "revokeToken") &&
|
|
385
|
+
hasFunction(value, "fork") &&
|
|
386
|
+
hasFunction(value, "log") &&
|
|
387
|
+
hasFunction(value, "readCommit") &&
|
|
388
|
+
hasFunction(value, "readTree");
|
|
389
|
+
|
|
390
|
+
/** Tests whether a value exposes the complete documented Artifacts namespace API. */
|
|
391
|
+
export const isArtifactsBinding = (value: unknown): value is ArtifactsBinding =>
|
|
392
|
+
typeof value === "object" &&
|
|
393
|
+
value !== null &&
|
|
394
|
+
hasFunction(value, "create") &&
|
|
395
|
+
hasFunction(value, "get") &&
|
|
396
|
+
hasFunction(value, "import") &&
|
|
397
|
+
hasFunction(value, "list") &&
|
|
398
|
+
hasFunction(value, "delete");
|
|
399
|
+
|
|
400
|
+
const wrapRepo = (binding: string, repo: ArtifactsRepoBinding): ArtifactsRepoClient => ({
|
|
401
|
+
id: repo.id,
|
|
402
|
+
name: repo.name,
|
|
403
|
+
description: repo.description,
|
|
404
|
+
defaultBranch: repo.defaultBranch,
|
|
405
|
+
createdAt: repo.createdAt,
|
|
406
|
+
updatedAt: repo.updatedAt,
|
|
407
|
+
lastPushAt: repo.lastPushAt,
|
|
408
|
+
source: repo.source,
|
|
409
|
+
readOnly: repo.readOnly,
|
|
410
|
+
remote: repo.remote,
|
|
411
|
+
createToken: Effect.fn(
|
|
412
|
+
"Artifacts.createToken",
|
|
413
|
+
spanOptions(binding, "createToken"),
|
|
414
|
+
)((scope?: ArtifactsTokenScope, ttl?: number) =>
|
|
415
|
+
tryArtifactsPromise(binding, "createToken", () => repo.createToken(scope, ttl)),
|
|
416
|
+
),
|
|
417
|
+
listTokens: tryArtifactsPromise(binding, "listTokens", () => repo.listTokens()).pipe(
|
|
418
|
+
Effect.withSpan("Artifacts.listTokens", spanOptions(binding, "listTokens")),
|
|
419
|
+
),
|
|
420
|
+
revokeToken: Effect.fn(
|
|
421
|
+
"Artifacts.revokeToken",
|
|
422
|
+
spanOptions(binding, "revokeToken"),
|
|
423
|
+
)((tokenOrId: string) =>
|
|
424
|
+
tryArtifactsPromise(binding, "revokeToken", () => repo.revokeToken(tokenOrId)),
|
|
425
|
+
),
|
|
426
|
+
fork: Effect.fn(
|
|
427
|
+
"Artifacts.fork",
|
|
428
|
+
spanOptions(binding, "fork"),
|
|
429
|
+
)((name: RepoName, options?: ArtifactsForkOptions) =>
|
|
430
|
+
tryArtifactsPromise(binding, "fork", () => repo.fork(name, options)),
|
|
431
|
+
),
|
|
432
|
+
log: Effect.fn(
|
|
433
|
+
"Artifacts.log",
|
|
434
|
+
spanOptions(binding, "log"),
|
|
435
|
+
)((options?: ArtifactsLogOptions) =>
|
|
436
|
+
tryArtifactsPromise(binding, "log", () => repo.log(options)),
|
|
437
|
+
),
|
|
438
|
+
readCommit: Effect.fn(
|
|
439
|
+
"Artifacts.readCommit",
|
|
440
|
+
spanOptions(binding, "readCommit"),
|
|
441
|
+
)((hash: string) => tryArtifactsPromise(binding, "readCommit", () => repo.readCommit(hash))),
|
|
442
|
+
readTree: Effect.fn(
|
|
443
|
+
"Artifacts.readTree",
|
|
444
|
+
spanOptions(binding, "readTree"),
|
|
445
|
+
)((hash: string) => tryArtifactsPromise(binding, "readTree", () => repo.readTree(hash))),
|
|
446
|
+
raw: repo,
|
|
447
|
+
});
|
|
448
|
+
|
|
449
|
+
export const makeClient =
|
|
450
|
+
(definition: ArtifactsDefinition) =>
|
|
451
|
+
(artifacts: ArtifactsBinding): ArtifactsClient => ({
|
|
452
|
+
definition,
|
|
453
|
+
create: Effect.fn(
|
|
454
|
+
"Artifacts.create",
|
|
455
|
+
spanOptions(definition.binding, "create"),
|
|
456
|
+
)((name: RepoName, options?: ArtifactsCreateOptions) =>
|
|
457
|
+
tryArtifactsPromise(definition.binding, "create", () => artifacts.create(name, options)),
|
|
458
|
+
),
|
|
459
|
+
get: Effect.fn(
|
|
460
|
+
"Artifacts.get",
|
|
461
|
+
spanOptions(definition.binding, "get"),
|
|
462
|
+
)((name: RepoName) =>
|
|
463
|
+
tryArtifactsPromise(definition.binding, "get", () => artifacts.get(name)).pipe(
|
|
464
|
+
Effect.flatMap((repo) =>
|
|
465
|
+
isArtifactsRepoBinding(repo)
|
|
466
|
+
? Effect.succeed(wrapRepo(definition.binding, repo))
|
|
467
|
+
: Effect.fail(
|
|
468
|
+
artifactsError(
|
|
469
|
+
definition.binding,
|
|
470
|
+
"get",
|
|
471
|
+
new TypeError(`Expected ${expectedArtifactsRepo}`),
|
|
472
|
+
),
|
|
473
|
+
),
|
|
474
|
+
),
|
|
475
|
+
),
|
|
476
|
+
),
|
|
477
|
+
import: Effect.fn(
|
|
478
|
+
"Artifacts.import",
|
|
479
|
+
spanOptions(definition.binding, "import"),
|
|
480
|
+
)((params: ArtifactsImportParams) =>
|
|
481
|
+
tryArtifactsPromise(definition.binding, "import", () => artifacts.import(params)),
|
|
482
|
+
),
|
|
483
|
+
list: Effect.fn(
|
|
484
|
+
"Artifacts.list",
|
|
485
|
+
spanOptions(definition.binding, "list"),
|
|
486
|
+
)((options?: ArtifactsListOptions) =>
|
|
487
|
+
tryArtifactsPromise(definition.binding, "list", () => artifacts.list(options)),
|
|
488
|
+
),
|
|
489
|
+
delete: Effect.fn(
|
|
490
|
+
"Artifacts.delete",
|
|
491
|
+
spanOptions(definition.binding, "delete"),
|
|
492
|
+
)((name: RepoName) =>
|
|
493
|
+
tryArtifactsPromise(definition.binding, "delete", () => artifacts.delete(name)),
|
|
494
|
+
),
|
|
495
|
+
rawUnsafe: Effect.succeed(artifacts),
|
|
496
|
+
});
|
|
497
|
+
|
|
498
|
+
export const layer = <Self>(
|
|
499
|
+
tag: Context.Service<Self, ArtifactsClient>,
|
|
500
|
+
definition: ArtifactsDefinition,
|
|
501
|
+
) =>
|
|
502
|
+
Binding.layer(tag, definition.binding, isArtifactsBinding, makeClient(definition), {
|
|
503
|
+
expected: expectedArtifactsBinding,
|
|
504
|
+
});
|
|
505
|
+
|
|
506
|
+
export const make = <Id extends string>(id: Id) => Tag<ArtifactsService<Id>>()<Id>(id);
|
|
507
|
+
|
|
508
|
+
export const Tag =
|
|
509
|
+
<Self>() =>
|
|
510
|
+
<Id extends string>(id: Id) => {
|
|
511
|
+
const tag = Context.Service<Self, ArtifactsClient>()(id);
|
|
512
|
+
|
|
513
|
+
const makeLayer = (definition: LayerOptions) => layer(tag, definition);
|
|
514
|
+
|
|
515
|
+
return Object.assign(tag, {
|
|
516
|
+
id,
|
|
517
|
+
layer: makeLayer,
|
|
518
|
+
}) as TagClass<Self, Id>;
|
|
519
|
+
};
|