@suluk/platform 0.5.0 → 0.5.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/plan.ts +23 -10
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@suluk/platform",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.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/plan.ts
CHANGED
|
@@ -78,7 +78,7 @@ export function planPlatform(input: PlatformManifest | Platform): PlatformPlan {
|
|
|
78
78
|
entry: buildEntry(services, manifest.opts, wiring, catalog, local),
|
|
79
79
|
provisionConfig: buildProvisionConfig(services, catalog),
|
|
80
80
|
packageJson: buildPackageJson(manifest.name, services, catalog, local),
|
|
81
|
-
tsconfig: buildTsconfig(),
|
|
81
|
+
tsconfig: buildTsconfig(local),
|
|
82
82
|
componentsJson: buildComponentsJson(),
|
|
83
83
|
envExample: buildEnvExample(env),
|
|
84
84
|
wranglerToml: buildWranglerToml(manifest.name, services, env, manifest.vars ?? {}),
|
|
@@ -586,13 +586,15 @@ export function mergePackageJson(baselineJson: string, existingJson: string | nu
|
|
|
586
586
|
return JSON.stringify(merged, null, 2) + "\n";
|
|
587
587
|
}
|
|
588
588
|
|
|
589
|
-
function buildTsconfig(): string {
|
|
589
|
+
function buildTsconfig(local = false): string {
|
|
590
590
|
return (
|
|
591
591
|
JSON.stringify(
|
|
592
592
|
{
|
|
593
593
|
compilerOptions: { module: "ESNext", target: "ESNext", moduleResolution: "bundler", types: ["node", "@cloudflare/workers-types"], skipLibCheck: true, strict: true, noEmit: true },
|
|
594
594
|
include: ["src", "provision.config.ts", "platform.config.ts"],
|
|
595
|
-
|
|
595
|
+
// src/dev.ts is a bun-only runtime file (bun:sqlite + Bun globals), NOT Worker code — exclude it from the Worker
|
|
596
|
+
// typecheck (it pulls @suluk/cloudflare/local, which the workers-types config can't type); it's boot-tested instead.
|
|
597
|
+
exclude: ["src/**/*.test.ts", ...(local ? ["src/dev.ts"] : [])], // the bun:test journeys harness runs under `bun test`, not the Worker build
|
|
596
598
|
},
|
|
597
599
|
null,
|
|
598
600
|
2,
|
|
@@ -694,24 +696,35 @@ function buildEntry(services: string[], opts?: Record<string, Record<string, unk
|
|
|
694
696
|
*/
|
|
695
697
|
function buildDevEntry(services: string[]): string {
|
|
696
698
|
const usesKv = services.includes("rate-credit");
|
|
697
|
-
const
|
|
699
|
+
const usesEmail = services.includes("email");
|
|
700
|
+
const usesBilling = services.includes("billing");
|
|
701
|
+
const localImports = ["d1FromSqlite", ...(usesKv ? ["jsonFileKvStore"] : []), ...(usesEmail ? ["jsonFileMailbox"] : []), "applyLocalSchema"];
|
|
702
|
+
const billingImport = usesBilling ? '\nimport { mockStripeFetch } from "@suluk/billing";' : "";
|
|
698
703
|
const kvBind = usesKv ? "\n RATE_CREDIT_KV: jsonFileKvStore(KV_PATH)," : "";
|
|
704
|
+
const mailboxBind = usesEmail ? "\n SULUK_MAILBOX_SINK: mailbox," : "";
|
|
705
|
+
// mock-until-keyed: only inject the Stripe fake when there is no real key (a provisioned app hits real Stripe).
|
|
706
|
+
const stripeInject = usesBilling
|
|
707
|
+
? '\nif (!env.STRIPE_SECRET_KEY) { env.STRIPE_SECRET_KEY = "sk_mock_local"; env.STRIPE_FETCH = mockStripeFetch(); }'
|
|
708
|
+
: "";
|
|
709
|
+
const mailboxRoute = usesEmail
|
|
710
|
+
? '\n// a dev-only inbox view of the emails the mock provider captured (never mounted on the deployed Worker).\napp.get("/api/email/dev/mailbox", async (c) => c.json(await mailbox.list()));\n'
|
|
711
|
+
: "";
|
|
699
712
|
return `// AUTO-GENERATED by @suluk/platform — the bun MOCK-PROVIDER dev server. Runs the wired app under bun with a
|
|
700
713
|
// bun:sqlite DB + JSON-file KV, so \`bun run dev\` works with ZERO Cloudflare account and no wrangler. A provider goes REAL
|
|
701
714
|
// the moment its key is present (mock-until-keyed): add real keys to .env.temp + \`bun run provision\` and this file uses
|
|
702
715
|
// them. NOTE: src/index.ts (the deployed Worker) imports NONE of these mocks — bun:sqlite never enters the Worker bundle.
|
|
703
716
|
import { app } from "./index";
|
|
704
717
|
import { Database } from "bun:sqlite";
|
|
705
|
-
import {
|
|
718
|
+
import { ${localImports.join(", ")} } from "@suluk/cloudflare/local";${billingImport}
|
|
706
719
|
import { loadEnvFile } from "@suluk/env/node";
|
|
707
720
|
|
|
708
|
-
const DB_PATH = process.env.SULUK_DB_PATH ?? ".suluk/dev.sqlite";${usesKv ? '\nconst KV_PATH = process.env.SULUK_KV_PATH ?? ".suluk/dev-kv.json";' : ""}
|
|
721
|
+
const DB_PATH = process.env.SULUK_DB_PATH ?? ".suluk/dev.sqlite";${usesKv ? '\nconst KV_PATH = process.env.SULUK_KV_PATH ?? ".suluk/dev-kv.json";' : ""}${usesEmail ? '\nconst MAILBOX_PATH = process.env.SULUK_MAILBOX_PATH ?? ".suluk/dev-mailbox.json";' : ""}
|
|
709
722
|
const PORT = Number(process.env.PORT ?? 8787);
|
|
710
723
|
|
|
711
724
|
const sqlite = new Database(DB_PATH, { create: true });
|
|
712
725
|
const tables = await applyLocalSchema(sqlite); // discover src/db/*.ts + create the tables from the drizzle schema
|
|
713
726
|
console.log(\`[suluk dev] sqlite \${DB_PATH} — \${tables.length} tables\`);
|
|
714
|
-
|
|
727
|
+
${usesEmail ? "const mailbox = jsonFileMailbox(MAILBOX_PATH); // a local inbox the mock email provider saves to\n" : ""}
|
|
715
728
|
// Real secrets (if this app has been provisioned): decrypt the committed .env with the local private key. Fresh app / no
|
|
716
729
|
// key → {} → every provider mocks. Best-effort: a decryption failure never blocks the mock path.
|
|
717
730
|
let secrets: Record<string, string> = {};
|
|
@@ -722,12 +735,12 @@ try { secrets = await loadEnvFile(); } catch {}
|
|
|
722
735
|
const env: Record<string, unknown> = {
|
|
723
736
|
...process.env,
|
|
724
737
|
...secrets,
|
|
725
|
-
DB: d1FromSqlite(sqlite),${kvBind}
|
|
738
|
+
DB: d1FromSqlite(sqlite),${kvBind}${mailboxBind}
|
|
726
739
|
};
|
|
727
740
|
|
|
728
741
|
const mocked = ["GOOGLE_CLIENT_ID", "STRIPE_SECRET_KEY", "RESEND_API_KEY"].filter((k) => !env[k]);
|
|
729
|
-
if (mocked.length) console.log(\`[suluk dev] mocked (no key): \${mocked.join(", ")}\`)
|
|
730
|
-
|
|
742
|
+
if (mocked.length) console.log(\`[suluk dev] mocked (no key): \${mocked.join(", ")}\`);${stripeInject}
|
|
743
|
+
${mailboxRoute}
|
|
731
744
|
const ctx = { waitUntil() {}, passThroughOnException() {} } as unknown as ExecutionContext;
|
|
732
745
|
Bun.serve({ port: PORT, idleTimeout: 120, fetch: (req) => app.fetch(req, env as Parameters<typeof app.fetch>[1], ctx) });
|
|
733
746
|
console.log(\`[suluk dev] → http://localhost:\${PORT} (mock-until-keyed; provision to go live)\`);
|