@ponharu/pkgflare 1.0.0 → 1.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.
package/README.md CHANGED
@@ -9,7 +9,7 @@ Deploy a scoped private npm registry to your own Cloudflare account.
9
9
  - Standard scoped package publish and install endpoints
10
10
  - Immutable tarballs in R2
11
11
  - Package metadata and mutable dist-tags in D1
12
- - Read and publish tokens stored as Cloudflare Secrets
12
+ - Cloudflare Secret tokens and short-lived GitHub Actions OIDC authentication
13
13
  - Repeatable deployment through one `pkgflare deploy` command
14
14
  - npm-compatible metadata and tarball responses tested with npm, pnpm, Yarn Classic, and Bun
15
15
 
@@ -144,7 +144,47 @@ The `.npmrc` contains an environment variable reference and can be committed; th
144
144
 
145
145
  Yarn Berry and other clients are outside the tested compatibility baseline. pkgflare does not implement `npm login`, `npm adduser`, `npm unpublish`, `npm deprecate`, search, or the npm audit API. It is a scoped private registry, not a complete replacement for the public npm service.
146
146
 
147
- A read token can read every package in the registry. A publish token can also publish packages and change dist-tags across all configured scopes. Permissions are not restricted per package or scope; use separate registry deployments when readers or publishers need different trust boundaries.
147
+ A Secret read token can read every package in the registry. A Secret publish token can also publish packages and change dist-tags across all configured scopes. Secret-token permissions are not restricted per package or scope; use GitHub OIDC package grants or separate registry deployments when publishers need narrower trust boundaries.
148
+
149
+ GitHub Actions jobs can instead use short-lived OIDC tokens with per-package grants and no stored registry token. Configure the trusted repository IDs, owner ID, ref, workflow, permissions, and package names under `auth.githubOidc`, then request the configured audience in the job:
150
+
151
+ ```ts
152
+ auth: {
153
+ provider: "secrets",
154
+ tokens: [
155
+ { binding: "PKGFLARE_READ_TOKEN", permissions: ["read"] },
156
+ { binding: "PKGFLARE_PUBLISH_TOKEN", permissions: ["publish"] },
157
+ ],
158
+ githubOidc: {
159
+ audience: "pkgflare://packages.example.com",
160
+ subjects: [{
161
+ repositoryId: "123456789",
162
+ repositoryOwnerId: "987654321",
163
+ ref: "refs/heads/main",
164
+ workflowRef: "acme/example/.github/workflows/publish.yml@refs/heads/main",
165
+ permissions: ["publish"],
166
+ packages: ["@acme/example"],
167
+ }],
168
+ },
169
+ }
170
+ ```
171
+
172
+ ```yaml
173
+ permissions:
174
+ contents: read
175
+ id-token: write
176
+
177
+ steps:
178
+ - uses: actions/checkout@v4
179
+ - uses: actions/setup-node@v4
180
+ with:
181
+ node-version: 22
182
+ - run: npm ci
183
+ - name: Publish
184
+ run: NPM_TOKEN="$(npx pkgflare auth github --audience 'pkgflare://packages.example.com')" npm publish
185
+ ```
186
+
187
+ The package repository's `.npmrc` still points its scope to pkgflare and references `${NPM_TOKEN}`. Use the same command with `npm ci` or another supported client for OIDC-authenticated reads. See [GitHub Actions OIDC](./docs/operations.md#github-actions-oidc) for reusable workflows, wildcard rules, and the security model.
148
188
 
149
189
  Versions are immutable. To promote or roll back an existing version, use the publish token with `npm dist-tag`:
150
190
 
@@ -159,12 +199,15 @@ The first command assumes `1.1.0` has already been published. Moving a tag affec
159
199
 
160
200
  ```text
161
201
  pkgflare deploy [--config <path>] [--secrets-file <path>] [--adopt-existing]
202
+ pkgflare auth github --audience <audience>
162
203
  pkgflare init
163
204
  pkgflare token generate
164
205
  ```
165
206
 
166
207
  `token generate` creates a cryptographically random token locally and prints it once. pkgflare does not store, distribute, list, or revoke tokens.
167
208
 
209
+ `auth github` requests a short-lived GitHub Actions OIDC JWT and writes only that JWT to standard output. It is intended for command substitution and fails outside the GitHub Actions OIDC environment.
210
+
168
211
  ## Publish consistency
169
212
 
170
213
  A package version is immutable, while dist-tags remain mutable for promotion and rollback. pkgflare incrementally parses the standard npm publish document, decodes its Base64 attachment into fixed-size R2 multipart chunks, and calculates SHA-1 and SHA-512 without holding the complete tarball in Worker memory. A unique attempt object is published in D1 only after R2 completes; D1's package-and-version constraint chooses the sole winner of concurrent publishes.
package/dist/cli.js CHANGED
@@ -23,9 +23,89 @@ var scopePattern = /^@[a-z0-9](?:[a-z0-9._-]*[a-z0-9])?$/;
23
23
  var bindingPattern = /^[A-Z][A-Z0-9_]*$/;
24
24
  var hostnamePattern = /^(?=.{1,253}$)(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z](?:[a-z0-9-]{0,61}[a-z0-9])?$/;
25
25
  var reservedBindings = /* @__PURE__ */ new Set(["PKGFLARE_DB", "PKGFLARE_BUCKET", "PKGFLARE_CONFIG"]);
26
+ var githubIdPattern = /^[1-9][0-9]{0,19}$/;
27
+ var audiencePattern = /^[\x21-\x7e]{1,256}$/;
28
+ var refPattern = /^refs\/(?:heads|tags)\/[A-Za-z0-9._/-]+\*?$/;
29
+ var workflowRefPattern = /^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+\/\.github\/workflows\/[A-Za-z0-9_.-]+\.ya?ml@refs\/(?:heads|tags)\/[A-Za-z0-9._/-]+\*?$/;
30
+ var jobWorkflowRefPattern = /^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+\/\.github\/workflows\/[A-Za-z0-9_.-]+\.ya?ml@(?:refs\/(?:heads|tags)\/[A-Za-z0-9._/-]+\*?|[0-9a-f]{40})$/;
31
+ var packageSegmentPattern = /^(?!\.)(?:[a-z0-9._-]+)$/;
32
+ var maximumGithubSubjects = 128;
33
+ var maximumPackagesPerSubject = 128;
34
+ var maximumRuntimeConfigBytes = 5 * 1024;
26
35
  function isObject(value) {
27
36
  return typeof value === "object" && value !== null && !Array.isArray(value);
28
37
  }
