@alchemy.run/pkg 0.0.0-placeholder → 2.0.0-beta.79

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 (70) hide show
  1. package/LICENSE +201 -0
  2. package/NOTICE +5 -0
  3. package/README.md +117 -0
  4. package/dist/Manifest.d.ts +107 -0
  5. package/dist/Manifest.d.ts.map +1 -0
  6. package/dist/Manifest.js +58 -0
  7. package/dist/Manifest.js.map +1 -0
  8. package/dist/Protocol.d.ts +186 -0
  9. package/dist/Protocol.d.ts.map +1 -0
  10. package/dist/Protocol.js +115 -0
  11. package/dist/Protocol.js.map +1 -0
  12. package/dist/Registry/Bindings.d.ts +134 -0
  13. package/dist/Registry/Bindings.d.ts.map +1 -0
  14. package/dist/Registry/Bindings.js +92 -0
  15. package/dist/Registry/Bindings.js.map +1 -0
  16. package/dist/Registry/GitHub.d.ts +96 -0
  17. package/dist/Registry/GitHub.d.ts.map +1 -0
  18. package/dist/Registry/GitHub.js +226 -0
  19. package/dist/Registry/GitHub.js.map +1 -0
  20. package/dist/Registry/Handler.d.ts +53 -0
  21. package/dist/Registry/Handler.d.ts.map +1 -0
  22. package/dist/Registry/Handler.js +375 -0
  23. package/dist/Registry/Handler.js.map +1 -0
  24. package/dist/Registry/KVCache.d.ts +24 -0
  25. package/dist/Registry/KVCache.d.ts.map +1 -0
  26. package/dist/Registry/KVCache.js +42 -0
  27. package/dist/Registry/KVCache.js.map +1 -0
  28. package/dist/Registry/Sweep.d.ts +12 -0
  29. package/dist/Registry/Sweep.d.ts.map +1 -0
  30. package/dist/Registry/Sweep.js +69 -0
  31. package/dist/Registry/Sweep.js.map +1 -0
  32. package/dist/Registry/Tags.d.ts +49 -0
  33. package/dist/Registry/Tags.d.ts.map +1 -0
  34. package/dist/Registry/Tags.js +80 -0
  35. package/dist/Registry/Tags.js.map +1 -0
  36. package/dist/Registry.d.ts +378 -0
  37. package/dist/Registry.d.ts.map +1 -0
  38. package/dist/Registry.js +119 -0
  39. package/dist/Registry.js.map +1 -0
  40. package/dist/cli/bin.d.ts +18 -0
  41. package/dist/cli/bin.d.ts.map +1 -0
  42. package/dist/cli/bin.js +33 -0
  43. package/dist/cli/bin.js.map +1 -0
  44. package/dist/cli/pack.d.ts +169 -0
  45. package/dist/cli/pack.d.ts.map +1 -0
  46. package/dist/cli/pack.js +447 -0
  47. package/dist/cli/pack.js.map +1 -0
  48. package/dist/cli/publish.d.ts +33 -0
  49. package/dist/cli/publish.d.ts.map +1 -0
  50. package/dist/cli/publish.js +76 -0
  51. package/dist/cli/publish.js.map +1 -0
  52. package/dist/index.d.ts +3 -0
  53. package/dist/index.d.ts.map +1 -0
  54. package/dist/index.js +6 -0
  55. package/dist/index.js.map +1 -0
  56. package/migrations/0001_init.sql +19 -0
  57. package/package.json +89 -1
  58. package/src/Manifest.ts +76 -0
  59. package/src/Protocol.ts +163 -0
  60. package/src/Registry/Bindings.ts +134 -0
  61. package/src/Registry/GitHub.ts +365 -0
  62. package/src/Registry/Handler.ts +549 -0
  63. package/src/Registry/KVCache.ts +68 -0
  64. package/src/Registry/Sweep.ts +117 -0
  65. package/src/Registry/Tags.ts +117 -0
  66. package/src/Registry.ts +197 -0
  67. package/src/cli/bin.ts +101 -0
  68. package/src/cli/pack.ts +603 -0
  69. package/src/cli/publish.ts +129 -0
  70. package/src/index.ts +5 -0
