create-safest-tools 0.3.0 → 0.3.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
@@ -48,6 +48,8 @@ npm run setup
48
48
 
49
49
  After deployment, setup prints a 256-bit, single-use owner link that expires after 15 minutes. The raw token stays in the URL fragment, D1 stores only its digest, and the installer never writes it to disk. Open it to create the Safest owner account. If it expires, run `npm run owner:setup`. For later break-glass recovery, authenticate Wrangler and run `npm run owner:recover`.
50
50
 
51
+ Custom-domain installations disable both the Worker’s `workers.dev` route and version preview URLs. A `workers.dev` public URL is available only when explicitly supplied as the installation URL.
52
+
51
53
  The owner then invites administrators, and administrators invite analysts. All users sign in with Safest accounts and do not need Cloudflare accounts.
52
54
 
53
55
  Invited users may join with a password or any configured OAuth provider, then choose a natural display name and optional JPEG, PNG, or WebP profile picture up to 2 MB. Better Auth stores credentials, OAuth accounts, sessions, verification state, and one-time password-reset tokens in D1. Cloudflare Email Service sends invitations, verification links, and 30-minute password-reset links.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-safest-tools",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "description": "Create customer-owned abuse-reporting infrastructure on Cloudflare",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
package/src/config.mjs CHANGED
@@ -69,14 +69,15 @@ export function buildConfiguration(options) {
69
69
 
70
70
  export function buildWranglerConfiguration(config) {
71
71
  const publicHostname = new URL(config.publicBaseUrl).hostname.toLowerCase();
72
+ const usesWorkersDev = publicHostname.endsWith(".workers.dev");
72
73
  const wrangler = {
73
74
  $schema: "node_modules/wrangler/config-schema.json",
74
75
  name: config.resources.workerName,
75
76
  main: "src/index.ts",
76
77
  compatibility_date: "2026-08-28",
77
78
  compatibility_flags: ["nodejs_compat"],
78
- workers_dev: true,
79
- preview_urls: true,
79
+ workers_dev: usesWorkersDev,
80
+ preview_urls: false,
80
81
  observability: { enabled: true },
81
82
  ai: { binding: "AI", remote: true },
82
83
  assets: { directory: "public", binding: "ASSETS", run_worker_first: true },
@@ -131,7 +132,7 @@ export function buildWranglerConfiguration(config) {
131
132
  },
132
133
  triggers: { crons: ["*/5 * * * *"] },
133
134
  };
134
- if (!publicHostname.endsWith(".workers.dev")) {
135
+ if (!usesWorkersDev) {
135
136
  wrangler.routes = [{ pattern: publicHostname, custom_domain: true }];
136
137
  }
137
138
  wrangler.send_email = [{ name: "EMAIL" }];
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "safest-resolve-installation",
3
- "version": "0.3.0",
4
- "safestToolsVersion": "0.3.0-resolve",
3
+ "version": "0.3.1",
4
+ "safestToolsVersion": "0.3.1-resolve",
5
5
  "private": true,
6
6
  "license": "Apache-2.0",
7
7
  "type": "module",
@@ -13,11 +13,18 @@ function sqlLiteral(value) {
13
13
  return `'${String(value).replaceAll("'", "''")}'`;
14
14
  }
15
15
 
16
+ export function ownerSetupWranglerEnvironment(env = process.env) {
17
+ return { ...env, WRANGLER_LOG: "log", WRANGLER_WRITE_LOGS: "false" };
18
+ }
19
+
16
20
  function runWrangler(args) {
17
21
  return new Promise((resolvePromise, reject) => {
18
22
  const child = spawn(process.execPath, [wrangler, ...args], {
19
23
  cwd: projectRoot,
20
- env: { ...process.env, WRANGLER_LOG: "none", WRANGLER_WRITE_LOGS: "false" },
24
+ // Wrangler 4.127 emits `d1 execute --json` through its logger. Keep log
25
+ // output in the captured pipe while preventing the OAuth-backed response
26
+ // from being persisted to Wrangler's log directory.
27
+ env: ownerSetupWranglerEnvironment(),
21
28
  stdio: ["ignore", "pipe", "pipe"],
22
29
  });
23
30
  let stdout = "";
@@ -82,18 +89,26 @@ RETURNING id, email, purpose, expires_at;
82
89
  `.trim();
83
90
  }
84
91
 
85
- function executionRows(stdout) {
86
- let parsed;
87
- try { parsed = JSON.parse(stdout.trim()); } catch { throw new Error("Wrangler returned unreadable D1 JSON while creating the owner setup token"); }
88
- const results = Array.isArray(parsed) ? parsed : Array.isArray(parsed?.result) ? parsed.result : [parsed];
89
- return results.flatMap((entry) => Array.isArray(entry?.results) ? entry.results : []);
92
+ export function ownerSetupExecutionRows(output) {
93
+ const candidates = typeof output === "string" ? [output] : [output?.stdout, output?.stderr];
94
+ for (const candidate of candidates) {
95
+ if (typeof candidate !== "string" || !candidate.trim()) continue;
96
+ try {
97
+ const parsed = JSON.parse(candidate.trim());
98
+ const results = Array.isArray(parsed) ? parsed : Array.isArray(parsed?.result) ? parsed.result : [parsed];
99
+ return results.flatMap((entry) => Array.isArray(entry?.results) ? entry.results : []);
100
+ } catch {
101
+ // Try the other captured stream before reporting incompatible output.
102
+ }
103
+ }
104
+ throw new Error("Wrangler returned unreadable D1 JSON while creating the owner setup token");
90
105
  }
91
106
 
92
107
  export async function issueOwnerSetup({ config, email, purpose = "bootstrap", runner = runWrangler, now, token, id } = {}) {
93
108
  if (!config?.publicBaseUrl || !config?.owner?.email) throw new Error("owner setup requires a parsed Safest Resolve configuration");
94
109
  const record = createOwnerSetupRecord({ email: email || config.owner.email, purpose, now, token, id });
95
110
  const result = await runner(["d1", "execute", "DB", "--remote", "--command", ownerSetupSql(record), "--json", "--yes"]);
96
- const created = executionRows(result.stdout).find((row) => row?.id === record.id);
111
+ const created = ownerSetupExecutionRows(result).find((row) => row?.id === record.id);
97
112
  if (!created) {
98
113
  throw new Error(purpose === "bootstrap"
99
114
  ? "An active infrastructure owner already exists. Use `npm run owner:recover` for break-glass access."