@suluk/platform 0.3.1 → 0.3.2
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/package.json +1 -1
- package/src/generate.ts +1 -0
- package/src/plan.ts +47 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@suluk/platform",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.2",
|
|
4
4
|
"description": "The platform generator (C051): write one `definePlatform` manifest → it plans the shadcn-registry adds, generates the wired Hono entry, and merges each module's provision fragment into a single provision.config. The manifest compiles to a shadcn-add list + a C047 provision.config; the generator runs the adds + `@suluk/provision`. Turns the Suluk backend registry into a one-command platform. CANDIDATE tooling.",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
package/src/generate.ts
CHANGED
|
@@ -58,6 +58,7 @@ export async function generatePlatform(input: PlatformManifest | Platform, opts:
|
|
|
58
58
|
["scripts/env-check.ts", plan.envCheck, true], // the encrypted-env preflight
|
|
59
59
|
["src/env.ts", plan.envTs, true], // the @suluk/env declare-once (derived from the manifest's secrets)
|
|
60
60
|
["scripts/sync-secrets.ts", plan.syncSecrets, true], // the deploy-time secret push (derived)
|
|
61
|
+
["scripts/link-key.ts", plan.linkKey, true], // register the private key into ~/.suluk/settings.json (the central store)
|
|
61
62
|
[".env", plan.envScaffold, false], // the COMMITTED encrypted-secrets file — SCAFFOLD IF ABSENT (never clobber secrets)
|
|
62
63
|
] as const) {
|
|
63
64
|
if (always || (await read(file)) == null) {
|
package/src/plan.ts
CHANGED
|
@@ -36,6 +36,9 @@ export interface PlatformPlan {
|
|
|
36
36
|
/** the generated `scripts/sync-secrets.ts` — decrypt the cloudflare-surfaced secrets from the committed .env and push them
|
|
37
37
|
* as `wrangler secret`s (the toolfactory-exact deploy path; the alternative is the entry's runtime `loadEnv`). */
|
|
38
38
|
syncSecrets: string;
|
|
39
|
+
/** the generated `scripts/link-key.ts` — register the private key into the centralized `~/.suluk/settings.json` (the store
|
|
40
|
+
* `@suluk/env` reads by default for local dev/deploy/CI), the toolfactory model. */
|
|
41
|
+
linkKey: string;
|
|
39
42
|
/** the generated `.env` SCAFFOLD (committed) — a header + the setup steps, NO values. `generate` writes it only if absent
|
|
40
43
|
* (never clobbering the operator's encrypted secrets). Secret VALUES are added encrypted via `suluk-env set`. */
|
|
41
44
|
envScaffold: string;
|
|
@@ -71,6 +74,7 @@ export function planPlatform(input: PlatformManifest | Platform): PlatformPlan {
|
|
|
71
74
|
envCheck: buildEnvCheckScript(env),
|
|
72
75
|
envTs: buildEnvTs(env),
|
|
73
76
|
syncSecrets: buildSyncSecrets(),
|
|
77
|
+
linkKey: buildLinkKey(),
|
|
74
78
|
envScaffold: buildEnvScaffold(env),
|
|
75
79
|
};
|
|
76
80
|
}
|
|
@@ -87,7 +91,8 @@ function buildEnvExample(env: EnvVar[]): string {
|
|
|
87
91
|
const optional = secrets.filter((e) => !e.required);
|
|
88
92
|
return [
|
|
89
93
|
"# .env keys checklist (generated). The `.env` is COMMITTED with these values ENCRYPTED (@suluk/env, ML-KEM-768):",
|
|
90
|
-
"# bunx suluk-env keygen # once — keypair (SULUK_PUBLIC_KEY → .env; private → .env.keys
|
|
94
|
+
"# bunx suluk-env keygen # once — keypair (SULUK_PUBLIC_KEY → .env; private → .env.keys)",
|
|
95
|
+
"# bun run link-key # register the private key in ~/.suluk/settings.json (@suluk/env reads it by default)",
|
|
91
96
|
"# bunx suluk-env set KEY=value # per secret — encrypts it into .env",
|
|
92
97
|
"# Non-secret config lives in platform.config.ts `vars` (→ wrangler.toml [vars]), NOT here.",
|
|
93
98
|
"",
|
|
@@ -151,6 +156,43 @@ console.log(\`✓ synced \${names.length} secret(s) to the Worker.\`);
|
|
|
151
156
|
`;
|
|
152
157
|
}
|
|
153
158
|
|
|
159
|
+
/**
|
|
160
|
+
* `scripts/link-key.ts` — register THIS project's @suluk/env private key into the centralized `~/.suluk/settings.json`
|
|
161
|
+
* (keyed by the repo's absolute path), the toolfactory model. `readPrivateKey()` then resolves it from there BY DEFAULT
|
|
162
|
+
* (precedence: `SULUK_PRIVATE_KEY` env > `~/.suluk/settings.json` by path > legacy `.env.keys`), so local dev, deploy, and a
|
|
163
|
+
* CI worktree (which checks out the encrypted .env but not `.env.keys`, via `SULUK_PROJECT_DIR`) all decrypt from one store.
|
|
164
|
+
*/
|
|
165
|
+
function buildLinkKey(): string {
|
|
166
|
+
return `#!/usr/bin/env bun
|
|
167
|
+
// AUTO-GENERATED by @suluk/platform. Register this project's @suluk/env private key into ~/.suluk/settings.json (keyed by the
|
|
168
|
+
// repo path) — the central, out-of-git store @suluk/env reads by default. Run once after \`bunx suluk-env keygen\`; idempotent.
|
|
169
|
+
import { readFileSync, writeFileSync, mkdirSync } from "node:fs";
|
|
170
|
+
import { homedir } from "node:os";
|
|
171
|
+
import { join, dirname } from "node:path";
|
|
172
|
+
import { readPrivateKey } from "@suluk/env/node";
|
|
173
|
+
|
|
174
|
+
const repo = process.cwd();
|
|
175
|
+
const name = repo.split("/").filter(Boolean).pop() ?? "project";
|
|
176
|
+
const priv = readPrivateKey(); // SULUK_PRIVATE_KEY env > ~/.suluk/settings.json > .env.keys (legacy)
|
|
177
|
+
if (!priv) { console.error("✗ no private key — run \`bunx suluk-env keygen\` first"); process.exit(1); }
|
|
178
|
+
|
|
179
|
+
const settingsPath = process.env.SULUK_SETTINGS_PATH || join(homedir(), ".suluk", "settings.json");
|
|
180
|
+
type Proj = { name?: string; path?: string; env?: Array<{ key: string; value: string }> };
|
|
181
|
+
let data: { projects?: Proj[] } = {};
|
|
182
|
+
try { data = JSON.parse(readFileSync(settingsPath, "utf8")); } catch { /* fresh */ }
|
|
183
|
+
const projects: Proj[] = Array.isArray(data.projects) ? data.projects : [];
|
|
184
|
+
let entry = projects.find((p) => p.path === repo);
|
|
185
|
+
if (!entry) { entry = { name, path: repo, env: [] }; projects.push(entry); }
|
|
186
|
+
entry.name = name; entry.path = repo; entry.env = Array.isArray(entry.env) ? entry.env : [];
|
|
187
|
+
const existing = entry.env.find((e) => e.key === "SULUK_PRIVATE_KEY");
|
|
188
|
+
if (existing) existing.value = priv; else entry.env.push({ key: "SULUK_PRIVATE_KEY", value: priv });
|
|
189
|
+
data.projects = projects;
|
|
190
|
+
mkdirSync(dirname(settingsPath), { recursive: true });
|
|
191
|
+
writeFileSync(settingsPath, JSON.stringify(data, null, 2) + "\\n");
|
|
192
|
+
console.log(\`✓ linked \${name} → \${settingsPath}. You can now \\\`rm .env.keys\\\` — the key lives in the central store.\`);
|
|
193
|
+
`;
|
|
194
|
+
}
|
|
195
|
+
|
|
154
196
|
/**
|
|
155
197
|
* The `.env` SCAFFOLD — a header + setup steps, NO values (safe to commit). `generate` writes it ONLY IF ABSENT so it never
|
|
156
198
|
* clobbers the operator's encrypted secrets. Its presence also lets `src/index.ts`'s `import "../.env"` resolve on a fresh app.
|
|
@@ -160,7 +202,9 @@ function buildEnvScaffold(env: EnvVar[]): string {
|
|
|
160
202
|
return [
|
|
161
203
|
"# This file is COMMITTED. Secret VALUES are stored ENCRYPTED (@suluk/env, post-quantum ML-KEM-768) — safe to push to git.",
|
|
162
204
|
"# Setup:",
|
|
163
|
-
"# bunx suluk-env keygen # keypair: SULUK_PUBLIC_KEY here (commit); private key → .env.keys
|
|
205
|
+
"# bunx suluk-env keygen # keypair: SULUK_PUBLIC_KEY here (commit); private key → .env.keys",
|
|
206
|
+
"# bun run link-key # register the private key in ~/.suluk/settings.json (the central store @suluk/env",
|
|
207
|
+
"# # reads by DEFAULT for local dev/deploy/CI); then `rm .env.keys` if you like",
|
|
164
208
|
"# bunx suluk-env set BETTER_AUTH_SECRET=... # encrypts + adds each secret" + (required.length ? ` (required: ${required.map((e) => e.name).join(", ")})` : ""),
|
|
165
209
|
"# Get the secrets into the Worker EITHER way:",
|
|
166
210
|
"# • runtime: `wrangler secret put SULUK_PRIVATE_KEY` → src/index.ts decrypts this file on the first request",
|
|
@@ -314,6 +358,7 @@ export function buildPackageJson(name: string, services: string[], catalog: Reco
|
|
|
314
358
|
dev: "wrangler dev",
|
|
315
359
|
deploy: "wrangler deploy",
|
|
316
360
|
"env:keygen": "suluk-env keygen", // create the @suluk/env keypair (SULUK_PUBLIC_KEY → .env; private → .env.keys)
|
|
361
|
+
"link-key": "bun run scripts/link-key.ts", // register the private key in ~/.suluk/settings.json (the central store)
|
|
317
362
|
"env:set": "suluk-env set", // encrypt + add a secret: `bun run env:set BETTER_AUTH_SECRET=...`
|
|
318
363
|
"sync-secrets": "bun run scripts/sync-secrets.ts", // decrypt cloudflare-surfaced secrets → `wrangler secret put` each
|
|
319
364
|
typecheck: "tsc --noEmit -p .",
|