@@ -0,0 +1,375 @@
1
+ import * as Cloudflare from "alchemy/Cloudflare";
2
+ import * as SQL from "alchemy/SQL/D1";
3
+ import { sha256 } from "alchemy/Util/sha256";
4
+ import * as Clock from "effect/Clock";
5
+ import * as Duration from "effect/Duration";
6
+ import * as Effect from "effect/Effect";
7
+ import * as Encoding from "effect/Encoding";
8
+ import * as Layer from "effect/Layer";
9
+ import * as Path from "effect/Path";
10
+ import * as Result from "effect/Result";
11
+ import * as Schema from "effect/Schema";
12
+ import * as Etag from "effect/unstable/http/Etag";
13
+ import * as FetchHttpClient from "effect/unstable/http/FetchHttpClient";
14
+ import * as HttpPlatform from "effect/unstable/http/HttpPlatform";
15
+ import * as HttpRouter from "effect/unstable/http/HttpRouter";
16
+ import { HttpServerRequest } from "effect/unstable/http/HttpServerRequest";
17
+ import * as HttpServerResponse from "effect/unstable/http/HttpServerResponse";
18
+ import * as HttpApiBuilder from "effect/unstable/httpapi/HttpApiBuilder";
19
+ import { ManifestJson } from "../Manifest.js";
20
+ import { BadRequest, Forbidden, manifestArtifactName, MissingTarballs, PackageTooLarge, PkgApi, RunNotInProgress, RunRef, Upstream, } from "../Protocol.js";
21
+ import { Bucket, Cache, COMMENT_MARKER, Database, RegistryConfig, tarballKey, } from "./Bindings.js";
22
+ import * as GitHub from "./GitHub.js";
23
+ import * as KVCache from "./KVCache.js";
24
+ import { sweep } from "./Sweep.js";
25
+ import * as Tags from "./Tags.js";
26
+ /** What GitHub says about a run. */
27
+ const Run = Schema.Struct({
28
+ ...RunRef.fields,
29
+ headSha: Schema.String,
30
+ headBranch: Schema.NullOr(Schema.String),
31
+ headRepo: Schema.String,
32
+ pr: Schema.NullOr(Schema.Number),
33
+ });
34
+ const bindings = Layer.mergeAll(Cloudflare.R2.ReadWriteBucketBinding, Cloudflare.D1.QueryDatabaseBinding, Cloudflare.KV.ReadWriteNamespaceBinding, Cloudflare.Workers.CronEventSourceLive, FetchHttpClient.layer);
35
+ const SHORT = 7;
36
+ /** How long a resolved run is reused for uploads before asking GitHub again. */
37
+ const RUN_CACHE = Duration.minutes(1);
38
+ const CHECK_NAME = "Preview packages";
39
+ /** The public origin a request arrived on. */
40
+ const origin = Effect.map(HttpServerRequest, (request) => `https://${request.headers.host ?? "localhost"}`);
41
+ /**
42
+ * A run from a fork: its head commit belongs to another repository, so its
43
+ * workflow file, and therefore everything it packs, is the fork's.
44
+ */
45
+ const isFork = (run) => run.headRepo !== run.repo;
46
+ /**
47
+ * Tags every package in a publication receives, all derived from the run.
48
+ * Runs on the repository's own commits get the head commit, the short
49
+ * commit, `branch:<name>`, and `pr:N` for pull requests. A fork's run gets
50
+ * only `pr:N`: commit tags are shared by every publisher, and a fork can
51
+ * run any commit it likes, including one already published from the
52
+ * repository, so letting it write them would let it repoint them.
53
+ */
54
+ export const tagsFor = (run) => {
55
+ if (isFork(run)) {
56
+ return run.pr === null ? [] : [`pr:${run.pr}`];
57
+ }
58
+ const tags = [run.headSha, run.headSha.slice(0, SHORT)];
59
+ if (run.pr !== null)
60
+ tags.push(`pr:${run.pr}`);
61
+ if (run.headBranch)
62
+ tags.push(`branch:${run.headBranch}`);
63
+ return tags;
64
+ };
65
+ /** The tag install commands are written against. */
66
+ export const installTag = (run) => isFork(run) ? `pr:${run.pr}` : run.headSha.slice(0, SHORT);
67
+ const upstream = (e) => new Upstream({ message: GitHub.describe(e) });
68
+ /**
69
+ * Storage failures are not part of the protocol: they are defects, which
70
+ * the router answers with a 500 after logging the cause.
71
+ */
72
+ const storageFailures = ["R2Error", "SqlError", "SchemaError"];
73
+ /**
74
+ * Resolve the run a request names through GitHub; nothing about it is
75
+ * trusted from the client. Only allowed repositories are looked up at all,
76
+ * and the run must be in progress, since requests come from inside it.
77
+ */
78
+ const lookupRun = Effect.fn("lookupRun")(function* (ref) {
79
+ const { policy } = yield* RegistryConfig;
80
+ const github = yield* GitHub.GitHubApp;
81
+ if (!policy.repos.includes(ref.repo)) {
82
+ return yield* new Forbidden({ message: `${ref.repo} may not publish` });
83
+ }
84
+ const data = yield* github
85
+ .getRun(ref.repo, ref.runId)
86
+ .pipe(Effect.mapError(upstream));
87
+ if (data.status !== "in_progress" ||
88
+ (data.run_attempt !== undefined && data.run_attempt !== ref.attempt)) {
89
+ return yield* new RunNotInProgress({ message: "run is not in progress" });
90
+ }
91
+ if (data.event !== "push" && data.event !== "pull_request") {
92
+ return yield* new BadRequest({
93
+ message: `unsupported event ${data.event}`,
94
+ });
95
+ }
96
+ const headRepo = data.head_repository?.full_name ?? data.repository.full_name;
97
+ let pr = null;
98
+ if (data.event === "pull_request") {
99
+ // The pull request whose head is this run's head, from the repository
100
+ // the run's head lives in. The same commit can head several pull
101
+ // requests, including one opened from a fork against a commit the
102
+ // repository already published; matching the head repository keeps a
103
+ // run's publication on its own pull request.
104
+ const pulls = yield* github
105
+ .pullRequestsForCommit(ref.repo, headRepo, data.head_sha)
106
+ .pipe(Effect.mapError(upstream));
107
+ const first = pulls[0];
108
+ if (first === undefined) {
109
+ return yield* new BadRequest({
110
+ message: `no pull request from ${headRepo} has head ${data.head_sha}`,
111
+ });
112
+ }
113
+ pr = first.number;
114
+ }
115
+ else if (headRepo !== ref.repo) {
116
+ return yield* new BadRequest({
117
+ message: `push run ${ref.runId} is for ${headRepo}, not ${ref.repo}`,
118
+ });
119
+ }
120
+ return {
121
+ ...ref,
122
+ headSha: data.head_sha,
123
+ headBranch: data.head_branch,
124
+ headRepo,
125
+ pr,
126
+ };
127
+ });
128
+ /**
129
+ * The proof. The job uploaded the manifest as an artifact of its run,
130
+ * named by the manifest's hash. Only the job can add artifacts to the
131
+ * run, and GitHub reports the run's artifacts to the App, so a matching
132
+ * name means this run vouched for exactly this manifest text.
133
+ */
134
+ const requireVouched = Effect.fn("requireVouched")(function* (run, manifestText) {
135
+ const github = yield* GitHub.GitHubApp;
136
+ const expected = manifestArtifactName(yield* sha256(manifestText));
137
+ const artifacts = yield* github
138
+ .listRunArtifacts(run.repo, run.runId, expected)
139
+ .pipe(Effect.mapError(upstream));
140
+ if (!artifacts.some((a) => a.name === expected && !a.expired)) {
141
+ return yield* new Forbidden({
142
+ message: `run ${run.runId} has not vouched for this manifest (no artifact ${expected})`,
143
+ });
144
+ }
145
+ });
146
+ const publish = Effect.fn("publish")(function* (run, manifestText) {
147
+ const { policy } = yield* RegistryConfig;
148
+ const r2 = yield* Cloudflare.R2.ReadWriteBucket(Bucket);
149
+ const github = yield* GitHub.GitHubApp;
150
+ const base = yield* origin;
151
+ yield* requireVouched(run, manifestText);
152
+ const manifest = yield* Schema.decodeUnknownEffect(ManifestJson)(manifestText).pipe(Effect.mapError((e) => new BadRequest({ message: `invalid manifest: ${String(e)}` })));
153
+ // The run vouched for the manifest, but the tags come from the run's
154
+ // head, so the packed checkout has to be that commit: a `pull_request`
155
+ // job that packs the synthetic merge commit would otherwise publish bytes
156
+ // built from a commit that exists nowhere under the commit's name.
157
+ if (manifest.head !== run.headSha) {
158
+ return yield* new BadRequest({
159
+ message: `manifest was packed at ${manifest.head}, but the run's head is ${run.headSha}`,
160
+ });
161
+ }
162
+ const packages = manifest.packages;
163
+ const maxSize = policy.maxPackageSize;
164
+ const tooLarge = maxSize === undefined
165
+ ? undefined
166
+ : packages.find((pkg) => BigInt(pkg.size) > maxSize);
167
+ if (tooLarge !== undefined) {
168
+ return yield* new PackageTooLarge({
169
+ message: `${tooLarge.name} exceeds ${maxSize} bytes`,
170
+ });
171
+ }
172
+ const missing = yield* Effect.filter(packages, (pkg) => r2
173
+ .head(tarballKey(pkg.name, pkg.sha256))
174
+ .pipe(Effect.map((object) => object === null)), { concurrency: 8 }).pipe(Effect.map((packages) => packages.map(({ name, sha256 }) => ({ name, sha256 }))));
175
+ if (missing.length > 0) {
176
+ return yield* new MissingTarballs({ missing });
177
+ }
178
+ const now = yield* Clock.currentTimeMillis;
179
+ const expiresAt = now + Duration.toMillis(policy.ttl);
180
+ const prs = run.pr !== null ? [`${run.repo}#${run.pr}`] : [];
181
+ const tags = tagsFor(run);
182
+ const tag = installTag(run);
183
+ const published = yield* Effect.forEach(packages, Effect.fn(function* (pkg) {
184
+ yield* Effect.forEach(tags, (tag) => Tags.upsert({
185
+ package: pkg.name,
186
+ tag,
187
+ sha256: pkg.sha256,
188
+ expiresAt,
189
+ prs,
190
+ }), { discard: true });
191
+ return {
192
+ name: pkg.name,
193
+ group: pkg.group,
194
+ url: `${base}/${pkg.name}/${tag}`,
195
+ tags,
196
+ };
197
+ }), { concurrency: 4 });
198
+ // A check on the commit itself, so the install lines are visible on
199
+ // pushes and on fork pull requests alike.
200
+ yield* github
201
+ .createCheckRun(run.repo, {
202
+ headSha: run.headSha,
203
+ name: CHECK_NAME,
204
+ title: `${packages.length} package(s) published`,
205
+ summary: GitHub.renderInstalls(published, manifest.groups),
206
+ detailsUrl: base,
207
+ })
208
+ .pipe(Effect.catch((e) => Effect.logWarning(`check run on ${run.repo}@${run.headSha} failed: ${GitHub.describe(e)}`)));
209
+ if (run.pr !== null) {
210
+ const body = GitHub.renderComment(published, manifest.groups, {
211
+ publishedAt: now,
212
+ expiresAt,
213
+ });
214
+ yield* github
215
+ .upsertComment(run.repo, run.pr, COMMENT_MARKER, body)
216
+ .pipe(Effect.catch((e) => Effect.logWarning(`comment on ${run.repo}#${run.pr} failed: ${GitHub.describe(e)}`)));
217
+ }
218
+ return { packages: published };
219
+ });
220
+ /**
221
+ * Content-addressed upload, streamed straight into R2 with the hash
222
+ * verified by R2 itself. Untagged objects are swept after a day.
223
+ */
224
+ const uploadTarball = Effect.fn("uploadTarball")(function* (request, name, sha256) {
225
+ const { policy } = yield* RegistryConfig;
226
+ const r2 = yield* Cloudflare.R2.ReadWriteBucket(Bucket);
227
+ const contentLength = Number(request.headers["content-length"] ?? 0);
228
+ if (!Number.isSafeInteger(contentLength) || contentLength <= 0) {
229
+ return yield* new BadRequest({ message: "Content-Length is required" });
230
+ }
231
+ const maxSize = policy.maxPackageSize;
232
+ if (maxSize !== undefined && BigInt(contentLength) > maxSize) {
233
+ return yield* new PackageTooLarge({
234
+ message: `tarball exceeds ${maxSize} bytes`,
235
+ });
236
+ }
237
+ const key = tarballKey(name, sha256);
238
+ const existing = yield* r2.head(key);
239
+ if (existing !== null) {
240
+ return { name, sha256, size: existing.size, uploaded: false };
241
+ }
242
+ yield* r2
243
+ .put(key, request.stream, {
244
+ contentLength,
245
+ // The params schema already constrained this to 64 hex chars.
246
+ sha256: Result.getOrThrow(Encoding.decodeHex(sha256)),
247
+ })
248
+ .pipe(Effect.mapError((e) => new BadRequest({ message: `upload rejected: ${String(e)}` })));
249
+ return { name, sha256, size: contentLength, uploaded: true };
250
+ });
251
+ /**
252
+ * Parse `/<name>/<tag>` and `/<name>/-/<sha256>.tgz`. Scoped names take
253
+ * two segments; the tag is everything after the name and may itself contain
254
+ * `/` and `:`.
255
+ */
256
+ export const parseInstallPath = (pathname, scope) => {
257
+ let path;
258
+ try {
259
+ path = decodeURIComponent(pathname.replace(/^\/+/, ""));
260
+ }
261
+ catch {
262
+ // Malformed percent-encoding is a path nothing can be published under.
263
+ return undefined;
264
+ }
265
+ const tarball = path.match(/^(@[^/]+\/[^/@]+|[^/@]+)\/-\/([a-f0-9]{64})\.tgz$/);
266
+ if (tarball) {
267
+ return {
268
+ kind: "tarball",
269
+ name: qualify(tarball[1], scope),
270
+ sha256: tarball[2],
271
+ };
272
+ }
273
+ const segments = path.split("/");
274
+ const nameLength = path.startsWith("@") ? 2 : 1;
275
+ const name = segments.slice(0, nameLength).join("/");
276
+ const tag = segments.slice(nameLength).join("/");
277
+ if (segments.length <= nameLength || name === "" || tag === "") {
278
+ return undefined;
279
+ }
280
+ return { kind: "tag", name: qualify(name, scope), tag };
281
+ };
282
+ const qualify = (name, scope) => scope !== undefined && !name.startsWith("@") ? `${scope}/${name}` : name;
283
+ const notFound = (message) => HttpServerResponse.json({ error: message }, { status: 404 });
284
+ /**
285
+ * Install URLs: `/<name>/<tag>` redirects to the immutable tarball URL,
286
+ * `/<name>/-/<sha256>.tgz` streams it from R2. Everything the API routes
287
+ * do not claim lands here.
288
+ */
289
+ const install = Effect.gen(function* () {
290
+ const request = yield* HttpServerRequest;
291
+ const { aliases } = yield* RegistryConfig;
292
+ const r2 = yield* Cloudflare.R2.ReadWriteBucket(Bucket);
293
+ if (request.method !== "GET" && request.method !== "HEAD") {
294
+ return yield* HttpServerResponse.json({ error: "method not allowed" }, { status: 405 });
295
+ }
296
+ const host = request.headers.host ?? "localhost";
297
+ const target = parseInstallPath(new URL(request.url, `https://${host}`).pathname, aliases[host]);
298
+ if (target === undefined) {
299
+ return yield* notFound("not found");
300
+ }
301
+ if (target.kind === "tag") {
302
+ const sha256 = yield* Tags.resolve(target.name, target.tag);
303
+ if (sha256 === undefined) {
304
+ return yield* notFound(`${target.name}@${target.tag} not found`);
305
+ }
306
+ return HttpServerResponse.redirect(`/${target.name}/-/${sha256}.tgz`, {
307
+ status: 302,
308
+ headers: { "cache-control": "no-store" },
309
+ });
310
+ }
311
+ const object = yield* r2.get(tarballKey(target.name, target.sha256));
312
+ if (object === null) {
313
+ return yield* notFound("tarball not found");
314
+ }
315
+ const headers = {
316
+ "content-type": "application/gzip",
317
+ "content-length": String(object.size),
318
+ "cache-control": "public, max-age=31536000, immutable",
319
+ };
320
+ return request.method === "HEAD"
321
+ ? HttpServerResponse.empty({ status: 200, headers })
322
+ : HttpServerResponse.stream(object.body, { status: 200, headers });
323
+ });
324
+ const banner = Effect.map(origin, (base) => HttpServerResponse.text(`Preview package registry. Install with: bun add ${base}/<package>/<commit|branch:name|pr:N>\n`));
325
+ /**
326
+ * The registry never serves files, so the HTTP platform's file surface is
327
+ * stubbed rather than pulling a file system into the Worker.
328
+ */
329
+ const HttpPlatformStub = Layer.succeed(HttpPlatform.HttpPlatform, {
330
+ platform: "web",
331
+ compression: {
332
+ algorithms: new Set(),
333
+ compressResponse: (response) => Effect.succeed(response),
334
+ },
335
+ fileResponse: () => Effect.die("fileResponse is not supported"),
336
+ fileWebResponse: () => Effect.die("fileWebResponse is not supported"),
337
+ });
338
+ /**
339
+ * The registry Worker's Init phase. Runs at plan time to register bindings
340
+ * and the cron trigger, and once per isolate at runtime to build the
341
+ * router. Everything it needs comes from {@link RegistryConfig}.
342
+ */
343
+ export const handler = Effect.gen(function* () {
344
+ const config = yield* RegistryConfig;
345
+ // Binding the capabilities here is what registers the R2, D1, and KV
346
+ // bindings on the Worker at plan time. Handlers bind them again per event,
347
+ // which at runtime is just a lookup in the Worker's environment.
348
+ yield* Cloudflare.R2.ReadWriteBucket(Bucket);
349
+ yield* Cloudflare.KV.ReadWriteNamespace(Cache);
350
+ const d1 = yield* Cloudflare.D1.QueryDatabase(Database);
351
+ // Built once per isolate. The D1 client memoizes its connection on each
352
+ // event's scope, so its layer is safe to share.
353
+ const github = yield* GitHub.GitHubApp.pipe(Effect.provide(GitHub.GitHubAppLive));
354
+ const services = Layer.mergeAll(Cloudflare.R2.ReadWriteBucketBinding, Cloudflare.KV.ReadWriteNamespaceBinding, SQL.D1Layer(d1), Layer.succeed(GitHub.GitHubApp, github), Layer.succeed(RegistryConfig, config));
355
+ // Recently resolved runs are reused so the uploads that follow a publish
356
+ // do not repeat the lookup. Failures are not kept.
357
+ const runs = KVCache.make((ref) => `run:${ref.repo}#${ref.runId}:${ref.attempt}`, Run, (ref) => Effect.map(lookupRun(ref), (value) => ({ value, ttl: RUN_CACHE })));
358
+ yield* Cloudflare.Workers.cron(config.cron, () => sweep.pipe(Effect.provide(services)));
359
+ const registry = HttpApiBuilder.group(PkgApi, "Registry", (handlers) => handlers
360
+ .handle("publish", ({ payload }) => Effect.flatMap(runs(payload.run), (run) => publish(run, payload.manifest)).pipe(Effect.catchTag(storageFailures, (e) => Effect.die(e))))
361
+ // Raw so the body streams into R2 instead of being buffered.
362
+ .handleRaw("uploadTarball", ({ query, params, request }) => Effect.andThen(runs(query), uploadTarball(request, params.name, params.sha256)).pipe(Effect.catchTag("R2Error", (e) => Effect.die(e)))));
363
+ const healthGroup = HttpApiBuilder.group(PkgApi, "Health", (handlers) => handlers.handle("health", () => Effect.succeed({ ok: true })));
364
+ // Unlike `HttpApiBuilder.group`, the router defers a route's requirements
365
+ // to request time rather than the layer build, so the services are
366
+ // provided on the route effect itself.
367
+ const installRoutes = HttpRouter.use((router) => Effect.all([
368
+ router.add("GET", "/", banner),
369
+ router.add("*", "/*", install.pipe(Effect.catchTag(storageFailures, (e) => Effect.die(e)), Effect.provide(services))),
370
+ ]));
371
+ return {
372
+ fetch: Layer.mergeAll(HttpApiBuilder.layer(PkgApi), installRoutes).pipe(Layer.provide([registry, healthGroup]), Layer.provide([Etag.layer, HttpPlatformStub, Path.layer]), Layer.provide(services), HttpRouter.toHttpEffect),
373
+ };
374
+ }).pipe(Effect.provide(bindings));
375
+ //# sourceMappingURL=Handler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Handler.js","sourceRoot":"","sources":["../../src/Registry/Handler.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import * as Cloudflare from "alchemy/Cloudflare";
2
+ import * as Duration from "effect/Duration";
3
+ import * as Effect from "effect/Effect";
4
+ import * as Schema from "effect/Schema";
5
+ /**
6
+ * A lookup-through cache on the registry's KV namespace, shared by every
7
+ * isolate of the Worker.
8
+ *
9
+ * Concurrent misses each run the lookup and each write; the last write wins.
10
+ * That is deliberate: a cache that shares an in-flight lookup, like Effect's
11
+ * `Cache`, has later callers join the first caller's fiber, and workerd drops
12
+ * a fiber resumed from another request's context once that request
13
+ * completes, which surfaces as the joining request hanging.
14
+ *
15
+ * Reads set `cacheTtl`, so a value can still be served from the colo's edge
16
+ * cache for up to a minute after it expired; a lookup's `ttl` must leave
17
+ * that margin. Values with less than a minute left are not stored. KV
18
+ * failures are logged and fall through to the lookup.
19
+ */
20
+ export declare const make: <K, A, I, E, R>(key: (input: K) => string, value: Schema.Codec<A, I>, lookup: (input: K) => Effect.Effect<{
21
+ value: A;
22
+ ttl: Duration.Duration;
23
+ }, E, R>) => (input: K) => Effect.Effect<A, E, R | Cloudflare.Providers | Cloudflare.KV.ReadWriteNamespace | import("alchemy").RuntimeContext>;
24
+ //# sourceMappingURL=KVCache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"KVCache.d.ts","sourceRoot":"","sources":["../../src/Registry/KVCache.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,UAAU,MAAM,oBAAoB,CAAC;AACjD,OAAO,KAAK,QAAQ,MAAM,iBAAiB,CAAC;AAC5C,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AASxC;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,IAAI,GAAI,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,OAC3B,CAAC,KAAK,EAAE,CAAC,KAAK,MAAM,SAClB,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,UACjB,CACN,KAAK,EAAE,CAAC,KACL,MAAM,CAAC,MAAM,CAAC;IAAE,KAAK,EAAE,CAAC,CAAC;IAAC,GAAG,EAAE,QAAQ,CAAC,QAAQ,CAAA;CAAE,EAAE,CAAC,EAAE,CAAC,CAAC,aAK/C,CAAC,wHA8BjB,CAAC"}
@@ -0,0 +1,42 @@
1
+ import * as Cloudflare from "alchemy/Cloudflare";
2
+ import * as Duration from "effect/Duration";
3
+ import * as Effect from "effect/Effect";
4
+ import * as Schema from "effect/Schema";
5
+ import { Cache } from "./Bindings.js";
6
+ /** KV's floor for both `expirationTtl` and `cacheTtl`. */
7
+ const MIN_TTL = Duration.minutes(1);
8
+ const seconds = (duration) => Math.floor(Duration.toSeconds(duration));
9
+ /**
10
+ * A lookup-through cache on the registry's KV namespace, shared by every
11
+ * isolate of the Worker.
12
+ *
13
+ * Concurrent misses each run the lookup and each write; the last write wins.
14
+ * That is deliberate: a cache that shares an in-flight lookup, like Effect's
15
+ * `Cache`, has later callers join the first caller's fiber, and workerd drops
16
+ * a fiber resumed from another request's context once that request
17
+ * completes, which surfaces as the joining request hanging.
18
+ *
19
+ * Reads set `cacheTtl`, so a value can still be served from the colo's edge
20
+ * cache for up to a minute after it expired; a lookup's `ttl` must leave
21
+ * that margin. Values with less than a minute left are not stored. KV
22
+ * failures are logged and fall through to the lookup.
23
+ */
24
+ export const make = (key, value, lookup) => {
25
+ const json = Schema.fromJsonString(value);
26
+ const decode = Schema.decodeUnknownEffect(json);
27
+ const encode = Schema.encodeEffect(json);
28
+ return (input) => Effect.gen(function* () {
29
+ const kv = yield* Cloudflare.KV.ReadWriteNamespace(Cache);
30
+ const id = key(input);
31
+ const hit = yield* kv.get(id, { cacheTtl: seconds(MIN_TTL) }).pipe(Effect.flatMap((text) => text === null ? Effect.succeed(undefined) : decode(text)), Effect.catch((e) => Effect.logWarning(`cache read of ${id} failed: ${e}`).pipe(Effect.as(undefined))));
32
+ if (hit !== undefined) {
33
+ return hit;
34
+ }
35
+ const fresh = yield* lookup(input);
36
+ if (Duration.isGreaterThanOrEqualTo(fresh.ttl, MIN_TTL)) {
37
+ yield* encode(fresh.value).pipe(Effect.flatMap((text) => kv.put(id, text, { expirationTtl: seconds(fresh.ttl) })), Effect.catch((e) => Effect.logWarning(`cache write of ${id} failed: ${e}`)));
38
+ }
39
+ return fresh.value;
40
+ });
41
+ };
42
+ //# sourceMappingURL=KVCache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"KVCache.js","sourceRoot":"","sources":["../../src/Registry/KVCache.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,UAAU,MAAM,oBAAoB,CAAC;AACjD,OAAO,KAAK,QAAQ,MAAM,iBAAiB,CAAC;AAC5C,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAEtC,0DAA0D;AAC1D,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAEpC,MAAM,OAAO,GAAG,CAAC,QAA2B,EAAE,EAAE,CAC9C,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC;AAE3C;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,MAAM,IAAI,GAAG,CAClB,GAAyB,EACzB,KAAyB,EACzB,MAE8D,EAC9D,EAAE;IACF,MAAM,IAAI,GAAG,MAAM,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;IAC1C,MAAM,MAAM,GAAG,MAAM,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC;IAChD,MAAM,MAAM,GAAG,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;IACzC,OAAO,CAAC,KAAQ,EAAE,EAAE,CAClB,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;QAClB,MAAM,EAAE,GAAG,KAAK,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC;QAC1D,MAAM,EAAE,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC;QACtB,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,QAAQ,EAAE,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,IAAI,CAChE,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CACtB,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CACzD,EACD,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CACjB,MAAM,CAAC,UAAU,CAAC,iBAAiB,EAAE,YAAY,CAAC,EAAE,CAAC,CAAC,IAAI,CACxD,MAAM,CAAC,EAAE,CAAC,SAAS,CAAC,CACrB,CACF,CACF,CAAC;QACF,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;YACtB,OAAO,GAAG,CAAC;QACb,CAAC;QACD,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACnC,IAAI,QAAQ,CAAC,sBAAsB,CAAC,KAAK,CAAC,GAAG,EAAE,OAAO,CAAC,EAAE,CAAC;YACxD,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,CAC7B,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CACtB,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,EAAE,EAAE,aAAa,EAAE,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,CACxD,EACD,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CACjB,MAAM,CAAC,UAAU,CAAC,kBAAkB,EAAE,YAAY,CAAC,EAAE,CAAC,CACvD,CACF,CAAC;QACJ,CAAC;QACD,OAAO,KAAK,CAAC,KAAK,CAAC;IACrB,CAAC,CAAC,CAAC;AACP,CAAC,CAAC"}
@@ -0,0 +1,12 @@
1
+ import * as Cloudflare from "alchemy/Cloudflare";
2
+ import * as Effect from "effect/Effect";
3
+ import { RegistryConfig } from "./Bindings.ts";
4
+ import * as GitHub from "./GitHub.ts";
5
+ /**
6
+ * Expiry sweep. Tags tied to pull requests are extended while any of those
7
+ * pull requests is open and pinned to the latest close time plus TTL once
8
+ * they all close. Expired tags go away, and tarballs nothing points at are
9
+ * deleted from R2.
10
+ */
11
+ export declare const sweep: Effect.Effect<void, Cloudflare.R2.R2Error | import("effect/Schema").SchemaError | import("effect/unstable/sql/SqlError").SqlError, GitHub.GitHubApp | Cloudflare.Providers | Cloudflare.R2.ReadWriteBucket | Cloudflare.KV.ReadWriteNamespace | RegistryConfig | import("alchemy").RuntimeContext | import("effect/unstable/sql/SqlClient").SqlClient>;
12
+ //# sourceMappingURL=Sweep.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Sweep.d.ts","sourceRoot":"","sources":["../../src/Registry/Sweep.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,UAAU,MAAM,oBAAoB,CAAC;AAGjD,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAGxC,OAAO,EAGL,cAAc,EAGf,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,MAAM,MAAM,aAAa,CAAC;AAGtC;;;;;GAKG;AACH,eAAO,MAAM,KAAK,wVA8FhB,CAAC"}
@@ -0,0 +1,69 @@
1
+ import * as Cloudflare from "alchemy/Cloudflare";
2
+ import * as Clock from "effect/Clock";
3
+ import * as Duration from "effect/Duration";
4
+ import * as Effect from "effect/Effect";
5
+ import * as Option from "effect/Option";
6
+ import * as Stream from "effect/Stream";
7
+ import { Bucket, ORPHAN_GRACE, RegistryConfig, SWEEP_LOOKAHEAD, tarballKey, } from "./Bindings.js";
8
+ import * as GitHub from "./GitHub.js";
9
+ import * as Tags from "./Tags.js";
10
+ /**
11
+ * Expiry sweep. Tags tied to pull requests are extended while any of those
12
+ * pull requests is open and pinned to the latest close time plus TTL once
13
+ * they all close. Expired tags go away, and tarballs nothing points at are
14
+ * deleted from R2.
15
+ */
16
+ export const sweep = Effect.gen(function* () {
17
+ const { policy } = yield* RegistryConfig;
18
+ const r2 = yield* Cloudflare.R2.ReadWriteBucket(Bucket);
19
+ const github = yield* GitHub.GitHubApp;
20
+ const now = yield* Clock.currentTimeMillis;
21
+ const ttl = Duration.toMillis(policy.ttl);
22
+ const due = yield* Tags.dueLinked(now + Duration.toMillis(SWEEP_LOOKAHEAD));
23
+ // One lookup per pull request across every due row. `undefined` means the
24
+ // pull request is still open; a failed lookup is recorded as such.
25
+ const lookups = yield* Effect.forEach(new Set(due.flatMap((row) => row.linked_prs)), (ref) => {
26
+ const [repo, number] = ref.split("#");
27
+ return github.getPullRequest(repo, Number(number)).pipe(Effect.map((pr) => pr.state === "open"
28
+ ? undefined
29
+ : Date.parse(pr.merged_at ?? pr.closed_at ?? "") || now), Effect.map((closedAt) => [ref, { closedAt }]), Effect.catch((e) => Effect.logWarning(`pull request ${ref} lookup failed: ${GitHub.describe(e)}`).pipe(Effect.as([ref, undefined]))));
30
+ }, { concurrency: 4 });
31
+ const results = new Map(lookups);
32
+ const extended = yield* Effect.forEach(due, (row) => {
33
+ const known = row.linked_prs.flatMap((ref) => {
34
+ const result = results.get(ref);
35
+ return result === undefined ? [] : [result.closedAt];
36
+ });
37
+ // Open pull requests dominate; otherwise the latest close wins. A row
38
+ // whose pull requests could not all be checked is kept past the next
39
+ // sweep rather than left to expire: it is re-checked, never deleted,
40
+ // on GitHub's bad day.
41
+ const closes = known.filter((closedAt) => closedAt !== undefined);
42
+ const expiresAt = closes.length < known.length
43
+ ? now + ttl
44
+ : known.length < row.linked_prs.length
45
+ ? Math.max(row.expires_at, now + Duration.toMillis(SWEEP_LOOKAHEAD))
46
+ : Math.max(...closes) + ttl;
47
+ return expiresAt === row.expires_at
48
+ ? Effect.succeed(false)
49
+ : Tags.setExpiry(row.package, row.tag, expiresAt).pipe(Effect.as(true));
50
+ }).pipe(Effect.map((changed) => changed.filter(Boolean).length));
51
+ const removed = yield* Tags.deleteExpired(now);
52
+ const referenced = yield* Tags.referencedTarballs();
53
+ const unreferenced = removed.filter(({ package: pkg, sha256 }) => !referenced.has(`${pkg}/${sha256}`));
54
+ yield* Effect.forEach(unreferenced, ({ package: pkg, sha256 }) => r2.delete(tarballKey(pkg, sha256)), { discard: true });
55
+ // Uploads that never got tagged.
56
+ const orphans = yield* Stream.paginate(undefined, (cursor) => r2
57
+ .list({ cursor, limit: 500 })
58
+ .pipe(Effect.map((page) => [
59
+ page.objects,
60
+ page.truncated ? Option.some(page.cursor) : Option.none(),
61
+ ]))).pipe(Stream.filter((object) => {
62
+ const match = object.key.match(/^(.+)\/([a-f0-9]{64})\.tgz$/);
63
+ return (match !== null &&
64
+ !referenced.has(`${decodeURIComponent(match[1])}/${match[2]}`) &&
65
+ object.uploaded.getTime() < now - Duration.toMillis(ORPHAN_GRACE));
66
+ }), Stream.mapEffect((object) => r2.delete(object.key)), Stream.runCount);
67
+ yield* Effect.logInfo(`sweep: ${due.length} due, ${extended} extended, ${removed.length} tags expired, ${unreferenced.length + orphans} tarballs deleted`);
68
+ });
69
+ //# sourceMappingURL=Sweep.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Sweep.js","sourceRoot":"","sources":["../../src/Registry/Sweep.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,49 @@
1
+ import * as Effect from "effect/Effect";
2
+ import * as Schema from "effect/Schema";
3
+ import * as SqlClient from "effect/unstable/sql/SqlClient";
4
+ export declare const TagRow: Schema.Struct<{
5
+ readonly package: Schema.String;
6
+ readonly tag: Schema.String;
7
+ readonly sha256: Schema.String;
8
+ readonly expires_at: Schema.Number;
9
+ /** Pull requests whose runs produced this tag, as `owner/repo#N`. */
10
+ readonly linked_prs: Schema.fromJsonString<Schema.$Array<Schema.String>>;
11
+ }>;
12
+ export type TagRow = typeof TagRow.Type;
13
+ export declare const get: (pkg: string, tag: string) => Effect.Effect<{
14
+ readonly package: string;
15
+ readonly tag: string;
16
+ readonly sha256: string;
17
+ readonly expires_at: number;
18
+ readonly linked_prs: readonly string[];
19
+ }, Schema.SchemaError | import("effect/unstable/sql/SqlError").SqlError, SqlClient.SqlClient>;
20
+ /**
21
+ * Point `tag` at `sha256`, keeping the row alive for at least `expiresAt`
22
+ * and remembering every pull request that produced it. One statement, so
23
+ * concurrent publications of a shared tag merge rather than overwrite.
24
+ */
25
+ export declare const upsert: (input: {
26
+ readonly package: string;
27
+ readonly tag: string;
28
+ readonly sha256: string;
29
+ readonly expiresAt: number;
30
+ readonly prs: ReadonlyArray<string>;
31
+ }) => Effect.Effect<void, Schema.SchemaError | import("effect/unstable/sql/SqlError").SqlError, SqlClient.SqlClient>;
32
+ export declare const resolve: (pkg: string, tag: string) => Effect.Effect<string, Schema.SchemaError | import("effect/unstable/sql/SqlError").SqlError, SqlClient.SqlClient>;
33
+ /** Rows tied to pull requests whose expiry falls before `before`. */
34
+ export declare const dueLinked: (before: number) => Effect.Effect<readonly {
35
+ readonly package: string;
36
+ readonly tag: string;
37
+ readonly sha256: string;
38
+ readonly expires_at: number;
39
+ readonly linked_prs: readonly string[];
40
+ }[], Schema.SchemaError | import("effect/unstable/sql/SqlError").SqlError, SqlClient.SqlClient>;
41
+ export declare const setExpiry: (pkg: string, tag: string, expiresAt: number) => Effect.Effect<void, import("effect/unstable/sql/SqlError").SqlError, SqlClient.SqlClient>;
42
+ /** Delete every expired row and return the tarballs those rows pointed at. */
43
+ export declare const deleteExpired: (now: number) => Effect.Effect<readonly {
44
+ readonly package: string;
45
+ readonly sha256: string;
46
+ }[], Schema.SchemaError | import("effect/unstable/sql/SqlError").SqlError, SqlClient.SqlClient>;
47
+ /** Every tarball some tag still points at, as `<package>/<sha256>`. */
48
+ export declare const referencedTarballs: () => Effect.Effect<Set<string>, Schema.SchemaError | import("effect/unstable/sql/SqlError").SqlError, SqlClient.SqlClient>;
49
+ //# sourceMappingURL=Tags.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Tags.d.ts","sourceRoot":"","sources":["../../src/Registry/Tags.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,SAAS,MAAM,+BAA+B,CAAC;AAW3D,eAAO,MAAM,MAAM;;;;;IAKjB,qEAAqE;;EAErE,CAAC;AACH,MAAM,MAAM,MAAM,GAAG,OAAO,MAAM,CAAC,IAAI,CAAC;AAUxC,eAAO,MAAM,GAAG;;;;;;6FAMd,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,MAAM;sBACC,MAAM;kBACV,MAAM;qBACH,MAAM;wBACH,MAAM;kBACZ,aAAa,CAAC,MAAM,CAAC;oHAkBnC,CAAC;AAEH,eAAO,MAAM,OAAO,QAAS,MAAM,OAAO,MAAM,qHACC,CAAC;AAElD,qEAAqE;AACrE,eAAO,MAAM,SAAS;;;;;;+FASpB,CAAC;AAEH,eAAO,MAAM,SAAS,4IASpB,CAAC;AAEH,8EAA8E;AAC9E,eAAO,MAAM,aAAa;;;+FASxB,CAAC;AAEH,uEAAuE;AACvE,eAAO,MAAM,kBAAkB,6HAQ9B,CAAC"}