spfn 0.3.0-beta.6 → 0.3.0-beta.7
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 +6 -0
- package/dist/index.js +463 -280
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -948,7 +948,7 @@ import { dirname as dirname2, join as join10 } from "path";
|
|
|
948
948
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
949
949
|
function getCliVersion() {
|
|
950
950
|
if (true) {
|
|
951
|
-
return "0.3.0-beta.
|
|
951
|
+
return "0.3.0-beta.7";
|
|
952
952
|
}
|
|
953
953
|
return fromPackageJson ?? (fromPackageJson = readPackageVersion());
|
|
954
954
|
}
|
|
@@ -1190,6 +1190,7 @@ function envLocalTemplate(mode) {
|
|
|
1190
1190
|
# Full scaffold: auth session encryption (Next.js server only; never NEXT_PUBLIC_*)
|
|
1191
1191
|
SPFN_AUTH_SESSION_SECRET=${randomSecret("base64url")}
|
|
1192
1192
|
SPFN_AUTH_SESSION_TTL=7d
|
|
1193
|
+
${CSRF_ENV_LINES}
|
|
1193
1194
|
NEXT_PUBLIC_SPFN_APP_URL=http://localhost:3790
|
|
1194
1195
|
`;
|
|
1195
1196
|
}
|
|
@@ -1386,7 +1387,7 @@ function updateTsconfig(cwd) {
|
|
|
1386
1387
|
logger.warn('Could not update tsconfig.json (you can add "src/server" to exclude manually)');
|
|
1387
1388
|
}
|
|
1388
1389
|
}
|
|
1389
|
-
var writeFileSync8, ENV_LOCAL_TEMPLATE, FULL_ENV_LOCAL_EXAMPLE, ENV_SERVER_TEMPLATE, FULL_ENV_SERVER_EXAMPLE;
|
|
1390
|
+
var writeFileSync8, ENV_LOCAL_TEMPLATE, CSRF_ENV_LINES, FULL_ENV_LOCAL_EXAMPLE, ENV_SERVER_TEMPLATE, FULL_ENV_SERVER_EXAMPLE;
|
|
1390
1391
|
var init_config_files = __esm({
|
|
1391
1392
|
"src/commands/init/steps/config-files.ts"() {
|
|
1392
1393
|
"use strict";
|
|
@@ -1404,10 +1405,13 @@ NEXT_PUBLIC_SPFN_API_URL=http://localhost:8790
|
|
|
1404
1405
|
# Next.js app URL (used by the SPFN server for CORS/redirects)
|
|
1405
1406
|
SPFN_APP_URL=http://localhost:3790
|
|
1406
1407
|
`;
|
|
1408
|
+
CSRF_ENV_LINES = `# CSRF for cookie-session mutations: off | warn | enforce (unset = warn)
|
|
1409
|
+
SPFN_AUTH_CSRF=enforce`;
|
|
1407
1410
|
FULL_ENV_LOCAL_EXAMPLE = `
|
|
1408
1411
|
# Full scaffold: auth session encryption (Next.js server only; never NEXT_PUBLIC_*)
|
|
1409
1412
|
SPFN_AUTH_SESSION_SECRET=replace-with-a-random-secret-at-least-32-characters
|
|
1410
1413
|
SPFN_AUTH_SESSION_TTL=7d
|
|
1414
|
+
${CSRF_ENV_LINES}
|
|
1411
1415
|
NEXT_PUBLIC_SPFN_APP_URL=http://localhost:3790
|
|
1412
1416
|
`;
|
|
1413
1417
|
ENV_SERVER_TEMPLATE = `# SPFN backend environment
|
|
@@ -1981,16 +1985,182 @@ init_init();
|
|
|
1981
1985
|
|
|
1982
1986
|
// src/commands/dev.ts
|
|
1983
1987
|
init_logger();
|
|
1984
|
-
init_package_manager();
|
|
1985
1988
|
import { Command as Command4 } from "commander";
|
|
1986
|
-
import { existsSync as
|
|
1987
|
-
import { join as
|
|
1989
|
+
import { existsSync as existsSync16, readFileSync as readFileSync9, writeFileSync as writeFileSync11, mkdirSync, unlinkSync, rmSync, watch } from "fs";
|
|
1990
|
+
import { join as join17, relative, sep as sep2 } from "path";
|
|
1988
1991
|
import { execa as execa6 } from "execa";
|
|
1989
1992
|
import chokidar from "chokidar";
|
|
1990
1993
|
|
|
1994
|
+
// src/lib/agent-instructions.ts
|
|
1995
|
+
import { existsSync as existsSync15, readFileSync as readFileSync8, writeFileSync as writeFileSync10 } from "fs";
|
|
1996
|
+
import { join as join15 } from "path";
|
|
1997
|
+
|
|
1998
|
+
// src/lib/agent-instructions-template.ts
|
|
1999
|
+
init_version();
|
|
2000
|
+
var BEGIN_MARKER = "<!-- spfn:agent-instructions:begin \u2014 generated by spfn dev; edits inside are overwritten -->";
|
|
2001
|
+
var END_MARKER = "<!-- spfn:agent-instructions:end -->";
|
|
2002
|
+
function renderAgentInstructions(version = getCliVersion()) {
|
|
2003
|
+
return `${BEGIN_MARKER}
|
|
2004
|
+
## SPFN conventions for coding agents
|
|
2005
|
+
|
|
2006
|
+
This is not the stack you know. An SPFN app looks like Next.js plus Drizzle, but
|
|
2007
|
+
its idioms are not the ecosystem defaults, and code written from general priors
|
|
2008
|
+
is wrong here. Read the docs below before writing server, data or auth code.
|
|
2009
|
+
|
|
2010
|
+
**Data access.** Every query goes through a repository extending
|
|
2011
|
+
\`BaseRepository\` \u2014 \`this.db\` writes, \`this.readDb\` reads. Handlers and
|
|
2012
|
+
services never import drizzle query builders directly.
|
|
2013
|
+
|
|
2014
|
+
\`\`\`typescript
|
|
2015
|
+
import { BaseRepository } from '@spfn/core/db';
|
|
2016
|
+
import { orders } from '../entities/order.entity';
|
|
2017
|
+
|
|
2018
|
+
export class OrderRepository extends BaseRepository
|
|
2019
|
+
{
|
|
2020
|
+
async findByCustomer(customerId: bigint)
|
|
2021
|
+
{
|
|
2022
|
+
return this._findMany(orders, { where: { customerId } });
|
|
2023
|
+
}
|
|
2024
|
+
}
|
|
2025
|
+
\`\`\`
|
|
2026
|
+
|
|
2027
|
+
The scaffold's \`src/server/repositories/\` shows the shape.
|
|
2028
|
+
|
|
2029
|
+
**Transactions.** Wrap the route in \`Transactional()\`, or call
|
|
2030
|
+
\`runInTransaction\` in a service or script. Never accept or pass a \`tx\`
|
|
2031
|
+
parameter: repositories pick the transaction up from the async context. Side
|
|
2032
|
+
effects that must not fire on a rollback go in \`onAfterCommit(...)\`.
|
|
2033
|
+
|
|
2034
|
+
**Auth.** Read the principal with \`getAuth(c)\` from \`@spfn/auth/server\`.
|
|
2035
|
+
Authorization is declared route middleware \u2014
|
|
2036
|
+
\`.use([authenticate, requirePermissions('order:write')])\` \u2014 never an ad-hoc
|
|
2037
|
+
check inside the handler body.
|
|
2038
|
+
|
|
2039
|
+
**Frontend data.** A page's initial data is awaited in a Server Component
|
|
2040
|
+
through the isomorphic \`api.\` client; cookies forward automatically. Fetching
|
|
2041
|
+
initial data from a \`'use client'\` component in \`useEffect\` is the
|
|
2042
|
+
anti-pattern. Mutations go through server actions, or the same \`api.\` client
|
|
2043
|
+
from a Client Component.
|
|
2044
|
+
|
|
2045
|
+
**Generated files.** Route maps under \`src/generated/\` come from
|
|
2046
|
+
\`pnpm codegen\` \u2014 never hand-edit them. Migrations come from
|
|
2047
|
+
\`spfn db generate\` off the entities; never hand-write migration SQL.
|
|
2048
|
+
|
|
2049
|
+
**Read before writing.** \`node_modules/@spfn/core/README.md\`,
|
|
2050
|
+
\`node_modules/@spfn/core/src/db/README.md\`, \`node_modules/@spfn/auth/README.md\`.
|
|
2051
|
+
Online: \`https://superfunction.xyz/docs/packages/core/<module>\` for cache,
|
|
2052
|
+
codegen, config, db, env, errors, event, job, logger, middleware, nextjs, route,
|
|
2053
|
+
security and server; \`https://superfunction.xyz/docs/guides/<guide>\` for
|
|
2054
|
+
authentication, custom-generators, deployment, file-upload, monitoring and
|
|
2055
|
+
websockets. Do not guess other paths \u2014 they 404.
|
|
2056
|
+
|
|
2057
|
+
<!-- spfn CLI v${version} -->
|
|
2058
|
+
${END_MARKER}`;
|
|
2059
|
+
}
|
|
2060
|
+
|
|
2061
|
+
// src/lib/agent-instructions.ts
|
|
2062
|
+
var AGENTS_FILE = "AGENTS.md";
|
|
2063
|
+
var CLAUDE_FILE = "CLAUDE.md";
|
|
2064
|
+
function syncAgentInstructions(projectRoot, options = {}) {
|
|
2065
|
+
if (isOptedOut(options)) {
|
|
2066
|
+
return { action: "skipped" };
|
|
2067
|
+
}
|
|
2068
|
+
const agentsPath = join15(projectRoot, AGENTS_FILE);
|
|
2069
|
+
const block = renderAgentInstructions();
|
|
2070
|
+
if (!existsSync15(agentsPath)) {
|
|
2071
|
+
writeFileSync10(agentsPath, `${block}
|
|
2072
|
+
`, "utf8");
|
|
2073
|
+
ensureClaudeReference(projectRoot);
|
|
2074
|
+
return { action: "created" };
|
|
2075
|
+
}
|
|
2076
|
+
const content = withoutByteOrderMark(readFileSync8(agentsPath, "utf8"));
|
|
2077
|
+
const lines = content.split("\n");
|
|
2078
|
+
const location = locateBlock(lines);
|
|
2079
|
+
if (location.kind === "malformed") {
|
|
2080
|
+
return {
|
|
2081
|
+
action: "skipped",
|
|
2082
|
+
warning: `${AGENTS_FILE} has a malformed spfn block \u2014 expected exactly one "${BEGIN_MARKER}" line followed by one "${END_MARKER}" line. Fix or delete the markers; nothing was written.`
|
|
2083
|
+
};
|
|
2084
|
+
}
|
|
2085
|
+
ensureClaudeReference(projectRoot);
|
|
2086
|
+
if (location.kind === "absent") {
|
|
2087
|
+
const eol = content.includes("\r\n") ? "\r\n" : "\n";
|
|
2088
|
+
const existing = content.replace(/(\r?\n)+$/, "");
|
|
2089
|
+
const separator = existing.length > 0 ? `${eol}${eol}` : "";
|
|
2090
|
+
writeFileSync10(agentsPath, `${existing}${separator}${block.split("\n").join(eol)}${eol}`, "utf8");
|
|
2091
|
+
return { action: "appended" };
|
|
2092
|
+
}
|
|
2093
|
+
const carriageReturn = lines[location.begin].endsWith("\r") ? "\r" : "";
|
|
2094
|
+
const blockLines = block.split("\n").map((line) => line + carriageReturn);
|
|
2095
|
+
const currentLines = lines.slice(location.begin, location.end + 1);
|
|
2096
|
+
if (currentLines.length === blockLines.length && currentLines.every((line, index) => line === blockLines[index])) {
|
|
2097
|
+
return { action: "unchanged" };
|
|
2098
|
+
}
|
|
2099
|
+
lines.splice(location.begin, location.end - location.begin + 1, ...blockLines);
|
|
2100
|
+
writeFileSync10(agentsPath, lines.join("\n"), "utf8");
|
|
2101
|
+
return { action: "replaced" };
|
|
2102
|
+
}
|
|
2103
|
+
function isOptedOut(options) {
|
|
2104
|
+
const fromEnv = (process.env.SPFN_AGENT_FILES ?? "").toLowerCase();
|
|
2105
|
+
return options.agentFiles === false || fromEnv === "0" || fromEnv === "false";
|
|
2106
|
+
}
|
|
2107
|
+
function locateBlock(lines) {
|
|
2108
|
+
const fenced = fencedLines(lines);
|
|
2109
|
+
const begins = lineIndicesOf(lines, BEGIN_MARKER, fenced);
|
|
2110
|
+
const ends = lineIndicesOf(lines, END_MARKER, fenced);
|
|
2111
|
+
if (begins.length === 0 && ends.length === 0) {
|
|
2112
|
+
return { kind: "absent" };
|
|
2113
|
+
}
|
|
2114
|
+
if (begins.length !== 1 || ends.length !== 1 || ends[0] < begins[0]) {
|
|
2115
|
+
return { kind: "malformed" };
|
|
2116
|
+
}
|
|
2117
|
+
return { kind: "found", begin: begins[0], end: ends[0] };
|
|
2118
|
+
}
|
|
2119
|
+
function lineIndicesOf(lines, marker, fenced) {
|
|
2120
|
+
const found = [];
|
|
2121
|
+
lines.forEach((line, index) => {
|
|
2122
|
+
if (!fenced[index] && withoutCarriageReturn(line) === marker) {
|
|
2123
|
+
found.push(index);
|
|
2124
|
+
}
|
|
2125
|
+
});
|
|
2126
|
+
return found;
|
|
2127
|
+
}
|
|
2128
|
+
var FENCE_LINE = /^\s*(`{3,}|~{3,})(.*)$/;
|
|
2129
|
+
function fencedLines(lines) {
|
|
2130
|
+
let open = null;
|
|
2131
|
+
return lines.map((rawLine) => {
|
|
2132
|
+
const fence = FENCE_LINE.exec(withoutCarriageReturn(rawLine));
|
|
2133
|
+
if (open === null) {
|
|
2134
|
+
open = fence ? { character: fence[1][0], length: fence[1].length } : null;
|
|
2135
|
+
return false;
|
|
2136
|
+
}
|
|
2137
|
+
if (fence && fence[1][0] === open.character && fence[1].length >= open.length && fence[2].trim() === "") {
|
|
2138
|
+
open = null;
|
|
2139
|
+
}
|
|
2140
|
+
return true;
|
|
2141
|
+
});
|
|
2142
|
+
}
|
|
2143
|
+
function withoutCarriageReturn(line) {
|
|
2144
|
+
return line.endsWith("\r") ? line.slice(0, -1) : line;
|
|
2145
|
+
}
|
|
2146
|
+
function withoutByteOrderMark(content) {
|
|
2147
|
+
return content.startsWith("\uFEFF") ? content.slice(1) : content;
|
|
2148
|
+
}
|
|
2149
|
+
function ensureClaudeReference(projectRoot) {
|
|
2150
|
+
const claudePath = join15(projectRoot, CLAUDE_FILE);
|
|
2151
|
+
if (existsSync15(claudePath)) {
|
|
2152
|
+
return;
|
|
2153
|
+
}
|
|
2154
|
+
writeFileSync10(claudePath, `@${AGENTS_FILE}
|
|
2155
|
+
`, "utf8");
|
|
2156
|
+
}
|
|
2157
|
+
|
|
2158
|
+
// src/commands/dev.ts
|
|
2159
|
+
init_package_manager();
|
|
2160
|
+
|
|
1991
2161
|
// src/utils/secret-store/index.ts
|
|
1992
2162
|
init_env_file();
|
|
1993
|
-
import { join as
|
|
2163
|
+
import { join as join16 } from "path";
|
|
1994
2164
|
|
|
1995
2165
|
// src/utils/secret-store/macos.ts
|
|
1996
2166
|
import { execa as execa4 } from "execa";
|
|
@@ -2177,7 +2347,7 @@ function keychainRef(key) {
|
|
|
2177
2347
|
return `${KEYCHAIN_REF_PREFIX}${keychainName(key)}`;
|
|
2178
2348
|
}
|
|
2179
2349
|
async function resolveKeychainEnv(cwd) {
|
|
2180
|
-
const parsed = parseEnvFile(
|
|
2350
|
+
const parsed = parseEnvFile(join16(cwd, ".env.server"));
|
|
2181
2351
|
const refs = Object.entries(parsed).filter(([, value]) => value.startsWith(KEYCHAIN_REF_PREFIX));
|
|
2182
2352
|
if (refs.length === 0) {
|
|
2183
2353
|
return { env: {}, missing: [] };
|
|
@@ -2205,33 +2375,45 @@ import { loadAppConfig, resolvePorts, resolveHost } from "@spfn/core/app-config"
|
|
|
2205
2375
|
function ignoreDotfilesUnder(root) {
|
|
2206
2376
|
return (watchedPath) => relative(root, watchedPath).split(sep2).some((segment) => segment.startsWith(".") && segment !== "." && segment !== "..");
|
|
2207
2377
|
}
|
|
2378
|
+
function writeAgentInstructions(cwd, agentFiles) {
|
|
2379
|
+
try {
|
|
2380
|
+
const { action, warning } = syncAgentInstructions(cwd, { agentFiles });
|
|
2381
|
+
if (warning) {
|
|
2382
|
+
logger.warn(`[SPFN] ${warning}`);
|
|
2383
|
+
} else if (action !== "unchanged" && action !== "skipped") {
|
|
2384
|
+
logger.info(`[SPFN] Agent instructions ${action} in AGENTS.md`);
|
|
2385
|
+
}
|
|
2386
|
+
} catch (error) {
|
|
2387
|
+
logger.warn(`[SPFN] Could not write the agent instruction files (AGENTS.md, CLAUDE.md): ${error instanceof Error ? error.message : String(error)}`);
|
|
2388
|
+
}
|
|
2389
|
+
}
|
|
2208
2390
|
function waitForReadyFile(filePath, timeoutMs = 3e4) {
|
|
2209
2391
|
return new Promise((resolve4, reject) => {
|
|
2210
|
-
if (
|
|
2392
|
+
if (existsSync16(filePath)) {
|
|
2211
2393
|
unlinkSync(filePath);
|
|
2212
2394
|
}
|
|
2213
2395
|
const timer = setTimeout(() => {
|
|
2214
2396
|
watcher.close();
|
|
2215
2397
|
reject(new Error(`Server did not become ready within ${timeoutMs / 1e3}s`));
|
|
2216
2398
|
}, timeoutMs);
|
|
2217
|
-
const dir =
|
|
2399
|
+
const dir = join17(filePath, "..");
|
|
2218
2400
|
const fileName = filePath.split("/").pop();
|
|
2219
2401
|
const watcher = watch(dir, (_event, name) => {
|
|
2220
|
-
if (name === fileName &&
|
|
2402
|
+
if (name === fileName && existsSync16(filePath)) {
|
|
2221
2403
|
watcher.close();
|
|
2222
2404
|
clearTimeout(timer);
|
|
2223
|
-
resolve4(
|
|
2405
|
+
resolve4(readFileSync9(filePath, "utf-8").trim());
|
|
2224
2406
|
}
|
|
2225
2407
|
});
|
|
2226
2408
|
});
|
|
2227
2409
|
}
|
|
2228
|
-
var devCommand = new Command4("dev").description("Start SPFN development server (detects and runs Next.js + Hono)").option("-p, --port <port>", "Server port").option("-H, --host <host>", "Server host").option("--server-only", "Run only Hono server (skip Next.js)").option("--watch", "Enable hot reload (watch mode)").option("--allow-pending-migrations", "Start even when migrations are pending (they are listed as a warning)").action(async (options) => {
|
|
2410
|
+
var devCommand = new Command4("dev").description("Start SPFN development server (detects and runs Next.js + Hono)").option("-p, --port <port>", "Server port").option("-H, --host <host>", "Server host").option("--server-only", "Run only Hono server (skip Next.js)").option("--watch", "Enable hot reload (watch mode)").option("--allow-pending-migrations", "Start even when migrations are pending (they are listed as a warning)").option("--no-agent-files", "Do not write the SPFN instruction block into AGENTS.md (same as SPFN_AGENT_FILES=0)").action(async (options) => {
|
|
2229
2411
|
process.setMaxListeners(20);
|
|
2230
2412
|
if (!process.env.NODE_ENV) {
|
|
2231
2413
|
process.env.NODE_ENV = "development";
|
|
2232
2414
|
}
|
|
2233
2415
|
const cwd = process.cwd();
|
|
2234
|
-
const serverDir =
|
|
2416
|
+
const serverDir = join17(cwd, "src", "server");
|
|
2235
2417
|
if (options.port) {
|
|
2236
2418
|
process.env.SPFN_PORT = String(options.port);
|
|
2237
2419
|
}
|
|
@@ -2241,11 +2423,12 @@ var devCommand = new Command4("dev").description("Start SPFN development server
|
|
|
2241
2423
|
const appConfig = await loadAppConfig(cwd);
|
|
2242
2424
|
const { next: nextPort, server: serverPort } = resolvePorts(appConfig);
|
|
2243
2425
|
const serverHost = resolveHost(appConfig);
|
|
2244
|
-
if (!
|
|
2426
|
+
if (!existsSync16(serverDir)) {
|
|
2245
2427
|
logger.error("src/server directory not found.");
|
|
2246
2428
|
logger.info('Run "spfn init" first to initialize SPFN in your project.');
|
|
2247
2429
|
process.exit(1);
|
|
2248
2430
|
}
|
|
2431
|
+
writeAgentInstructions(cwd, options.agentFiles !== false);
|
|
2249
2432
|
const { env: keychainEnv, missing: keychainMissing } = await resolveKeychainEnv(cwd);
|
|
2250
2433
|
const injectedCount = Object.keys(keychainEnv).length;
|
|
2251
2434
|
if (injectedCount > 0) {
|
|
@@ -2267,28 +2450,28 @@ var devCommand = new Command4("dev").description("Start SPFN development server
|
|
|
2267
2450
|
if (migrationCheck.allowPending) {
|
|
2268
2451
|
serverEnv.SPFN_ALLOW_PENDING_MIGRATIONS = "true";
|
|
2269
2452
|
}
|
|
2270
|
-
const packageJsonPath =
|
|
2453
|
+
const packageJsonPath = join17(cwd, "package.json");
|
|
2271
2454
|
let hasNext = false;
|
|
2272
|
-
if (
|
|
2273
|
-
const packageJson = JSON.parse(
|
|
2455
|
+
if (existsSync16(packageJsonPath)) {
|
|
2456
|
+
const packageJson = JSON.parse(readFileSync9(packageJsonPath, "utf-8"));
|
|
2274
2457
|
hasNext = !!(packageJson.dependencies?.next || packageJson.devDependencies?.next);
|
|
2275
2458
|
}
|
|
2276
|
-
const tempDir =
|
|
2277
|
-
const serverEntry =
|
|
2278
|
-
const watcherEntry =
|
|
2459
|
+
const tempDir = join17(cwd, ".spfn");
|
|
2460
|
+
const serverEntry = join17(tempDir, "server.mjs");
|
|
2461
|
+
const watcherEntry = join17(tempDir, "watcher.mjs");
|
|
2279
2462
|
mkdirSync(tempDir, { recursive: true });
|
|
2280
|
-
const serverBuildDir =
|
|
2281
|
-
if (
|
|
2463
|
+
const serverBuildDir = join17(tempDir, "server");
|
|
2464
|
+
if (existsSync16(serverBuildDir)) {
|
|
2282
2465
|
rmSync(serverBuildDir, { recursive: true, force: true });
|
|
2283
2466
|
logger.info("[SPFN] Cleaned stale build cache (.spfn/server)");
|
|
2284
2467
|
}
|
|
2285
|
-
const readySignal =
|
|
2286
|
-
if (
|
|
2468
|
+
const readySignal = join17(tempDir, "server-ready");
|
|
2469
|
+
if (existsSync16(readySignal)) {
|
|
2287
2470
|
unlinkSync(readySignal);
|
|
2288
2471
|
}
|
|
2289
2472
|
const configParts = ["debug: true"];
|
|
2290
|
-
const readyFile =
|
|
2291
|
-
|
|
2473
|
+
const readyFile = join17(tempDir, "server-ready");
|
|
2474
|
+
writeFileSync11(serverEntry, `
|
|
2292
2475
|
import { writeFileSync } from 'fs';
|
|
2293
2476
|
|
|
2294
2477
|
// Load environment variables FIRST (before any imports that depend on them)
|
|
@@ -2304,7 +2487,7 @@ const instance = await startServer({
|
|
|
2304
2487
|
// Signal ready with actual port
|
|
2305
2488
|
writeFileSync(${JSON.stringify(readyFile)}, String(instance.config.port));
|
|
2306
2489
|
`);
|
|
2307
|
-
|
|
2490
|
+
writeFileSync11(watcherEntry, `
|
|
2308
2491
|
// Load environment variables
|
|
2309
2492
|
// const { loadEnvFiles } = await import('@spfn/core/server');
|
|
2310
2493
|
// loadEnvFiles();
|
|
@@ -2575,8 +2758,8 @@ catch (error)
|
|
|
2575
2758
|
init_logger();
|
|
2576
2759
|
init_package_manager();
|
|
2577
2760
|
import { Command as Command5 } from "commander";
|
|
2578
|
-
import { existsSync as
|
|
2579
|
-
import { join as
|
|
2761
|
+
import { existsSync as existsSync17, writeFileSync as writeFileSync12, mkdirSync as mkdirSync2, readdirSync } from "fs";
|
|
2762
|
+
import { join as join18 } from "path";
|
|
2580
2763
|
import { execa as execa7 } from "execa";
|
|
2581
2764
|
import ora5 from "ora";
|
|
2582
2765
|
import chalk7 from "chalk";
|
|
@@ -2603,16 +2786,16 @@ async function buildProject(options) {
|
|
|
2603
2786
|
}
|
|
2604
2787
|
const cwd = process.cwd();
|
|
2605
2788
|
const pm = detectPackageManager(cwd);
|
|
2606
|
-
const packageJsonPath =
|
|
2789
|
+
const packageJsonPath = join18(cwd, "package.json");
|
|
2607
2790
|
let hasNext = false;
|
|
2608
|
-
if (
|
|
2791
|
+
if (existsSync17(packageJsonPath)) {
|
|
2609
2792
|
const packageJson = JSON.parse(await import("fs").then(
|
|
2610
2793
|
(fs5) => fs5.promises.readFile(packageJsonPath, "utf-8")
|
|
2611
2794
|
));
|
|
2612
2795
|
hasNext = !!(packageJson.dependencies?.next || packageJson.devDependencies?.next);
|
|
2613
2796
|
}
|
|
2614
|
-
const serverDir =
|
|
2615
|
-
const hasServer =
|
|
2797
|
+
const serverDir = join18(cwd, "src", "server");
|
|
2798
|
+
const hasServer = existsSync17(serverDir);
|
|
2616
2799
|
console.log(chalk7.blue.bold("\n\u{1F3D7}\uFE0F Building SPFN project for production...\n"));
|
|
2617
2800
|
if (hasServer) {
|
|
2618
2801
|
const spinner = ora5("Generating API client...").start();
|
|
@@ -2654,10 +2837,10 @@ async function buildProject(options) {
|
|
|
2654
2837
|
if (hasServer && !options.nextOnly) {
|
|
2655
2838
|
const spinner = ora5("Building SPFN server...").start();
|
|
2656
2839
|
try {
|
|
2657
|
-
const outputDir =
|
|
2840
|
+
const outputDir = join18(cwd, ".spfn", "server");
|
|
2658
2841
|
mkdirSync2(outputDir, { recursive: true });
|
|
2659
|
-
const serverDir2 =
|
|
2660
|
-
if (!
|
|
2842
|
+
const serverDir2 = join18(cwd, "src", "server");
|
|
2843
|
+
if (!existsSync17(serverDir2)) {
|
|
2661
2844
|
spinner.fail("SPFN server build failed");
|
|
2662
2845
|
logger.error("src/server/ directory not found");
|
|
2663
2846
|
logger.error('Please run "spfn init" to initialize the project.');
|
|
@@ -2691,12 +2874,12 @@ async function buildProject(options) {
|
|
|
2691
2874
|
onSuccess: async () => {
|
|
2692
2875
|
}
|
|
2693
2876
|
});
|
|
2694
|
-
const prodServerPath =
|
|
2877
|
+
const prodServerPath = join18(cwd, ".spfn", "prod-server.mjs");
|
|
2695
2878
|
const prodServerContent = renderProdServerEntry();
|
|
2696
|
-
|
|
2879
|
+
writeFileSync12(prodServerPath, prodServerContent);
|
|
2697
2880
|
spinner.succeed(`SPFN server build completed \u2192 .spfn/server`);
|
|
2698
|
-
const routesDir =
|
|
2699
|
-
if (
|
|
2881
|
+
const routesDir = join18(cwd, ".spfn", "server", "routes");
|
|
2882
|
+
if (existsSync17(routesDir)) {
|
|
2700
2883
|
console.log();
|
|
2701
2884
|
console.log(chalk7.bold("Route (api)"));
|
|
2702
2885
|
try {
|
|
@@ -2752,8 +2935,8 @@ var buildCommand = new Command5("build").description("Build SPFN project for pro
|
|
|
2752
2935
|
init_logger();
|
|
2753
2936
|
init_package_manager();
|
|
2754
2937
|
import { Command as Command6 } from "commander";
|
|
2755
|
-
import { existsSync as
|
|
2756
|
-
import { join as
|
|
2938
|
+
import { existsSync as existsSync18, readFileSync as readFileSync10 } from "fs";
|
|
2939
|
+
import { join as join19 } from "path";
|
|
2757
2940
|
import { execa as execa8 } from "execa";
|
|
2758
2941
|
import chalk8 from "chalk";
|
|
2759
2942
|
import { loadAppConfig as loadAppConfig2, resolvePorts as resolvePorts2 } from "@spfn/core/app-config";
|
|
@@ -2762,16 +2945,16 @@ var startCommand = new Command6("start").description("Start SPFN production serv
|
|
|
2762
2945
|
process.env.NODE_ENV = "production";
|
|
2763
2946
|
}
|
|
2764
2947
|
const cwd = process.cwd();
|
|
2765
|
-
const packageJsonPath =
|
|
2948
|
+
const packageJsonPath = join19(cwd, "package.json");
|
|
2766
2949
|
let hasNext = false;
|
|
2767
|
-
if (
|
|
2768
|
-
const packageJson = JSON.parse(
|
|
2950
|
+
if (existsSync18(packageJsonPath)) {
|
|
2951
|
+
const packageJson = JSON.parse(readFileSync10(packageJsonPath, "utf-8"));
|
|
2769
2952
|
hasNext = !!(packageJson.dependencies?.next || packageJson.devDependencies?.next);
|
|
2770
2953
|
}
|
|
2771
|
-
const builtServerDir =
|
|
2772
|
-
const hasBuiltServer =
|
|
2773
|
-
const nextBuildDir =
|
|
2774
|
-
const hasNextBuild =
|
|
2954
|
+
const builtServerDir = join19(cwd, ".spfn", "server");
|
|
2955
|
+
const hasBuiltServer = existsSync18(builtServerDir);
|
|
2956
|
+
const nextBuildDir = join19(cwd, ".next");
|
|
2957
|
+
const hasNextBuild = existsSync18(nextBuildDir);
|
|
2775
2958
|
if (!options.nextOnly && !hasBuiltServer) {
|
|
2776
2959
|
logger.error('.spfn/server directory not found. Please run "spfn build" first.');
|
|
2777
2960
|
process.exit(1);
|
|
@@ -2781,8 +2964,8 @@ var startCommand = new Command6("start").description("Start SPFN production serv
|
|
|
2781
2964
|
process.exit(1);
|
|
2782
2965
|
}
|
|
2783
2966
|
const pm = detectPackageManager(cwd);
|
|
2784
|
-
const serverEntry =
|
|
2785
|
-
if (!
|
|
2967
|
+
const serverEntry = join19(cwd, ".spfn", "prod-server.mjs");
|
|
2968
|
+
if (!existsSync18(serverEntry)) {
|
|
2786
2969
|
logger.error('.spfn/prod-server.mjs not found. Please run "spfn build" first.');
|
|
2787
2970
|
process.exit(1);
|
|
2788
2971
|
}
|
|
@@ -2864,8 +3047,8 @@ var startCommand = new Command6("start").description("Start SPFN production serv
|
|
|
2864
3047
|
init_logger();
|
|
2865
3048
|
init_package_manager();
|
|
2866
3049
|
import { Command as Command7 } from "commander";
|
|
2867
|
-
import { existsSync as
|
|
2868
|
-
import { join as
|
|
3050
|
+
import { existsSync as existsSync19, mkdirSync as mkdirSync3, writeFileSync as writeFileSync13 } from "fs";
|
|
3051
|
+
import { join as join20 } from "path";
|
|
2869
3052
|
import { pathToFileURL } from "url";
|
|
2870
3053
|
import { execa as execa9 } from "execa";
|
|
2871
3054
|
var CONFIG_FILE_PATHS = [
|
|
@@ -2875,7 +3058,7 @@ var CONFIG_FILE_PATHS = [
|
|
|
2875
3058
|
"src/server/server.config.js"
|
|
2876
3059
|
];
|
|
2877
3060
|
function findServerConfig(cwd) {
|
|
2878
|
-
return CONFIG_FILE_PATHS.map((path5) =>
|
|
3061
|
+
return CONFIG_FILE_PATHS.map((path5) => join20(cwd, path5)).find(existsSync19);
|
|
2879
3062
|
}
|
|
2880
3063
|
var provisionCommand = new Command7("provision").description("Run deploy-time provisioning (seed/RBAC lifecycle hooks) \u2014 once per deploy, not per cold start").action(async () => {
|
|
2881
3064
|
if (!process.env.NODE_ENV) {
|
|
@@ -2896,10 +3079,10 @@ var provisionCommand = new Command7("provision").description("Run deploy-time pr
|
|
|
2896
3079
|
if (keychainMissing.length > 0) {
|
|
2897
3080
|
logger.warn(`[SPFN] Could not resolve keychain secret(s): ${keychainMissing.join(", ")} \u2014 run \`spfn secret set <KEY>\``);
|
|
2898
3081
|
}
|
|
2899
|
-
const tempDir =
|
|
2900
|
-
const runnerEntry =
|
|
3082
|
+
const tempDir = join20(cwd, ".spfn");
|
|
3083
|
+
const runnerEntry = join20(tempDir, "provision.mjs");
|
|
2901
3084
|
mkdirSync3(tempDir, { recursive: true });
|
|
2902
|
-
|
|
3085
|
+
writeFileSync13(runnerEntry, `
|
|
2903
3086
|
if (!process.env.NODE_ENV)
|
|
2904
3087
|
{
|
|
2905
3088
|
process.env.NODE_ENV = 'production';
|
|
@@ -2942,13 +3125,13 @@ process.exit(0);
|
|
|
2942
3125
|
// src/commands/codegen.ts
|
|
2943
3126
|
init_logger();
|
|
2944
3127
|
import { Command as Command8 } from "commander";
|
|
2945
|
-
import { existsSync as
|
|
2946
|
-
import { join as
|
|
3128
|
+
import { existsSync as existsSync20, writeFileSync as writeFileSync14 } from "fs";
|
|
3129
|
+
import { join as join21 } from "path";
|
|
2947
3130
|
import chalk9 from "chalk";
|
|
2948
3131
|
async function initCodegen(options) {
|
|
2949
3132
|
const cwd = process.cwd();
|
|
2950
|
-
const rcPath =
|
|
2951
|
-
if (
|
|
3133
|
+
const rcPath = join21(cwd, ".spfnrc.ts");
|
|
3134
|
+
if (existsSync20(rcPath)) {
|
|
2952
3135
|
logger.warn(".spfnrc.ts already exists");
|
|
2953
3136
|
logger.info("Edit manually to add custom generators");
|
|
2954
3137
|
process.exit(0);
|
|
@@ -2973,7 +3156,7 @@ export default defineConfig({
|
|
|
2973
3156
|
],
|
|
2974
3157
|
});
|
|
2975
3158
|
`;
|
|
2976
|
-
|
|
3159
|
+
writeFileSync14(rcPath, content);
|
|
2977
3160
|
console.log("\n" + chalk9.green.bold("\u2713 Created .spfnrc.ts\n"));
|
|
2978
3161
|
console.log(chalk9.gray("Configured the @spfn/core:route-map generator."));
|
|
2979
3162
|
if (options.withExample) {
|
|
@@ -3041,18 +3224,18 @@ codegenCommand.command("run").description("Run code generators once (no watch mo
|
|
|
3041
3224
|
// src/commands/contract.ts
|
|
3042
3225
|
init_logger();
|
|
3043
3226
|
import { Command as Command9 } from "commander";
|
|
3044
|
-
import { join as
|
|
3227
|
+
import { join as join22 } from "path";
|
|
3045
3228
|
import chalk10 from "chalk";
|
|
3046
3229
|
async function resolveContractsDir(cwd, override) {
|
|
3047
3230
|
if (override) {
|
|
3048
|
-
return
|
|
3231
|
+
return join22(cwd, override);
|
|
3049
3232
|
}
|
|
3050
3233
|
const { loadCodegenConfig } = await import("@spfn/core/codegen");
|
|
3051
3234
|
const config = loadCodegenConfig(cwd);
|
|
3052
3235
|
const generator = config.generators?.find(
|
|
3053
3236
|
(entry) => "name" in entry && entry.name === "@spfn/core:contract"
|
|
3054
3237
|
);
|
|
3055
|
-
return
|
|
3238
|
+
return join22(cwd, generator?.outputDir ?? "./contracts");
|
|
3056
3239
|
}
|
|
3057
3240
|
async function regenerate(cwd) {
|
|
3058
3241
|
const { loadCodegenConfig, createGeneratorsFromConfig, CodegenOrchestrator } = await import("@spfn/core/codegen");
|
|
@@ -3320,7 +3503,7 @@ import { Command as Command11 } from "commander";
|
|
|
3320
3503
|
import chalk13 from "chalk";
|
|
3321
3504
|
|
|
3322
3505
|
// src/commands/db/utils/drizzle.ts
|
|
3323
|
-
import { existsSync as
|
|
3506
|
+
import { existsSync as existsSync21, writeFileSync as writeFileSync15, unlinkSync as unlinkSync2 } from "fs";
|
|
3324
3507
|
import { spawn } from "child_process";
|
|
3325
3508
|
import { pathToFileURL as pathToFileURL2 } from "url";
|
|
3326
3509
|
import chalk12 from "chalk";
|
|
@@ -3387,7 +3570,7 @@ function validateDatabasePrerequisites() {
|
|
|
3387
3570
|
}
|
|
3388
3571
|
}
|
|
3389
3572
|
async function runDrizzleCommand(command) {
|
|
3390
|
-
const hasUserConfig =
|
|
3573
|
+
const hasUserConfig = existsSync21("./drizzle.config.ts");
|
|
3391
3574
|
const tempConfigPath = `./drizzle.config.${process.pid}.${Date.now()}.temp.ts`;
|
|
3392
3575
|
const configPath = hasUserConfig ? "./drizzle.config.ts" : tempConfigPath;
|
|
3393
3576
|
if (!hasUserConfig) {
|
|
@@ -3406,7 +3589,7 @@ async function runDrizzleCommand(command) {
|
|
|
3406
3589
|
expandGlobs: true,
|
|
3407
3590
|
autoDetectSchemas: true
|
|
3408
3591
|
});
|
|
3409
|
-
|
|
3592
|
+
writeFileSync15(tempConfigPath, configContent);
|
|
3410
3593
|
console.log(chalk12.dim("Using auto-generated Drizzle config\n"));
|
|
3411
3594
|
}
|
|
3412
3595
|
const args = command.split(" ");
|
|
@@ -3419,7 +3602,7 @@ async function runDrizzleCommand(command) {
|
|
|
3419
3602
|
env: shouldRelaxDbTls(env2.DATABASE_URL) ? { ...process.env, NODE_TLS_REJECT_UNAUTHORIZED: "0" } : { ...process.env }
|
|
3420
3603
|
});
|
|
3421
3604
|
const cleanup = () => {
|
|
3422
|
-
if (!hasUserConfig &&
|
|
3605
|
+
if (!hasUserConfig && existsSync21(tempConfigPath)) {
|
|
3423
3606
|
unlinkSync2(tempConfigPath);
|
|
3424
3607
|
}
|
|
3425
3608
|
};
|
|
@@ -3739,8 +3922,8 @@ async function applyFunctionMigrations(plans) {
|
|
|
3739
3922
|
|
|
3740
3923
|
// src/commands/db/migrate.ts
|
|
3741
3924
|
import chalk21 from "chalk";
|
|
3742
|
-
import { join as
|
|
3743
|
-
import { existsSync as
|
|
3925
|
+
import { join as join23 } from "path";
|
|
3926
|
+
import { existsSync as existsSync23 } from "fs";
|
|
3744
3927
|
|
|
3745
3928
|
// src/commands/db/backup.ts
|
|
3746
3929
|
import { promises as fs3 } from "fs";
|
|
@@ -3833,7 +4016,7 @@ function formatTimestamp() {
|
|
|
3833
4016
|
|
|
3834
4017
|
// src/commands/db/utils/backup-files.ts
|
|
3835
4018
|
import { promises as fs2 } from "fs";
|
|
3836
|
-
import { existsSync as
|
|
4019
|
+
import { existsSync as existsSync22 } from "fs";
|
|
3837
4020
|
import path2 from "path";
|
|
3838
4021
|
import chalk19 from "chalk";
|
|
3839
4022
|
|
|
@@ -3933,7 +4116,7 @@ async function ensureBackupInGitignore() {
|
|
|
3933
4116
|
const gitignorePath = path2.join(process.cwd(), ".gitignore");
|
|
3934
4117
|
try {
|
|
3935
4118
|
let content = "";
|
|
3936
|
-
let exists =
|
|
4119
|
+
let exists = existsSync22(gitignorePath);
|
|
3937
4120
|
if (exists) {
|
|
3938
4121
|
content = await fs2.readFile(gitignorePath, "utf-8");
|
|
3939
4122
|
}
|
|
@@ -3955,7 +4138,7 @@ async function ensureBackupDir() {
|
|
|
3955
4138
|
try {
|
|
3956
4139
|
await fs2.mkdir(backupDir, { recursive: true });
|
|
3957
4140
|
const gitignorePath = path2.join(backupDir, ".gitignore");
|
|
3958
|
-
const gitignoreExists =
|
|
4141
|
+
const gitignoreExists = existsSync22(gitignorePath);
|
|
3959
4142
|
if (!gitignoreExists) {
|
|
3960
4143
|
await fs2.writeFile(gitignorePath, "# Ignore all backup files\n*.sql\n*.dump\n*.meta.json\n");
|
|
3961
4144
|
}
|
|
@@ -4149,8 +4332,8 @@ async function dbMigrate(options = {}) {
|
|
|
4149
4332
|
await executeFunctionMigrations2(loadFunctionMigrationPlans2(functions));
|
|
4150
4333
|
console.log(chalk21.green("\u2705 Function migrations applied\n"));
|
|
4151
4334
|
}
|
|
4152
|
-
const projectMigrationsDir =
|
|
4153
|
-
if (
|
|
4335
|
+
const projectMigrationsDir = join23(process.cwd(), "src/server/drizzle");
|
|
4336
|
+
if (existsSync23(projectMigrationsDir)) {
|
|
4154
4337
|
const projConn = postgres.default(env5.DATABASE_URL, { max: 1 });
|
|
4155
4338
|
const projDb = drizzle({ client: projConn });
|
|
4156
4339
|
try {
|
|
@@ -4256,7 +4439,7 @@ function printReport(report2) {
|
|
|
4256
4439
|
|
|
4257
4440
|
// src/commands/db/studio.ts
|
|
4258
4441
|
import chalk23 from "chalk";
|
|
4259
|
-
import { existsSync as
|
|
4442
|
+
import { existsSync as existsSync24, writeFileSync as writeFileSync16, unlinkSync as unlinkSync3 } from "fs";
|
|
4260
4443
|
import { spawn as spawn3 } from "child_process";
|
|
4261
4444
|
import { env as env6 } from "@spfn/core/config";
|
|
4262
4445
|
async function dbStudio(requestedPort) {
|
|
@@ -4274,7 +4457,7 @@ async function dbStudio(requestedPort) {
|
|
|
4274
4457
|
console.error(chalk23.red(error instanceof Error ? error.message : "Failed to find available port"));
|
|
4275
4458
|
process.exit(1);
|
|
4276
4459
|
}
|
|
4277
|
-
const hasUserConfig =
|
|
4460
|
+
const hasUserConfig = existsSync24("./drizzle.config.ts");
|
|
4278
4461
|
const tempConfigPath = `./drizzle.config.${process.pid}.${Date.now()}.temp.ts`;
|
|
4279
4462
|
try {
|
|
4280
4463
|
const configPath = hasUserConfig ? "./drizzle.config.ts" : tempConfigPath;
|
|
@@ -4291,7 +4474,7 @@ async function dbStudio(requestedPort) {
|
|
|
4291
4474
|
expandGlobs: true
|
|
4292
4475
|
// Expand glob patterns for Studio compatibility
|
|
4293
4476
|
});
|
|
4294
|
-
|
|
4477
|
+
writeFileSync16(tempConfigPath, configContent);
|
|
4295
4478
|
console.log(chalk23.dim("Using auto-generated Drizzle config\n"));
|
|
4296
4479
|
}
|
|
4297
4480
|
const studioProcess = spawn3("drizzle-kit", ["studio", `--port=${port}`, `--config=${configPath}`], {
|
|
@@ -4300,7 +4483,7 @@ async function dbStudio(requestedPort) {
|
|
|
4300
4483
|
env: shouldRelaxDbTls(env6.DATABASE_URL) ? { ...process.env, NODE_TLS_REJECT_UNAUTHORIZED: "0" } : { ...process.env }
|
|
4301
4484
|
});
|
|
4302
4485
|
const cleanup = () => {
|
|
4303
|
-
if (!hasUserConfig &&
|
|
4486
|
+
if (!hasUserConfig && existsSync24(tempConfigPath)) {
|
|
4304
4487
|
unlinkSync3(tempConfigPath);
|
|
4305
4488
|
}
|
|
4306
4489
|
};
|
|
@@ -4330,7 +4513,7 @@ async function dbStudio(requestedPort) {
|
|
|
4330
4513
|
process.exit(0);
|
|
4331
4514
|
});
|
|
4332
4515
|
} catch (error) {
|
|
4333
|
-
if (!hasUserConfig &&
|
|
4516
|
+
if (!hasUserConfig && existsSync24(tempConfigPath)) {
|
|
4334
4517
|
unlinkSync3(tempConfigPath);
|
|
4335
4518
|
}
|
|
4336
4519
|
console.error(chalk23.red("\u274C Failed to start Drizzle Studio"));
|
|
@@ -4717,8 +4900,8 @@ async function dbBackupClean(options) {
|
|
|
4717
4900
|
}
|
|
4718
4901
|
|
|
4719
4902
|
// src/commands/db/reindex.ts
|
|
4720
|
-
import { existsSync as
|
|
4721
|
-
import { join as
|
|
4903
|
+
import { existsSync as existsSync25, readFileSync as readFileSync11, writeFileSync as writeFileSync17, renameSync, copyFileSync } from "fs";
|
|
4904
|
+
import { join as join24 } from "path";
|
|
4722
4905
|
import chalk29 from "chalk";
|
|
4723
4906
|
import { loadEnv as loadEnv9 } from "@spfn/core/server";
|
|
4724
4907
|
function isTimestampPrefix(tag) {
|
|
@@ -4740,13 +4923,13 @@ async function dbReindex(options = {}) {
|
|
|
4740
4923
|
const { getDrizzleConfig } = await import("@spfn/core/db");
|
|
4741
4924
|
const config = getDrizzleConfig({ disablePackageDiscovery: true });
|
|
4742
4925
|
const outDir = config.out;
|
|
4743
|
-
const journalPath =
|
|
4744
|
-
if (!
|
|
4926
|
+
const journalPath = join24(outDir, "meta", "_journal.json");
|
|
4927
|
+
if (!existsSync25(journalPath)) {
|
|
4745
4928
|
console.error(chalk29.red("\u274C No _journal.json found at:"), journalPath);
|
|
4746
4929
|
console.log(chalk29.yellow("\u{1F4A1} Run `spfn db generate` first to create migrations"));
|
|
4747
4930
|
process.exit(1);
|
|
4748
4931
|
}
|
|
4749
|
-
const journal = JSON.parse(
|
|
4932
|
+
const journal = JSON.parse(readFileSync11(journalPath, "utf-8"));
|
|
4750
4933
|
if (journal.entries.length === 0) {
|
|
4751
4934
|
console.log(chalk29.yellow("No migration entries found \u2014 nothing to reindex."));
|
|
4752
4935
|
return;
|
|
@@ -4762,14 +4945,14 @@ async function dbReindex(options = {}) {
|
|
|
4762
4945
|
const { prefix: oldPrefix, suffix } = parseTag(entry.tag);
|
|
4763
4946
|
const newPrefix = String(entry.when);
|
|
4764
4947
|
const newTag = suffix ? `${newPrefix}_${suffix}` : newPrefix;
|
|
4765
|
-
const oldSql =
|
|
4766
|
-
const newSql =
|
|
4767
|
-
if (
|
|
4948
|
+
const oldSql = join24(outDir, `${entry.tag}.sql`);
|
|
4949
|
+
const newSql = join24(outDir, `${newTag}.sql`);
|
|
4950
|
+
if (existsSync25(oldSql)) {
|
|
4768
4951
|
renames.push({ type: "sql", from: oldSql, to: newSql });
|
|
4769
4952
|
}
|
|
4770
|
-
const oldSnapshot =
|
|
4771
|
-
const newSnapshot =
|
|
4772
|
-
if (
|
|
4953
|
+
const oldSnapshot = join24(outDir, "meta", `${oldPrefix}_snapshot.json`);
|
|
4954
|
+
const newSnapshot = join24(outDir, "meta", `${newPrefix}_snapshot.json`);
|
|
4955
|
+
if (existsSync25(oldSnapshot)) {
|
|
4773
4956
|
renames.push({ type: "snapshot", from: oldSnapshot, to: newSnapshot });
|
|
4774
4957
|
}
|
|
4775
4958
|
tagUpdates.push({ idx: entry.idx, oldTag: entry.tag, newTag });
|
|
@@ -4812,7 +4995,7 @@ async function dbReindex(options = {}) {
|
|
|
4812
4995
|
entry.tag = update.newTag;
|
|
4813
4996
|
}
|
|
4814
4997
|
}
|
|
4815
|
-
|
|
4998
|
+
writeFileSync17(journalPath, JSON.stringify(journal, null, 2) + "\n");
|
|
4816
4999
|
console.log(chalk29.green(`
|
|
4817
5000
|
\u2705 Reindex complete \u2014 ${tagUpdates.length} migration(s) converted to timestamp prefix.`));
|
|
4818
5001
|
}
|
|
@@ -4835,21 +5018,21 @@ dbCommand.command("reindex").description("Convert migration files from sequentia
|
|
|
4835
5018
|
// src/commands/add.ts
|
|
4836
5019
|
init_package_manager();
|
|
4837
5020
|
import { Command as Command12 } from "commander";
|
|
4838
|
-
import { existsSync as
|
|
4839
|
-
import { join as
|
|
5021
|
+
import { existsSync as existsSync27, readFileSync as readFileSync13 } from "fs";
|
|
5022
|
+
import { join as join26 } from "path";
|
|
4840
5023
|
import { execa as execa10 } from "execa";
|
|
4841
5024
|
import chalk31 from "chalk";
|
|
4842
5025
|
import ora11 from "ora";
|
|
4843
5026
|
|
|
4844
5027
|
// src/commands/add-vercel.ts
|
|
4845
5028
|
init_templates();
|
|
4846
|
-
import { copyFileSync as copyFileSync2, existsSync as
|
|
4847
|
-
import { dirname as dirname4, join as
|
|
5029
|
+
import { copyFileSync as copyFileSync2, existsSync as existsSync26, mkdirSync as mkdirSync4, readFileSync as readFileSync12 } from "fs";
|
|
5030
|
+
import { dirname as dirname4, join as join25 } from "path";
|
|
4848
5031
|
import chalk30 from "chalk";
|
|
4849
5032
|
var FILES = [
|
|
4850
5033
|
{
|
|
4851
5034
|
template: "route.ts",
|
|
4852
|
-
target:
|
|
5035
|
+
target: join25("src", "app", "api", "backend", "[[...route]]", "route.ts"),
|
|
4853
5036
|
description: "hono/vercel adapter (mounts the SPFN app under /api/backend)"
|
|
4854
5037
|
},
|
|
4855
5038
|
{
|
|
@@ -4864,7 +5047,7 @@ var FILES = [
|
|
|
4864
5047
|
}
|
|
4865
5048
|
];
|
|
4866
5049
|
function registryEnvValue(templatesDir) {
|
|
4867
|
-
const scopeLines =
|
|
5050
|
+
const scopeLines = readFileSync12(join25(templatesDir, "npmrc"), "utf8").trim();
|
|
4868
5051
|
const registryUrl = scopeLines.split("\n")[0].split("=")[1];
|
|
4869
5052
|
const authKey = `${registryUrl.replace(/^https?:/, "").replace(/\/*$/, "/")}:_authToken`;
|
|
4870
5053
|
return [
|
|
@@ -4877,15 +5060,15 @@ function registryEnvValue(templatesDir) {
|
|
|
4877
5060
|
async function addVercel() {
|
|
4878
5061
|
console.log(chalk30.blue("\n\u{1F4E6} Setting up the Vercel serverless target...\n"));
|
|
4879
5062
|
const cwd = process.cwd();
|
|
4880
|
-
const templatesDir =
|
|
5063
|
+
const templatesDir = join25(findTemplatesPath(), "vercel");
|
|
4881
5064
|
for (const file of FILES) {
|
|
4882
|
-
const targetPath =
|
|
4883
|
-
if (
|
|
5065
|
+
const targetPath = join25(cwd, file.target);
|
|
5066
|
+
if (existsSync26(targetPath)) {
|
|
4884
5067
|
console.log(chalk30.yellow(`\u23ED\uFE0F ${file.target} already exists \u2014 skipped (not overwritten)`));
|
|
4885
5068
|
continue;
|
|
4886
5069
|
}
|
|
4887
5070
|
mkdirSync4(dirname4(targetPath), { recursive: true });
|
|
4888
|
-
copyFileSync2(
|
|
5071
|
+
copyFileSync2(join25(templatesDir, file.template), targetPath);
|
|
4889
5072
|
console.log(chalk30.green(`\u2705 ${file.target}`) + chalk30.gray(` \u2014 ${file.description}`));
|
|
4890
5073
|
}
|
|
4891
5074
|
console.log(chalk30.green("\n\u2705 Vercel target ready!\n"));
|
|
@@ -4930,9 +5113,9 @@ async function addPackage(packageName) {
|
|
|
4930
5113
|
console.log(chalk31.blue(`
|
|
4931
5114
|
\u{1F4E6} Setting up ${packageName}...
|
|
4932
5115
|
`));
|
|
4933
|
-
const pkgPath =
|
|
4934
|
-
const pkgJsonPath =
|
|
4935
|
-
if (!
|
|
5116
|
+
const pkgPath = join26(process.cwd(), "node_modules", ...packageName.split("/"));
|
|
5117
|
+
const pkgJsonPath = join26(pkgPath, "package.json");
|
|
5118
|
+
if (!existsSync27(pkgJsonPath)) {
|
|
4936
5119
|
const pm = detectPackageManager(process.cwd());
|
|
4937
5120
|
const installSpinner = ora11("Installing package...").start();
|
|
4938
5121
|
try {
|
|
@@ -4946,11 +5129,11 @@ async function addPackage(packageName) {
|
|
|
4946
5129
|
} else {
|
|
4947
5130
|
console.log(chalk31.gray("\u2713 Package already installed (using local version)\n"));
|
|
4948
5131
|
}
|
|
4949
|
-
if (!
|
|
5132
|
+
if (!existsSync27(pkgJsonPath)) {
|
|
4950
5133
|
console.error(chalk31.red(`\u274C Package ${packageName} not found after installation`));
|
|
4951
5134
|
process.exit(1);
|
|
4952
5135
|
}
|
|
4953
|
-
const pkgJson = JSON.parse(
|
|
5136
|
+
const pkgJson = JSON.parse(readFileSync13(pkgJsonPath, "utf-8"));
|
|
4954
5137
|
if (pkgJson.spfn?.migrations) {
|
|
4955
5138
|
console.log(chalk31.blue(`
|
|
4956
5139
|
\u{1F5C4}\uFE0F Setting up database for ${packageName}...
|
|
@@ -4996,7 +5179,7 @@ var addCommand = new Command12("add").description("Add a capability to this proj
|
|
|
4996
5179
|
// src/commands/env.ts
|
|
4997
5180
|
import { Command as Command13 } from "commander";
|
|
4998
5181
|
import chalk32 from "chalk";
|
|
4999
|
-
import { existsSync as
|
|
5182
|
+
import { existsSync as existsSync28, readFileSync as readFileSync14, writeFileSync as writeFileSync18 } from "fs";
|
|
5000
5183
|
import { resolve as resolve2 } from "path";
|
|
5001
5184
|
import { parse as parse2 } from "dotenv";
|
|
5002
5185
|
|
|
@@ -5287,11 +5470,11 @@ async function initEnvFiles(options) {
|
|
|
5287
5470
|
}
|
|
5288
5471
|
function writeEnvTemplate(cwd, file, vars, force) {
|
|
5289
5472
|
const filePath = resolve2(cwd, file);
|
|
5290
|
-
if (
|
|
5473
|
+
if (existsSync28(filePath) && !force) {
|
|
5291
5474
|
console.log(chalk32.yellow(` \u23ED\uFE0F ${file} already exists (use --force to overwrite)`));
|
|
5292
5475
|
return;
|
|
5293
5476
|
}
|
|
5294
|
-
|
|
5477
|
+
writeFileSync18(filePath, generateEnvFileContent(vars), "utf-8");
|
|
5295
5478
|
console.log(chalk32.green(` \u2705 ${file} (${vars.length} variables)`));
|
|
5296
5479
|
}
|
|
5297
5480
|
function generateEnvFileContent(vars) {
|
|
@@ -5336,10 +5519,10 @@ async function checkEnvFiles(options) {
|
|
|
5336
5519
|
const warnings = [];
|
|
5337
5520
|
for (const file of filesToCheck) {
|
|
5338
5521
|
const filePath = resolve2(cwd, file);
|
|
5339
|
-
if (!
|
|
5522
|
+
if (!existsSync28(filePath)) {
|
|
5340
5523
|
continue;
|
|
5341
5524
|
}
|
|
5342
|
-
const content =
|
|
5525
|
+
const content = readFileSync14(filePath, "utf-8");
|
|
5343
5526
|
const parsed = parse2(content);
|
|
5344
5527
|
for (const [key, value] of Object.entries(parsed)) {
|
|
5345
5528
|
loadedEnv[key] = { value: value || "", file };
|
|
@@ -6046,12 +6229,12 @@ import chalk34 from "chalk";
|
|
|
6046
6229
|
|
|
6047
6230
|
// src/utils/ops/auth-crypto.ts
|
|
6048
6231
|
import { createRequire } from "module";
|
|
6049
|
-
import { join as
|
|
6232
|
+
import { join as join27 } from "path";
|
|
6050
6233
|
import { pathToFileURL as pathToFileURL3 } from "url";
|
|
6051
6234
|
var CRYPTO_ENTRY_SINCE = "0.3.0-beta.2";
|
|
6052
6235
|
var CRYPTO_ENTRY = "@spfn/auth/crypto";
|
|
6053
6236
|
async function importFromApp(specifier) {
|
|
6054
|
-
const requireFromApp = createRequire(
|
|
6237
|
+
const requireFromApp = createRequire(join27(process.cwd(), "noop.js"));
|
|
6055
6238
|
return await import(pathToFileURL3(requireFromApp.resolve(specifier)).href);
|
|
6056
6239
|
}
|
|
6057
6240
|
async function loadAuthCrypto() {
|
|
@@ -6468,12 +6651,12 @@ function resolveEnv(env9) {
|
|
|
6468
6651
|
|
|
6469
6652
|
// src/commands/secret/store-value.ts
|
|
6470
6653
|
init_logger();
|
|
6471
|
-
import { join as
|
|
6654
|
+
import { join as join29 } from "path";
|
|
6472
6655
|
init_env_file();
|
|
6473
6656
|
|
|
6474
6657
|
// src/utils/sops.ts
|
|
6475
6658
|
import { execa as execa11 } from "execa";
|
|
6476
|
-
import { existsSync as
|
|
6659
|
+
import { existsSync as existsSync29, mkdirSync as mkdirSync5, writeFileSync as writeFileSync19 } from "fs";
|
|
6477
6660
|
import { dirname as dirname5 } from "path";
|
|
6478
6661
|
async function ensureSopsInstalled() {
|
|
6479
6662
|
try {
|
|
@@ -6483,14 +6666,14 @@ async function ensureSopsInstalled() {
|
|
|
6483
6666
|
}
|
|
6484
6667
|
}
|
|
6485
6668
|
async function sopsDecrypt(absFile) {
|
|
6486
|
-
if (!
|
|
6669
|
+
if (!existsSync29(absFile)) {
|
|
6487
6670
|
return {};
|
|
6488
6671
|
}
|
|
6489
6672
|
const { stdout } = await execa11("sops", ["--decrypt", "--output-type", "json", absFile]);
|
|
6490
6673
|
return JSON.parse(stdout);
|
|
6491
6674
|
}
|
|
6492
6675
|
async function sopsSetValue(absFile, relFile, key, value) {
|
|
6493
|
-
if (
|
|
6676
|
+
if (existsSync29(absFile)) {
|
|
6494
6677
|
await execa11("sops", ["set", absFile, `["${key}"]`, JSON.stringify(value)]);
|
|
6495
6678
|
return;
|
|
6496
6679
|
}
|
|
@@ -6509,27 +6692,27 @@ async function sopsSetValue(absFile, relFile, key, value) {
|
|
|
6509
6692
|
],
|
|
6510
6693
|
{ input: JSON.stringify({ [key]: value }) }
|
|
6511
6694
|
);
|
|
6512
|
-
|
|
6695
|
+
writeFileSync19(absFile, stdout);
|
|
6513
6696
|
}
|
|
6514
6697
|
async function sopsUpdateKeys(absFile) {
|
|
6515
6698
|
await execa11("sops", ["updatekeys", "-y", absFile]);
|
|
6516
6699
|
}
|
|
6517
6700
|
|
|
6518
6701
|
// src/utils/secret-config.ts
|
|
6519
|
-
import { existsSync as
|
|
6520
|
-
import { join as
|
|
6702
|
+
import { existsSync as existsSync30, readdirSync as readdirSync2 } from "fs";
|
|
6703
|
+
import { join as join28 } from "path";
|
|
6521
6704
|
var SECRETS_DIR = "secrets";
|
|
6522
6705
|
function getSopsFile(cwd, env9) {
|
|
6523
6706
|
const relFile = `${SECRETS_DIR}/${env9}.enc.json`;
|
|
6524
|
-
return { absFile:
|
|
6707
|
+
return { absFile: join28(cwd, relFile), relFile };
|
|
6525
6708
|
}
|
|
6526
6709
|
function findUp(cwd, filename, maxDepth = 6) {
|
|
6527
6710
|
let dir = cwd;
|
|
6528
6711
|
for (let depth = 0; depth < maxDepth; depth++) {
|
|
6529
|
-
if (
|
|
6712
|
+
if (existsSync30(join28(dir, filename))) {
|
|
6530
6713
|
return dir;
|
|
6531
6714
|
}
|
|
6532
|
-
const parent =
|
|
6715
|
+
const parent = join28(dir, "..");
|
|
6533
6716
|
if (parent === dir) {
|
|
6534
6717
|
break;
|
|
6535
6718
|
}
|
|
@@ -6539,17 +6722,17 @@ function findUp(cwd, filename, maxDepth = 6) {
|
|
|
6539
6722
|
}
|
|
6540
6723
|
function findSopsConfig(cwd) {
|
|
6541
6724
|
const dir = findUp(cwd, ".sops.yaml");
|
|
6542
|
-
return dir ?
|
|
6725
|
+
return dir ? join28(dir, ".sops.yaml") : null;
|
|
6543
6726
|
}
|
|
6544
6727
|
function hasSopsConfig(cwd) {
|
|
6545
6728
|
return findSopsConfig(cwd) !== null;
|
|
6546
6729
|
}
|
|
6547
6730
|
function listSopsFiles(cwd) {
|
|
6548
|
-
const dir =
|
|
6549
|
-
if (!
|
|
6731
|
+
const dir = join28(cwd, SECRETS_DIR);
|
|
6732
|
+
if (!existsSync30(dir)) {
|
|
6550
6733
|
return [];
|
|
6551
6734
|
}
|
|
6552
|
-
return readdirSync2(dir).filter((name) => name.endsWith(".enc.json")).map((name) =>
|
|
6735
|
+
return readdirSync2(dir).filter((name) => name.endsWith(".enc.json")).map((name) => join28(dir, name));
|
|
6553
6736
|
}
|
|
6554
6737
|
|
|
6555
6738
|
// src/commands/secret/store-value.ts
|
|
@@ -6578,7 +6761,7 @@ async function storeSecret(cwd, env9, key, value) {
|
|
|
6578
6761
|
);
|
|
6579
6762
|
}
|
|
6580
6763
|
await store.set(keychainName(key), value);
|
|
6581
|
-
const serverEnvPath =
|
|
6764
|
+
const serverEnvPath = join29(cwd, ".env.server");
|
|
6582
6765
|
const result = upsertEnvVar(serverEnvPath, key, keychainRef(key));
|
|
6583
6766
|
restrictEnvFilePerms(serverEnvPath);
|
|
6584
6767
|
ensureGitignored(cwd, [{ pattern: ".env.server", comment: "spfn server env (secrets)" }]);
|
|
@@ -6816,12 +6999,12 @@ function requireEntry(schema, key) {
|
|
|
6816
6999
|
// src/commands/secret/keygen.ts
|
|
6817
7000
|
init_logger();
|
|
6818
7001
|
import { execa as execa12 } from "execa";
|
|
6819
|
-
import { existsSync as
|
|
7002
|
+
import { existsSync as existsSync31, mkdirSync as mkdirSync6 } from "fs";
|
|
6820
7003
|
import { homedir } from "os";
|
|
6821
|
-
import { dirname as dirname6, join as
|
|
7004
|
+
import { dirname as dirname6, join as join30 } from "path";
|
|
6822
7005
|
import chalk41 from "chalk";
|
|
6823
7006
|
function ageKeyFile() {
|
|
6824
|
-
return process.env.SOPS_AGE_KEY_FILE ??
|
|
7007
|
+
return process.env.SOPS_AGE_KEY_FILE ?? join30(homedir(), ".config", "sops", "age", "keys.txt");
|
|
6825
7008
|
}
|
|
6826
7009
|
async function ensureAgeInstalled() {
|
|
6827
7010
|
try {
|
|
@@ -6841,7 +7024,7 @@ async function secretKeygen() {
|
|
|
6841
7024
|
process.exit(1);
|
|
6842
7025
|
}
|
|
6843
7026
|
const keyFile = ageKeyFile();
|
|
6844
|
-
if (
|
|
7027
|
+
if (existsSync31(keyFile)) {
|
|
6845
7028
|
const { stdout } = await execa12("age-keygen", ["-y", keyFile]);
|
|
6846
7029
|
logger.warn(`age key file already exists: ${keyFile}`);
|
|
6847
7030
|
printPublicKeys(publicKeys(stdout));
|
|
@@ -6868,8 +7051,8 @@ function printPublicKeys(keys) {
|
|
|
6868
7051
|
|
|
6869
7052
|
// src/commands/secret/recipients.ts
|
|
6870
7053
|
init_logger();
|
|
6871
|
-
import { existsSync as
|
|
6872
|
-
import { join as
|
|
7054
|
+
import { existsSync as existsSync32, readFileSync as readFileSync15, writeFileSync as writeFileSync20 } from "fs";
|
|
7055
|
+
import { join as join31 } from "path";
|
|
6873
7056
|
import { parse as parse3, stringify } from "yaml";
|
|
6874
7057
|
import chalk42 from "chalk";
|
|
6875
7058
|
var SOPS_CONFIG = ".sops.yaml";
|
|
@@ -6877,7 +7060,7 @@ var DEFAULT_PATH_REGEX = "secrets/.*\\.enc\\.json$";
|
|
|
6877
7060
|
var AGE_RECIPIENT = /^age1[0-9a-z]+$/;
|
|
6878
7061
|
async function secretRecipients(action, key, _options) {
|
|
6879
7062
|
const cwd = process.cwd();
|
|
6880
|
-
const configPath =
|
|
7063
|
+
const configPath = join31(cwd, SOPS_CONFIG);
|
|
6881
7064
|
if (action === "list") {
|
|
6882
7065
|
listRecipients(configPath);
|
|
6883
7066
|
return;
|
|
@@ -6904,12 +7087,12 @@ async function secretRecipients(action, key, _options) {
|
|
|
6904
7087
|
logger.warn("Removing a recipient does not revoke values they already decrypted \u2014 rotate those values.");
|
|
6905
7088
|
}
|
|
6906
7089
|
rule.age = [...recipients].join(",");
|
|
6907
|
-
|
|
7090
|
+
writeFileSync20(configPath, stringify(config));
|
|
6908
7091
|
logger.success(`${action === "add" ? "Added" : "Removed"} recipient; updated ${SOPS_CONFIG}.`);
|
|
6909
7092
|
await reencrypt(cwd);
|
|
6910
7093
|
}
|
|
6911
7094
|
function listRecipients(configPath) {
|
|
6912
|
-
if (!
|
|
7095
|
+
if (!existsSync32(configPath)) {
|
|
6913
7096
|
logger.info(`No ${SOPS_CONFIG} found.`);
|
|
6914
7097
|
return;
|
|
6915
7098
|
}
|
|
@@ -6927,10 +7110,10 @@ function listRecipients(configPath) {
|
|
|
6927
7110
|
console.log();
|
|
6928
7111
|
}
|
|
6929
7112
|
function loadConfig(configPath) {
|
|
6930
|
-
if (!
|
|
7113
|
+
if (!existsSync32(configPath)) {
|
|
6931
7114
|
return { creation_rules: [] };
|
|
6932
7115
|
}
|
|
6933
|
-
return parse3(
|
|
7116
|
+
return parse3(readFileSync15(configPath, "utf-8")) ?? { creation_rules: [] };
|
|
6934
7117
|
}
|
|
6935
7118
|
function ensureRule(config) {
|
|
6936
7119
|
if (!config.creation_rules) {
|
|
@@ -6962,7 +7145,7 @@ async function reencrypt(cwd) {
|
|
|
6962
7145
|
|
|
6963
7146
|
// src/commands/secret/check.ts
|
|
6964
7147
|
init_logger();
|
|
6965
|
-
import { join as
|
|
7148
|
+
import { join as join32 } from "path";
|
|
6966
7149
|
import chalk43 from "chalk";
|
|
6967
7150
|
init_env_file();
|
|
6968
7151
|
var COMMITTED_FILES = [".env", ".env.example"];
|
|
@@ -6981,14 +7164,14 @@ async function secretCheck(options) {
|
|
|
6981
7164
|
const issues = [];
|
|
6982
7165
|
const warnings = [];
|
|
6983
7166
|
for (const file of COMMITTED_FILES) {
|
|
6984
|
-
const parsed = parseEnvFile(
|
|
7167
|
+
const parsed = parseEnvFile(join32(cwd, file));
|
|
6985
7168
|
for (const [key, value] of Object.entries(parsed)) {
|
|
6986
7169
|
if (secretKeys.has(key) && value.length > 0 && !PLACEHOLDER.test(value)) {
|
|
6987
7170
|
issues.push(`${chalk43.cyan(key)} has a real value in committed ${chalk43.yellow(file)} \u2014 move it to the keychain/SOPS.`);
|
|
6988
7171
|
}
|
|
6989
7172
|
}
|
|
6990
7173
|
}
|
|
6991
|
-
const serverEnv = parseEnvFile(
|
|
7174
|
+
const serverEnv = parseEnvFile(join32(cwd, ".env.server"));
|
|
6992
7175
|
for (const key of secretKeys) {
|
|
6993
7176
|
const value = serverEnv[key];
|
|
6994
7177
|
if (value && !value.startsWith(KEYCHAIN_REF_PREFIX)) {
|
|
@@ -7074,20 +7257,20 @@ async function deleteCloudToken(provider) {
|
|
|
7074
7257
|
|
|
7075
7258
|
// src/utils/cloud/config.ts
|
|
7076
7259
|
init_env_file();
|
|
7077
|
-
import { existsSync as
|
|
7078
|
-
import { dirname as dirname7, join as
|
|
7079
|
-
var CONFIG_REL_PATH =
|
|
7260
|
+
import { existsSync as existsSync33, mkdirSync as mkdirSync7, readFileSync as readFileSync16, writeFileSync as writeFileSync21 } from "fs";
|
|
7261
|
+
import { dirname as dirname7, join as join33 } from "path";
|
|
7262
|
+
var CONFIG_REL_PATH = join33(".spfn", "cloud.json");
|
|
7080
7263
|
function cloudConfigPath(cwd) {
|
|
7081
|
-
return
|
|
7264
|
+
return join33(cwd, CONFIG_REL_PATH);
|
|
7082
7265
|
}
|
|
7083
7266
|
function readCloudConfig(cwd) {
|
|
7084
7267
|
const path5 = cloudConfigPath(cwd);
|
|
7085
|
-
if (!
|
|
7268
|
+
if (!existsSync33(path5)) {
|
|
7086
7269
|
return {};
|
|
7087
7270
|
}
|
|
7088
7271
|
let parsed;
|
|
7089
7272
|
try {
|
|
7090
|
-
parsed = JSON.parse(
|
|
7273
|
+
parsed = JSON.parse(readFileSync16(path5, "utf-8"));
|
|
7091
7274
|
} catch {
|
|
7092
7275
|
throw new Error(`${path5} is not valid JSON \u2014 delete it and run \`spfn cloud link\` again.`);
|
|
7093
7276
|
}
|
|
@@ -7099,7 +7282,7 @@ function readCloudConfig(cwd) {
|
|
|
7099
7282
|
function writeCloudConfig(cwd, config) {
|
|
7100
7283
|
const path5 = cloudConfigPath(cwd);
|
|
7101
7284
|
mkdirSync7(dirname7(path5), { recursive: true });
|
|
7102
|
-
|
|
7285
|
+
writeFileSync21(path5, JSON.stringify(config, null, 4) + "\n", "utf-8");
|
|
7103
7286
|
ensureGitignored(cwd, [{ pattern: ".spfn/cloud.json", comment: "spfn cloud link state (per-user accounts)" }]);
|
|
7104
7287
|
}
|
|
7105
7288
|
function requireLinked(config, provider) {
|
|
@@ -7740,8 +7923,8 @@ function printMigrationPrompt(nearLimit) {
|
|
|
7740
7923
|
|
|
7741
7924
|
// src/commands/cloud/keepalive.ts
|
|
7742
7925
|
init_logger();
|
|
7743
|
-
import { existsSync as
|
|
7744
|
-
import { dirname as dirname8, join as
|
|
7926
|
+
import { existsSync as existsSync34, mkdirSync as mkdirSync8, readFileSync as readFileSync17, writeFileSync as writeFileSync22 } from "fs";
|
|
7927
|
+
import { dirname as dirname8, join as join34 } from "path";
|
|
7745
7928
|
import chalk49 from "chalk";
|
|
7746
7929
|
var DEFAULT_HEALTH_PATH = "/api/backend/_core/health?detailed=true";
|
|
7747
7930
|
var DEFAULT_SCHEDULE = "0 3 * * *";
|
|
@@ -7767,12 +7950,12 @@ async function cloudKeepalive(options) {
|
|
|
7767
7950
|
logger.info("The DB ping needs detailed health checks: keep `healthCheck: { detailed: true }` in your server config.");
|
|
7768
7951
|
}
|
|
7769
7952
|
function setupVercelCron(cwd, healthPath) {
|
|
7770
|
-
const vercelJsonPath =
|
|
7953
|
+
const vercelJsonPath = join34(cwd, "vercel.json");
|
|
7771
7954
|
let vercelJson = {};
|
|
7772
|
-
if (
|
|
7955
|
+
if (existsSync34(vercelJsonPath)) {
|
|
7773
7956
|
let parsed;
|
|
7774
7957
|
try {
|
|
7775
|
-
parsed = JSON.parse(
|
|
7958
|
+
parsed = JSON.parse(readFileSync17(vercelJsonPath, "utf-8"));
|
|
7776
7959
|
} catch {
|
|
7777
7960
|
logger.error("vercel.json is not valid JSON (comments and trailing commas are not allowed) \u2014 fix it and re-run.");
|
|
7778
7961
|
process.exit(1);
|
|
@@ -7793,7 +7976,7 @@ function setupVercelCron(cwd, healthPath) {
|
|
|
7793
7976
|
logger.info(`Point the existing cron at ${chalk49.cyan(healthPath)} yourself, or use \`--github-actions --url <deployed-url>\`.`);
|
|
7794
7977
|
process.exit(1);
|
|
7795
7978
|
}
|
|
7796
|
-
|
|
7979
|
+
writeFileSync22(vercelJsonPath, JSON.stringify(vercelJson, null, 4) + "\n", "utf-8");
|
|
7797
7980
|
logger.success(`vercel.json: daily cron added (${DEFAULT_SCHEDULE} UTC \u2192 ${healthPath}). Deploy to activate.`);
|
|
7798
7981
|
warnIfBackendRouteMissing(cwd);
|
|
7799
7982
|
}
|
|
@@ -7813,8 +7996,8 @@ function setupGithubActions(cwd, healthPath, url) {
|
|
|
7813
7996
|
logger.error("`--github-actions` needs `--url <deployed-url>` \u2014 the workflow runs outside your app and must know where it lives.");
|
|
7814
7997
|
process.exit(1);
|
|
7815
7998
|
}
|
|
7816
|
-
const workflowPath =
|
|
7817
|
-
if (
|
|
7999
|
+
const workflowPath = join34(cwd, ".github", "workflows", "spfn-keepalive.yml");
|
|
8000
|
+
if (existsSync34(workflowPath)) {
|
|
7818
8001
|
logger.success(`${workflowPath} already exists \u2014 nothing to do.`);
|
|
7819
8002
|
return;
|
|
7820
8003
|
}
|
|
@@ -7824,7 +8007,7 @@ function setupGithubActions(cwd, healthPath, url) {
|
|
|
7824
8007
|
process.exit(1);
|
|
7825
8008
|
}
|
|
7826
8009
|
mkdirSync8(dirname8(workflowPath), { recursive: true });
|
|
7827
|
-
|
|
8010
|
+
writeFileSync22(workflowPath, githubWorkflow(new URL(healthPath, base).toString()), "utf-8");
|
|
7828
8011
|
logger.success(".github/workflows/spfn-keepalive.yml: daily keep-alive workflow added. Commit and push to activate.");
|
|
7829
8012
|
}
|
|
7830
8013
|
function normalizeDeployUrl(url) {
|
|
@@ -7861,8 +8044,8 @@ jobs:
|
|
|
7861
8044
|
`;
|
|
7862
8045
|
}
|
|
7863
8046
|
function warnIfBackendRouteMissing(cwd) {
|
|
7864
|
-
const routePath =
|
|
7865
|
-
if (!
|
|
8047
|
+
const routePath = join34(cwd, "src", "app", "api", "backend", "[[...route]]", "route.ts");
|
|
8048
|
+
if (!existsSync34(routePath)) {
|
|
7866
8049
|
logger.warn("src/app/api/backend/[[...route]]/route.ts not found \u2014 the cron path answers only after `spfn add vercel`.");
|
|
7867
8050
|
}
|
|
7868
8051
|
}
|
|
@@ -7870,7 +8053,7 @@ function warnIfBackendRouteMissing(cwd) {
|
|
|
7870
8053
|
// src/commands/cloud/env.ts
|
|
7871
8054
|
init_logger();
|
|
7872
8055
|
init_env_file();
|
|
7873
|
-
import { join as
|
|
8056
|
+
import { join as join35 } from "path";
|
|
7874
8057
|
import prompts13 from "prompts";
|
|
7875
8058
|
import chalk50 from "chalk";
|
|
7876
8059
|
async function cloudEnvPull(options) {
|
|
@@ -7891,7 +8074,7 @@ async function cloudEnvPull(options) {
|
|
|
7891
8074
|
logger.info("Values were written to files/keychain only \u2014 none were displayed.");
|
|
7892
8075
|
}
|
|
7893
8076
|
function writePublicValues(cwd, projectRef2, keys) {
|
|
7894
|
-
const envLocalPath =
|
|
8077
|
+
const envLocalPath = join35(cwd, ".env.local");
|
|
7895
8078
|
ensureGitignored(cwd, [{ pattern: ".env.local", comment: "local env (per-machine values)" }]);
|
|
7896
8079
|
upsertEnvVar(envLocalPath, "NEXT_PUBLIC_SUPABASE_URL", `https://${projectRef2}.supabase.co`);
|
|
7897
8080
|
logger.success("NEXT_PUBLIC_SUPABASE_URL \u2192 .env.local");
|
|
@@ -7985,8 +8168,8 @@ async function cloudEnvPush(keys) {
|
|
|
7985
8168
|
}
|
|
7986
8169
|
}
|
|
7987
8170
|
async function resolveLocalValues(cwd, keys) {
|
|
7988
|
-
const publicEnv = { ...parseEnvFile(
|
|
7989
|
-
const serverEnv = parseEnvFile(
|
|
8171
|
+
const publicEnv = { ...parseEnvFile(join35(cwd, ".env")), ...parseEnvFile(join35(cwd, ".env.local")) };
|
|
8172
|
+
const serverEnv = parseEnvFile(join35(cwd, ".env.server"));
|
|
7990
8173
|
const keychain = await resolveKeychainEnv(cwd);
|
|
7991
8174
|
const vars = [];
|
|
7992
8175
|
const missing = [];
|
|
@@ -8142,8 +8325,8 @@ async function resolveKitAdapters(request2) {
|
|
|
8142
8325
|
// src/kit/operations/install.ts
|
|
8143
8326
|
import { createHash as createHash2 } from "crypto";
|
|
8144
8327
|
import { hostname as hostname2, tmpdir } from "os";
|
|
8145
|
-
import { mkdtempSync, existsSync as
|
|
8146
|
-
import { join as
|
|
8328
|
+
import { mkdtempSync, existsSync as existsSync46 } from "fs";
|
|
8329
|
+
import { join as join45 } from "path";
|
|
8147
8330
|
|
|
8148
8331
|
// src/kit/events.ts
|
|
8149
8332
|
import chalk51 from "chalk";
|
|
@@ -8220,8 +8403,8 @@ function nextLine(event) {
|
|
|
8220
8403
|
}
|
|
8221
8404
|
|
|
8222
8405
|
// src/kit/journal.ts
|
|
8223
|
-
import { mkdirSync as mkdirSync10, readdirSync as readdirSync3, readFileSync as
|
|
8224
|
-
import { dirname as dirname9, join as
|
|
8406
|
+
import { mkdirSync as mkdirSync10, readdirSync as readdirSync3, readFileSync as readFileSync18, renameSync as renameSync2, rmSync as rmSync2, writeFileSync as writeFileSync24, existsSync as existsSync36, statSync } from "fs";
|
|
8407
|
+
import { dirname as dirname9, join as join37 } from "path";
|
|
8225
8408
|
|
|
8226
8409
|
// src/kit/digest.ts
|
|
8227
8410
|
import { createHash } from "crypto";
|
|
@@ -8262,8 +8445,8 @@ function digestOfJson(value) {
|
|
|
8262
8445
|
}
|
|
8263
8446
|
|
|
8264
8447
|
// src/kit/paths.ts
|
|
8265
|
-
import { mkdirSync as mkdirSync9, writeFileSync as
|
|
8266
|
-
import { join as
|
|
8448
|
+
import { mkdirSync as mkdirSync9, writeFileSync as writeFileSync23, existsSync as existsSync35 } from "fs";
|
|
8449
|
+
import { join as join36 } from "path";
|
|
8267
8450
|
var KIT_STATE_DIR = ".spfn";
|
|
8268
8451
|
var OPERATIONS_IGNORE = [
|
|
8269
8452
|
"# Written by `spfn kit`. One machine's run is not part of the project.",
|
|
@@ -8271,27 +8454,27 @@ var OPERATIONS_IGNORE = [
|
|
|
8271
8454
|
""
|
|
8272
8455
|
].join("\n");
|
|
8273
8456
|
function kitPaths(root) {
|
|
8274
|
-
const stateDir =
|
|
8275
|
-
const operationsDir =
|
|
8276
|
-
const lockDir =
|
|
8457
|
+
const stateDir = join36(root, KIT_STATE_DIR);
|
|
8458
|
+
const operationsDir = join36(stateDir, "operations");
|
|
8459
|
+
const lockDir = join36(operationsDir, "operation.lock");
|
|
8277
8460
|
return {
|
|
8278
8461
|
root,
|
|
8279
8462
|
stateDir,
|
|
8280
|
-
licenseFile:
|
|
8281
|
-
lockFile:
|
|
8463
|
+
licenseFile: join36(stateDir, "license.json"),
|
|
8464
|
+
lockFile: join36(stateDir, "kit-lock.json"),
|
|
8282
8465
|
operationsDir,
|
|
8283
|
-
activeJournal:
|
|
8284
|
-
historyDir:
|
|
8466
|
+
activeJournal: join36(operationsDir, "active.json"),
|
|
8467
|
+
historyDir: join36(operationsDir, "history"),
|
|
8285
8468
|
lockDir,
|
|
8286
|
-
lockOwnerFile:
|
|
8469
|
+
lockOwnerFile: join36(lockDir, "owner.json")
|
|
8287
8470
|
};
|
|
8288
8471
|
}
|
|
8289
8472
|
function ensureOperationsDir(root) {
|
|
8290
8473
|
const paths = kitPaths(root);
|
|
8291
|
-
const ignoreFile =
|
|
8474
|
+
const ignoreFile = join36(paths.stateDir, ".gitignore");
|
|
8292
8475
|
mkdirSync9(paths.stateDir, { recursive: true });
|
|
8293
|
-
if (!
|
|
8294
|
-
|
|
8476
|
+
if (!existsSync35(ignoreFile)) {
|
|
8477
|
+
writeFileSync23(ignoreFile, OPERATIONS_IGNORE, "utf8");
|
|
8295
8478
|
}
|
|
8296
8479
|
mkdirSync9(paths.operationsDir, { recursive: true });
|
|
8297
8480
|
return paths.operationsDir;
|
|
@@ -8578,14 +8761,14 @@ var JournalStore = class {
|
|
|
8578
8761
|
return readJournalFile(this.paths.activeJournal);
|
|
8579
8762
|
}
|
|
8580
8763
|
readHistory(operationId) {
|
|
8581
|
-
return readJournalFile(
|
|
8764
|
+
return readJournalFile(join37(this.paths.historyDir, `${operationId}.json`));
|
|
8582
8765
|
}
|
|
8583
8766
|
/** Every journal this project still has, newest update first. */
|
|
8584
8767
|
listHistory() {
|
|
8585
|
-
if (!
|
|
8768
|
+
if (!existsSync36(this.paths.historyDir)) {
|
|
8586
8769
|
return [];
|
|
8587
8770
|
}
|
|
8588
|
-
return readdirSync3(this.paths.historyDir).filter((name) => name.endsWith(".json")).map((name) => readJournalFile(
|
|
8771
|
+
return readdirSync3(this.paths.historyDir).filter((name) => name.endsWith(".json")).map((name) => readJournalFile(join37(this.paths.historyDir, name))).filter((journal) => journal !== null).sort((left, right) => right.updatedAt.localeCompare(left.updatedAt));
|
|
8589
8772
|
}
|
|
8590
8773
|
create(init) {
|
|
8591
8774
|
const timestamp = this.now();
|
|
@@ -8644,15 +8827,15 @@ var JournalStore = class {
|
|
|
8644
8827
|
}
|
|
8645
8828
|
/** Move a finished operation into history and clear the active slot. */
|
|
8646
8829
|
archive(journal) {
|
|
8647
|
-
writeJsonAtomically(
|
|
8830
|
+
writeJsonAtomically(join37(this.paths.historyDir, `${journal.operationId}.json`), journal);
|
|
8648
8831
|
rmSync2(this.paths.activeJournal, { force: true });
|
|
8649
8832
|
this.pruneHistory();
|
|
8650
8833
|
}
|
|
8651
8834
|
pruneHistory() {
|
|
8652
|
-
if (!
|
|
8835
|
+
if (!existsSync36(this.paths.historyDir)) {
|
|
8653
8836
|
return;
|
|
8654
8837
|
}
|
|
8655
|
-
const files = readdirSync3(this.paths.historyDir).filter((name) => name.endsWith(".json")).map((name) =>
|
|
8838
|
+
const files = readdirSync3(this.paths.historyDir).filter((name) => name.endsWith(".json")).map((name) => join37(this.paths.historyDir, name)).sort((left, right) => statSync(right).mtimeMs - statSync(left).mtimeMs);
|
|
8656
8839
|
for (const file of files.slice(this.historyLimit)) {
|
|
8657
8840
|
rmSync2(file, { force: true });
|
|
8658
8841
|
}
|
|
@@ -8674,11 +8857,11 @@ function upsertCheckpoint(checkpoints, entry) {
|
|
|
8674
8857
|
return next;
|
|
8675
8858
|
}
|
|
8676
8859
|
function readJournalFile(file) {
|
|
8677
|
-
if (!
|
|
8860
|
+
if (!existsSync36(file)) {
|
|
8678
8861
|
return null;
|
|
8679
8862
|
}
|
|
8680
8863
|
try {
|
|
8681
|
-
const parsed = JSON.parse(
|
|
8864
|
+
const parsed = JSON.parse(readFileSync18(file, "utf8"));
|
|
8682
8865
|
return validateOperationJournal(parsed).valid ? parsed : null;
|
|
8683
8866
|
} catch {
|
|
8684
8867
|
return null;
|
|
@@ -8687,13 +8870,13 @@ function readJournalFile(file) {
|
|
|
8687
8870
|
function writeJsonAtomically(file, value) {
|
|
8688
8871
|
mkdirSync10(dirname9(file), { recursive: true });
|
|
8689
8872
|
const temporary = `${file}.tmp`;
|
|
8690
|
-
|
|
8873
|
+
writeFileSync24(temporary, `${JSON.stringify(value, null, 4)}
|
|
8691
8874
|
`, { encoding: "utf8", mode: 384 });
|
|
8692
8875
|
renameSync2(temporary, file);
|
|
8693
8876
|
}
|
|
8694
8877
|
|
|
8695
8878
|
// src/kit/lock.ts
|
|
8696
|
-
import { mkdirSync as mkdirSync11, readFileSync as
|
|
8879
|
+
import { mkdirSync as mkdirSync11, readFileSync as readFileSync19, rmSync as rmSync3, writeFileSync as writeFileSync25, existsSync as existsSync37 } from "fs";
|
|
8697
8880
|
import { hostname } from "os";
|
|
8698
8881
|
function defaultIsProcessAlive(pid) {
|
|
8699
8882
|
try {
|
|
@@ -8729,11 +8912,11 @@ function acquireOperationLock(options) {
|
|
|
8729
8912
|
}
|
|
8730
8913
|
function readLockOwner(root) {
|
|
8731
8914
|
const paths = kitPaths(root);
|
|
8732
|
-
if (!
|
|
8915
|
+
if (!existsSync37(paths.lockOwnerFile)) {
|
|
8733
8916
|
return null;
|
|
8734
8917
|
}
|
|
8735
8918
|
try {
|
|
8736
|
-
const parsed = JSON.parse(
|
|
8919
|
+
const parsed = JSON.parse(readFileSync19(paths.lockOwnerFile, "utf8"));
|
|
8737
8920
|
return typeof parsed?.pid === "number" && typeof parsed?.operationId === "string" ? parsed : null;
|
|
8738
8921
|
} catch {
|
|
8739
8922
|
return null;
|
|
@@ -8802,7 +8985,7 @@ function tryCreateLockDir(paths) {
|
|
|
8802
8985
|
}
|
|
8803
8986
|
}
|
|
8804
8987
|
function writeOwner(paths, owner) {
|
|
8805
|
-
|
|
8988
|
+
writeFileSync25(paths.lockOwnerFile, `${JSON.stringify(owner, null, 4)}
|
|
8806
8989
|
`, "utf8");
|
|
8807
8990
|
}
|
|
8808
8991
|
function handle(paths, owner, reclaimed) {
|
|
@@ -8816,18 +8999,18 @@ function handle(paths, owner, reclaimed) {
|
|
|
8816
8999
|
}
|
|
8817
9000
|
|
|
8818
9001
|
// src/kit/operation-context.ts
|
|
8819
|
-
import { mkdirSync as mkdirSync12, readFileSync as
|
|
8820
|
-
import { dirname as dirname10, join as
|
|
9002
|
+
import { mkdirSync as mkdirSync12, readFileSync as readFileSync20, renameSync as renameSync3, rmSync as rmSync4, writeFileSync as writeFileSync26, existsSync as existsSync38 } from "fs";
|
|
9003
|
+
import { dirname as dirname10, join as join38 } from "path";
|
|
8821
9004
|
function contextFile(root) {
|
|
8822
|
-
return
|
|
9005
|
+
return join38(kitPaths(root).operationsDir, "context.json");
|
|
8823
9006
|
}
|
|
8824
9007
|
function readOperationContext(root) {
|
|
8825
9008
|
const file = contextFile(root);
|
|
8826
|
-
if (!
|
|
9009
|
+
if (!existsSync38(file)) {
|
|
8827
9010
|
return null;
|
|
8828
9011
|
}
|
|
8829
9012
|
try {
|
|
8830
|
-
const parsed = JSON.parse(
|
|
9013
|
+
const parsed = JSON.parse(readFileSync20(file, "utf8"));
|
|
8831
9014
|
return parsed?.schemaVersion === 1 && typeof parsed.operationId === "string" ? parsed : null;
|
|
8832
9015
|
} catch {
|
|
8833
9016
|
return null;
|
|
@@ -8837,7 +9020,7 @@ function writeOperationContext(root, context) {
|
|
|
8837
9020
|
const file = contextFile(root);
|
|
8838
9021
|
mkdirSync12(dirname10(file), { recursive: true });
|
|
8839
9022
|
const temporary = `${file}.tmp`;
|
|
8840
|
-
|
|
9023
|
+
writeFileSync26(temporary, `${JSON.stringify(context, null, 4)}
|
|
8841
9024
|
`, "utf8");
|
|
8842
9025
|
renameSync3(temporary, file);
|
|
8843
9026
|
}
|
|
@@ -9472,8 +9655,8 @@ var KeychainKitCredentialStore = class {
|
|
|
9472
9655
|
};
|
|
9473
9656
|
|
|
9474
9657
|
// src/kit/tooling.ts
|
|
9475
|
-
import { cpSync, mkdirSync as mkdirSync13, readdirSync as readdirSync4, readFileSync as
|
|
9476
|
-
import { join as
|
|
9658
|
+
import { cpSync, mkdirSync as mkdirSync13, readdirSync as readdirSync4, readFileSync as readFileSync21, rmSync as rmSync5, statSync as statSync2, existsSync as existsSync39 } from "fs";
|
|
9659
|
+
import { join as join39, relative as relative2, sep as sep3 } from "path";
|
|
9477
9660
|
|
|
9478
9661
|
// src/kit/manifest.ts
|
|
9479
9662
|
var DEFAULT_AGENT_PACK_ROOT = ".spfn/agent-pack";
|
|
@@ -9784,7 +9967,7 @@ function snapshotTree(root, ignore = ["node_modules", ".git"]) {
|
|
|
9784
9967
|
if (ignore.includes(entry.name)) {
|
|
9785
9968
|
continue;
|
|
9786
9969
|
}
|
|
9787
|
-
const absolute =
|
|
9970
|
+
const absolute = join39(directory, entry.name);
|
|
9788
9971
|
if (entry.isDirectory()) {
|
|
9789
9972
|
walk(absolute);
|
|
9790
9973
|
continue;
|
|
@@ -9794,11 +9977,11 @@ function snapshotTree(root, ignore = ["node_modules", ".git"]) {
|
|
|
9794
9977
|
}
|
|
9795
9978
|
files.set(
|
|
9796
9979
|
relative2(root, absolute).split(sep3).join("/"),
|
|
9797
|
-
sha256Digest(
|
|
9980
|
+
sha256Digest(readFileSync21(absolute))
|
|
9798
9981
|
);
|
|
9799
9982
|
}
|
|
9800
9983
|
};
|
|
9801
|
-
if (
|
|
9984
|
+
if (existsSync39(root) && statSync2(root).isDirectory()) {
|
|
9802
9985
|
walk(root);
|
|
9803
9986
|
}
|
|
9804
9987
|
return { files };
|
|
@@ -9855,22 +10038,22 @@ function assertWritesWithinAllowlist(diff, allowlist, context) {
|
|
|
9855
10038
|
}
|
|
9856
10039
|
|
|
9857
10040
|
// src/kit/agent-pack.ts
|
|
9858
|
-
import { existsSync as
|
|
9859
|
-
import { dirname as dirname11, join as
|
|
10041
|
+
import { existsSync as existsSync40, mkdirSync as mkdirSync14, readFileSync as readFileSync22, writeFileSync as writeFileSync27 } from "fs";
|
|
10042
|
+
import { dirname as dirname11, join as join40 } from "path";
|
|
9860
10043
|
var AGENT_PACK_RECORD_PATH = ".spfn/agent-pack.json";
|
|
9861
10044
|
function writeAgentPackRecord(projectDir2, record) {
|
|
9862
|
-
const file =
|
|
10045
|
+
const file = join40(projectDir2, AGENT_PACK_RECORD_PATH);
|
|
9863
10046
|
mkdirSync14(dirname11(file), { recursive: true });
|
|
9864
|
-
|
|
10047
|
+
writeFileSync27(file, `${JSON.stringify(record, null, 4)}
|
|
9865
10048
|
`, "utf8");
|
|
9866
10049
|
}
|
|
9867
10050
|
function readAgentPackRecord(projectDir2) {
|
|
9868
|
-
const file =
|
|
9869
|
-
if (!
|
|
10051
|
+
const file = join40(projectDir2, AGENT_PACK_RECORD_PATH);
|
|
10052
|
+
if (!existsSync40(file)) {
|
|
9870
10053
|
return null;
|
|
9871
10054
|
}
|
|
9872
10055
|
try {
|
|
9873
|
-
const parsed = JSON.parse(
|
|
10056
|
+
const parsed = JSON.parse(readFileSync22(file, "utf8"));
|
|
9874
10057
|
return parsed.schemaVersion === 1 && typeof parsed.files === "object" && parsed.files !== null ? parsed : null;
|
|
9875
10058
|
} catch {
|
|
9876
10059
|
return null;
|
|
@@ -9878,7 +10061,7 @@ function readAgentPackRecord(projectDir2) {
|
|
|
9878
10061
|
}
|
|
9879
10062
|
|
|
9880
10063
|
// src/kit/installed-state.ts
|
|
9881
|
-
import { mkdirSync as mkdirSync15, readFileSync as
|
|
10064
|
+
import { mkdirSync as mkdirSync15, readFileSync as readFileSync23, renameSync as renameSync4, writeFileSync as writeFileSync28, existsSync as existsSync41 } from "fs";
|
|
9882
10065
|
import { dirname as dirname12 } from "path";
|
|
9883
10066
|
function readLicenseFile(file) {
|
|
9884
10067
|
const parsed = readJson(file);
|
|
@@ -9921,7 +10104,7 @@ function requireInstalledLock(file) {
|
|
|
9921
10104
|
const lock = readInstalledLock(file);
|
|
9922
10105
|
if (lock === null) {
|
|
9923
10106
|
throw new KitError("KIT_LOCK_INVALID", "This project has no readable .spfn/kit-lock.json.", {
|
|
9924
|
-
evidence: { file, exists:
|
|
10107
|
+
evidence: { file, exists: existsSync41(file) },
|
|
9925
10108
|
next: { command: "spfn kit recover --json", requiresHumanApproval: false }
|
|
9926
10109
|
});
|
|
9927
10110
|
}
|
|
@@ -9956,11 +10139,11 @@ function lockFromManifest(manifest, context) {
|
|
|
9956
10139
|
};
|
|
9957
10140
|
}
|
|
9958
10141
|
function readJson(file) {
|
|
9959
|
-
if (!
|
|
10142
|
+
if (!existsSync41(file)) {
|
|
9960
10143
|
return null;
|
|
9961
10144
|
}
|
|
9962
10145
|
try {
|
|
9963
|
-
return JSON.parse(
|
|
10146
|
+
return JSON.parse(readFileSync23(file, "utf8"));
|
|
9964
10147
|
} catch {
|
|
9965
10148
|
return null;
|
|
9966
10149
|
}
|
|
@@ -9968,17 +10151,17 @@ function readJson(file) {
|
|
|
9968
10151
|
function writeJsonAtomically2(file, value) {
|
|
9969
10152
|
mkdirSync15(dirname12(file), { recursive: true });
|
|
9970
10153
|
const temporary = `${file}.tmp`;
|
|
9971
|
-
|
|
10154
|
+
writeFileSync28(temporary, `${JSON.stringify(value, null, 4)}
|
|
9972
10155
|
`, "utf8");
|
|
9973
10156
|
renameSync4(temporary, file);
|
|
9974
10157
|
}
|
|
9975
10158
|
|
|
9976
10159
|
// src/kit/drift.ts
|
|
9977
|
-
import { readFileSync as
|
|
9978
|
-
import { join as
|
|
10160
|
+
import { readFileSync as readFileSync24, existsSync as existsSync42 } from "fs";
|
|
10161
|
+
import { join as join41 } from "path";
|
|
9979
10162
|
function fileDigest(root, relativePath) {
|
|
9980
|
-
const file =
|
|
9981
|
-
return
|
|
10163
|
+
const file = join41(root, relativePath);
|
|
10164
|
+
return existsSync42(file) ? sha256Digest(readFileSync24(file)) : null;
|
|
9982
10165
|
}
|
|
9983
10166
|
function agentPackTargets(root, lock) {
|
|
9984
10167
|
if (lock.agentPack.root === void 0) {
|
|
@@ -10009,12 +10192,12 @@ function managedDigests(root, lock) {
|
|
|
10009
10192
|
}
|
|
10010
10193
|
|
|
10011
10194
|
// src/kit/operations/shared.ts
|
|
10012
|
-
import { mkdirSync as mkdirSync17, readdirSync as readdirSync5, readFileSync as
|
|
10013
|
-
import { dirname as dirname14, join as
|
|
10195
|
+
import { mkdirSync as mkdirSync17, readdirSync as readdirSync5, readFileSync as readFileSync27, writeFileSync as writeFileSync31, existsSync as existsSync45 } from "fs";
|
|
10196
|
+
import { dirname as dirname14, join as join44 } from "path";
|
|
10014
10197
|
|
|
10015
10198
|
// src/kit/expand.ts
|
|
10016
|
-
import { mkdirSync as mkdirSync16, existsSync as
|
|
10017
|
-
import { dirname as dirname13, join as
|
|
10199
|
+
import { mkdirSync as mkdirSync16, existsSync as existsSync43, readFileSync as readFileSync25, writeFileSync as writeFileSync29 } from "fs";
|
|
10200
|
+
import { dirname as dirname13, join as join42 } from "path";
|
|
10018
10201
|
|
|
10019
10202
|
// src/kit/tar.ts
|
|
10020
10203
|
var BLOCK = 512;
|
|
@@ -10116,26 +10299,26 @@ function expandArchive(bytes, request2) {
|
|
|
10116
10299
|
let matched = 0;
|
|
10117
10300
|
for (const entry of entries) {
|
|
10118
10301
|
const relative3 = request2.root === void 0 || request2.root.length === 0 ? entry.path : `${request2.root.replace(/\/+$/, "")}/${entry.path}`;
|
|
10119
|
-
const destination =
|
|
10302
|
+
const destination = join42(request2.targetDir, relative3);
|
|
10120
10303
|
if (entry.kind === "directory") {
|
|
10121
10304
|
mkdirSync16(destination, { recursive: true });
|
|
10122
10305
|
continue;
|
|
10123
10306
|
}
|
|
10124
10307
|
const digest = sha256Digest(entry.bytes);
|
|
10125
10308
|
files[relative3] = digest;
|
|
10126
|
-
if (
|
|
10309
|
+
if (existsSync43(destination) && request2.existing !== "replace") {
|
|
10127
10310
|
assertSameBytes(destination, relative3, digest);
|
|
10128
10311
|
matched += 1;
|
|
10129
10312
|
continue;
|
|
10130
10313
|
}
|
|
10131
10314
|
mkdirSync16(dirname13(destination), { recursive: true });
|
|
10132
|
-
|
|
10315
|
+
writeFileSync29(destination, entry.bytes, { mode: entry.mode === 0 ? 420 : entry.mode });
|
|
10133
10316
|
written += 1;
|
|
10134
10317
|
}
|
|
10135
10318
|
return { files, written, matched };
|
|
10136
10319
|
}
|
|
10137
10320
|
function assertSameBytes(destination, relative3, expected) {
|
|
10138
|
-
const actual = sha256Digest(
|
|
10321
|
+
const actual = sha256Digest(readFileSync25(destination));
|
|
10139
10322
|
if (actual === expected) {
|
|
10140
10323
|
return;
|
|
10141
10324
|
}
|
|
@@ -10243,15 +10426,15 @@ function registryNpmrc(scopes, registryUrl) {
|
|
|
10243
10426
|
}
|
|
10244
10427
|
|
|
10245
10428
|
// src/kit/package-graph.ts
|
|
10246
|
-
import { existsSync as
|
|
10247
|
-
import { join as
|
|
10429
|
+
import { existsSync as existsSync44, readFileSync as readFileSync26, writeFileSync as writeFileSync30 } from "fs";
|
|
10430
|
+
import { join as join43 } from "path";
|
|
10248
10431
|
var DEPENDENCY_BLOCKS = ["dependencies", "devDependencies", "optionalDependencies"];
|
|
10249
10432
|
function applyManifestVersions(projectDir2, manifest) {
|
|
10250
|
-
const file =
|
|
10251
|
-
if (!
|
|
10433
|
+
const file = join43(projectDir2, "package.json");
|
|
10434
|
+
if (!existsSync44(file)) {
|
|
10252
10435
|
return [];
|
|
10253
10436
|
}
|
|
10254
|
-
const raw =
|
|
10437
|
+
const raw = readFileSync26(file, "utf8");
|
|
10255
10438
|
const document = JSON.parse(raw);
|
|
10256
10439
|
const wanted = new Map(manifest.packages.map((entry) => [entry.name, entry.version]));
|
|
10257
10440
|
const changes = [];
|
|
@@ -10270,7 +10453,7 @@ function applyManifestVersions(projectDir2, manifest) {
|
|
|
10270
10453
|
}
|
|
10271
10454
|
}
|
|
10272
10455
|
if (changes.length > 0) {
|
|
10273
|
-
|
|
10456
|
+
writeFileSync30(file, `${JSON.stringify(document, null, indentationOf(raw))}${trailingNewline(raw)}`);
|
|
10274
10457
|
}
|
|
10275
10458
|
return changes;
|
|
10276
10459
|
}
|
|
@@ -10298,12 +10481,12 @@ function installedGraphMismatches(projectDir2, manifest, skip = () => false) {
|
|
|
10298
10481
|
return mismatches;
|
|
10299
10482
|
}
|
|
10300
10483
|
function installedVersion(projectDir2, name) {
|
|
10301
|
-
const file =
|
|
10302
|
-
if (!
|
|
10484
|
+
const file = join43(projectDir2, "node_modules", ...name.split("/"), "package.json");
|
|
10485
|
+
if (!existsSync44(file)) {
|
|
10303
10486
|
return null;
|
|
10304
10487
|
}
|
|
10305
10488
|
try {
|
|
10306
|
-
const version = JSON.parse(
|
|
10489
|
+
const version = JSON.parse(readFileSync26(file, "utf8")).version;
|
|
10307
10490
|
return typeof version === "string" ? version : null;
|
|
10308
10491
|
} catch {
|
|
10309
10492
|
return null;
|
|
@@ -10390,7 +10573,7 @@ function latestActiveRelease(catalog) {
|
|
|
10390
10573
|
return active[0];
|
|
10391
10574
|
}
|
|
10392
10575
|
function assertEmptyTarget(targetDir) {
|
|
10393
|
-
if (!
|
|
10576
|
+
if (!existsSync45(targetDir)) {
|
|
10394
10577
|
return;
|
|
10395
10578
|
}
|
|
10396
10579
|
const entries = readdirSync5(targetDir).filter((name) => name !== ".DS_Store");
|
|
@@ -10421,13 +10604,13 @@ async function materializeTargets(adapters, projectDir2, targets, options = {})
|
|
|
10421
10604
|
continue;
|
|
10422
10605
|
}
|
|
10423
10606
|
written[target.path] = digest;
|
|
10424
|
-
writeManagedFile(
|
|
10607
|
+
writeManagedFile(join44(projectDir2, target.path), target.path, bytes, digest, options.existing);
|
|
10425
10608
|
}
|
|
10426
10609
|
return written;
|
|
10427
10610
|
}
|
|
10428
10611
|
function writeManagedFile(file, path5, bytes, digest, existing = "verify") {
|
|
10429
|
-
if (
|
|
10430
|
-
const actual = sha256Digest(
|
|
10612
|
+
if (existsSync45(file) && existing !== "replace") {
|
|
10613
|
+
const actual = sha256Digest(readFileSync27(file));
|
|
10431
10614
|
if (actual === digest) {
|
|
10432
10615
|
return;
|
|
10433
10616
|
}
|
|
@@ -10437,7 +10620,7 @@ function writeManagedFile(file, path5, bytes, digest, existing = "verify") {
|
|
|
10437
10620
|
});
|
|
10438
10621
|
}
|
|
10439
10622
|
mkdirSync17(dirname14(file), { recursive: true });
|
|
10440
|
-
|
|
10623
|
+
writeFileSync31(file, bytes);
|
|
10441
10624
|
}
|
|
10442
10625
|
async function installFrozenGraph(adapters, options) {
|
|
10443
10626
|
const maxAttempts = options.allowSessionRetry === false ? 1 : 2;
|
|
@@ -10499,7 +10682,7 @@ function scopesOf(manifest) {
|
|
|
10499
10682
|
return scopes.length === 0 ? ["@superfunction"] : [...new Set(scopes)];
|
|
10500
10683
|
}
|
|
10501
10684
|
function writeRegistryNpmrc(projectDir2, manifest, registryUrl) {
|
|
10502
|
-
|
|
10685
|
+
writeFileSync31(join44(projectDir2, ".npmrc"), registryNpmrc(scopesOf(manifest), registryUrl), "utf8");
|
|
10503
10686
|
}
|
|
10504
10687
|
function assertGraphInstalled(options) {
|
|
10505
10688
|
if (options.expect === void 0) {
|
|
@@ -10747,10 +10930,10 @@ function installSteps(options) {
|
|
|
10747
10930
|
return { kind: "done", evidence: { attempts: evidence.attempts, tooling: tooling.specifier } };
|
|
10748
10931
|
},
|
|
10749
10932
|
async verify() {
|
|
10750
|
-
if (!
|
|
10933
|
+
if (!existsSync46(join45(projectDir2, "node_modules"))) {
|
|
10751
10934
|
return { ok: false, reason: "dependencies-missing" };
|
|
10752
10935
|
}
|
|
10753
|
-
if (!
|
|
10936
|
+
if (!existsSync46(paths.lockFile)) {
|
|
10754
10937
|
writeLock(options, projectDir2, adapters.clock.now());
|
|
10755
10938
|
}
|
|
10756
10939
|
return { ok: true };
|
|
@@ -10849,7 +11032,7 @@ async function verifyToolingPlan(options, projectDir2, operationId) {
|
|
|
10849
11032
|
});
|
|
10850
11033
|
const isolated = await runIsolated(
|
|
10851
11034
|
projectDir2,
|
|
10852
|
-
|
|
11035
|
+
join45(mkdtempSync(join45(tmpdir(), "spfn-kit-")), operationId),
|
|
10853
11036
|
(workingCopy) => discovered.tooling.planInstall({
|
|
10854
11037
|
projectDir: workingCopy,
|
|
10855
11038
|
release: options.manifest.version
|
|
@@ -11157,8 +11340,8 @@ async function startRecovery(sink, adapters, activationId) {
|
|
|
11157
11340
|
}
|
|
11158
11341
|
|
|
11159
11342
|
// src/kit/customer-source.ts
|
|
11160
|
-
import { existsSync as
|
|
11161
|
-
import { dirname as dirname15, join as
|
|
11343
|
+
import { existsSync as existsSync47, mkdirSync as mkdirSync18, readFileSync as readFileSync28, writeFileSync as writeFileSync32 } from "fs";
|
|
11344
|
+
import { dirname as dirname15, join as join46 } from "path";
|
|
11162
11345
|
var IGNORED_DIRECTORIES = ["node_modules", ".git", ".next", ".turbo", ".vercel", "dist", "coverage"];
|
|
11163
11346
|
var KIT_OWNED_FILES = ["pnpm-lock.yaml", "package.json", ".npmrc", "tsconfig.tsbuildinfo"];
|
|
11164
11347
|
function declaredPaths(declaration) {
|
|
@@ -11203,21 +11386,21 @@ function compareCustomerSource(before, after) {
|
|
|
11203
11386
|
return paths.filter((path5) => before[path5] !== after[path5]).map((path5) => ({ path: path5, before: before[path5] ?? null, after: after[path5] ?? null }));
|
|
11204
11387
|
}
|
|
11205
11388
|
function customerBaselinePath(projectDir2, operationId) {
|
|
11206
|
-
return
|
|
11389
|
+
return join46(projectDir2, ".spfn", "operations", `${operationId}.customer-source.json`);
|
|
11207
11390
|
}
|
|
11208
11391
|
function writeCustomerBaseline(projectDir2, baseline) {
|
|
11209
11392
|
const path5 = customerBaselinePath(projectDir2, baseline.operationId);
|
|
11210
11393
|
mkdirSync18(dirname15(path5), { recursive: true });
|
|
11211
|
-
|
|
11394
|
+
writeFileSync32(path5, `${JSON.stringify(baseline, null, 4)}
|
|
11212
11395
|
`);
|
|
11213
11396
|
}
|
|
11214
11397
|
function readCustomerBaseline(projectDir2, operationId) {
|
|
11215
11398
|
const path5 = customerBaselinePath(projectDir2, operationId);
|
|
11216
|
-
if (!
|
|
11399
|
+
if (!existsSync47(path5)) {
|
|
11217
11400
|
return null;
|
|
11218
11401
|
}
|
|
11219
11402
|
try {
|
|
11220
|
-
const parsed = JSON.parse(
|
|
11403
|
+
const parsed = JSON.parse(readFileSync28(path5, "utf8"));
|
|
11221
11404
|
return parsed?.schemaVersion === 1 && typeof parsed.files === "object" ? parsed : null;
|
|
11222
11405
|
} catch {
|
|
11223
11406
|
return null;
|
|
@@ -11619,8 +11802,8 @@ function planResult(sink, plan, digest) {
|
|
|
11619
11802
|
}
|
|
11620
11803
|
|
|
11621
11804
|
// src/kit/operations/inspect.ts
|
|
11622
|
-
import { existsSync as
|
|
11623
|
-
import { join as
|
|
11805
|
+
import { existsSync as existsSync48 } from "fs";
|
|
11806
|
+
import { join as join47 } from "path";
|
|
11624
11807
|
async function runStatus(request2, adapters) {
|
|
11625
11808
|
const paths = kitPaths(request2.projectDir);
|
|
11626
11809
|
const lock = readInstalledLock(paths.lockFile);
|
|
@@ -11733,7 +11916,7 @@ async function runCheck(request2, adapters) {
|
|
|
11733
11916
|
fixCommand: `spfn kit resume ${journal.operationId} --json`
|
|
11734
11917
|
});
|
|
11735
11918
|
}
|
|
11736
|
-
if (!
|
|
11919
|
+
if (!existsSync48(join47(request2.projectDir, "node_modules"))) {
|
|
11737
11920
|
diagnostics.push({
|
|
11738
11921
|
code: "KIT_GATE_FAILED",
|
|
11739
11922
|
severity: "warning",
|
|
@@ -12145,8 +12328,8 @@ function parseKeys(raw) {
|
|
|
12145
12328
|
}
|
|
12146
12329
|
|
|
12147
12330
|
// src/kit/scaffold.ts
|
|
12148
|
-
import { mkdirSync as mkdirSync19, existsSync as
|
|
12149
|
-
import { dirname as dirname16, join as
|
|
12331
|
+
import { mkdirSync as mkdirSync19, existsSync as existsSync49, readFileSync as readFileSync29, writeFileSync as writeFileSync33 } from "fs";
|
|
12332
|
+
import { dirname as dirname16, join as join48 } from "path";
|
|
12150
12333
|
|
|
12151
12334
|
// src/kit/http/registry.ts
|
|
12152
12335
|
import { createHash as createHash3 } from "crypto";
|
|
@@ -12492,20 +12675,20 @@ var ArtifactScaffoldPort = class {
|
|
|
12492
12675
|
}
|
|
12493
12676
|
};
|
|
12494
12677
|
function seedProjectName(targetDir, name) {
|
|
12495
|
-
const file =
|
|
12496
|
-
if (!
|
|
12678
|
+
const file = join48(targetDir, "package.json");
|
|
12679
|
+
if (!existsSync49(file)) {
|
|
12497
12680
|
return;
|
|
12498
12681
|
}
|
|
12499
12682
|
let parsed;
|
|
12500
12683
|
try {
|
|
12501
|
-
parsed = JSON.parse(
|
|
12684
|
+
parsed = JSON.parse(readFileSync29(file, "utf8"));
|
|
12502
12685
|
} catch {
|
|
12503
12686
|
throw new KitError("KIT_MANIFEST_INVALID", "The release scaffold's package.json is not readable JSON.", {
|
|
12504
12687
|
evidence: { path: "package.json" }
|
|
12505
12688
|
});
|
|
12506
12689
|
}
|
|
12507
12690
|
parsed.name = packageNameOf(name);
|
|
12508
|
-
|
|
12691
|
+
writeFileSync33(file, `${JSON.stringify(parsed, null, 4)}
|
|
12509
12692
|
`, "utf8");
|
|
12510
12693
|
}
|
|
12511
12694
|
function packageNameOf(name) {
|
|
@@ -12513,9 +12696,9 @@ function packageNameOf(name) {
|
|
|
12513
12696
|
return cleaned.length === 0 ? "kit-project" : cleaned;
|
|
12514
12697
|
}
|
|
12515
12698
|
function writeScaffoldRecord(targetDir, record) {
|
|
12516
|
-
const file =
|
|
12699
|
+
const file = join48(targetDir, SCAFFOLD_RECORD_PATH);
|
|
12517
12700
|
mkdirSync19(dirname16(file), { recursive: true });
|
|
12518
|
-
|
|
12701
|
+
writeFileSync33(file, `${JSON.stringify(record, null, 4)}
|
|
12519
12702
|
`, "utf8");
|
|
12520
12703
|
}
|
|
12521
12704
|
|
|
@@ -12895,7 +13078,7 @@ function requireCatalogUrl(projectDir2) {
|
|
|
12895
13078
|
|
|
12896
13079
|
// src/kit/local/index.ts
|
|
12897
13080
|
import { createRequire as createRequire2 } from "module";
|
|
12898
|
-
import { join as
|
|
13081
|
+
import { join as join52 } from "path";
|
|
12899
13082
|
import { pathToFileURL as pathToFileURL4 } from "url";
|
|
12900
13083
|
|
|
12901
13084
|
// src/kit/local/process.ts
|
|
@@ -13044,8 +13227,8 @@ ${result.stdout}`;
|
|
|
13044
13227
|
}
|
|
13045
13228
|
|
|
13046
13229
|
// src/kit/local/database.ts
|
|
13047
|
-
import { existsSync as
|
|
13048
|
-
import { dirname as dirname17, join as
|
|
13230
|
+
import { existsSync as existsSync50 } from "fs";
|
|
13231
|
+
import { dirname as dirname17, join as join49 } from "path";
|
|
13049
13232
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
13050
13233
|
var DEFAULT_DATABASE_TIMEOUT_MS = 9e5;
|
|
13051
13234
|
var SpfnDatabasePort = class {
|
|
@@ -13130,8 +13313,8 @@ function spfnCommand() {
|
|
|
13130
13313
|
function resolveSpfnBin(from = fileURLToPath3(import.meta.url)) {
|
|
13131
13314
|
let directory = dirname17(from);
|
|
13132
13315
|
for (let depth = 0; depth < 8; depth += 1) {
|
|
13133
|
-
const candidate =
|
|
13134
|
-
if (
|
|
13316
|
+
const candidate = join49(directory, "bin", "spfn.js");
|
|
13317
|
+
if (existsSync50(candidate)) {
|
|
13135
13318
|
return candidate;
|
|
13136
13319
|
}
|
|
13137
13320
|
const parent = dirname17(directory);
|
|
@@ -13144,8 +13327,8 @@ function resolveSpfnBin(from = fileURLToPath3(import.meta.url)) {
|
|
|
13144
13327
|
}
|
|
13145
13328
|
|
|
13146
13329
|
// src/kit/local/gates.ts
|
|
13147
|
-
import { existsSync as
|
|
13148
|
-
import { join as
|
|
13330
|
+
import { existsSync as existsSync51, readFileSync as readFileSync30 } from "fs";
|
|
13331
|
+
import { join as join50 } from "path";
|
|
13149
13332
|
var DEFAULT_GATE_TIMEOUT_MS = 9e5;
|
|
13150
13333
|
var GATE_PLANS = {
|
|
13151
13334
|
"kit-check": { scripts: [], fallback: spfnFallback(["kit", "check", "--json"]) },
|
|
@@ -13196,12 +13379,12 @@ var CommandGatePort = class {
|
|
|
13196
13379
|
}
|
|
13197
13380
|
};
|
|
13198
13381
|
function projectScripts(cwd) {
|
|
13199
|
-
const file =
|
|
13200
|
-
if (!
|
|
13382
|
+
const file = join50(cwd, "package.json");
|
|
13383
|
+
if (!existsSync51(file)) {
|
|
13201
13384
|
return {};
|
|
13202
13385
|
}
|
|
13203
13386
|
try {
|
|
13204
|
-
const parsed = JSON.parse(
|
|
13387
|
+
const parsed = JSON.parse(readFileSync30(file, "utf8"));
|
|
13205
13388
|
return parsed.scripts ?? {};
|
|
13206
13389
|
} catch {
|
|
13207
13390
|
return {};
|
|
@@ -13213,8 +13396,8 @@ function spfnFallback(args) {
|
|
|
13213
13396
|
}
|
|
13214
13397
|
|
|
13215
13398
|
// src/kit/local/git.ts
|
|
13216
|
-
import { existsSync as
|
|
13217
|
-
import { join as
|
|
13399
|
+
import { existsSync as existsSync52 } from "fs";
|
|
13400
|
+
import { join as join51 } from "path";
|
|
13218
13401
|
var FALLBACK_AUTHOR_NAME = "spfn kit";
|
|
13219
13402
|
var FALLBACK_AUTHOR_EMAIL = "kit@superfunction.xyz";
|
|
13220
13403
|
var DEFAULT_GIT_TIMEOUT_MS = 12e4;
|
|
@@ -13225,7 +13408,7 @@ var SystemGitPort = class {
|
|
|
13225
13408
|
}
|
|
13226
13409
|
/** Start a repository, or leave the one that is already there alone. */
|
|
13227
13410
|
async init(request2) {
|
|
13228
|
-
if (
|
|
13411
|
+
if (existsSync52(join51(request2.cwd, ".git"))) {
|
|
13229
13412
|
return;
|
|
13230
13413
|
}
|
|
13231
13414
|
const result = await this.git(request2.cwd, ["init"]);
|
|
@@ -13342,7 +13525,7 @@ function createKitLocalPorts(options = {}) {
|
|
|
13342
13525
|
}
|
|
13343
13526
|
function createProjectModuleLoader() {
|
|
13344
13527
|
return async (specifier, projectDir2) => {
|
|
13345
|
-
const resolve4 = createRequire2(
|
|
13528
|
+
const resolve4 = createRequire2(join52(projectDir2, "package.json"));
|
|
13346
13529
|
return import(pathToFileURL4(resolve4.resolve(specifier)).href);
|
|
13347
13530
|
};
|
|
13348
13531
|
}
|