@fungi.computer/burrow 0.0.0-stage → 0.0.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.
@@ -0,0 +1,93 @@
1
+ /** Host-only Artifacts namespace. Repository credentials never enter App results. */
2
+ export type ArtifactsRepositoryInfo = Readonly<{
3
+ id: string;
4
+ name: string;
5
+ defaultBranch: string;
6
+ remote: string;
7
+ lastPushAt?: string | null;
8
+ source?: string | null;
9
+ }>;
10
+ /** Initial revocation reference: a Workers token or an already-revoked REST ID. */
11
+ export type ArtifactsCreatedRepository = ArtifactsRepositoryInfo & Readonly<{
12
+ token: string;
13
+ }>;
14
+ /** Provider commit metadata and parent object IDs. */
15
+ export type ArtifactsCommit = Readonly<{
16
+ hash: string;
17
+ treeHash: string;
18
+ message: string;
19
+ author: Readonly<{
20
+ name: string;
21
+ email: string;
22
+ }>;
23
+ committer: Readonly<{
24
+ name: string;
25
+ email: string;
26
+ }>;
27
+ parents: readonly string[];
28
+ authoredAt: number;
29
+ committedAt: number;
30
+ }>;
31
+ /** One provider tree entry, including its mode and object kind. */
32
+ export type ArtifactsTreeEntry = Readonly<{
33
+ name: string;
34
+ mode: string;
35
+ hash: string;
36
+ type: "blob" | "tree" | "commit";
37
+ }>;
38
+ /** Host-only repository operations; secrets never belong in App results. */
39
+ export type ArtifactsRepositoryHandle = Readonly<{
40
+ /** Read current provider repository metadata. */
41
+ info(): Promise<ArtifactsRepositoryInfo>;
42
+ /** Mint a read or write credential for the requested lifetime; keep it host-only. */
43
+ createToken(scope: "read" | "write", ttl: number): Promise<Readonly<{
44
+ id: string;
45
+ plaintext: string;
46
+ expiresAt: string;
47
+ }>>;
48
+ /** Revoke this exact token or token ID; false means it is no longer present. */
49
+ revokeToken(tokenOrId: string): Promise<boolean>;
50
+ /** Fork this repository and return the new destination with its revocation reference. */
51
+ fork(name: string, options: {
52
+ description?: string;
53
+ readOnly: false;
54
+ defaultBranchOnly: boolean;
55
+ }): Promise<ArtifactsCreatedRepository>;
56
+ /** Read a bounded page of commits at the requested ref. */
57
+ log(options: {
58
+ ref: string;
59
+ limit: number;
60
+ offset: number;
61
+ }): Promise<readonly ArtifactsCommit[]>;
62
+ /** Read one commit object, or null if that object is absent. */
63
+ readCommit(hash: string): Promise<ArtifactsCommit | null>;
64
+ /** Read one tree object, or null if that object is absent. */
65
+ readTree(hash: string): Promise<readonly ArtifactsTreeEntry[] | null>;
66
+ /** Read one blob object, or null if that object is absent. */
67
+ readBlob(hash: string): Promise<Blob | null>;
68
+ }>;
69
+ /** Configured provider namespace with repository-name-addressed handles. */
70
+ export type ArtifactsNamespace = Readonly<{
71
+ /** Create a repository; its initial credential must be revoked before activation. */
72
+ create(name: string, options: {
73
+ description?: string;
74
+ readOnly: false;
75
+ setDefaultBranch: string;
76
+ }): Promise<ArtifactsCreatedRepository>;
77
+ /** Address a repository handle; its operations establish live provider availability. */
78
+ get(name: string): Promise<ArtifactsRepositoryHandle>;
79
+ /** Read a bounded repository-status page and its optional next cursor. */
80
+ list(options?: {
81
+ limit?: number;
82
+ cursor?: string;
83
+ }): Promise<Readonly<{
84
+ repos: readonly Readonly<{
85
+ name: string;
86
+ status: string;
87
+ }>[];
88
+ total: number;
89
+ cursor?: string;
90
+ }>>;
91
+ /** Delete the named repository; return false when it is already absent. */
92
+ delete(name: string): Promise<boolean>;
93
+ }>;
@@ -0,0 +1 @@
1
+ export {};
package/dist/rest.d.ts ADDED
@@ -0,0 +1,17 @@
1
+ import type { ArtifactsNamespace } from "./namespace.js";
2
+ /** Where the REST API is and how to reach it. */
3
+ export type ArtifactsRestOptions = Readonly<{
4
+ accountId: string;
5
+ namespace: string;
6
+ /** A Cloudflare API token with Artifacts read and write. */
7
+ apiToken: string;
8
+ /** Defaults to the global `fetch`. */
9
+ fetch?: typeof fetch;
10
+ }>;
11
+ /** A failed Artifacts REST call, with the binding's error `code`. */
12
+ export declare class ArtifactsRestError extends Error {
13
+ readonly code: string;
14
+ constructor(code: string, message: string);
15
+ }
16
+ /** An Artifacts namespace reached over REST, with the binding's shape. */
17
+ export declare function createArtifactsRestNamespace(options: ArtifactsRestOptions): ArtifactsNamespace;
package/dist/rest.js ADDED
@@ -0,0 +1,288 @@
1
+ import * as Schema from "effect/Schema";
2
+ const repoSchema = Schema.Struct({
3
+ id: Schema.String,
4
+ name: Schema.String,
5
+ default_branch: Schema.String,
6
+ remote: Schema.String,
7
+ last_push_at: Schema.optional(Schema.NullOr(Schema.String)),
8
+ source: Schema.optional(Schema.NullOr(Schema.String)),
9
+ status: Schema.optional(Schema.String),
10
+ });
11
+ const envelopeSchema = Schema.Struct({
12
+ success: Schema.Boolean,
13
+ result: Schema.Unknown,
14
+ errors: Schema.Array(Schema.Struct({ code: Schema.Number, message: Schema.String })),
15
+ result_info: Schema.optional(Schema.Struct({
16
+ cursor: Schema.optional(Schema.NullOr(Schema.String)),
17
+ total_pages: Schema.optional(Schema.Number),
18
+ total_count: Schema.optional(Schema.Number),
19
+ })),
20
+ });
21
+ const tokenSchema = Schema.Struct({
22
+ id: Schema.NonEmptyString,
23
+ plaintext: Schema.NonEmptyString,
24
+ expires_at: Schema.NonEmptyString,
25
+ });
26
+ const createdSchema = Schema.Struct({
27
+ ...repoSchema.fields,
28
+ token: Schema.NonEmptyString,
29
+ });
30
+ const listedTokensSchema = Schema.Array(Schema.Struct({
31
+ id: Schema.NonEmptyString,
32
+ state: Schema.Literals(["active", "expired", "revoked"]),
33
+ }));
34
+ /** The string codes the binding throws, from the REST API's numeric codes. */
35
+ const errorCodes = new Map([
36
+ [10200, "NOT_FOUND"],
37
+ [10201, "ALREADY_EXISTS"],
38
+ [10302, "IMPORT_IN_PROGRESS"],
39
+ [10303, "FORK_IN_PROGRESS"],
40
+ ]);
41
+ /** A failed Artifacts REST call, with the binding's error `code`. */
42
+ export class ArtifactsRestError extends Error {
43
+ code;
44
+ constructor(code, message) {
45
+ super(message);
46
+ this.code = code;
47
+ }
48
+ }
49
+ function decode(schema, raw) {
50
+ try {
51
+ return Schema.decodeUnknownSync(schema)(raw);
52
+ }
53
+ catch {
54
+ throw new ArtifactsRestError("INVALID_RESPONSE", "Artifacts returned an invalid response");
55
+ }
56
+ }
57
+ function toInfo(repo) {
58
+ return {
59
+ id: repo.id,
60
+ name: repo.name,
61
+ defaultBranch: repo.default_branch,
62
+ remote: repo.remote,
63
+ lastPushAt: repo.last_push_at ?? null,
64
+ source: repo.source ?? null,
65
+ };
66
+ }
67
+ /** An Artifacts namespace reached over REST, with the binding's shape. */
68
+ export function createArtifactsRestNamespace(options) {
69
+ const base = `https://api.cloudflare.com/client/v4/accounts/${encodeURIComponent(options.accountId)}/artifacts/namespaces/${encodeURIComponent(options.namespace)}`;
70
+ const send = options.fetch ?? ((input, init) => fetch(input, init));
71
+ const request = async (path, init = {}) => {
72
+ const headers = new Headers(init.headers);
73
+ headers.set("Authorization", `Bearer ${options.apiToken}`);
74
+ if (init.body !== undefined)
75
+ headers.set("Content-Type", "application/json");
76
+ return send(`${base}${path}`, { ...init, headers, redirect: "manual" });
77
+ };
78
+ const json = async (path, init = {}) => {
79
+ const response = await request(path, init);
80
+ if (response.status >= 300 && response.status < 400) {
81
+ await response.body?.cancel();
82
+ throw new ArtifactsRestError("REDIRECT_REFUSED", "Artifacts redirect refused");
83
+ }
84
+ let raw;
85
+ try {
86
+ raw = await response.json();
87
+ }
88
+ catch {
89
+ throw new ArtifactsRestError("INVALID_RESPONSE", "Artifacts returned an invalid response");
90
+ }
91
+ const body = decode(envelopeSchema, raw);
92
+ if (!response.ok || !body.success) {
93
+ const [first] = body.errors;
94
+ throw new ArtifactsRestError((first && errorCodes.get(first.code)) ?? "INTERNAL_ERROR", `Artifacts request failed (${String(response.status)})`);
95
+ }
96
+ return body;
97
+ };
98
+ const bytes = async (path) => {
99
+ const response = await request(path);
100
+ if (response.status === 404) {
101
+ await response.body?.cancel();
102
+ return null;
103
+ }
104
+ if (!response.ok)
105
+ throw new ArtifactsRestError("INTERNAL_ERROR", `Artifacts read failed (${String(response.status)})`);
106
+ return new Uint8Array(await response.arrayBuffer());
107
+ };
108
+ const orNull = async (read) => {
109
+ try {
110
+ return await read();
111
+ }
112
+ catch (error) {
113
+ if (error instanceof ArtifactsRestError && error.code === "NOT_FOUND")
114
+ return null;
115
+ throw error;
116
+ }
117
+ };
118
+ const repoPath = (name) => `/repos/${encodeURIComponent(name)}`;
119
+ const revokedInitialTokenIds = new Set();
120
+ const mintedTokenIds = new Map();
121
+ const readInitialTokens = async (path) => {
122
+ const page = await json(path);
123
+ const tokens = decode(listedTokensSchema, page.result);
124
+ if (page.result_info?.total_pages !== 1 ||
125
+ page.result_info.total_count !== tokens.length ||
126
+ tokens.length > 100)
127
+ throw new Error("Artifacts initial token page is incomplete");
128
+ return tokens;
129
+ };
130
+ const finishCreated = async (name, raw) => {
131
+ try {
132
+ const created = Schema.decodeUnknownSync(createdSchema)(raw);
133
+ if (created.name !== name)
134
+ throw new Error("Artifacts repository identity conflicts");
135
+ const tokenPath = `${repoPath(name)}/tokens?state=all&per_page=100&page=1`;
136
+ const listed = await readInitialTokens(tokenPath);
137
+ const active = listed.filter((token) => token.state === "active");
138
+ const [initial] = active;
139
+ if (active.length !== 1 || !initial)
140
+ throw new Error("Artifacts initial token is ambiguous");
141
+ await json(`/tokens/${encodeURIComponent(initial.id)}`, {
142
+ method: "DELETE",
143
+ });
144
+ const verified = await readInitialTokens(tokenPath);
145
+ if (verified.filter((token) => token.id === initial.id && token.state === "revoked").length !== 1 ||
146
+ verified.some((token) => token.state === "active"))
147
+ throw new Error("Artifacts initial token revocation was not verified");
148
+ revokedInitialTokenIds.add(initial.id);
149
+ return { ...toInfo(created), token: initial.id };
150
+ }
151
+ catch {
152
+ // Only a successful create/fork reply reaches this cleanup. Existing
153
+ // repositories and the fork's source are never deleted by this path.
154
+ await json(repoPath(name), { method: "DELETE" });
155
+ throw new ArtifactsRestError("INITIAL_TOKEN_REFUSED", "Artifacts initial token cleanup refused repository activation");
156
+ }
157
+ };
158
+ return {
159
+ async create(name, opts) {
160
+ const created = await json("/repos", {
161
+ method: "POST",
162
+ body: JSON.stringify({
163
+ name,
164
+ description: opts.description,
165
+ default_branch: opts.setDefaultBranch,
166
+ read_only: false,
167
+ }),
168
+ });
169
+ return finishCreated(name, created.result);
170
+ },
171
+ async list(opts = {}) {
172
+ const query = new URLSearchParams({ limit: String(opts.limit ?? 200) });
173
+ if (opts.cursor !== undefined)
174
+ query.set("cursor", opts.cursor);
175
+ const page = await json(`/repos?${query.toString()}`);
176
+ const repos = decode(Schema.Array(repoSchema), page.result).map((repo) => ({
177
+ name: repo.name,
178
+ status: repo.status ?? "ready",
179
+ }));
180
+ const cursor = page.result_info?.cursor ?? undefined;
181
+ return cursor === undefined
182
+ ? { repos, total: repos.length }
183
+ : { repos, total: repos.length, cursor };
184
+ },
185
+ async delete(name) {
186
+ return ((await orNull(() => json(repoPath(name), { method: "DELETE" }))) !==
187
+ null);
188
+ },
189
+ async get(name) {
190
+ const path = repoPath(name);
191
+ return Promise.resolve({
192
+ async info() {
193
+ return toInfo(decode(repoSchema, (await json(path)).result));
194
+ },
195
+ async createToken(scope, ttl) {
196
+ const created = await json("/tokens", {
197
+ method: "POST",
198
+ body: JSON.stringify({ repo: name, scope, ttl }),
199
+ });
200
+ const token = decode(tokenSchema, created.result);
201
+ mintedTokenIds.set(token.plaintext, token.id);
202
+ return {
203
+ id: token.id,
204
+ plaintext: token.plaintext,
205
+ expiresAt: token.expires_at,
206
+ };
207
+ },
208
+ async revokeToken(tokenOrId) {
209
+ if (revokedInitialTokenIds.delete(tokenOrId))
210
+ return false;
211
+ const id = mintedTokenIds.get(tokenOrId) ?? tokenOrId;
212
+ const revoked = await orNull(() => json(`/tokens/${encodeURIComponent(id)}`, { method: "DELETE" }));
213
+ for (const [plaintext, tokenId] of mintedTokenIds)
214
+ if (tokenId === id)
215
+ mintedTokenIds.delete(plaintext);
216
+ return revoked !== null;
217
+ },
218
+ async fork(target, opts) {
219
+ const forked = await json(`${path}/fork`, {
220
+ method: "POST",
221
+ body: JSON.stringify({
222
+ name: target,
223
+ description: opts.description,
224
+ read_only: false,
225
+ default_branch_only: opts.defaultBranchOnly,
226
+ }),
227
+ });
228
+ return finishCreated(target, forked.result);
229
+ },
230
+ async log(opts) {
231
+ const query = new URLSearchParams({
232
+ ref: opts.ref,
233
+ limit: String(opts.limit),
234
+ offset: String(opts.offset),
235
+ });
236
+ const page = await orNull(() => json(`${path}/log?${query.toString()}`));
237
+ // The binding answers an unknown ref with no history.
238
+ return page === null
239
+ ? []
240
+ : decodeCommits(decode(Schema.Array(commitSchema), page.result));
241
+ },
242
+ async readCommit(hash) {
243
+ const page = await orNull(() => json(`${path}/commit/${encodeURIComponent(hash)}`));
244
+ return page === null
245
+ ? null
246
+ : (decodeCommits(decode(Schema.Array(commitSchema), [page.result]))[0] ?? null);
247
+ },
248
+ async readTree(hash) {
249
+ const page = await orNull(() => json(`${path}/tree/${encodeURIComponent(hash)}`));
250
+ return page === null
251
+ ? null
252
+ : decodeTree(decode(Schema.Array(treeSchema), page.result));
253
+ },
254
+ async readBlob(hash) {
255
+ const content = await bytes(`${path}/blob/${encodeURIComponent(hash)}`);
256
+ return content === null ? null : new Blob([new Uint8Array(content)]);
257
+ },
258
+ });
259
+ },
260
+ };
261
+ }
262
+ const commitSchema = Schema.Struct({
263
+ hash: Schema.String,
264
+ treeHash: Schema.String,
265
+ message: Schema.String,
266
+ author: Schema.Struct({ name: Schema.String, email: Schema.String }),
267
+ committer: Schema.Struct({ name: Schema.String, email: Schema.String }),
268
+ parents: Schema.Array(Schema.String),
269
+ authoredAt: Schema.Number,
270
+ committedAt: Schema.Number,
271
+ });
272
+ const treeSchema = Schema.Struct({
273
+ name: Schema.String,
274
+ mode: Schema.String,
275
+ hash: Schema.String,
276
+ type: Schema.Literals(["blob", "tree", "commit"]),
277
+ });
278
+ function decodeCommits(commits) {
279
+ return commits.map((commit) => ({
280
+ ...commit,
281
+ author: { ...commit.author },
282
+ committer: { ...commit.committer },
283
+ parents: [...commit.parents],
284
+ }));
285
+ }
286
+ function decodeTree(entries) {
287
+ return [...entries];
288
+ }
@@ -0,0 +1,15 @@
1
+ <!-- Generated by Botanical API docs (TypeDoc + typedoc-plugin-markdown). Do not edit. -->
2
+
3
+ **@fungi.computer/burrow**
4
+
5
+ ---
6
+
7
+ # @fungi.computer/burrow
8
+
9
+ ## Modules
10
+
11
+ | Module | Description |
12
+ | --------------------------- | ----------- |
13
+ | [cloudflare](cloudflare.md) | - |
14
+ | [index](index.md) | - |
15
+ | [namespace](namespace.md) | - |
@@ -0,0 +1,271 @@
1
+ <!-- Generated by Botanical API docs (TypeDoc + typedoc-plugin-markdown). Do not edit. -->
2
+
3
+ [**@fungi.computer/burrow**](README.md)
4
+
5
+ ---
6
+
7
+ [@fungi.computer/burrow](README.md) / cloudflare
8
+
9
+ # cloudflare
10
+
11
+ ## Classes
12
+
13
+ ### ArtifactsForkStuckError
14
+
15
+ A repository did not finish importing or forking within the readiness window.
16
+
17
+ #### Extends
18
+
19
+ - `Error`
20
+
21
+ #### Constructors
22
+
23
+ ##### Constructor
24
+
25
+ ```ts
26
+ new ArtifactsForkStuckError(repository, status): ArtifactsForkStuckError;
27
+ ```
28
+
29
+ ###### Parameters
30
+
31
+ | Parameter | Type |
32
+ | ------------ | ------------------------------------------- |
33
+ | `repository` | `string` |
34
+ | `status` | `"importing"` \| `"forking"` \| `"missing"` |
35
+
36
+ ###### Returns
37
+
38
+ [`ArtifactsForkStuckError`](#artifactsforkstuckerror)
39
+
40
+ ###### Overrides
41
+
42
+ ```ts
43
+ Error.constructor;
44
+ ```
45
+
46
+ #### Properties
47
+
48
+ ##### name
49
+
50
+ ```ts
51
+ readonly name: "ArtifactsForkStuckError" = "ArtifactsForkStuckError";
52
+ ```
53
+
54
+ ###### Overrides
55
+
56
+ ```ts
57
+ Error.name;
58
+ ```
59
+
60
+ ##### repository
61
+
62
+ ```ts
63
+ readonly repository: string;
64
+ ```
65
+
66
+ ##### status
67
+
68
+ ```ts
69
+ readonly status: "importing" | "forking" | "missing";
70
+ ```
71
+
72
+ ## Type Aliases
73
+
74
+ ### CloudflareArtifactsRepositoryHandle
75
+
76
+ ```ts
77
+ type CloudflareArtifactsRepositoryHandle = Readonly<{
78
+ info?: () => Promise<ArtifactsRepositoryInfo>;
79
+ createToken: Promise<
80
+ Readonly<{
81
+ id: string;
82
+ plaintext: string;
83
+ expiresAt: string;
84
+ }>
85
+ >;
86
+ revokeToken: Promise<boolean>;
87
+ fork: Promise<
88
+ Readonly<{
89
+ id: string;
90
+ name: string;
91
+ remote: string;
92
+ defaultBranch: string;
93
+ token: string;
94
+ }>
95
+ >;
96
+ }>;
97
+ ```
98
+
99
+ Repository handle accepted by the Cloudflare Artifacts namespace.
100
+
101
+ ---
102
+
103
+ ### CloudflareArtifactsRepositoryMetadata
104
+
105
+ ```ts
106
+ type CloudflareArtifactsRepositoryMetadata = Readonly<{
107
+ id: string;
108
+ name: string;
109
+ defaultBranch: string;
110
+ remote: string;
111
+ parentRepository: string | null;
112
+ }>;
113
+ ```
114
+
115
+ Provider identity recorded at creation; used to pin later remote access.
116
+
117
+ ---
118
+
119
+ ### CloudflareArtifactsRepositoryMetadataStore
120
+
121
+ ```ts
122
+ type CloudflareArtifactsRepositoryMetadataStore = Readonly<{
123
+ read: Promise<Readonly<{
124
+ id: string;
125
+ name: string;
126
+ defaultBranch: string;
127
+ remote: string;
128
+ parentRepository: string | null;
129
+ }> | null>;
130
+ readPending: Promise<Readonly<{
131
+ metadata: CloudflareArtifactsRepositoryMetadata;
132
+ initialToken: string;
133
+ }> | null>;
134
+ recordPending: Promise<void>;
135
+ activate: Promise<void>;
136
+ }>;
137
+ ```
138
+
139
+ Host-owned durable metadata and pending initial-token revocation records.
140
+
141
+ ---
142
+
143
+ ### CloudflareArtifactsNamespace
144
+
145
+ ```ts
146
+ type CloudflareArtifactsNamespace = Readonly<{
147
+ get: Promise<
148
+ Readonly<{
149
+ info?: () => Promise<ArtifactsRepositoryInfo>;
150
+ createToken: Promise<
151
+ Readonly<{
152
+ id: string;
153
+ plaintext: string;
154
+ expiresAt: string;
155
+ }>
156
+ >;
157
+ revokeToken: Promise<boolean>;
158
+ fork: Promise<
159
+ Readonly<{
160
+ id: string;
161
+ name: string;
162
+ remote: string;
163
+ defaultBranch: string;
164
+ token: string;
165
+ }>
166
+ >;
167
+ }>
168
+ >;
169
+ list: Promise<
170
+ Readonly<{
171
+ repos: readonly Readonly<{
172
+ name: string;
173
+ }>[];
174
+ total: number;
175
+ cursor?: string;
176
+ }>
177
+ >;
178
+ create: Promise<
179
+ Readonly<{
180
+ id: string;
181
+ name: string;
182
+ remote: string;
183
+ defaultBranch: string;
184
+ token: string;
185
+ }>
186
+ >;
187
+ }>;
188
+ ```
189
+
190
+ The maintained Cloudflare namespace methods used by this private adapter.
191
+
192
+ ---
193
+
194
+ ### CloudflareArtifactsRepositoryPage
195
+
196
+ ```ts
197
+ type CloudflareArtifactsRepositoryPage = Readonly<{
198
+ repos: readonly Readonly<{
199
+ name: string;
200
+ }>[];
201
+ total: number;
202
+ cursor?: string;
203
+ }>;
204
+ ```
205
+
206
+ Repository listing page used to observe fork/import readiness.
207
+
208
+ ---
209
+
210
+ ### CloudflareArtifactsOptions
211
+
212
+ ```ts
213
+ type CloudflareArtifactsOptions = Readonly<{
214
+ namespace: CloudflareArtifactsNamespace;
215
+ repositories: CloudflareArtifactsRepositoryMetadataStore;
216
+ gitHttp?: typeof http;
217
+ gitFetch?: typeof fetch;
218
+ }>;
219
+ ```
220
+
221
+ Provider, durable metadata store and optional Git protocol transports.
222
+
223
+ ## Functions
224
+
225
+ ### exchangeCloudflareArtifactsGit()
226
+
227
+ ```ts
228
+ function exchangeCloudflareArtifactsGit(
229
+ metadata,
230
+ input,
231
+ credential,
232
+ gitFetch,
233
+ ): Promise<Response>;
234
+ ```
235
+
236
+ Execute Git with an already-held repo credential. The custody owner chooses
237
+ metadata and credential; caller URLs and authorization headers never enter.
238
+
239
+ #### Parameters
240
+
241
+ | Parameter | Type |
242
+ | ------------ | -------------------------------------------------------------------------------------------------------------------------------------------- |
243
+ | `metadata` | [`CloudflareArtifactsRepositoryMetadata`](#cloudflareartifactsrepositorymetadata) |
244
+ | `input` | [`GitExchange`](index.md#gitexchange) |
245
+ | `credential` | `string` |
246
+ | `gitFetch` | \{ (`input`, `init?`): `Promise`\<`Response`\>; (`input`, `init?`): `Promise`\<`Response`\>; (`input`, `init?`): `Promise`\<`Response`\>; \} |
247
+
248
+ #### Returns
249
+
250
+ `Promise`\<`Response`\>
251
+
252
+ ---
253
+
254
+ ### createCloudflareArtifacts()
255
+
256
+ ```ts
257
+ function createCloudflareArtifacts(options): Artifacts;
258
+ ```
259
+
260
+ Configure the Artifacts owner once; provider remotes and credentials stay
261
+ private.
262
+
263
+ #### Parameters
264
+
265
+ | Parameter | Type |
266
+ | --------- | ----------------------------------------------------------- |
267
+ | `options` | [`CloudflareArtifactsOptions`](#cloudflareartifactsoptions) |
268
+
269
+ #### Returns
270
+
271
+ [`Artifacts`](index.md#artifacts)