38
+ function normalizePermissions(value, label) {
39
+ if (!Array.isArray(value) || value.length === 0 || value.some((permission) => permission !== "read" && permission !== "publish")) {
40
+ throw new Error(`invalid permissions for ${label}`);
41
+ }
42
+ return [...new Set(value)];
43
+ }
44
+ function isSafePattern(value, pattern) {
45
+ if (!pattern.test(value)) return false;
46
+ const wildcard = value.indexOf("*");
47
+ return wildcard === -1 || wildcard === value.length - 1;
48
+ }
49
+ function normalizeGithubOidc(value, configuredScopes) {
50
+ if (!isObject(value) || typeof value.audience !== "string") {
51
+ throw new Error("githubOidc must define an audience and trusted subjects");
52
+ }
53
+ if (!audiencePattern.test(value.audience)) {
54
+ throw new Error("githubOidc audience must be 1-256 printable ASCII characters");
55
+ }
56
+ if (!Array.isArray(value.subjects) || value.subjects.length === 0 || value.subjects.length > maximumGithubSubjects) {
57
+ throw new Error(`githubOidc must define 1-${String(maximumGithubSubjects)} subjects`);
58
+ }
59
+ const subjects = value.subjects.map((subjectValue, index) => {
60
+ const label = `githubOidc subject ${String(index + 1)}`;
61
+ if (!isObject(subjectValue)) throw new Error(`${label} must be an object`);
62
+ const { repositoryId, repositoryOwnerId, ref, workflowRef, jobWorkflowRef } = subjectValue;
63
+ if (typeof repositoryId !== "string" || !githubIdPattern.test(repositoryId)) {
64
+ throw new Error(`${label} repositoryId must be a decimal GitHub repository ID`);
65
+ }
66
+ if (typeof repositoryOwnerId !== "string" || !githubIdPattern.test(repositoryOwnerId)) {
67
+ throw new Error(`${label} repositoryOwnerId must be a decimal GitHub owner ID`);
68
+ }
69
+ if (typeof ref !== "string" || !isSafePattern(ref, refPattern)) {
70
+ throw new Error(`${label} ref must be an exact branch/tag ref or trailing-wildcard pattern`);
71
+ }
72
+ if (typeof workflowRef !== "string" || !isSafePattern(workflowRef, workflowRefPattern)) {
73
+ throw new Error(
74
+ `${label} workflowRef must identify a workflow file at an exact or trailing-wildcard ref`
75
+ );
76
+ }
77
+ if (jobWorkflowRef !== void 0 && (typeof jobWorkflowRef !== "string" || !isSafePattern(jobWorkflowRef, jobWorkflowRefPattern))) {
78
+ throw new Error(
79
+ `${label} jobWorkflowRef must identify a reusable workflow at a full commit SHA or an exact/trailing-wildcard branch or tag ref`
80
+ );
81
+ }
82
+ const permissions = normalizePermissions(subjectValue.permissions, label);
83
+ if (!Array.isArray(subjectValue.packages) || subjectValue.packages.length === 0 || subjectValue.packages.length > maximumPackagesPerSubject || subjectValue.packages.some((packageName) => typeof packageName !== "string")) {
84
+ throw new Error(
85
+ `${label} must define 1-${String(maximumPackagesPerSubject)} package patterns`
86
+ );
87
+ }
88
+ const packages = [...new Set(subjectValue.packages)];
89
+ for (const packagePattern of packages) {
90
+ const slash = packagePattern.indexOf("/");
91
+ const scope = packagePattern.slice(0, slash);
92
+ const packageSegment = packagePattern.slice(slash + 1);
93
+ if (slash === -1 || packagePattern.length > 214 || !configuredScopes.includes(scope) || packageSegment !== "*" && !packageSegmentPattern.test(packageSegment)) {
94
+ throw new Error(`${label} contains an invalid or unconfigured package pattern`);
95
+ }
96
+ }
97
+ return {
98
+ repositoryId,
99
+ repositoryOwnerId,
100
+ ref,
101
+ workflowRef,
102
+ ...jobWorkflowRef === void 0 ? {} : { jobWorkflowRef },
103
+ permissions,
104
+ packages
105
+ };
106
+ });
107
+ return { audience: value.audience, subjects };
108
+ }
29
109
  function normalizeConfig(value) {
30
110
  if (!isObject(value)) throw new Error("configuration must be an object");
31
111
  const { name, scopes: scopeValues, accountId, hostname, auth } = value;
@@ -50,11 +130,12 @@ function normalizeConfig(value) {
50
130
  if (!isObject(auth) || auth.provider !== "secrets") {
51
131
  throw new Error("unsupported authentication provider");
52
132
  }
53
- if (!Array.isArray(auth.tokens) || auth.tokens.length === 0) {
54
- throw new Error("at least one authentication token binding is required");
133
+ const tokenValues = auth.tokens ?? [];
134
+ if (!Array.isArray(tokenValues)) {
135
+ throw new Error("authentication token bindings must be an array");
55
136
  }
56
137
  const seenBindings = /* @__PURE__ */ new Set();
57
- const tokens = auth.tokens.map((tokenValue) => {
138
+ const tokens = tokenValues.map((tokenValue) => {
58
139
  if (!isObject(tokenValue) || typeof tokenValue.binding !== "string") {
59
140
  throw new Error("authentication token binding must be an object with a binding name");
60
141
  }
@@ -69,19 +150,28 @@ function normalizeConfig(value) {
69
150
  throw new Error(`duplicate secret binding: ${binding}`);
70
151
  }
71
152
  seenBindings.add(binding);
72
- if (!Array.isArray(permissionValues) || permissionValues.length === 0 || permissionValues.some((permission) => permission !== "read" && permission !== "publish")) {
73
- throw new Error(`invalid permissions for ${binding}`);
74
- }
75
- const permissions = [...new Set(permissionValues)];
153
+ const permissions = normalizePermissions(permissionValues, binding);
76
154
  return { binding, permissions };
77
155
  });
78
- return {
156
+ const githubOidc = auth.githubOidc === void 0 ? void 0 : normalizeGithubOidc(auth.githubOidc, scopes);
157
+ if (tokens.length === 0 && githubOidc === void 0) {
158
+ throw new Error("at least one authentication method is required");
159
+ }
160
+ const normalized = {
79
161
  name,
80
162
  scopes,
81
163
  ...accountId === void 0 ? {} : { accountId },
82
164
  ...hostname === void 0 ? {} : { hostname },
83
- auth: { provider: "secrets", tokens }
165
+ auth: {
166
+ provider: "secrets",
167
+ tokens,
168
+ ...githubOidc === void 0 ? {} : { githubOidc }
169
+ }
84
170
  };
171
+ if (new TextEncoder().encode(JSON.stringify(normalized)).byteLength > maximumRuntimeConfigBytes) {
172
+ throw new Error("normalized configuration exceeds the 5 KiB Worker variable limit");
173
+ }
174
+ return normalized;
85
175
  }
86
176
 
87
177
  // src/cli/config-loader.ts
@@ -419,6 +509,74 @@ async function deploy(options) {
419
509
  };
420
510
  }
421
511
 
512
+ // src/cli/github-oidc.ts
513
+ async function readGithubTokenResponse(response) {
514
+ const maximumBytes = 32 * 1024;
515
+ if (response.body === null) throw new Error("GitHub OIDC token response is empty");
516
+ const reader = response.body.getReader();
517
+ const decoder = new TextDecoder("utf-8", { fatal: true });
518
+ let size = 0;
519
+ let contents = "";
520
+ try {
521
+ while (true) {
522
+ const { done, value: value2 } = await reader.read();
523
+ if (done) break;
524
+ size += value2.byteLength;
525
+ if (size > maximumBytes) {
526
+ await reader.cancel();
527
+ throw new Error("GitHub OIDC token response is too large");
528
+ }
529
+ contents += decoder.decode(value2, { stream: true });
530
+ }
531
+ contents += decoder.decode();
532
+ } finally {
533
+ reader.releaseLock();
534
+ }
535
+ let value;
536
+ try {
537
+ value = JSON.parse(contents);
538
+ } catch {
539
+ throw new Error("GitHub OIDC token response is invalid");
540
+ }
541
+ if (typeof value !== "object" || value === null || !("value" in value) || typeof value.value !== "string" || value.value.length > 16 * 1024 || !/^[^.]+\.[^.]+\.[^.]+$/.test(value.value)) {
542
+ throw new Error("GitHub OIDC token response is invalid");
543
+ }
544
+ return value.value;
545
+ }
546
+ async function requestGithubOidcToken(audience, environment = process.env) {
547
+ if (audience === void 0) throw new Error("--audience is required");
548
+ if (!/^[\x21-\x7e]{1,256}$/.test(audience)) {
549
+ throw new Error("--audience must be 1-256 printable ASCII characters");
550
+ }
551
+ const requestUrlValue = environment.ACTIONS_ID_TOKEN_REQUEST_URL;
552
+ const requestToken = environment.ACTIONS_ID_TOKEN_REQUEST_TOKEN;
553
+ if (requestUrlValue === void 0 || requestToken === void 0 || requestToken.length === 0) {
554
+ throw new Error("GitHub Actions OIDC environment is unavailable");
555
+ }
556
+ let requestUrl;
557
+ try {
558
+ requestUrl = new URL(requestUrlValue);
559
+ } catch {
560
+ throw new Error("GitHub Actions OIDC request URL is invalid");
561
+ }
562
+ if (requestUrl.protocol !== "https:" || requestUrl.hostname !== "token.actions.githubusercontent.com" && !requestUrl.hostname.endsWith(".actions.githubusercontent.com") || requestUrl.username !== "" || requestUrl.password !== "") {
563
+ throw new Error("GitHub Actions OIDC request URL is not trusted");
564
+ }
565
+ requestUrl.searchParams.set("audience", audience);
566
+ let response;
567
+ try {
568
+ response = await fetch(requestUrl, {
569
+ headers: { authorization: `bearer ${requestToken}` },
570
+ redirect: "error",
571
+ signal: AbortSignal.timeout(5e3)
572
+ });
573
+ } catch {
574
+ throw new Error("GitHub Actions OIDC token request failed");
575
+ }
576
+ if (!response.ok) throw new Error("GitHub Actions OIDC token request failed");
577
+ return readGithubTokenResponse(response);
578
+ }
579
+
422
580
  // src/cli.ts
423
581
  function valueAfter(arguments_, flag) {
424
582
  const index = arguments_.indexOf(flag);
@@ -433,6 +591,7 @@ function help() {
433
591
 
434
592
  Usage:
435
593
  pkgflare deploy [--config <path>] [--secrets-file <path>] [--adopt-existing]
594
+ pkgflare auth github --audience <audience>
436
595
  pkgflare init
437
596
  pkgflare token generate
438
597
  `
@@ -509,6 +668,12 @@ Deployment state: ${statePath}
509
668
  await init(process.cwd());
510
669
  return;
511
670
  }
671
+ if (command === "auth" && subcommand === "github") {
672
+ const token = await requestGithubOidcToken(valueAfter(arguments_, "--audience"));
673
+ process.stdout.write(`${token}
674
+ `);
675
+ return;
676
+ }
512
677
  if (command === "token" && subcommand === "generate") {
513
678
  let binary = "";
514
679
  for (const byte of randomBytes(32)) binary += String.fromCharCode(byte);
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli.ts","../src/cli/deploy.ts","../src/cli/config-loader.ts","../src/config.ts","../src/cli/runner.ts"],"sourcesContent":["import { randomBytes } from \"node:crypto\";\nimport { open } from \"node:fs/promises\";\nimport { relative, resolve } from \"node:path\";\nimport { deploy } from \"./cli/deploy.js\";\n\nfunction valueAfter(arguments_: readonly string[], flag: string): string | undefined {\n const index = arguments_.indexOf(flag);\n if (index === -1) return undefined;\n const value = arguments_[index + 1];\n if (value === undefined || value.startsWith(\"--\")) throw new Error(`${flag} requires a value`);\n return value;\n}\n\nfunction help(): void {\n process.stdout.write(\n `pkgflare\\n\\nUsage:\\n pkgflare deploy [--config <path>] [--secrets-file <path>] [--adopt-existing]\\n pkgflare init\\n pkgflare token generate\\n`,\n );\n}\n\nasync function init(cwd: string): Promise<void> {\n const path = resolve(cwd, \"pkgflare.config.ts\");\n const file = await open(path, \"wx\").catch((error: unknown) => {\n if ((error as NodeJS.ErrnoException).code === \"EEXIST\")\n throw new Error(\"pkgflare.config.ts already exists\");\n throw error;\n });\n await file.writeFile(\n `import { defineConfig } from \"@ponharu/pkgflare\";\\n\\nexport default defineConfig({\\n name: \"acme-registry\",\\n scopes: [\"@acme\"],\\n auth: {\\n provider: \"secrets\",\\n tokens: [\\n { binding: \"PKGFLARE_READ_TOKEN\", permissions: [\"read\"] },\\n { binding: \"PKGFLARE_PUBLISH_TOKEN\", permissions: [\"publish\"] },\\n ],\\n },\\n});\\n`,\n );\n await file.close();\n process.stdout.write(\"Created pkgflare.config.ts\\n\");\n}\n\nasync function main(arguments_: string[]): Promise<void> {\n const [command, subcommand] = arguments_;\n if (command === undefined || command === \"--help\" || command === \"-h\") {\n help();\n return;\n }\n if (command === \"deploy\") {\n const configFile = valueAfter(arguments_, \"--config\");\n const secretsFile = valueAfter(arguments_, \"--secrets-file\");\n const adoptExisting = arguments_.includes(\"--adopt-existing\");\n const result = await deploy({\n cwd: process.cwd(),\n ...(configFile === undefined ? {} : { configFile }),\n ...(secretsFile === undefined ? {} : { secretsFile }),\n adoptExisting,\n });\n const statePath = relative(process.cwd(), result.stateFile);\n process.stdout.write(`\\nDeployment state: ${statePath}\\n`);\n if (result.registryUrl !== null) {\n process.stdout.write(`Registry: ${result.registryUrl}\\n`);\n }\n process.stdout.write(\"\\nRegister each token secret if it was not supplied during deploy:\\n\");\n for (const binding of result.secretBindings) {\n process.stdout.write(` npx wrangler secret put ${binding} --config ${statePath}\\n`);\n }\n if (result.registryUrl !== null) {\n const host = new URL(result.registryUrl).host;\n process.stdout.write(\"\\n.npmrc:\\n\");\n for (const scope of result.scopes) {\n process.stdout.write(` ${scope}:registry=${result.registryUrl}\\n`);\n }\n process.stdout.write(` //${host}/:_authToken=\\${NPM_TOKEN}\\n`);\n }\n return;\n }\n if (command === \"init\") {\n await init(process.cwd());\n return;\n }\n if (command === \"token\" && subcommand === \"generate\") {\n let binary = \"\";\n for (const byte of randomBytes(32)) binary += String.fromCharCode(byte);\n const token = btoa(binary).replace(/\\+/g, \"-\").replace(/\\//g, \"_\").replace(/=+$/, \"\");\n process.stdout.write(`${token}\\n`);\n return;\n }\n throw new Error(`unknown command: ${arguments_.join(\" \")}`);\n}\n\nmain(process.argv.slice(2)).catch((error: unknown) => {\n const message = error instanceof Error ? error.message : String(error);\n process.stderr.write(`pkgflare: ${message}\\n`);\n process.exitCode = 1;\n});\n","import { copyFile, mkdir, readFile, readdir, writeFile } from \"node:fs/promises\";\nimport { dirname, join, relative, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport type { NormalizedConfig } from \"../config.js\";\nimport { loadConfig } from \"./config-loader.js\";\nimport { createWranglerRunner, type WranglerRunner } from \"./runner.js\";\n\nconst stateDirectoryName = \".pkgflare\";\nconst stateFileName = \"wrangler.json\";\nconst ownershipFileName = \"ownership.json\";\nconst d1Binding = \"PKGFLARE_DB\";\nconst r2Binding = \"PKGFLARE_BUCKET\";\n\ninterface D1Binding {\n binding: string;\n database_name: string;\n database_id: string;\n migrations_dir?: string;\n}\n\ninterface R2Binding {\n binding: string;\n bucket_name: string;\n}\n\ninterface WranglerState {\n $schema: string;\n account_id?: string;\n name: string;\n main: string;\n compatibility_date: string;\n workers_dev: boolean;\n routes?: Array<{ pattern: string; custom_domain: true }>;\n vars: { PKGFLARE_CONFIG: string };\n d1_databases: D1Binding[];\n r2_buckets: R2Binding[];\n}\n\ninterface D1ListEntry {\n name?: unknown;\n uuid?: unknown;\n}\n\ninterface WhoamiResult {\n loggedIn?: unknown;\n accounts?: unknown;\n}\n\ninterface AccountEntry {\n id: string;\n name?: string;\n}\n\ninterface OwnershipState {\n account_id: string;\n worker_name: string;\n}\n\nexport interface DeployOptions {\n cwd: string;\n configFile?: string;\n secretsFile?: string;\n adoptExisting?: boolean;\n runner?: WranglerRunner;\n assetsDirectory?: string;\n}\n\nexport interface DeployResult {\n registryUrl: string | null;\n stateFile: string;\n secretBindings: string[];\n scopes: string[];\n}\n\nfunction packageRoot(): string {\n return dirname(fileURLToPath(import.meta.url));\n}\n\nfunction stateFor(\n config: NormalizedConfig,\n accountId: string,\n previous?: WranglerState,\n): WranglerState {\n if (previous?.account_id !== undefined && previous.account_id !== accountId) {\n throw new Error(\"authenticated Cloudflare account does not match the deployment state\");\n }\n const state: WranglerState = {\n $schema:\n \"https://raw.githubusercontent.com/cloudflare/workers-sdk/main/packages/wrangler/config-schema.json\",\n account_id: accountId,\n name: config.name,\n main: \"runtime/worker.js\",\n compatibility_date: \"2026-08-01\",\n workers_dev: config.hostname === undefined,\n vars: { PKGFLARE_CONFIG: JSON.stringify(config) },\n d1_databases: previous?.d1_databases ?? [],\n r2_buckets: previous?.r2_buckets ?? [],\n };\n if (config.hostname !== undefined) {\n state.routes = [{ pattern: config.hostname, custom_domain: true }];\n }\n return state;\n}\n\nasync function readState(\n path: string,\n config: NormalizedConfig,\n): Promise<WranglerState | undefined> {\n let contents: string;\n try {\n contents = await readFile(path, \"utf8\");\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return undefined;\n throw error;\n }\n const state = JSON.parse(contents) as WranglerState;\n if (state.name !== config.name) {\n throw new Error(\n `existing deployment state belongs to ${state.name}; remove ${stateDirectoryName} only after verifying the remote resources`,\n );\n }\n return state;\n}\n\nasync function writeState(path: string, state: WranglerState): Promise<void> {\n await writeFile(path, `${JSON.stringify(state, null, 2)}\\n`, \"utf8\");\n}\n\nasync function readWorkerOwnership(\n path: string,\n workerName: string,\n accountId: string,\n): Promise<boolean> {\n let contents: string;\n try {\n contents = await readFile(path, \"utf8\");\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return false;\n throw error;\n }\n const ownership = JSON.parse(contents) as Partial<OwnershipState>;\n if (ownership.worker_name !== workerName || ownership.account_id !== accountId) {\n throw new Error(\"deployment ownership state does not match the configured Worker and account\");\n }\n return true;\n}\n\nasync function writeWorkerOwnership(\n path: string,\n workerName: string,\n accountId: string,\n): Promise<void> {\n const ownership: OwnershipState = { account_id: accountId, worker_name: workerName };\n await writeFile(path, `${JSON.stringify(ownership, null, 2)}\\n`, \"utf8\");\n}\n\nasync function copyRuntimeFiles(stateDirectory: string, root: string): Promise<void> {\n const runtimeDirectory = join(stateDirectory, \"runtime\");\n const migrationsDirectory = join(stateDirectory, \"migrations\");\n await Promise.all([\n mkdir(runtimeDirectory, { recursive: true }),\n mkdir(migrationsDirectory, { recursive: true }),\n ]);\n const sourceMigrations = resolve(root, \"..\", \"migrations\");\n const migrationFiles = (await readdir(sourceMigrations, { withFileTypes: true }))\n .filter((entry) => entry.isFile() && entry.name.endsWith(\".sql\"))\n .map((entry) => entry.name);\n // oxlint-disable-next-line unicorn/no-array-sort -- this array has just been created locally\n migrationFiles.sort();\n if (migrationFiles.length === 0) throw new Error(\"pkgflare package contains no D1 migrations\");\n await Promise.all([\n copyFile(join(root, \"worker.js\"), join(runtimeDirectory, \"worker.js\")),\n copyFile(join(root, \"worker.js.map\"), join(runtimeDirectory, \"worker.js.map\")),\n ...migrationFiles.map((file) =>\n copyFile(join(sourceMigrations, file), join(migrationsDirectory, file)),\n ),\n ]);\n await writeFile(join(stateDirectory, \".gitignore\"), \"runtime/\\nmigrations/\\n\", {\n flag: \"wx\",\n }).catch((error: unknown) => {\n if ((error as NodeJS.ErrnoException).code !== \"EEXIST\") throw error;\n });\n}\n\nfunction configArguments(stateFile: string, cwd: string): string[] {\n return [\"--config\", relative(cwd, stateFile)];\n}\n\nasync function recoverD1(\n runner: WranglerRunner,\n databaseName: string,\n configArgs: readonly string[],\n): Promise<D1Binding | null> {\n const result = await runner([\"d1\", \"list\", \"--json\", ...configArgs], { silent: true });\n const entries = JSON.parse(result.stdout) as D1ListEntry[];\n const matches = entries.filter(\n (entry) => entry.name === databaseName && typeof entry.uuid === \"string\",\n );\n if (matches.length > 1) throw new Error(`multiple D1 databases are named ${databaseName}`);\n const match = matches[0];\n return match === undefined\n ? null\n : {\n binding: d1Binding,\n database_name: databaseName,\n database_id: match.uuid as string,\n migrations_dir: \"migrations\",\n };\n}\n\nasync function recoverR2(\n runner: WranglerRunner,\n bucketName: string,\n configArgs: readonly string[],\n): Promise<R2Binding | null> {\n const result = await runner([\"r2\", \"bucket\", \"info\", bucketName, \"--json\", ...configArgs], {\n silent: true,\n allowFailure: true,\n });\n if (result.exitCode === 0) return { binding: r2Binding, bucket_name: bucketName };\n if (/not found|does not exist|10006/i.test(result.stderr)) return null;\n throw new Error(`unable to inspect the ${bucketName} R2 bucket with the current credentials`);\n}\n\nfunction accountsFromWhoami(value: unknown): AccountEntry[] {\n if (typeof value !== \"object\" || value === null)\n throw new Error(\"Wrangler returned invalid account information\");\n const accounts = (value as WhoamiResult).accounts;\n if (!Array.isArray(accounts)) throw new Error(\"Wrangler returned invalid account information\");\n return accounts.flatMap((account) => {\n if (\n typeof account !== \"object\" ||\n account === null ||\n !(\"id\" in account) ||\n typeof account.id !== \"string\"\n ) {\n return [];\n }\n return [\n {\n id: account.id,\n ...(typeof (account as { name?: unknown }).name === \"string\"\n ? { name: (account as { name: string }).name }\n : {}),\n },\n ];\n });\n}\n\nasync function resolveAccountId(\n runner: WranglerRunner,\n configuredAccountId: string | undefined,\n): Promise<string> {\n if (configuredAccountId !== undefined) return configuredAccountId;\n const result = await runner([\"whoami\", \"--json\"], { silent: true });\n const accounts = accountsFromWhoami(JSON.parse(result.stdout) as unknown);\n if (accounts.length !== 1) {\n throw new Error(\"accountId is required when Wrangler credentials can access multiple accounts\");\n }\n const account = accounts[0];\n if (account === undefined)\n throw new Error(\"Wrangler credentials do not provide a Cloudflare account\");\n return account.id;\n}\n\nasync function workerExists(\n runner: WranglerRunner,\n workerName: string,\n configArgs: readonly string[],\n): Promise<boolean> {\n const result = await runner([\"versions\", \"list\", \"--name\", workerName, \"--json\", ...configArgs], {\n silent: true,\n allowFailure: true,\n });\n if (result.exitCode === 0) return true;\n if (/not found|does not exist|10007/i.test(result.stderr)) return false;\n throw new Error(`unable to inspect the ${workerName} Worker with the current credentials`);\n}\n\nasync function verifyWorkerOwnership(\n workerName: string,\n configArgs: readonly string[],\n runner: WranglerRunner,\n adoptExisting: boolean,\n): Promise<boolean> {\n const exists = await workerExists(runner, workerName, configArgs);\n if (exists && !adoptExisting) {\n throw new Error(\n `the ${workerName} Worker already exists; verify it, then rerun with --adopt-existing`,\n );\n }\n return exists;\n}\n\nasync function ensureResources(\n state: WranglerState,\n stateFile: string,\n cwd: string,\n runner: WranglerRunner,\n adoptExisting: boolean,\n): Promise<WranglerState> {\n const d1Name = `${state.name}-metadata`;\n const r2Name = `${state.name}-packages`;\n const configArgs = configArguments(stateFile, cwd);\n const configuredD1 = state.d1_databases.filter((database) => database.binding === d1Binding);\n const configuredR2 = state.r2_buckets.filter((bucket) => bucket.binding === r2Binding);\n const selectedD1 = configuredD1[0];\n const selectedR2 = configuredR2[0];\n if (\n configuredD1.length > 1 ||\n (selectedD1 !== undefined && selectedD1.database_name !== d1Name)\n ) {\n throw new Error(`${d1Binding} must reference the ${d1Name} D1 database`);\n }\n if (configuredR2.length > 1 || (selectedR2 !== undefined && selectedR2.bucket_name !== r2Name)) {\n throw new Error(`${r2Binding} must reference the ${r2Name} R2 bucket`);\n }\n\n if (configuredD1.length === 0) {\n const recovered = await recoverD1(runner, d1Name, configArgs);\n if (recovered !== null) {\n if (!adoptExisting) {\n throw new Error(\n `the ${d1Name} D1 database already exists; verify it, then rerun with --adopt-existing`,\n );\n }\n state.d1_databases.push(recovered);\n await writeState(stateFile, state);\n } else {\n await runner([\n \"d1\",\n \"create\",\n d1Name,\n \"--binding\",\n d1Binding,\n \"--update-config\",\n ...configArgs,\n ]);\n state = JSON.parse(await readFile(stateFile, \"utf8\")) as WranglerState;\n }\n }\n\n if (configuredR2.length === 0) {\n const recovered = await recoverR2(runner, r2Name, configArgs);\n if (recovered !== null) {\n if (!adoptExisting) {\n throw new Error(\n `the ${r2Name} R2 bucket already exists; verify it, then rerun with --adopt-existing`,\n );\n }\n state.r2_buckets.push(recovered);\n await writeState(stateFile, state);\n } else {\n await runner([\n \"r2\",\n \"bucket\",\n \"create\",\n r2Name,\n \"--binding\",\n r2Binding,\n \"--update-config\",\n ...configArgs,\n ]);\n state = JSON.parse(await readFile(stateFile, \"utf8\")) as WranglerState;\n }\n }\n\n state.d1_databases = state.d1_databases.map((database) =>\n database.binding === d1Binding ? { ...database, migrations_dir: \"migrations\" } : database,\n );\n await writeState(stateFile, state);\n return state;\n}\n\nfunction deploymentUrl(output: string, config: NormalizedConfig): string | null {\n if (config.hostname !== undefined) return `https://${config.hostname}`;\n return output.match(/https:\\/\\/[^\\s]+\\.workers\\.dev\\b/)?.[0] ?? null;\n}\n\nexport async function deploy(options: DeployOptions): Promise<DeployResult> {\n const cwd = resolve(options.cwd);\n const config = await loadConfig(cwd, options.configFile);\n const stateDirectory = join(cwd, stateDirectoryName);\n const stateFile = join(stateDirectory, stateFileName);\n const ownershipFile = join(stateDirectory, ownershipFileName);\n await mkdir(stateDirectory, { recursive: true });\n\n const previous = await readState(stateFile, config);\n const runner = options.runner ?? createWranglerRunner(cwd);\n const environmentAccountId = process.env.CLOUDFLARE_ACCOUNT_ID;\n const configuredAccountId = config.accountId ?? previous?.account_id;\n if (\n environmentAccountId !== undefined &&\n configuredAccountId !== undefined &&\n environmentAccountId !== configuredAccountId\n ) {\n throw new Error(\"CLOUDFLARE_ACCOUNT_ID does not match the configured deployment account\");\n }\n const accountId = await resolveAccountId(runner, configuredAccountId ?? environmentAccountId);\n const ownsWorker = await readWorkerOwnership(ownershipFile, config.name, accountId);\n let state = stateFor(config, accountId, previous);\n await writeState(stateFile, state);\n await copyRuntimeFiles(stateDirectory, options.assetsDirectory ?? packageRoot());\n\n state = await ensureResources(state, stateFile, cwd, runner, options.adoptExisting ?? false);\n const configArgs = configArguments(stateFile, cwd);\n await runner([\"d1\", \"migrations\", \"apply\", d1Binding, \"--remote\", ...configArgs]);\n\n const adoptedWorker = ownsWorker\n ? false\n : await verifyWorkerOwnership(state.name, configArgs, runner, options.adoptExisting ?? false);\n if (adoptedWorker) await writeWorkerOwnership(ownershipFile, state.name, accountId);\n\n const deployArguments = [\"deploy\", \"--no-bundle\", ...configArgs];\n if (options.secretsFile !== undefined) {\n deployArguments.push(\"--secrets-file\", options.secretsFile);\n }\n const deployed = await runner(deployArguments);\n if (!ownsWorker && !adoptedWorker)\n await writeWorkerOwnership(ownershipFile, state.name, accountId);\n return {\n registryUrl: deploymentUrl(deployed.stdout, config),\n stateFile,\n secretBindings: config.auth.tokens.map((token) => token.binding),\n scopes: config.scopes,\n };\n}\n","import { access } from \"node:fs/promises\";\nimport { resolve } from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\nimport { createJiti } from \"jiti\";\nimport { normalizeConfig, type NormalizedConfig } from \"../config.js\";\n\nexport const defaultConfigFile = \"pkgflare.config.ts\";\n\nexport async function loadConfig(\n cwd: string,\n configFile = defaultConfigFile,\n): Promise<NormalizedConfig> {\n const path = resolve(cwd, configFile);\n try {\n await access(path);\n } catch {\n throw new Error(`configuration file not found: ${configFile}`);\n }\n\n const jiti = createJiti(pathToFileURL(import.meta.url).href, {\n interopDefault: true,\n moduleCache: false,\n });\n const imported = await jiti.import(path, { default: true });\n return normalizeConfig(imported);\n}\n","export type Permission = \"read\" | \"publish\";\n\nexport interface SecretTokenConfig {\n binding: string;\n permissions: readonly Permission[];\n}\n\nexport interface SecretsAuthConfig {\n provider: \"secrets\";\n tokens: readonly SecretTokenConfig[];\n}\n\nexport interface PkgflareConfig {\n name: string;\n scopes: readonly string[];\n accountId?: string;\n hostname?: string;\n auth: SecretsAuthConfig;\n}\n\nexport interface NormalizedConfig {\n name: string;\n scopes: string[];\n accountId?: string;\n hostname?: string;\n auth: {\n provider: \"secrets\";\n tokens: Array<{\n binding: string;\n permissions: Permission[];\n }>;\n };\n}\n\nconst workerNamePattern = /^[a-z](?:[a-z0-9-]{0,52}[a-z0-9])?$/;\nconst accountIdPattern = /^[a-f0-9]{32}$/;\nconst scopePattern = /^@[a-z0-9](?:[a-z0-9._-]*[a-z0-9])?$/;\nconst bindingPattern = /^[A-Z][A-Z0-9_]*$/;\nconst hostnamePattern =\n /^(?=.{1,253}$)(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\\.)+[a-z](?:[a-z0-9-]{0,61}[a-z0-9])?$/;\nconst reservedBindings = new Set([\"PKGFLARE_DB\", \"PKGFLARE_BUCKET\", \"PKGFLARE_CONFIG\"]);\n\nexport function defineConfig(config: PkgflareConfig): PkgflareConfig {\n return config;\n}\n\nfunction isObject(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nexport function normalizeConfig(value: unknown): NormalizedConfig {\n if (!isObject(value)) throw new Error(\"configuration must be an object\");\n const { name, scopes: scopeValues, accountId, hostname, auth } = value;\n if (typeof name !== \"string\" || !workerNamePattern.test(name)) {\n throw new Error(\"name must be a lowercase Cloudflare resource name of at most 54 characters\");\n }\n\n if (\n accountId !== undefined &&\n (typeof accountId !== \"string\" || !accountIdPattern.test(accountId))\n ) {\n throw new Error(\"accountId must be a 32-character lowercase hexadecimal Cloudflare account ID\");\n }\n\n if (\n !Array.isArray(scopeValues) ||\n scopeValues.length === 0 ||\n scopeValues.some((scope) => typeof scope !== \"string\")\n ) {\n throw new Error(\"at least one package scope is required\");\n }\n\n const scopes = [...new Set(scopeValues as string[])];\n for (const scope of scopes) {\n if (!scopePattern.test(scope)) {\n throw new Error(`invalid package scope: ${scope}`);\n }\n }\n\n if (hostname !== undefined && (typeof hostname !== \"string\" || !hostnamePattern.test(hostname))) {\n throw new Error(\"hostname must be a valid DNS hostname without a scheme or path\");\n }\n\n if (!isObject(auth) || auth.provider !== \"secrets\") {\n throw new Error(\"unsupported authentication provider\");\n }\n\n if (!Array.isArray(auth.tokens) || auth.tokens.length === 0) {\n throw new Error(\"at least one authentication token binding is required\");\n }\n\n const seenBindings = new Set<string>();\n const tokens = auth.tokens.map((tokenValue) => {\n if (!isObject(tokenValue) || typeof tokenValue.binding !== \"string\") {\n throw new Error(\"authentication token binding must be an object with a binding name\");\n }\n const { binding, permissions: permissionValues } = tokenValue;\n if (!bindingPattern.test(binding)) {\n throw new Error(`invalid secret binding: ${binding}`);\n }\n if (reservedBindings.has(binding)) {\n throw new Error(`secret binding is reserved by pkgflare: ${binding}`);\n }\n if (seenBindings.has(binding)) {\n throw new Error(`duplicate secret binding: ${binding}`);\n }\n seenBindings.add(binding);\n\n if (\n !Array.isArray(permissionValues) ||\n permissionValues.length === 0 ||\n permissionValues.some((permission) => permission !== \"read\" && permission !== \"publish\")\n ) {\n throw new Error(`invalid permissions for ${binding}`);\n }\n const permissions = [...new Set(permissionValues)] as Permission[];\n\n return { binding, permissions };\n });\n\n return {\n name,\n scopes,\n ...(accountId === undefined ? {} : { accountId }),\n ...(hostname === undefined ? {} : { hostname }),\n auth: { provider: \"secrets\", tokens },\n };\n}\n","import { spawn } from \"node:child_process\";\nimport { createRequire } from \"node:module\";\nimport { dirname, join } from \"node:path\";\n\nexport interface CommandResult {\n exitCode: number;\n stdout: string;\n stderr: string;\n}\n\nexport type WranglerRunner = (\n arguments_: readonly string[],\n options?: { allowFailure?: boolean; silent?: boolean },\n) => Promise<CommandResult>;\n\nfunction wranglerEntry(): string {\n const require = createRequire(import.meta.url);\n return join(dirname(require.resolve(\"wrangler/package.json\")), \"bin\", \"wrangler.js\");\n}\n\nexport function createWranglerRunner(cwd: string): WranglerRunner {\n return async (arguments_, options = {}) => {\n const result = await new Promise<CommandResult>((resolve, reject) => {\n const child = spawn(process.execPath, [wranglerEntry(), ...arguments_], {\n cwd,\n env: process.env,\n shell: false,\n stdio: [\"inherit\", \"pipe\", \"pipe\"],\n });\n let stdout = \"\";\n let stderr = \"\";\n child.stdout.setEncoding(\"utf8\");\n child.stderr.setEncoding(\"utf8\");\n child.stdout.on(\"data\", (chunk: string) => {\n stdout += chunk;\n if (!options.silent) process.stdout.write(chunk);\n });\n child.stderr.on(\"data\", (chunk: string) => {\n stderr += chunk;\n if (!options.silent) process.stderr.write(chunk);\n });\n child.once(\"error\", reject);\n child.once(\"close\", (code) => resolve({ exitCode: code ?? 1, stdout, stderr }));\n });\n\n if (result.exitCode !== 0 && !options.allowFailure) {\n const operation = arguments_.slice(0, 3).join(\" \");\n throw new Error(\n `Wrangler command ${JSON.stringify(operation)} exited with status ${String(result.exitCode)}`,\n );\n }\n return result;\n };\n}\n"],"mappings":"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","names":["relative","resolve","dirname","join","resolve","require","resolve","dirname","join","resolve","resolve","relative"]}
1
+ {"version":3,"sources":["../src/cli.ts","../src/cli/deploy.ts","../src/cli/config-loader.ts","../src/config.ts","../src/cli/runner.ts","../src/cli/github-oidc.ts"],"sourcesContent":["import { randomBytes } from \"node:crypto\";\nimport { open } from \"node:fs/promises\";\nimport { relative, resolve } from \"node:path\";\nimport { deploy } from \"./cli/deploy.js\";\nimport { requestGithubOidcToken } from \"./cli/github-oidc.js\";\n\nfunction valueAfter(arguments_: readonly string[], flag: string): string | undefined {\n const index = arguments_.indexOf(flag);\n if (index === -1) return undefined;\n const value = arguments_[index + 1];\n if (value === undefined || value.startsWith(\"--\")) throw new Error(`${flag} requires a value`);\n return value;\n}\n\nfunction help(): void {\n process.stdout.write(\n `pkgflare\\n\\nUsage:\\n pkgflare deploy [--config <path>] [--secrets-file <path>] [--adopt-existing]\\n pkgflare auth github --audience <audience>\\n pkgflare init\\n pkgflare token generate\\n`,\n );\n}\n\nasync function init(cwd: string): Promise<void> {\n const path = resolve(cwd, \"pkgflare.config.ts\");\n const file = await open(path, \"wx\").catch((error: unknown) => {\n if ((error as NodeJS.ErrnoException).code === \"EEXIST\")\n throw new Error(\"pkgflare.config.ts already exists\");\n throw error;\n });\n await file.writeFile(\n `import { defineConfig } from \"@ponharu/pkgflare\";\\n\\nexport default defineConfig({\\n name: \"acme-registry\",\\n scopes: [\"@acme\"],\\n auth: {\\n provider: \"secrets\",\\n tokens: [\\n { binding: \"PKGFLARE_READ_TOKEN\", permissions: [\"read\"] },\\n { binding: \"PKGFLARE_PUBLISH_TOKEN\", permissions: [\"publish\"] },\\n ],\\n },\\n});\\n`,\n );\n await file.close();\n process.stdout.write(\"Created pkgflare.config.ts\\n\");\n}\n\nasync function main(arguments_: string[]): Promise<void> {\n const [command, subcommand] = arguments_;\n if (command === undefined || command === \"--help\" || command === \"-h\") {\n help();\n return;\n }\n if (command === \"deploy\") {\n const configFile = valueAfter(arguments_, \"--config\");\n const secretsFile = valueAfter(arguments_, \"--secrets-file\");\n const adoptExisting = arguments_.includes(\"--adopt-existing\");\n const result = await deploy({\n cwd: process.cwd(),\n ...(configFile === undefined ? {} : { configFile }),\n ...(secretsFile === undefined ? {} : { secretsFile }),\n adoptExisting,\n });\n const statePath = relative(process.cwd(), result.stateFile);\n process.stdout.write(`\\nDeployment state: ${statePath}\\n`);\n if (result.registryUrl !== null) {\n process.stdout.write(`Registry: ${result.registryUrl}\\n`);\n }\n process.stdout.write(\"\\nRegister each token secret if it was not supplied during deploy:\\n\");\n for (const binding of result.secretBindings) {\n process.stdout.write(` npx wrangler secret put ${binding} --config ${statePath}\\n`);\n }\n if (result.registryUrl !== null) {\n const host = new URL(result.registryUrl).host;\n process.stdout.write(\"\\n.npmrc:\\n\");\n for (const scope of result.scopes) {\n process.stdout.write(` ${scope}:registry=${result.registryUrl}\\n`);\n }\n process.stdout.write(` //${host}/:_authToken=\\${NPM_TOKEN}\\n`);\n }\n return;\n }\n if (command === \"init\") {\n await init(process.cwd());\n return;\n }\n if (command === \"auth\" && subcommand === \"github\") {\n const token = await requestGithubOidcToken(valueAfter(arguments_, \"--audience\"));\n process.stdout.write(`${token}\\n`);\n return;\n }\n if (command === \"token\" && subcommand === \"generate\") {\n let binary = \"\";\n for (const byte of randomBytes(32)) binary += String.fromCharCode(byte);\n const token = btoa(binary).replace(/\\+/g, \"-\").replace(/\\//g, \"_\").replace(/=+$/, \"\");\n process.stdout.write(`${token}\\n`);\n return;\n }\n throw new Error(`unknown command: ${arguments_.join(\" \")}`);\n}\n\nmain(process.argv.slice(2)).catch((error: unknown) => {\n const message = error instanceof Error ? error.message : String(error);\n process.stderr.write(`pkgflare: ${message}\\n`);\n process.exitCode = 1;\n});\n","import { copyFile, mkdir, readFile, readdir, writeFile } from \"node:fs/promises\";\nimport { dirname, join, relative, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport type { NormalizedConfig } from \"../config.js\";\nimport { loadConfig } from \"./config-loader.js\";\nimport { createWranglerRunner, type WranglerRunner } from \"./runner.js\";\n\nconst stateDirectoryName = \".pkgflare\";\nconst stateFileName = \"wrangler.json\";\nconst ownershipFileName = \"ownership.json\";\nconst d1Binding = \"PKGFLARE_DB\";\nconst r2Binding = \"PKGFLARE_BUCKET\";\n\ninterface D1Binding {\n binding: string;\n database_name: string;\n database_id: string;\n migrations_dir?: string;\n}\n\ninterface R2Binding {\n binding: string;\n bucket_name: string;\n}\n\ninterface WranglerState {\n $schema: string;\n account_id?: string;\n name: string;\n main: string;\n compatibility_date: string;\n workers_dev: boolean;\n routes?: Array<{ pattern: string; custom_domain: true }>;\n vars: { PKGFLARE_CONFIG: string };\n d1_databases: D1Binding[];\n r2_buckets: R2Binding[];\n}\n\ninterface D1ListEntry {\n name?: unknown;\n uuid?: unknown;\n}\n\ninterface WhoamiResult {\n loggedIn?: unknown;\n accounts?: unknown;\n}\n\ninterface AccountEntry {\n id: string;\n name?: string;\n}\n\ninterface OwnershipState {\n account_id: string;\n worker_name: string;\n}\n\nexport interface DeployOptions {\n cwd: string;\n configFile?: string;\n secretsFile?: string;\n adoptExisting?: boolean;\n runner?: WranglerRunner;\n assetsDirectory?: string;\n}\n\nexport interface DeployResult {\n registryUrl: string | null;\n stateFile: string;\n secretBindings: string[];\n scopes: string[];\n}\n\nfunction packageRoot(): string {\n return dirname(fileURLToPath(import.meta.url));\n}\n\nfunction stateFor(\n config: NormalizedConfig,\n accountId: string,\n previous?: WranglerState,\n): WranglerState {\n if (previous?.account_id !== undefined && previous.account_id !== accountId) {\n throw new Error(\"authenticated Cloudflare account does not match the deployment state\");\n }\n const state: WranglerState = {\n $schema:\n \"https://raw.githubusercontent.com/cloudflare/workers-sdk/main/packages/wrangler/config-schema.json\",\n account_id: accountId,\n name: config.name,\n main: \"runtime/worker.js\",\n compatibility_date: \"2026-08-01\",\n workers_dev: config.hostname === undefined,\n vars: { PKGFLARE_CONFIG: JSON.stringify(config) },\n d1_databases: previous?.d1_databases ?? [],\n r2_buckets: previous?.r2_buckets ?? [],\n };\n if (config.hostname !== undefined) {\n state.routes = [{ pattern: config.hostname, custom_domain: true }];\n }\n return state;\n}\n\nasync function readState(\n path: string,\n config: NormalizedConfig,\n): Promise<WranglerState | undefined> {\n let contents: string;\n try {\n contents = await readFile(path, \"utf8\");\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return undefined;\n throw error;\n }\n const state = JSON.parse(contents) as WranglerState;\n if (state.name !== config.name) {\n throw new Error(\n `existing deployment state belongs to ${state.name}; remove ${stateDirectoryName} only after verifying the remote resources`,\n );\n }\n return state;\n}\n\nasync function writeState(path: string, state: WranglerState): Promise<void> {\n await writeFile(path, `${JSON.stringify(state, null, 2)}\\n`, \"utf8\");\n}\n\nasync function readWorkerOwnership(\n path: string,\n workerName: string,\n accountId: string,\n): Promise<boolean> {\n let contents: string;\n try {\n contents = await readFile(path, \"utf8\");\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return false;\n throw error;\n }\n const ownership = JSON.parse(contents) as Partial<OwnershipState>;\n if (ownership.worker_name !== workerName || ownership.account_id !== accountId) {\n throw new Error(\"deployment ownership state does not match the configured Worker and account\");\n }\n return true;\n}\n\nasync function writeWorkerOwnership(\n path: string,\n workerName: string,\n accountId: string,\n): Promise<void> {\n const ownership: OwnershipState = { account_id: accountId, worker_name: workerName };\n await writeFile(path, `${JSON.stringify(ownership, null, 2)}\\n`, \"utf8\");\n}\n\nasync function copyRuntimeFiles(stateDirectory: string, root: string): Promise<void> {\n const runtimeDirectory = join(stateDirectory, \"runtime\");\n const migrationsDirectory = join(stateDirectory, \"migrations\");\n await Promise.all([\n mkdir(runtimeDirectory, { recursive: true }),\n mkdir(migrationsDirectory, { recursive: true }),\n ]);\n const sourceMigrations = resolve(root, \"..\", \"migrations\");\n const migrationFiles = (await readdir(sourceMigrations, { withFileTypes: true }))\n .filter((entry) => entry.isFile() && entry.name.endsWith(\".sql\"))\n .map((entry) => entry.name);\n // oxlint-disable-next-line unicorn/no-array-sort -- this array has just been created locally\n migrationFiles.sort();\n if (migrationFiles.length === 0) throw new Error(\"pkgflare package contains no D1 migrations\");\n await Promise.all([\n copyFile(join(root, \"worker.js\"), join(runtimeDirectory, \"worker.js\")),\n copyFile(join(root, \"worker.js.map\"), join(runtimeDirectory, \"worker.js.map\")),\n ...migrationFiles.map((file) =>\n copyFile(join(sourceMigrations, file), join(migrationsDirectory, file)),\n ),\n ]);\n await writeFile(join(stateDirectory, \".gitignore\"), \"runtime/\\nmigrations/\\n\", {\n flag: \"wx\",\n }).catch((error: unknown) => {\n if ((error as NodeJS.ErrnoException).code !== \"EEXIST\") throw error;\n });\n}\n\nfunction configArguments(stateFile: string, cwd: string): string[] {\n return [\"--config\", relative(cwd, stateFile)];\n}\n\nasync function recoverD1(\n runner: WranglerRunner,\n databaseName: string,\n configArgs: readonly string[],\n): Promise<D1Binding | null> {\n const result = await runner([\"d1\", \"list\", \"--json\", ...configArgs], { silent: true });\n const entries = JSON.parse(result.stdout) as D1ListEntry[];\n const matches = entries.filter(\n (entry) => entry.name === databaseName && typeof entry.uuid === \"string\",\n );\n if (matches.length > 1) throw new Error(`multiple D1 databases are named ${databaseName}`);\n const match = matches[0];\n return match === undefined\n ? null\n : {\n binding: d1Binding,\n database_name: databaseName,\n database_id: match.uuid as string,\n migrations_dir: \"migrations\",\n };\n}\n\nasync function recoverR2(\n runner: WranglerRunner,\n bucketName: string,\n configArgs: readonly string[],\n): Promise<R2Binding | null> {\n const result = await runner([\"r2\", \"bucket\", \"info\", bucketName, \"--json\", ...configArgs], {\n silent: true,\n allowFailure: true,\n });\n if (result.exitCode === 0) return { binding: r2Binding, bucket_name: bucketName };\n if (/not found|does not exist|10006/i.test(result.stderr)) return null;\n throw new Error(`unable to inspect the ${bucketName} R2 bucket with the current credentials`);\n}\n\nfunction accountsFromWhoami(value: unknown): AccountEntry[] {\n if (typeof value !== \"object\" || value === null)\n throw new Error(\"Wrangler returned invalid account information\");\n const accounts = (value as WhoamiResult).accounts;\n if (!Array.isArray(accounts)) throw new Error(\"Wrangler returned invalid account information\");\n return accounts.flatMap((account) => {\n if (\n typeof account !== \"object\" ||\n account === null ||\n !(\"id\" in account) ||\n typeof account.id !== \"string\"\n ) {\n return [];\n }\n return [\n {\n id: account.id,\n ...(typeof (account as { name?: unknown }).name === \"string\"\n ? { name: (account as { name: string }).name }\n : {}),\n },\n ];\n });\n}\n\nasync function resolveAccountId(\n runner: WranglerRunner,\n configuredAccountId: string | undefined,\n): Promise<string> {\n if (configuredAccountId !== undefined) return configuredAccountId;\n const result = await runner([\"whoami\", \"--json\"], { silent: true });\n const accounts = accountsFromWhoami(JSON.parse(result.stdout) as unknown);\n if (accounts.length !== 1) {\n throw new Error(\"accountId is required when Wrangler credentials can access multiple accounts\");\n }\n const account = accounts[0];\n if (account === undefined)\n throw new Error(\"Wrangler credentials do not provide a Cloudflare account\");\n return account.id;\n}\n\nasync function workerExists(\n runner: WranglerRunner,\n workerName: string,\n configArgs: readonly string[],\n): Promise<boolean> {\n const result = await runner([\"versions\", \"list\", \"--name\", workerName, \"--json\", ...configArgs], {\n silent: true,\n allowFailure: true,\n });\n if (result.exitCode === 0) return true;\n if (/not found|does not exist|10007/i.test(result.stderr)) return false;\n throw new Error(`unable to inspect the ${workerName} Worker with the current credentials`);\n}\n\nasync function verifyWorkerOwnership(\n workerName: string,\n configArgs: readonly string[],\n runner: WranglerRunner,\n adoptExisting: boolean,\n): Promise<boolean> {\n const exists = await workerExists(runner, workerName, configArgs);\n if (exists && !adoptExisting) {\n throw new Error(\n `the ${workerName} Worker already exists; verify it, then rerun with --adopt-existing`,\n );\n }\n return exists;\n}\n\nasync function ensureResources(\n state: WranglerState,\n stateFile: string,\n cwd: string,\n runner: WranglerRunner,\n adoptExisting: boolean,\n): Promise<WranglerState> {\n const d1Name = `${state.name}-metadata`;\n const r2Name = `${state.name}-packages`;\n const configArgs = configArguments(stateFile, cwd);\n const configuredD1 = state.d1_databases.filter((database) => database.binding === d1Binding);\n const configuredR2 = state.r2_buckets.filter((bucket) => bucket.binding === r2Binding);\n const selectedD1 = configuredD1[0];\n const selectedR2 = configuredR2[0];\n if (\n configuredD1.length > 1 ||\n (selectedD1 !== undefined && selectedD1.database_name !== d1Name)\n ) {\n throw new Error(`${d1Binding} must reference the ${d1Name} D1 database`);\n }\n if (configuredR2.length > 1 || (selectedR2 !== undefined && selectedR2.bucket_name !== r2Name)) {\n throw new Error(`${r2Binding} must reference the ${r2Name} R2 bucket`);\n }\n\n if (configuredD1.length === 0) {\n const recovered = await recoverD1(runner, d1Name, configArgs);\n if (recovered !== null) {\n if (!adoptExisting) {\n throw new Error(\n `the ${d1Name} D1 database already exists; verify it, then rerun with --adopt-existing`,\n );\n }\n state.d1_databases.push(recovered);\n await writeState(stateFile, state);\n } else {\n await runner([\n \"d1\",\n \"create\",\n d1Name,\n \"--binding\",\n d1Binding,\n \"--update-config\",\n ...configArgs,\n ]);\n state = JSON.parse(await readFile(stateFile, \"utf8\")) as WranglerState;\n }\n }\n\n if (configuredR2.length === 0) {\n const recovered = await recoverR2(runner, r2Name, configArgs);\n if (recovered !== null) {\n if (!adoptExisting) {\n throw new Error(\n `the ${r2Name} R2 bucket already exists; verify it, then rerun with --adopt-existing`,\n );\n }\n state.r2_buckets.push(recovered);\n await writeState(stateFile, state);\n } else {\n await runner([\n \"r2\",\n \"bucket\",\n \"create\",\n r2Name,\n \"--binding\",\n r2Binding,\n \"--update-config\",\n ...configArgs,\n ]);\n state = JSON.parse(await readFile(stateFile, \"utf8\")) as WranglerState;\n }\n }\n\n state.d1_databases = state.d1_databases.map((database) =>\n database.binding === d1Binding ? { ...database, migrations_dir: \"migrations\" } : database,\n );\n await writeState(stateFile, state);\n return state;\n}\n\nfunction deploymentUrl(output: string, config: NormalizedConfig): string | null {\n if (config.hostname !== undefined) return `https://${config.hostname}`;\n return output.match(/https:\\/\\/[^\\s]+\\.workers\\.dev\\b/)?.[0] ?? null;\n}\n\nexport async function deploy(options: DeployOptions): Promise<DeployResult> {\n const cwd = resolve(options.cwd);\n const config = await loadConfig(cwd, options.configFile);\n const stateDirectory = join(cwd, stateDirectoryName);\n const stateFile = join(stateDirectory, stateFileName);\n const ownershipFile = join(stateDirectory, ownershipFileName);\n await mkdir(stateDirectory, { recursive: true });\n\n const previous = await readState(stateFile, config);\n const runner = options.runner ?? createWranglerRunner(cwd);\n const environmentAccountId = process.env.CLOUDFLARE_ACCOUNT_ID;\n const configuredAccountId = config.accountId ?? previous?.account_id;\n if (\n environmentAccountId !== undefined &&\n configuredAccountId !== undefined &&\n environmentAccountId !== configuredAccountId\n ) {\n throw new Error(\"CLOUDFLARE_ACCOUNT_ID does not match the configured deployment account\");\n }\n const accountId = await resolveAccountId(runner, configuredAccountId ?? environmentAccountId);\n const ownsWorker = await readWorkerOwnership(ownershipFile, config.name, accountId);\n let state = stateFor(config, accountId, previous);\n await writeState(stateFile, state);\n await copyRuntimeFiles(stateDirectory, options.assetsDirectory ?? packageRoot());\n\n state = await ensureResources(state, stateFile, cwd, runner, options.adoptExisting ?? false);\n const configArgs = configArguments(stateFile, cwd);\n await runner([\"d1\", \"migrations\", \"apply\", d1Binding, \"--remote\", ...configArgs]);\n\n const adoptedWorker = ownsWorker\n ? false\n : await verifyWorkerOwnership(state.name, configArgs, runner, options.adoptExisting ?? false);\n if (adoptedWorker) await writeWorkerOwnership(ownershipFile, state.name, accountId);\n\n const deployArguments = [\"deploy\", \"--no-bundle\", ...configArgs];\n if (options.secretsFile !== undefined) {\n deployArguments.push(\"--secrets-file\", options.secretsFile);\n }\n const deployed = await runner(deployArguments);\n if (!ownsWorker && !adoptedWorker)\n await writeWorkerOwnership(ownershipFile, state.name, accountId);\n return {\n registryUrl: deploymentUrl(deployed.stdout, config),\n stateFile,\n secretBindings: config.auth.tokens.map((token) => token.binding),\n scopes: config.scopes,\n };\n}\n","import { access } from \"node:fs/promises\";\nimport { resolve } from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\nimport { createJiti } from \"jiti\";\nimport { normalizeConfig, type NormalizedConfig } from \"../config.js\";\n\nexport const defaultConfigFile = \"pkgflare.config.ts\";\n\nexport async function loadConfig(\n cwd: string,\n configFile = defaultConfigFile,\n): Promise<NormalizedConfig> {\n const path = resolve(cwd, configFile);\n try {\n await access(path);\n } catch {\n throw new Error(`configuration file not found: ${configFile}`);\n }\n\n const jiti = createJiti(pathToFileURL(import.meta.url).href, {\n interopDefault: true,\n moduleCache: false,\n });\n const imported = await jiti.import(path, { default: true });\n return normalizeConfig(imported);\n}\n","export type Permission = \"read\" | \"publish\";\n\nexport interface SecretTokenConfig {\n binding: string;\n permissions: readonly Permission[];\n}\n\nexport interface GitHubOidcSubjectConfig {\n repositoryId: string;\n repositoryOwnerId: string;\n ref: string;\n workflowRef: string;\n jobWorkflowRef?: string;\n permissions: readonly Permission[];\n packages: readonly string[];\n}\n\nexport interface GitHubOidcConfig {\n audience: string;\n subjects: readonly GitHubOidcSubjectConfig[];\n}\n\nexport interface SecretsAuthConfig {\n provider: \"secrets\";\n tokens?: readonly SecretTokenConfig[];\n githubOidc?: GitHubOidcConfig;\n}\n\nexport interface PkgflareConfig {\n name: string;\n scopes: readonly string[];\n accountId?: string;\n hostname?: string;\n auth: SecretsAuthConfig;\n}\n\nexport interface NormalizedConfig {\n name: string;\n scopes: string[];\n accountId?: string;\n hostname?: string;\n auth: {\n provider: \"secrets\";\n tokens: Array<{\n binding: string;\n permissions: Permission[];\n }>;\n githubOidc?: {\n audience: string;\n subjects: Array<{\n repositoryId: string;\n repositoryOwnerId: string;\n ref: string;\n workflowRef: string;\n jobWorkflowRef?: string;\n permissions: Permission[];\n packages: string[];\n }>;\n };\n };\n}\n\nconst workerNamePattern = /^[a-z](?:[a-z0-9-]{0,52}[a-z0-9])?$/;\nconst accountIdPattern = /^[a-f0-9]{32}$/;\nconst scopePattern = /^@[a-z0-9](?:[a-z0-9._-]*[a-z0-9])?$/;\nconst bindingPattern = /^[A-Z][A-Z0-9_]*$/;\nconst hostnamePattern =\n /^(?=.{1,253}$)(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\\.)+[a-z](?:[a-z0-9-]{0,61}[a-z0-9])?$/;\nconst reservedBindings = new Set([\"PKGFLARE_DB\", \"PKGFLARE_BUCKET\", \"PKGFLARE_CONFIG\"]);\nconst githubIdPattern = /^[1-9][0-9]{0,19}$/;\nconst audiencePattern = /^[\\x21-\\x7e]{1,256}$/;\nconst refPattern = /^refs\\/(?:heads|tags)\\/[A-Za-z0-9._/-]+\\*?$/;\nconst workflowRefPattern =\n /^[A-Za-z0-9_.-]+\\/[A-Za-z0-9_.-]+\\/\\.github\\/workflows\\/[A-Za-z0-9_.-]+\\.ya?ml@refs\\/(?:heads|tags)\\/[A-Za-z0-9._/-]+\\*?$/;\nconst jobWorkflowRefPattern =\n /^[A-Za-z0-9_.-]+\\/[A-Za-z0-9_.-]+\\/\\.github\\/workflows\\/[A-Za-z0-9_.-]+\\.ya?ml@(?:refs\\/(?:heads|tags)\\/[A-Za-z0-9._/-]+\\*?|[0-9a-f]{40})$/;\nconst packageSegmentPattern = /^(?!\\.)(?:[a-z0-9._-]+)$/;\nconst maximumGithubSubjects = 128;\nconst maximumPackagesPerSubject = 128;\nconst maximumRuntimeConfigBytes = 5 * 1024;\n\nexport function defineConfig(config: PkgflareConfig): PkgflareConfig {\n return config;\n}\n\nfunction isObject(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction normalizePermissions(value: unknown, label: string): Permission[] {\n if (\n !Array.isArray(value) ||\n value.length === 0 ||\n value.some((permission) => permission !== \"read\" && permission !== \"publish\")\n ) {\n throw new Error(`invalid permissions for ${label}`);\n }\n return [...new Set(value)] as Permission[];\n}\n\nfunction isSafePattern(value: string, pattern: RegExp): boolean {\n if (!pattern.test(value)) return false;\n const wildcard = value.indexOf(\"*\");\n return wildcard === -1 || wildcard === value.length - 1;\n}\n\nfunction normalizeGithubOidc(\n value: unknown,\n configuredScopes: readonly string[],\n): NormalizedConfig[\"auth\"][\"githubOidc\"] {\n if (!isObject(value) || typeof value.audience !== \"string\") {\n throw new Error(\"githubOidc must define an audience and trusted subjects\");\n }\n if (!audiencePattern.test(value.audience)) {\n throw new Error(\"githubOidc audience must be 1-256 printable ASCII characters\");\n }\n if (\n !Array.isArray(value.subjects) ||\n value.subjects.length === 0 ||\n value.subjects.length > maximumGithubSubjects\n ) {\n throw new Error(`githubOidc must define 1-${String(maximumGithubSubjects)} subjects`);\n }\n\n const subjects = value.subjects.map((subjectValue, index) => {\n const label = `githubOidc subject ${String(index + 1)}`;\n if (!isObject(subjectValue)) throw new Error(`${label} must be an object`);\n const { repositoryId, repositoryOwnerId, ref, workflowRef, jobWorkflowRef } = subjectValue;\n if (typeof repositoryId !== \"string\" || !githubIdPattern.test(repositoryId)) {\n throw new Error(`${label} repositoryId must be a decimal GitHub repository ID`);\n }\n if (typeof repositoryOwnerId !== \"string\" || !githubIdPattern.test(repositoryOwnerId)) {\n throw new Error(`${label} repositoryOwnerId must be a decimal GitHub owner ID`);\n }\n if (typeof ref !== \"string\" || !isSafePattern(ref, refPattern)) {\n throw new Error(`${label} ref must be an exact branch/tag ref or trailing-wildcard pattern`);\n }\n if (typeof workflowRef !== \"string\" || !isSafePattern(workflowRef, workflowRefPattern)) {\n throw new Error(\n `${label} workflowRef must identify a workflow file at an exact or trailing-wildcard ref`,\n );\n }\n if (\n jobWorkflowRef !== undefined &&\n (typeof jobWorkflowRef !== \"string\" || !isSafePattern(jobWorkflowRef, jobWorkflowRefPattern))\n ) {\n throw new Error(\n `${label} jobWorkflowRef must identify a reusable workflow at a full commit SHA or an exact/trailing-wildcard branch or tag ref`,\n );\n }\n const permissions = normalizePermissions(subjectValue.permissions, label);\n if (\n !Array.isArray(subjectValue.packages) ||\n subjectValue.packages.length === 0 ||\n subjectValue.packages.length > maximumPackagesPerSubject ||\n subjectValue.packages.some((packageName) => typeof packageName !== \"string\")\n ) {\n throw new Error(\n `${label} must define 1-${String(maximumPackagesPerSubject)} package patterns`,\n );\n }\n const packages = [...new Set(subjectValue.packages as string[])];\n for (const packagePattern of packages) {\n const slash = packagePattern.indexOf(\"/\");\n const scope = packagePattern.slice(0, slash);\n const packageSegment = packagePattern.slice(slash + 1);\n if (\n slash === -1 ||\n packagePattern.length > 214 ||\n !configuredScopes.includes(scope) ||\n (packageSegment !== \"*\" && !packageSegmentPattern.test(packageSegment))\n ) {\n throw new Error(`${label} contains an invalid or unconfigured package pattern`);\n }\n }\n return {\n repositoryId,\n repositoryOwnerId,\n ref,\n workflowRef,\n ...(jobWorkflowRef === undefined ? {} : { jobWorkflowRef }),\n permissions,\n packages,\n };\n });\n return { audience: value.audience, subjects };\n}\n\nexport function normalizeConfig(value: unknown): NormalizedConfig {\n if (!isObject(value)) throw new Error(\"configuration must be an object\");\n const { name, scopes: scopeValues, accountId, hostname, auth } = value;\n if (typeof name !== \"string\" || !workerNamePattern.test(name)) {\n throw new Error(\"name must be a lowercase Cloudflare resource name of at most 54 characters\");\n }\n\n if (\n accountId !== undefined &&\n (typeof accountId !== \"string\" || !accountIdPattern.test(accountId))\n ) {\n throw new Error(\"accountId must be a 32-character lowercase hexadecimal Cloudflare account ID\");\n }\n\n if (\n !Array.isArray(scopeValues) ||\n scopeValues.length === 0 ||\n scopeValues.some((scope) => typeof scope !== \"string\")\n ) {\n throw new Error(\"at least one package scope is required\");\n }\n\n const scopes = [...new Set(scopeValues as string[])];\n for (const scope of scopes) {\n if (!scopePattern.test(scope)) {\n throw new Error(`invalid package scope: ${scope}`);\n }\n }\n\n if (hostname !== undefined && (typeof hostname !== \"string\" || !hostnamePattern.test(hostname))) {\n throw new Error(\"hostname must be a valid DNS hostname without a scheme or path\");\n }\n\n if (!isObject(auth) || auth.provider !== \"secrets\") {\n throw new Error(\"unsupported authentication provider\");\n }\n\n const tokenValues = auth.tokens ?? [];\n if (!Array.isArray(tokenValues)) {\n throw new Error(\"authentication token bindings must be an array\");\n }\n\n const seenBindings = new Set<string>();\n const tokens = tokenValues.map((tokenValue) => {\n if (!isObject(tokenValue) || typeof tokenValue.binding !== \"string\") {\n throw new Error(\"authentication token binding must be an object with a binding name\");\n }\n const { binding, permissions: permissionValues } = tokenValue;\n if (!bindingPattern.test(binding)) {\n throw new Error(`invalid secret binding: ${binding}`);\n }\n if (reservedBindings.has(binding)) {\n throw new Error(`secret binding is reserved by pkgflare: ${binding}`);\n }\n if (seenBindings.has(binding)) {\n throw new Error(`duplicate secret binding: ${binding}`);\n }\n seenBindings.add(binding);\n\n const permissions = normalizePermissions(permissionValues, binding);\n\n return { binding, permissions };\n });\n\n const githubOidc =\n auth.githubOidc === undefined ? undefined : normalizeGithubOidc(auth.githubOidc, scopes);\n if (tokens.length === 0 && githubOidc === undefined) {\n throw new Error(\"at least one authentication method is required\");\n }\n\n const normalized: NormalizedConfig = {\n name,\n scopes,\n ...(accountId === undefined ? {} : { accountId }),\n ...(hostname === undefined ? {} : { hostname }),\n auth: {\n provider: \"secrets\",\n tokens,\n ...(githubOidc === undefined ? {} : { githubOidc }),\n },\n };\n if (new TextEncoder().encode(JSON.stringify(normalized)).byteLength > maximumRuntimeConfigBytes) {\n throw new Error(\"normalized configuration exceeds the 5 KiB Worker variable limit\");\n }\n return normalized;\n}\n","import { spawn } from \"node:child_process\";\nimport { createRequire } from \"node:module\";\nimport { dirname, join } from \"node:path\";\n\nexport interface CommandResult {\n exitCode: number;\n stdout: string;\n stderr: string;\n}\n\nexport type WranglerRunner = (\n arguments_: readonly string[],\n options?: { allowFailure?: boolean; silent?: boolean },\n) => Promise<CommandResult>;\n\nfunction wranglerEntry(): string {\n const require = createRequire(import.meta.url);\n return join(dirname(require.resolve(\"wrangler/package.json\")), \"bin\", \"wrangler.js\");\n}\n\nexport function createWranglerRunner(cwd: string): WranglerRunner {\n return async (arguments_, options = {}) => {\n const result = await new Promise<CommandResult>((resolve, reject) => {\n const child = spawn(process.execPath, [wranglerEntry(), ...arguments_], {\n cwd,\n env: process.env,\n shell: false,\n stdio: [\"inherit\", \"pipe\", \"pipe\"],\n });\n let stdout = \"\";\n let stderr = \"\";\n child.stdout.setEncoding(\"utf8\");\n child.stderr.setEncoding(\"utf8\");\n child.stdout.on(\"data\", (chunk: string) => {\n stdout += chunk;\n if (!options.silent) process.stdout.write(chunk);\n });\n child.stderr.on(\"data\", (chunk: string) => {\n stderr += chunk;\n if (!options.silent) process.stderr.write(chunk);\n });\n child.once(\"error\", reject);\n child.once(\"close\", (code) => resolve({ exitCode: code ?? 1, stdout, stderr }));\n });\n\n if (result.exitCode !== 0 && !options.allowFailure) {\n const operation = arguments_.slice(0, 3).join(\" \");\n throw new Error(\n `Wrangler command ${JSON.stringify(operation)} exited with status ${String(result.exitCode)}`,\n );\n }\n return result;\n };\n}\n","async function readGithubTokenResponse(response: Response): Promise<string> {\n const maximumBytes = 32 * 1024;\n if (response.body === null) throw new Error(\"GitHub OIDC token response is empty\");\n const reader = response.body.getReader();\n const decoder = new TextDecoder(\"utf-8\", { fatal: true });\n let size = 0;\n let contents = \"\";\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n size += value.byteLength;\n if (size > maximumBytes) {\n await reader.cancel();\n throw new Error(\"GitHub OIDC token response is too large\");\n }\n contents += decoder.decode(value, { stream: true });\n }\n contents += decoder.decode();\n } finally {\n reader.releaseLock();\n }\n\n let value: unknown;\n try {\n value = JSON.parse(contents) as unknown;\n } catch {\n throw new Error(\"GitHub OIDC token response is invalid\");\n }\n if (\n typeof value !== \"object\" ||\n value === null ||\n !(\"value\" in value) ||\n typeof value.value !== \"string\" ||\n value.value.length > 16 * 1024 ||\n !/^[^.]+\\.[^.]+\\.[^.]+$/.test(value.value)\n ) {\n throw new Error(\"GitHub OIDC token response is invalid\");\n }\n return value.value;\n}\n\nexport async function requestGithubOidcToken(\n audience: string | undefined,\n environment: NodeJS.ProcessEnv = process.env,\n): Promise<string> {\n if (audience === undefined) throw new Error(\"--audience is required\");\n if (!/^[\\x21-\\x7e]{1,256}$/.test(audience)) {\n throw new Error(\"--audience must be 1-256 printable ASCII characters\");\n }\n const requestUrlValue = environment.ACTIONS_ID_TOKEN_REQUEST_URL;\n const requestToken = environment.ACTIONS_ID_TOKEN_REQUEST_TOKEN;\n if (requestUrlValue === undefined || requestToken === undefined || requestToken.length === 0) {\n throw new Error(\"GitHub Actions OIDC environment is unavailable\");\n }\n\n let requestUrl: URL;\n try {\n requestUrl = new URL(requestUrlValue);\n } catch {\n throw new Error(\"GitHub Actions OIDC request URL is invalid\");\n }\n if (\n requestUrl.protocol !== \"https:\" ||\n (requestUrl.hostname !== \"token.actions.githubusercontent.com\" &&\n !requestUrl.hostname.endsWith(\".actions.githubusercontent.com\")) ||\n requestUrl.username !== \"\" ||\n requestUrl.password !== \"\"\n ) {\n throw new Error(\"GitHub Actions OIDC request URL is not trusted\");\n }\n requestUrl.searchParams.set(\"audience\", audience);\n\n let response: Response;\n try {\n response = await fetch(requestUrl, {\n headers: { authorization: `bearer ${requestToken}` },\n redirect: \"error\",\n signal: AbortSignal.timeout(5000),\n });\n } catch {\n throw new Error(\"GitHub Actions OIDC token request failed\");\n }\n if (!response.ok) throw new Error(\"GitHub Actions OIDC token request failed\");\n return readGithubTokenResponse(response);\n}\n"],"mappings":"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","names":["relative","resolve","dirname","join","resolve","require","resolve","dirname","join","resolve","value","resolve","relative"]}
package/dist/index.d.ts CHANGED
@@ -3,9 +3,23 @@ interface SecretTokenConfig {
3
3
  binding: string;
4
4
  permissions: readonly Permission[];
5
5
  }
6
+ interface GitHubOidcSubjectConfig {
7
+ repositoryId: string;
8
+ repositoryOwnerId: string;
9
+ ref: string;
10
+ workflowRef: string;
11
+ jobWorkflowRef?: string;
12
+ permissions: readonly Permission[];
13
+ packages: readonly string[];
14
+ }
15
+ interface GitHubOidcConfig {
16
+ audience: string;
17
+ subjects: readonly GitHubOidcSubjectConfig[];
18
+ }
6
19
  interface SecretsAuthConfig {
7
20
  provider: "secrets";
8
- tokens: readonly SecretTokenConfig[];
21
+ tokens?: readonly SecretTokenConfig[];
22
+ githubOidc?: GitHubOidcConfig;
9
23
  }
10
24
  interface PkgflareConfig {
11
25
  name: string;
@@ -16,4 +30,4 @@ interface PkgflareConfig {
16
30
  }
17
31
  declare function defineConfig(config: PkgflareConfig): PkgflareConfig;
18
32
 
19
- export { type Permission, type PkgflareConfig, type SecretTokenConfig, type SecretsAuthConfig, defineConfig };
33
+ export { type GitHubOidcConfig, type GitHubOidcSubjectConfig, type Permission, type PkgflareConfig, type SecretTokenConfig, type SecretsAuthConfig, defineConfig };
package/dist/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  // src/config.ts
2
+ var maximumRuntimeConfigBytes = 5 * 1024;
2
3
  function defineConfig(config) {
3
4
  return config;
4
5
  }
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/config.ts"],"sourcesContent":["export type Permission = \"read\" | \"publish\";\n\nexport interface SecretTokenConfig {\n binding: string;\n permissions: readonly Permission[];\n}\n\nexport interface SecretsAuthConfig {\n provider: \"secrets\";\n tokens: readonly SecretTokenConfig[];\n}\n\nexport interface PkgflareConfig {\n name: string;\n scopes: readonly string[];\n accountId?: string;\n hostname?: string;\n auth: SecretsAuthConfig;\n}\n\nexport interface NormalizedConfig {\n name: string;\n scopes: string[];\n accountId?: string;\n hostname?: string;\n auth: {\n provider: \"secrets\";\n tokens: Array<{\n binding: string;\n permissions: Permission[];\n }>;\n };\n}\n\nconst workerNamePattern = /^[a-z](?:[a-z0-9-]{0,52}[a-z0-9])?$/;\nconst accountIdPattern = /^[a-f0-9]{32}$/;\nconst scopePattern = /^@[a-z0-9](?:[a-z0-9._-]*[a-z0-9])?$/;\nconst bindingPattern = /^[A-Z][A-Z0-9_]*$/;\nconst hostnamePattern =\n /^(?=.{1,253}$)(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\\.)+[a-z](?:[a-z0-9-]{0,61}[a-z0-9])?$/;\nconst reservedBindings = new Set([\"PKGFLARE_DB\", \"PKGFLARE_BUCKET\", \"PKGFLARE_CONFIG\"]);\n\nexport function defineConfig(config: PkgflareConfig): PkgflareConfig {\n return config;\n}\n\nfunction isObject(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nexport function normalizeConfig(value: unknown): NormalizedConfig {\n if (!isObject(value)) throw new Error(\"configuration must be an object\");\n const { name, scopes: scopeValues, accountId, hostname, auth } = value;\n if (typeof name !== \"string\" || !workerNamePattern.test(name)) {\n throw new Error(\"name must be a lowercase Cloudflare resource name of at most 54 characters\");\n }\n\n if (\n accountId !== undefined &&\n (typeof accountId !== \"string\" || !accountIdPattern.test(accountId))\n ) {\n throw new Error(\"accountId must be a 32-character lowercase hexadecimal Cloudflare account ID\");\n }\n\n if (\n !Array.isArray(scopeValues) ||\n scopeValues.length === 0 ||\n scopeValues.some((scope) => typeof scope !== \"string\")\n ) {\n throw new Error(\"at least one package scope is required\");\n }\n\n const scopes = [...new Set(scopeValues as string[])];\n for (const scope of scopes) {\n if (!scopePattern.test(scope)) {\n throw new Error(`invalid package scope: ${scope}`);\n }\n }\n\n if (hostname !== undefined && (typeof hostname !== \"string\" || !hostnamePattern.test(hostname))) {\n throw new Error(\"hostname must be a valid DNS hostname without a scheme or path\");\n }\n\n if (!isObject(auth) || auth.provider !== \"secrets\") {\n throw new Error(\"unsupported authentication provider\");\n }\n\n if (!Array.isArray(auth.tokens) || auth.tokens.length === 0) {\n throw new Error(\"at least one authentication token binding is required\");\n }\n\n const seenBindings = new Set<string>();\n const tokens = auth.tokens.map((tokenValue) => {\n if (!isObject(tokenValue) || typeof tokenValue.binding !== \"string\") {\n throw new Error(\"authentication token binding must be an object with a binding name\");\n }\n const { binding, permissions: permissionValues } = tokenValue;\n if (!bindingPattern.test(binding)) {\n throw new Error(`invalid secret binding: ${binding}`);\n }\n if (reservedBindings.has(binding)) {\n throw new Error(`secret binding is reserved by pkgflare: ${binding}`);\n }\n if (seenBindings.has(binding)) {\n throw new Error(`duplicate secret binding: ${binding}`);\n }\n seenBindings.add(binding);\n\n if (\n !Array.isArray(permissionValues) ||\n permissionValues.length === 0 ||\n permissionValues.some((permission) => permission !== \"read\" && permission !== \"publish\")\n ) {\n throw new Error(`invalid permissions for ${binding}`);\n }\n const permissions = [...new Set(permissionValues)] as Permission[];\n\n return { binding, permissions };\n });\n\n return {\n name,\n scopes,\n ...(accountId === undefined ? {} : { accountId }),\n ...(hostname === undefined ? {} : { hostname }),\n auth: { provider: \"secrets\", tokens },\n };\n}\n"],"mappings":";AA0CO,SAAS,aAAa,QAAwC;AACnE,SAAO;AACT;","names":[]}
1
+ {"version":3,"sources":["../src/config.ts"],"sourcesContent":["export type Permission = \"read\" | \"publish\";\n\nexport interface SecretTokenConfig {\n binding: string;\n permissions: readonly Permission[];\n}\n\nexport interface GitHubOidcSubjectConfig {\n repositoryId: string;\n repositoryOwnerId: string;\n ref: string;\n workflowRef: string;\n jobWorkflowRef?: string;\n permissions: readonly Permission[];\n packages: readonly string[];\n}\n\nexport interface GitHubOidcConfig {\n audience: string;\n subjects: readonly GitHubOidcSubjectConfig[];\n}\n\nexport interface SecretsAuthConfig {\n provider: \"secrets\";\n tokens?: readonly SecretTokenConfig[];\n githubOidc?: GitHubOidcConfig;\n}\n\nexport interface PkgflareConfig {\n name: string;\n scopes: readonly string[];\n accountId?: string;\n hostname?: string;\n auth: SecretsAuthConfig;\n}\n\nexport interface NormalizedConfig {\n name: string;\n scopes: string[];\n accountId?: string;\n hostname?: string;\n auth: {\n provider: \"secrets\";\n tokens: Array<{\n binding: string;\n permissions: Permission[];\n }>;\n githubOidc?: {\n audience: string;\n subjects: Array<{\n repositoryId: string;\n repositoryOwnerId: string;\n ref: string;\n workflowRef: string;\n jobWorkflowRef?: string;\n permissions: Permission[];\n packages: string[];\n }>;\n };\n };\n}\n\nconst workerNamePattern = /^[a-z](?:[a-z0-9-]{0,52}[a-z0-9])?$/;\nconst accountIdPattern = /^[a-f0-9]{32}$/;\nconst scopePattern = /^@[a-z0-9](?:[a-z0-9._-]*[a-z0-9])?$/;\nconst bindingPattern = /^[A-Z][A-Z0-9_]*$/;\nconst hostnamePattern =\n /^(?=.{1,253}$)(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\\.)+[a-z](?:[a-z0-9-]{0,61}[a-z0-9])?$/;\nconst reservedBindings = new Set([\"PKGFLARE_DB\", \"PKGFLARE_BUCKET\", \"PKGFLARE_CONFIG\"]);\nconst githubIdPattern = /^[1-9][0-9]{0,19}$/;\nconst audiencePattern = /^[\\x21-\\x7e]{1,256}$/;\nconst refPattern = /^refs\\/(?:heads|tags)\\/[A-Za-z0-9._/-]+\\*?$/;\nconst workflowRefPattern =\n /^[A-Za-z0-9_.-]+\\/[A-Za-z0-9_.-]+\\/\\.github\\/workflows\\/[A-Za-z0-9_.-]+\\.ya?ml@refs\\/(?:heads|tags)\\/[A-Za-z0-9._/-]+\\*?$/;\nconst jobWorkflowRefPattern =\n /^[A-Za-z0-9_.-]+\\/[A-Za-z0-9_.-]+\\/\\.github\\/workflows\\/[A-Za-z0-9_.-]+\\.ya?ml@(?:refs\\/(?:heads|tags)\\/[A-Za-z0-9._/-]+\\*?|[0-9a-f]{40})$/;\nconst packageSegmentPattern = /^(?!\\.)(?:[a-z0-9._-]+)$/;\nconst maximumGithubSubjects = 128;\nconst maximumPackagesPerSubject = 128;\nconst maximumRuntimeConfigBytes = 5 * 1024;\n\nexport function defineConfig(config: PkgflareConfig): PkgflareConfig {\n return config;\n}\n\nfunction isObject(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction normalizePermissions(value: unknown, label: string): Permission[] {\n if (\n !Array.isArray(value) ||\n value.length === 0 ||\n value.some((permission) => permission !== \"read\" && permission !== \"publish\")\n ) {\n throw new Error(`invalid permissions for ${label}`);\n }\n return [...new Set(value)] as Permission[];\n}\n\nfunction isSafePattern(value: string, pattern: RegExp): boolean {\n if (!pattern.test(value)) return false;\n const wildcard = value.indexOf(\"*\");\n return wildcard === -1 || wildcard === value.length - 1;\n}\n\nfunction normalizeGithubOidc(\n value: unknown,\n configuredScopes: readonly string[],\n): NormalizedConfig[\"auth\"][\"githubOidc\"] {\n if (!isObject(value) || typeof value.audience !== \"string\") {\n throw new Error(\"githubOidc must define an audience and trusted subjects\");\n }\n if (!audiencePattern.test(value.audience)) {\n throw new Error(\"githubOidc audience must be 1-256 printable ASCII characters\");\n }\n if (\n !Array.isArray(value.subjects) ||\n value.subjects.length === 0 ||\n value.subjects.length > maximumGithubSubjects\n ) {\n throw new Error(`githubOidc must define 1-${String(maximumGithubSubjects)} subjects`);\n }\n\n const subjects = value.subjects.map((subjectValue, index) => {\n const label = `githubOidc subject ${String(index + 1)}`;\n if (!isObject(subjectValue)) throw new Error(`${label} must be an object`);\n const { repositoryId, repositoryOwnerId, ref, workflowRef, jobWorkflowRef } = subjectValue;\n if (typeof repositoryId !== \"string\" || !githubIdPattern.test(repositoryId)) {\n throw new Error(`${label} repositoryId must be a decimal GitHub repository ID`);\n }\n if (typeof repositoryOwnerId !== \"string\" || !githubIdPattern.test(repositoryOwnerId)) {\n throw new Error(`${label} repositoryOwnerId must be a decimal GitHub owner ID`);\n }\n if (typeof ref !== \"string\" || !isSafePattern(ref, refPattern)) {\n throw new Error(`${label} ref must be an exact branch/tag ref or trailing-wildcard pattern`);\n }\n if (typeof workflowRef !== \"string\" || !isSafePattern(workflowRef, workflowRefPattern)) {\n throw new Error(\n `${label} workflowRef must identify a workflow file at an exact or trailing-wildcard ref`,\n );\n }\n if (\n jobWorkflowRef !== undefined &&\n (typeof jobWorkflowRef !== \"string\" || !isSafePattern(jobWorkflowRef, jobWorkflowRefPattern))\n ) {\n throw new Error(\n `${label} jobWorkflowRef must identify a reusable workflow at a full commit SHA or an exact/trailing-wildcard branch or tag ref`,\n );\n }\n const permissions = normalizePermissions(subjectValue.permissions, label);\n if (\n !Array.isArray(subjectValue.packages) ||\n subjectValue.packages.length === 0 ||\n subjectValue.packages.length > maximumPackagesPerSubject ||\n subjectValue.packages.some((packageName) => typeof packageName !== \"string\")\n ) {\n throw new Error(\n `${label} must define 1-${String(maximumPackagesPerSubject)} package patterns`,\n );\n }\n const packages = [...new Set(subjectValue.packages as string[])];\n for (const packagePattern of packages) {\n const slash = packagePattern.indexOf(\"/\");\n const scope = packagePattern.slice(0, slash);\n const packageSegment = packagePattern.slice(slash + 1);\n if (\n slash === -1 ||\n packagePattern.length > 214 ||\n !configuredScopes.includes(scope) ||\n (packageSegment !== \"*\" && !packageSegmentPattern.test(packageSegment))\n ) {\n throw new Error(`${label} contains an invalid or unconfigured package pattern`);\n }\n }\n return {\n repositoryId,\n repositoryOwnerId,\n ref,\n workflowRef,\n ...(jobWorkflowRef === undefined ? {} : { jobWorkflowRef }),\n permissions,\n packages,\n };\n });\n return { audience: value.audience, subjects };\n}\n\nexport function normalizeConfig(value: unknown): NormalizedConfig {\n if (!isObject(value)) throw new Error(\"configuration must be an object\");\n const { name, scopes: scopeValues, accountId, hostname, auth } = value;\n if (typeof name !== \"string\" || !workerNamePattern.test(name)) {\n throw new Error(\"name must be a lowercase Cloudflare resource name of at most 54 characters\");\n }\n\n if (\n accountId !== undefined &&\n (typeof accountId !== \"string\" || !accountIdPattern.test(accountId))\n ) {\n throw new Error(\"accountId must be a 32-character lowercase hexadecimal Cloudflare account ID\");\n }\n\n if (\n !Array.isArray(scopeValues) ||\n scopeValues.length === 0 ||\n scopeValues.some((scope) => typeof scope !== \"string\")\n ) {\n throw new Error(\"at least one package scope is required\");\n }\n\n const scopes = [...new Set(scopeValues as string[])];\n for (const scope of scopes) {\n if (!scopePattern.test(scope)) {\n throw new Error(`invalid package scope: ${scope}`);\n }\n }\n\n if (hostname !== undefined && (typeof hostname !== \"string\" || !hostnamePattern.test(hostname))) {\n throw new Error(\"hostname must be a valid DNS hostname without a scheme or path\");\n }\n\n if (!isObject(auth) || auth.provider !== \"secrets\") {\n throw new Error(\"unsupported authentication provider\");\n }\n\n const tokenValues = auth.tokens ?? [];\n if (!Array.isArray(tokenValues)) {\n throw new Error(\"authentication token bindings must be an array\");\n }\n\n const seenBindings = new Set<string>();\n const tokens = tokenValues.map((tokenValue) => {\n if (!isObject(tokenValue) || typeof tokenValue.binding !== \"string\") {\n throw new Error(\"authentication token binding must be an object with a binding name\");\n }\n const { binding, permissions: permissionValues } = tokenValue;\n if (!bindingPattern.test(binding)) {\n throw new Error(`invalid secret binding: ${binding}`);\n }\n if (reservedBindings.has(binding)) {\n throw new Error(`secret binding is reserved by pkgflare: ${binding}`);\n }\n if (seenBindings.has(binding)) {\n throw new Error(`duplicate secret binding: ${binding}`);\n }\n seenBindings.add(binding);\n\n const permissions = normalizePermissions(permissionValues, binding);\n\n return { binding, permissions };\n });\n\n const githubOidc =\n auth.githubOidc === undefined ? undefined : normalizeGithubOidc(auth.githubOidc, scopes);\n if (tokens.length === 0 && githubOidc === undefined) {\n throw new Error(\"at least one authentication method is required\");\n }\n\n const normalized: NormalizedConfig = {\n name,\n scopes,\n ...(accountId === undefined ? {} : { accountId }),\n ...(hostname === undefined ? {} : { hostname }),\n auth: {\n provider: \"secrets\",\n tokens,\n ...(githubOidc === undefined ? {} : { githubOidc }),\n },\n };\n if (new TextEncoder().encode(JSON.stringify(normalized)).byteLength > maximumRuntimeConfigBytes) {\n throw new Error(\"normalized configuration exceeds the 5 KiB Worker variable limit\");\n }\n return normalized;\n}\n"],"mappings":";AA+EA,IAAM,4BAA4B,IAAI;AAE/B,SAAS,aAAa,QAAwC;AACnE,SAAO;AACT;","names":[]}