@specific.dev/cli 0.1.43 → 0.1.45
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/dist/admin/404/index.html +1 -1
- package/dist/admin/404.html +1 -1
- package/dist/admin/__next.__PAGE__.txt +4 -4
- package/dist/admin/__next._full.txt +24 -17
- package/dist/admin/__next._head.txt +4 -4
- package/dist/admin/__next._index.txt +10 -4
- package/dist/admin/__next._tree.txt +3 -2
- package/dist/admin/_next/static/chunks/0cb2c4291ba35581.css +4 -0
- package/dist/admin/_next/static/chunks/63473a6cb811ed42.js +5 -0
- package/dist/admin/_next/static/chunks/65ce370ab86b6df6.js +1 -0
- package/dist/admin/_next/static/chunks/6877369fbd84f127.js +1 -0
- package/dist/admin/_next/static/chunks/721087f8fbaa34b3.js +1 -0
- package/dist/admin/_next/static/chunks/9f53491ced2668ee.js +1 -0
- package/dist/admin/_next/static/chunks/a308451471d4cb39.js +1 -0
- package/dist/admin/_next/static/chunks/a6dad97d9634a72d.js.map +1 -1
- package/dist/admin/_next/static/chunks/{ff1a16fafef87110.js → b2b4aada246f4749.js} +1 -1
- package/dist/admin/_next/static/chunks/b4fa9a08d6dc37c1.js +2 -0
- package/dist/admin/_next/static/chunks/db72df2e613a023e.js +5 -0
- package/dist/admin/_next/static/chunks/e3f73cf77dd1ede1.js +1 -0
- package/dist/admin/_next/static/chunks/turbopack-ebee0930f5a58b67.js +4 -0
- package/dist/admin/_next/static/media/1bffadaabf893a1e-s.7cd81963.woff2 +0 -0
- package/dist/admin/_next/static/media/2bbe8d2671613f1f-s.76dcb0b2.woff2 +0 -0
- package/dist/admin/_next/static/media/2c55a0e60120577a-s.2a48534a.woff2 +0 -0
- package/dist/admin/_next/static/media/5476f68d60460930-s.c995e352.woff2 +0 -0
- package/dist/admin/_next/static/media/83afe278b6a6bb3c-s.p.3a6ba036.woff2 +0 -0
- package/dist/admin/_next/static/media/9c72aa0f40e4eef8-s.18a48cbc.woff2 +0 -0
- package/dist/admin/_next/static/media/ad66f9afd8947f86-s.7a40eb73.woff2 +0 -0
- package/dist/admin/_next/static/media/icon.456b8582.svg +12 -0
- package/dist/admin/_not-found/__next._full.txt +19 -13
- package/dist/admin/_not-found/__next._head.txt +4 -4
- package/dist/admin/_not-found/__next._index.txt +10 -4
- package/dist/admin/_not-found/__next._not-found.__PAGE__.txt +2 -2
- package/dist/admin/_not-found/__next._not-found.txt +3 -3
- package/dist/admin/_not-found/__next._tree.txt +2 -2
- package/dist/admin/_not-found/index.html +1 -1
- package/dist/admin/_not-found/index.txt +19 -13
- package/dist/admin/databases/__next._full.txt +24 -17
- package/dist/admin/databases/__next._head.txt +4 -4
- package/dist/admin/databases/__next._index.txt +10 -4
- package/dist/admin/databases/__next._tree.txt +3 -2
- package/dist/admin/databases/__next.databases.__PAGE__.txt +4 -4
- package/dist/admin/databases/__next.databases.txt +3 -3
- package/dist/admin/databases/index.html +1 -1
- package/dist/admin/databases/index.txt +24 -17
- package/dist/admin/icon.svg +12 -0
- package/dist/admin/index.html +1 -1
- package/dist/admin/index.txt +24 -17
- package/dist/cli.js +308 -497
- package/dist/docs/integrations/nextjs.md +18 -0
- package/dist/docs/migrations/supabase.md +18 -0
- package/dist/docs/secrets-config.md +52 -8
- package/package.json +12 -4
- package/dist/admin/_next/static/chunks/1a608619ba3183f8.js +0 -5
- package/dist/admin/_next/static/chunks/1da818a0086b4acf.css +0 -3
- package/dist/admin/_next/static/chunks/42730c0491633b9d.js +0 -5
- package/dist/admin/_next/static/chunks/465f799faf41e6df.js +0 -1
- package/dist/admin/_next/static/chunks/806bdb8e4a6a9b95.js +0 -4
- package/dist/admin/_next/static/chunks/9054c84ba21a4c14.js +0 -2
- package/dist/admin/_next/static/chunks/b71388016463cab2.js +0 -1
- package/dist/admin/_next/static/chunks/cba5c081fc9dc612.js +0 -2
- package/dist/admin/_next/static/chunks/d2be314c3ece3fbe.js +0 -1
- package/dist/admin/_next/static/chunks/dde2c8e6322d1671.js +0 -1
- package/dist/admin/_next/static/chunks/turbopack-22b7312525502d51.js +0 -4
- /package/dist/admin/_next/static/{3dGrdrrH7RVk5ixe6lgRQ → WUdRH_Qksuvhq_ji1IkHb}/_buildManifest.js +0 -0
- /package/dist/admin/_next/static/{3dGrdrrH7RVk5ixe6lgRQ → WUdRH_Qksuvhq_ji1IkHb}/_clientMiddlewareManifest.json +0 -0
- /package/dist/admin/_next/static/{3dGrdrrH7RVk5ixe6lgRQ → WUdRH_Qksuvhq_ji1IkHb}/_ssgManifest.js +0 -0
package/dist/cli.js
CHANGED
|
@@ -38,7 +38,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
38
38
|
mod
|
|
39
39
|
));
|
|
40
40
|
|
|
41
|
-
//
|
|
41
|
+
// node_modules/.pnpm/is-docker@3.0.0/node_modules/is-docker/index.js
|
|
42
42
|
import fs4 from "node:fs";
|
|
43
43
|
function hasDockerEnv() {
|
|
44
44
|
try {
|
|
@@ -63,11 +63,11 @@ function isDocker() {
|
|
|
63
63
|
}
|
|
64
64
|
var isDockerCached;
|
|
65
65
|
var init_is_docker = __esm({
|
|
66
|
-
"
|
|
66
|
+
"node_modules/.pnpm/is-docker@3.0.0/node_modules/is-docker/index.js"() {
|
|
67
67
|
}
|
|
68
68
|
});
|
|
69
69
|
|
|
70
|
-
//
|
|
70
|
+
// node_modules/.pnpm/is-inside-container@1.0.0/node_modules/is-inside-container/index.js
|
|
71
71
|
import fs5 from "node:fs";
|
|
72
72
|
function isInsideContainer() {
|
|
73
73
|
if (cachedResult === void 0) {
|
|
@@ -77,7 +77,7 @@ function isInsideContainer() {
|
|
|
77
77
|
}
|
|
78
78
|
var cachedResult, hasContainerEnv;
|
|
79
79
|
var init_is_inside_container = __esm({
|
|
80
|
-
"
|
|
80
|
+
"node_modules/.pnpm/is-inside-container@1.0.0/node_modules/is-inside-container/index.js"() {
|
|
81
81
|
init_is_docker();
|
|
82
82
|
hasContainerEnv = () => {
|
|
83
83
|
try {
|
|
@@ -90,13 +90,13 @@ var init_is_inside_container = __esm({
|
|
|
90
90
|
}
|
|
91
91
|
});
|
|
92
92
|
|
|
93
|
-
//
|
|
93
|
+
// node_modules/.pnpm/is-wsl@3.1.0/node_modules/is-wsl/index.js
|
|
94
94
|
import process2 from "node:process";
|
|
95
95
|
import os3 from "node:os";
|
|
96
96
|
import fs6 from "node:fs";
|
|
97
97
|
var isWsl, is_wsl_default;
|
|
98
98
|
var init_is_wsl = __esm({
|
|
99
|
-
"
|
|
99
|
+
"node_modules/.pnpm/is-wsl@3.1.0/node_modules/is-wsl/index.js"() {
|
|
100
100
|
init_is_inside_container();
|
|
101
101
|
isWsl = () => {
|
|
102
102
|
if (process2.platform !== "linux") {
|
|
@@ -118,14 +118,14 @@ var init_is_wsl = __esm({
|
|
|
118
118
|
}
|
|
119
119
|
});
|
|
120
120
|
|
|
121
|
-
//
|
|
121
|
+
// node_modules/.pnpm/powershell-utils@0.1.0/node_modules/powershell-utils/index.js
|
|
122
122
|
import process3 from "node:process";
|
|
123
123
|
import { Buffer as Buffer2 } from "node:buffer";
|
|
124
124
|
import { promisify } from "node:util";
|
|
125
125
|
import childProcess from "node:child_process";
|
|
126
126
|
var execFile, powerShellPath, executePowerShell;
|
|
127
127
|
var init_powershell_utils = __esm({
|
|
128
|
-
"
|
|
128
|
+
"node_modules/.pnpm/powershell-utils@0.1.0/node_modules/powershell-utils/index.js"() {
|
|
129
129
|
execFile = promisify(childProcess.execFile);
|
|
130
130
|
powerShellPath = () => `${process3.env.SYSTEMROOT || process3.env.windir || String.raw`C:\Windows`}\\System32\\WindowsPowerShell\\v1.0\\powershell.exe`;
|
|
131
131
|
executePowerShell = async (command, options2 = {}) => {
|
|
@@ -158,7 +158,7 @@ var init_powershell_utils = __esm({
|
|
|
158
158
|
}
|
|
159
159
|
});
|
|
160
160
|
|
|
161
|
-
//
|
|
161
|
+
// node_modules/.pnpm/wsl-utils@0.3.1/node_modules/wsl-utils/utilities.js
|
|
162
162
|
function parseMountPointFromConfig(content) {
|
|
163
163
|
for (const line of content.split("\n")) {
|
|
164
164
|
if (/^\s*#/.test(line)) {
|
|
@@ -172,17 +172,17 @@ function parseMountPointFromConfig(content) {
|
|
|
172
172
|
}
|
|
173
173
|
}
|
|
174
174
|
var init_utilities = __esm({
|
|
175
|
-
"
|
|
175
|
+
"node_modules/.pnpm/wsl-utils@0.3.1/node_modules/wsl-utils/utilities.js"() {
|
|
176
176
|
}
|
|
177
177
|
});
|
|
178
178
|
|
|
179
|
-
//
|
|
179
|
+
// node_modules/.pnpm/wsl-utils@0.3.1/node_modules/wsl-utils/index.js
|
|
180
180
|
import { promisify as promisify2 } from "node:util";
|
|
181
181
|
import childProcess2 from "node:child_process";
|
|
182
182
|
import fs7, { constants as fsConstants } from "node:fs/promises";
|
|
183
183
|
var execFile2, wslDrivesMountPoint, powerShellPathFromWsl, powerShellPath2, canAccessPowerShellPromise, canAccessPowerShell, wslDefaultBrowser, convertWslPathToWindows;
|
|
184
184
|
var init_wsl_utils = __esm({
|
|
185
|
-
"
|
|
185
|
+
"node_modules/.pnpm/wsl-utils@0.3.1/node_modules/wsl-utils/index.js"() {
|
|
186
186
|
init_is_wsl();
|
|
187
187
|
init_powershell_utils();
|
|
188
188
|
init_utilities();
|
|
@@ -252,7 +252,7 @@ var init_wsl_utils = __esm({
|
|
|
252
252
|
}
|
|
253
253
|
});
|
|
254
254
|
|
|
255
|
-
//
|
|
255
|
+
// node_modules/.pnpm/define-lazy-prop@3.0.0/node_modules/define-lazy-prop/index.js
|
|
256
256
|
function defineLazyProperty(object, propertyName, valueGetter) {
|
|
257
257
|
const define = (value) => Object.defineProperty(object, propertyName, { value, enumerable: true, writable: true });
|
|
258
258
|
Object.defineProperty(object, propertyName, {
|
|
@@ -270,11 +270,11 @@ function defineLazyProperty(object, propertyName, valueGetter) {
|
|
|
270
270
|
return object;
|
|
271
271
|
}
|
|
272
272
|
var init_define_lazy_prop = __esm({
|
|
273
|
-
"
|
|
273
|
+
"node_modules/.pnpm/define-lazy-prop@3.0.0/node_modules/define-lazy-prop/index.js"() {
|
|
274
274
|
}
|
|
275
275
|
});
|
|
276
276
|
|
|
277
|
-
//
|
|
277
|
+
// node_modules/.pnpm/default-browser-id@5.0.1/node_modules/default-browser-id/index.js
|
|
278
278
|
import { promisify as promisify3 } from "node:util";
|
|
279
279
|
import process4 from "node:process";
|
|
280
280
|
import { execFile as execFile3 } from "node:child_process";
|
|
@@ -292,12 +292,12 @@ async function defaultBrowserId() {
|
|
|
292
292
|
}
|
|
293
293
|
var execFileAsync;
|
|
294
294
|
var init_default_browser_id = __esm({
|
|
295
|
-
"
|
|
295
|
+
"node_modules/.pnpm/default-browser-id@5.0.1/node_modules/default-browser-id/index.js"() {
|
|
296
296
|
execFileAsync = promisify3(execFile3);
|
|
297
297
|
}
|
|
298
298
|
});
|
|
299
299
|
|
|
300
|
-
//
|
|
300
|
+
// node_modules/.pnpm/run-applescript@7.1.0/node_modules/run-applescript/index.js
|
|
301
301
|
import process5 from "node:process";
|
|
302
302
|
import { promisify as promisify4 } from "node:util";
|
|
303
303
|
import { execFile as execFile4, execFileSync } from "node:child_process";
|
|
@@ -315,23 +315,23 @@ async function runAppleScript(script, { humanReadableOutput = true, signal } = {
|
|
|
315
315
|
}
|
|
316
316
|
var execFileAsync2;
|
|
317
317
|
var init_run_applescript = __esm({
|
|
318
|
-
"
|
|
318
|
+
"node_modules/.pnpm/run-applescript@7.1.0/node_modules/run-applescript/index.js"() {
|
|
319
319
|
execFileAsync2 = promisify4(execFile4);
|
|
320
320
|
}
|
|
321
321
|
});
|
|
322
322
|
|
|
323
|
-
//
|
|
323
|
+
// node_modules/.pnpm/bundle-name@4.1.0/node_modules/bundle-name/index.js
|
|
324
324
|
async function bundleName(bundleId) {
|
|
325
325
|
return runAppleScript(`tell application "Finder" to set app_path to application file id "${bundleId}" as string
|
|
326
326
|
tell application "System Events" to get value of property list item "CFBundleName" of property list file (app_path & ":Contents:Info.plist")`);
|
|
327
327
|
}
|
|
328
328
|
var init_bundle_name = __esm({
|
|
329
|
-
"
|
|
329
|
+
"node_modules/.pnpm/bundle-name@4.1.0/node_modules/bundle-name/index.js"() {
|
|
330
330
|
init_run_applescript();
|
|
331
331
|
}
|
|
332
332
|
});
|
|
333
333
|
|
|
334
|
-
//
|
|
334
|
+
// node_modules/.pnpm/default-browser@5.4.0/node_modules/default-browser/windows.js
|
|
335
335
|
import { promisify as promisify5 } from "node:util";
|
|
336
336
|
import { execFile as execFile5 } from "node:child_process";
|
|
337
337
|
async function defaultBrowser(_execFileAsync = execFileAsync3) {
|
|
@@ -354,7 +354,7 @@ async function defaultBrowser(_execFileAsync = execFileAsync3) {
|
|
|
354
354
|
}
|
|
355
355
|
var execFileAsync3, windowsBrowserProgIds, _windowsBrowserProgIdMap, UnknownBrowserError;
|
|
356
356
|
var init_windows = __esm({
|
|
357
|
-
"
|
|
357
|
+
"node_modules/.pnpm/default-browser@5.4.0/node_modules/default-browser/windows.js"() {
|
|
358
358
|
execFileAsync3 = promisify5(execFile5);
|
|
359
359
|
windowsBrowserProgIds = {
|
|
360
360
|
MSEdgeHTM: { name: "Edge", id: "com.microsoft.edge" },
|
|
@@ -381,7 +381,7 @@ var init_windows = __esm({
|
|
|
381
381
|
}
|
|
382
382
|
});
|
|
383
383
|
|
|
384
|
-
//
|
|
384
|
+
// node_modules/.pnpm/default-browser@5.4.0/node_modules/default-browser/index.js
|
|
385
385
|
import { promisify as promisify6 } from "node:util";
|
|
386
386
|
import process6 from "node:process";
|
|
387
387
|
import { execFile as execFile6 } from "node:child_process";
|
|
@@ -404,7 +404,7 @@ async function defaultBrowser2() {
|
|
|
404
404
|
}
|
|
405
405
|
var execFileAsync4, titleize;
|
|
406
406
|
var init_default_browser = __esm({
|
|
407
|
-
"
|
|
407
|
+
"node_modules/.pnpm/default-browser@5.4.0/node_modules/default-browser/index.js"() {
|
|
408
408
|
init_default_browser_id();
|
|
409
409
|
init_bundle_name();
|
|
410
410
|
init_windows();
|
|
@@ -414,17 +414,17 @@ var init_default_browser = __esm({
|
|
|
414
414
|
}
|
|
415
415
|
});
|
|
416
416
|
|
|
417
|
-
//
|
|
417
|
+
// node_modules/.pnpm/is-in-ssh@1.0.0/node_modules/is-in-ssh/index.js
|
|
418
418
|
import process7 from "node:process";
|
|
419
419
|
var isInSsh, is_in_ssh_default;
|
|
420
420
|
var init_is_in_ssh = __esm({
|
|
421
|
-
"
|
|
421
|
+
"node_modules/.pnpm/is-in-ssh@1.0.0/node_modules/is-in-ssh/index.js"() {
|
|
422
422
|
isInSsh = Boolean(process7.env.SSH_CONNECTION || process7.env.SSH_CLIENT || process7.env.SSH_TTY);
|
|
423
423
|
is_in_ssh_default = isInSsh;
|
|
424
424
|
}
|
|
425
425
|
});
|
|
426
426
|
|
|
427
|
-
//
|
|
427
|
+
// node_modules/.pnpm/open@11.0.0/node_modules/open/index.js
|
|
428
428
|
var open_exports = {};
|
|
429
429
|
__export(open_exports, {
|
|
430
430
|
apps: () => apps,
|
|
@@ -457,7 +457,7 @@ function detectPlatformBinary({ [platform2]: platformBinary }, { wsl } = {}) {
|
|
|
457
457
|
}
|
|
458
458
|
var fallbackAttemptSymbol, __dirname, localXdgOpenPath, platform2, arch, tryEachApp, baseOpen, open, openApp, apps, open_default;
|
|
459
459
|
var init_open = __esm({
|
|
460
|
-
"
|
|
460
|
+
"node_modules/.pnpm/open@11.0.0/node_modules/open/index.js"() {
|
|
461
461
|
init_wsl_utils();
|
|
462
462
|
init_powershell_utils();
|
|
463
463
|
init_define_lazy_prop();
|
|
@@ -744,9 +744,9 @@ var init_open = __esm({
|
|
|
744
744
|
}
|
|
745
745
|
});
|
|
746
746
|
|
|
747
|
-
//
|
|
747
|
+
// node_modules/.pnpm/hcl2-json-parser@1.0.1/node_modules/hcl2-json-parser/dist/index.js
|
|
748
748
|
var require_dist = __commonJS({
|
|
749
|
-
"
|
|
749
|
+
"node_modules/.pnpm/hcl2-json-parser@1.0.1/node_modules/hcl2-json-parser/dist/index.js"(exports, module) {
|
|
750
750
|
"use strict";
|
|
751
751
|
(function() {
|
|
752
752
|
var $goVersion = "go1.18.10";
|
|
@@ -754,8 +754,8 @@ var require_dist = __commonJS({
|
|
|
754
754
|
var $global, $module, $NaN = NaN;
|
|
755
755
|
if ("undefined" != typeof window ? $global = window : "undefined" != typeof self ? $global = self : "undefined" != typeof global ? ($global = global).require = __require : $global = this, void 0 === $global || void 0 === $global.Array) throw new Error("no global object found");
|
|
756
756
|
if ("undefined" != typeof module && ($module = module), !$global.fs && $global.require) try {
|
|
757
|
-
var
|
|
758
|
-
"object" == typeof
|
|
757
|
+
var fs24 = $global.require("fs");
|
|
758
|
+
"object" == typeof fs24 && null !== fs24 && 0 !== Object.keys(fs24).length && ($global.fs = fs24);
|
|
759
759
|
} catch (e) {
|
|
760
760
|
}
|
|
761
761
|
if (!$global.fs) {
|
|
@@ -183843,7 +183843,7 @@ function trackEvent(event, properties) {
|
|
|
183843
183843
|
event,
|
|
183844
183844
|
properties: {
|
|
183845
183845
|
...properties,
|
|
183846
|
-
cli_version: "0.1.
|
|
183846
|
+
cli_version: "0.1.45",
|
|
183847
183847
|
platform: process.platform,
|
|
183848
183848
|
node_version: process.version,
|
|
183849
183849
|
project_id: getProjectId(),
|
|
@@ -183911,7 +183911,7 @@ function appendOrCreateFile(filePath, content) {
|
|
|
183911
183911
|
}
|
|
183912
183912
|
function addToGitignore() {
|
|
183913
183913
|
const gitignorePath = path6.join(process.cwd(), ".gitignore");
|
|
183914
|
-
const entries = [".specific", "specific.
|
|
183914
|
+
const entries = [".specific", "specific.local"];
|
|
183915
183915
|
if (fs10.existsSync(gitignorePath)) {
|
|
183916
183916
|
const existing = fs10.readFileSync(gitignorePath, "utf-8");
|
|
183917
183917
|
const lines = existing.split("\n").map((l) => l.trim());
|
|
@@ -184172,7 +184172,7 @@ import Spinner3 from "ink-spinner";
|
|
|
184172
184172
|
import * as fs11 from "fs";
|
|
184173
184173
|
import * as path7 from "path";
|
|
184174
184174
|
|
|
184175
|
-
//
|
|
184175
|
+
// node_modules/.pnpm/@specific+config@file+..+config/node_modules/@specific/config/dist/parser.js
|
|
184176
184176
|
var import_hcl2_json_parser = __toESM(require_dist(), 1);
|
|
184177
184177
|
var { parseToObject } = import_hcl2_json_parser.default;
|
|
184178
184178
|
function parseReference(value) {
|
|
@@ -184740,13 +184740,13 @@ import Spinner4 from "ink-spinner";
|
|
|
184740
184740
|
import * as fs19 from "fs";
|
|
184741
184741
|
import * as path16 from "path";
|
|
184742
184742
|
|
|
184743
|
-
// node_modules/chokidar/index.js
|
|
184743
|
+
// node_modules/.pnpm/chokidar@5.0.0/node_modules/chokidar/index.js
|
|
184744
184744
|
import { EventEmitter } from "node:events";
|
|
184745
184745
|
import { stat as statcb, Stats } from "node:fs";
|
|
184746
184746
|
import { readdir as readdir2, stat as stat3 } from "node:fs/promises";
|
|
184747
184747
|
import * as sp2 from "node:path";
|
|
184748
184748
|
|
|
184749
|
-
// node_modules/readdirp/index.js
|
|
184749
|
+
// node_modules/.pnpm/readdirp@5.0.0/node_modules/readdirp/index.js
|
|
184750
184750
|
import { lstat, readdir, realpath, stat } from "node:fs/promises";
|
|
184751
184751
|
import { join as pjoin, relative as prelative, resolve as presolve, sep as psep } from "node:path";
|
|
184752
184752
|
import { Readable } from "node:stream";
|
|
@@ -184979,7 +184979,7 @@ function readdirp(root, options2 = {}) {
|
|
|
184979
184979
|
return new ReaddirpStream(options2);
|
|
184980
184980
|
}
|
|
184981
184981
|
|
|
184982
|
-
// node_modules/chokidar/handler.js
|
|
184982
|
+
// node_modules/.pnpm/chokidar@5.0.0/node_modules/chokidar/handler.js
|
|
184983
184983
|
import { watch as fs_watch, unwatchFile, watchFile } from "node:fs";
|
|
184984
184984
|
import { realpath as fsrealpath, lstat as lstat2, open as open2, stat as stat2 } from "node:fs/promises";
|
|
184985
184985
|
import { type as osType } from "node:os";
|
|
@@ -185738,7 +185738,7 @@ var NodeFsHandler = class {
|
|
|
185738
185738
|
}
|
|
185739
185739
|
};
|
|
185740
185740
|
|
|
185741
|
-
// node_modules/chokidar/index.js
|
|
185741
|
+
// node_modules/.pnpm/chokidar@5.0.0/node_modules/chokidar/index.js
|
|
185742
185742
|
var SLASH = "/";
|
|
185743
185743
|
var SLASH_SLASH = "//";
|
|
185744
185744
|
var ONE_DOT = ".";
|
|
@@ -187103,224 +187103,107 @@ function sleep2(ms) {
|
|
|
187103
187103
|
// src/lib/dev/service-runner.ts
|
|
187104
187104
|
import { spawn as spawn2 } from "child_process";
|
|
187105
187105
|
|
|
187106
|
-
// src/lib/
|
|
187106
|
+
// src/lib/local/parser.ts
|
|
187107
187107
|
var import_hcl2_json_parser2 = __toESM(require_dist(), 1);
|
|
187108
|
-
import { readFile, writeFile
|
|
187108
|
+
import { readFile, writeFile } from "fs/promises";
|
|
187109
187109
|
import { existsSync as existsSync10 } from "fs";
|
|
187110
|
-
import * as path11 from "path";
|
|
187111
|
-
import * as crypto2 from "crypto";
|
|
187112
187110
|
var { parseToObject: parseToObject2 } = import_hcl2_json_parser2.default;
|
|
187113
|
-
var
|
|
187114
|
-
var
|
|
187115
|
-
|
|
187111
|
+
var LOCAL_FILE = "specific.local";
|
|
187112
|
+
var HEADER_COMMENT = `# Local secrets and configuration
|
|
187113
|
+
# Do not commit this file
|
|
187114
|
+
|
|
187115
|
+
`;
|
|
187116
|
+
async function parseLocalFile(content) {
|
|
187116
187117
|
const secrets = /* @__PURE__ */ new Map();
|
|
187118
|
+
const configs = /* @__PURE__ */ new Map();
|
|
187117
187119
|
if (!content.trim()) {
|
|
187118
|
-
return secrets;
|
|
187120
|
+
return { secrets, configs };
|
|
187119
187121
|
}
|
|
187120
187122
|
const parsed = await parseToObject2(content);
|
|
187121
|
-
|
|
187122
|
-
|
|
187123
|
-
|
|
187124
|
-
|
|
187125
|
-
|
|
187126
|
-
|
|
187127
|
-
|
|
187128
|
-
|
|
187129
|
-
|
|
187130
|
-
return /* @__PURE__ */ new Map();
|
|
187131
|
-
}
|
|
187132
|
-
const content = await readFile(SECRETS_FILE, "utf-8");
|
|
187133
|
-
return await parseSecretsFile(content);
|
|
187134
|
-
}
|
|
187135
|
-
function generateRandomString(length = 64) {
|
|
187136
|
-
const chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
|
187137
|
-
const bytes = crypto2.randomBytes(length);
|
|
187138
|
-
let result = "";
|
|
187139
|
-
for (let i = 0; i < length; i++) {
|
|
187140
|
-
result += chars[bytes[i] % chars.length];
|
|
187141
|
-
}
|
|
187142
|
-
return result;
|
|
187143
|
-
}
|
|
187144
|
-
async function loadGeneratedSecrets() {
|
|
187145
|
-
if (!existsSync10(GENERATED_SECRETS_FILE)) {
|
|
187146
|
-
return /* @__PURE__ */ new Map();
|
|
187147
|
-
}
|
|
187148
|
-
const content = await readFile(GENERATED_SECRETS_FILE, "utf-8");
|
|
187149
|
-
const parsed = JSON.parse(content);
|
|
187150
|
-
return new Map(Object.entries(parsed));
|
|
187151
|
-
}
|
|
187152
|
-
async function saveGeneratedSecret(name, value) {
|
|
187153
|
-
let secrets = {};
|
|
187154
|
-
if (existsSync10(GENERATED_SECRETS_FILE)) {
|
|
187155
|
-
const content = await readFile(GENERATED_SECRETS_FILE, "utf-8");
|
|
187156
|
-
secrets = JSON.parse(content);
|
|
187157
|
-
}
|
|
187158
|
-
secrets[name] = value;
|
|
187159
|
-
const dir = path11.dirname(GENERATED_SECRETS_FILE);
|
|
187160
|
-
if (!existsSync10(dir)) {
|
|
187161
|
-
await mkdir(dir, { recursive: true });
|
|
187162
|
-
}
|
|
187163
|
-
await writeFile(GENERATED_SECRETS_FILE, JSON.stringify(secrets, null, 2) + "\n");
|
|
187164
|
-
}
|
|
187165
|
-
async function prepareSecrets(secretsConfig, isDevMode = false) {
|
|
187166
|
-
const userSecrets = await loadSecrets();
|
|
187167
|
-
const generatedSecrets = await loadGeneratedSecrets();
|
|
187168
|
-
const finalSecrets = /* @__PURE__ */ new Map();
|
|
187169
|
-
for (const secretDef of secretsConfig) {
|
|
187170
|
-
const userValue = userSecrets.get(secretDef.name);
|
|
187171
|
-
if (userValue !== void 0) {
|
|
187172
|
-
finalSecrets.set(secretDef.name, userValue);
|
|
187173
|
-
continue;
|
|
187174
|
-
}
|
|
187175
|
-
if (secretDef.generated) {
|
|
187176
|
-
let generatedValue = generatedSecrets.get(secretDef.name);
|
|
187177
|
-
if (generatedValue === void 0) {
|
|
187178
|
-
generatedValue = generateRandomString(secretDef.length ?? 64);
|
|
187179
|
-
await saveGeneratedSecret(secretDef.name, generatedValue);
|
|
187123
|
+
if (parsed.secrets) {
|
|
187124
|
+
const secretsBlocks = Array.isArray(parsed.secrets) ? parsed.secrets : [parsed.secrets];
|
|
187125
|
+
for (const block of secretsBlocks) {
|
|
187126
|
+
if (block && typeof block === "object") {
|
|
187127
|
+
for (const [key, value] of Object.entries(block)) {
|
|
187128
|
+
if (typeof value === "string") {
|
|
187129
|
+
secrets.set(key, value);
|
|
187130
|
+
}
|
|
187131
|
+
}
|
|
187180
187132
|
}
|
|
187181
|
-
finalSecrets.set(secretDef.name, generatedValue);
|
|
187182
|
-
continue;
|
|
187183
|
-
}
|
|
187184
|
-
if (isDevMode && secretDef.dev?.required === false) {
|
|
187185
|
-
finalSecrets.set(secretDef.name, "");
|
|
187186
|
-
continue;
|
|
187187
187133
|
}
|
|
187188
187134
|
}
|
|
187189
|
-
|
|
187190
|
-
|
|
187191
|
-
|
|
187192
|
-
|
|
187193
|
-
|
|
187194
|
-
|
|
187195
|
-
|
|
187196
|
-
|
|
187197
|
-
|
|
187198
|
-
}
|
|
187199
|
-
const escapedValue = value.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
187200
|
-
const secretPattern = new RegExp(`^${name}\\s*=\\s*"[^"]*"\\s*$`, "m");
|
|
187201
|
-
if (secretPattern.test(content)) {
|
|
187202
|
-
content = content.replace(secretPattern, `${name} = "${escapedValue}"`);
|
|
187203
|
-
} else {
|
|
187204
|
-
content = content.trimEnd() + `
|
|
187205
|
-
${name} = "${escapedValue}"
|
|
187206
|
-
`;
|
|
187207
|
-
}
|
|
187208
|
-
await writeFile(SECRETS_FILE, content);
|
|
187209
|
-
}
|
|
187210
|
-
function findUsedSecrets(services, isDevMode) {
|
|
187211
|
-
const used = /* @__PURE__ */ new Set();
|
|
187212
|
-
for (const service of services) {
|
|
187213
|
-
const mergedEnv = isDevMode ? { ...service.env, ...service.dev?.env } : service.env;
|
|
187214
|
-
for (const value of Object.values(mergedEnv ?? {})) {
|
|
187215
|
-
if (typeof value === "object" && value.type === "secret") {
|
|
187216
|
-
used.add(value.name);
|
|
187135
|
+
if (parsed.config) {
|
|
187136
|
+
const configBlocks = Array.isArray(parsed.config) ? parsed.config : [parsed.config];
|
|
187137
|
+
for (const block of configBlocks) {
|
|
187138
|
+
if (block && typeof block === "object") {
|
|
187139
|
+
for (const [key, value] of Object.entries(block)) {
|
|
187140
|
+
if (typeof value === "string") {
|
|
187141
|
+
configs.set(key, value);
|
|
187142
|
+
}
|
|
187143
|
+
}
|
|
187217
187144
|
}
|
|
187218
187145
|
}
|
|
187219
187146
|
}
|
|
187220
|
-
return
|
|
187221
|
-
}
|
|
187222
|
-
function findMissingSecrets(secretsDef, preparedSecrets, usedSecrets) {
|
|
187223
|
-
const missing = [];
|
|
187224
|
-
for (const secret of secretsDef) {
|
|
187225
|
-
if (secret.generated) continue;
|
|
187226
|
-
if (usedSecrets && !usedSecrets.has(secret.name)) continue;
|
|
187227
|
-
if (!preparedSecrets.has(secret.name)) {
|
|
187228
|
-
missing.push(secret.name);
|
|
187229
|
-
}
|
|
187230
|
-
}
|
|
187231
|
-
return missing;
|
|
187147
|
+
return { secrets, configs };
|
|
187232
187148
|
}
|
|
187233
|
-
|
|
187234
|
-
|
|
187235
|
-
|
|
187236
|
-
import { readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
|
|
187237
|
-
import { existsSync as existsSync11 } from "fs";
|
|
187238
|
-
var { parseToObject: parseToObject3 } = import_hcl2_json_parser3.default;
|
|
187239
|
-
var CONFIG_FILE = "specific.config";
|
|
187240
|
-
async function parseConfigFile(content) {
|
|
187241
|
-
const configs = /* @__PURE__ */ new Map();
|
|
187242
|
-
if (!content.trim()) {
|
|
187243
|
-
return configs;
|
|
187244
|
-
}
|
|
187245
|
-
const parsed = await parseToObject3(content);
|
|
187246
|
-
for (const [key, value] of Object.entries(parsed)) {
|
|
187247
|
-
if (typeof value === "string") {
|
|
187248
|
-
configs.set(key, value);
|
|
187249
|
-
}
|
|
187149
|
+
async function loadLocal() {
|
|
187150
|
+
if (!existsSync10(LOCAL_FILE)) {
|
|
187151
|
+
return { secrets: /* @__PURE__ */ new Map(), configs: /* @__PURE__ */ new Map() };
|
|
187250
187152
|
}
|
|
187251
|
-
|
|
187153
|
+
const content = await readFile(LOCAL_FILE, "utf-8");
|
|
187154
|
+
return await parseLocalFile(content);
|
|
187252
187155
|
}
|
|
187253
|
-
|
|
187254
|
-
|
|
187255
|
-
return /* @__PURE__ */ new Map();
|
|
187256
|
-
}
|
|
187257
|
-
const content = await readFile2(CONFIG_FILE, "utf-8");
|
|
187258
|
-
return await parseConfigFile(content);
|
|
187156
|
+
function escapeHclValue(value) {
|
|
187157
|
+
return value.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
187259
187158
|
}
|
|
187260
|
-
|
|
187261
|
-
|
|
187262
|
-
|
|
187263
|
-
|
|
187264
|
-
|
|
187265
|
-
|
|
187266
|
-
|
|
187267
|
-
|
|
187159
|
+
function updateBlockValue(content, blockName, key, value) {
|
|
187160
|
+
const escapedValue = escapeHclValue(value);
|
|
187161
|
+
const newLine = ` ${key} = "${escapedValue}"`;
|
|
187162
|
+
const blockRegex = new RegExp(`(${blockName}\\s*\\{)([^}]*)(\\})`, "s");
|
|
187163
|
+
const blockMatch = content.match(blockRegex);
|
|
187164
|
+
if (blockMatch) {
|
|
187165
|
+
const blockContent = blockMatch[2];
|
|
187166
|
+
const keyRegex = new RegExp(`^(\\s*)${key}\\s*=\\s*"[^"]*"\\s*$`, "m");
|
|
187167
|
+
const keyMatch = blockContent.match(keyRegex);
|
|
187168
|
+
if (keyMatch) {
|
|
187169
|
+
const updatedBlockContent = blockContent.replace(keyRegex, newLine);
|
|
187170
|
+
return content.replace(blockRegex, `$1${updatedBlockContent}$3`);
|
|
187171
|
+
} else {
|
|
187172
|
+
const trimmedContent = blockContent.trimEnd();
|
|
187173
|
+
const newBlockContent = trimmedContent ? `${trimmedContent}
|
|
187174
|
+
${newLine}
|
|
187175
|
+
` : `
|
|
187176
|
+
${newLine}
|
|
187268
187177
|
`;
|
|
187269
|
-
|
|
187270
|
-
|
|
187271
|
-
const configPattern = new RegExp(`^${name}\\s*=\\s*"[^"]*"\\s*$`, "m");
|
|
187272
|
-
if (configPattern.test(content)) {
|
|
187273
|
-
content = content.replace(configPattern, `${name} = "${escapedValue}"`);
|
|
187178
|
+
return content.replace(blockRegex, `$1${newBlockContent}$3`);
|
|
187179
|
+
}
|
|
187274
187180
|
} else {
|
|
187275
|
-
|
|
187276
|
-
${
|
|
187277
|
-
`;
|
|
187278
|
-
}
|
|
187279
|
-
await writeFile2(CONFIG_FILE, content);
|
|
187181
|
+
const newBlock = `${blockName} {
|
|
187182
|
+
${newLine}
|
|
187280
187183
|
}
|
|
187281
|
-
|
|
187282
|
-
|
|
187283
|
-
const finalConfigs = /* @__PURE__ */ new Map();
|
|
187284
|
-
for (const configDef of configsDef) {
|
|
187285
|
-
const userValue = userConfigs.get(configDef.name);
|
|
187286
|
-
if (userValue !== void 0) {
|
|
187287
|
-
finalConfigs.set(configDef.name, userValue);
|
|
187288
|
-
continue;
|
|
187289
|
-
}
|
|
187290
|
-
const envOverride = environmentOverrides?.[configDef.name];
|
|
187291
|
-
if (envOverride !== void 0) {
|
|
187292
|
-
finalConfigs.set(configDef.name, envOverride);
|
|
187293
|
-
continue;
|
|
187294
|
-
}
|
|
187295
|
-
const effectiveDefault = isDevMode && configDef.dev?.default !== void 0 ? configDef.dev.default : configDef.default;
|
|
187296
|
-
if (effectiveDefault !== void 0) {
|
|
187297
|
-
finalConfigs.set(configDef.name, effectiveDefault);
|
|
187298
|
-
continue;
|
|
187299
|
-
}
|
|
187184
|
+
`;
|
|
187185
|
+
return content.trimEnd() + "\n\n" + newBlock;
|
|
187300
187186
|
}
|
|
187301
|
-
return finalConfigs;
|
|
187302
187187
|
}
|
|
187303
|
-
function
|
|
187304
|
-
|
|
187305
|
-
|
|
187306
|
-
|
|
187307
|
-
|
|
187308
|
-
|
|
187309
|
-
used.add(value.name);
|
|
187310
|
-
}
|
|
187311
|
-
}
|
|
187188
|
+
async function saveLocalSecret(name, value) {
|
|
187189
|
+
let content = "";
|
|
187190
|
+
if (existsSync10(LOCAL_FILE)) {
|
|
187191
|
+
content = await readFile(LOCAL_FILE, "utf-8");
|
|
187192
|
+
} else {
|
|
187193
|
+
content = HEADER_COMMENT;
|
|
187312
187194
|
}
|
|
187313
|
-
|
|
187195
|
+
content = updateBlockValue(content, "secrets", name, value);
|
|
187196
|
+
await writeFile(LOCAL_FILE, content);
|
|
187314
187197
|
}
|
|
187315
|
-
function
|
|
187316
|
-
|
|
187317
|
-
|
|
187318
|
-
|
|
187319
|
-
|
|
187320
|
-
|
|
187321
|
-
}
|
|
187198
|
+
async function saveLocalConfig(name, value) {
|
|
187199
|
+
let content = "";
|
|
187200
|
+
if (existsSync10(LOCAL_FILE)) {
|
|
187201
|
+
content = await readFile(LOCAL_FILE, "utf-8");
|
|
187202
|
+
} else {
|
|
187203
|
+
content = HEADER_COMMENT;
|
|
187322
187204
|
}
|
|
187323
|
-
|
|
187205
|
+
content = updateBlockValue(content, "config", name, value);
|
|
187206
|
+
await writeFile(LOCAL_FILE, content);
|
|
187324
187207
|
}
|
|
187325
187208
|
|
|
187326
187209
|
// src/lib/dev/env-resolver.ts
|
|
@@ -187329,9 +187212,12 @@ var MissingSecretError = class extends Error {
|
|
|
187329
187212
|
super(
|
|
187330
187213
|
`Missing secret '${secretName}'
|
|
187331
187214
|
|
|
187332
|
-
This secret is declared in specific.hcl but has no value in ${
|
|
187215
|
+
This secret is declared in specific.hcl but has no value in ${LOCAL_FILE}.
|
|
187333
187216
|
|
|
187334
|
-
|
|
187217
|
+
Add it to the secrets block in ${LOCAL_FILE}:
|
|
187218
|
+
secrets {
|
|
187219
|
+
${secretName} = "your-value"
|
|
187220
|
+
}`
|
|
187335
187221
|
);
|
|
187336
187222
|
this.secretName = secretName;
|
|
187337
187223
|
this.name = "MissingSecretError";
|
|
@@ -187342,9 +187228,12 @@ var MissingConfigError = class extends Error {
|
|
|
187342
187228
|
super(
|
|
187343
187229
|
`Missing config '${configName}'
|
|
187344
187230
|
|
|
187345
|
-
This config is declared in specific.hcl but has no default value, environment override, or value in ${
|
|
187231
|
+
This config is declared in specific.hcl but has no default value, environment override, or value in ${LOCAL_FILE}.
|
|
187346
187232
|
|
|
187347
|
-
|
|
187233
|
+
Add it to the config block in ${LOCAL_FILE}:
|
|
187234
|
+
config {
|
|
187235
|
+
${configName} = "your-value"
|
|
187236
|
+
}`
|
|
187348
187237
|
);
|
|
187349
187238
|
this.configName = configName;
|
|
187350
187239
|
this.name = "MissingConfigError";
|
|
@@ -187608,7 +187497,7 @@ function startService(service, resources, secrets, configs, endpointPorts, servi
|
|
|
187608
187497
|
|
|
187609
187498
|
// src/lib/dev/instance-state.ts
|
|
187610
187499
|
import * as fs15 from "fs";
|
|
187611
|
-
import * as
|
|
187500
|
+
import * as path11 from "path";
|
|
187612
187501
|
var InstanceStateManager = class {
|
|
187613
187502
|
stateDir;
|
|
187614
187503
|
statePath;
|
|
@@ -187617,9 +187506,9 @@ var InstanceStateManager = class {
|
|
|
187617
187506
|
key;
|
|
187618
187507
|
constructor(projectRoot, key = "default") {
|
|
187619
187508
|
this.key = key;
|
|
187620
|
-
this.stateDir =
|
|
187621
|
-
this.statePath =
|
|
187622
|
-
this.lockPath =
|
|
187509
|
+
this.stateDir = path11.join(projectRoot, ".specific", "keys", key);
|
|
187510
|
+
this.statePath = path11.join(this.stateDir, "state.json");
|
|
187511
|
+
this.lockPath = path11.join(this.stateDir, "state.lock");
|
|
187623
187512
|
}
|
|
187624
187513
|
getKey() {
|
|
187625
187514
|
return this.key;
|
|
@@ -187821,11 +187710,11 @@ var InstanceStateManager = class {
|
|
|
187821
187710
|
import * as http from "http";
|
|
187822
187711
|
import * as https from "https";
|
|
187823
187712
|
import * as fs16 from "fs";
|
|
187824
|
-
import * as
|
|
187713
|
+
import * as path12 from "path";
|
|
187825
187714
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
187826
187715
|
import httpProxy from "http-proxy";
|
|
187827
|
-
var __dirname3 =
|
|
187828
|
-
var adminDir =
|
|
187716
|
+
var __dirname3 = path12.dirname(fileURLToPath3(import.meta.url));
|
|
187717
|
+
var adminDir = path12.join(__dirname3, "admin");
|
|
187829
187718
|
var HTTP_PORT = 80;
|
|
187830
187719
|
var HTTPS_PORT = 443;
|
|
187831
187720
|
var DOMAIN_SUFFIX = ".local.spcf.app";
|
|
@@ -188111,9 +188000,9 @@ function serveStaticFile(res, pathname) {
|
|
|
188111
188000
|
filePath = filePath + "index.html";
|
|
188112
188001
|
}
|
|
188113
188002
|
const relativePath = filePath.startsWith("/") ? filePath.slice(1) : filePath;
|
|
188114
|
-
const fullPath =
|
|
188115
|
-
const resolvedPath =
|
|
188116
|
-
const resolvedAdminDir =
|
|
188003
|
+
const fullPath = path12.join(adminDir, relativePath);
|
|
188004
|
+
const resolvedPath = path12.resolve(fullPath);
|
|
188005
|
+
const resolvedAdminDir = path12.resolve(adminDir);
|
|
188117
188006
|
if (!resolvedPath.startsWith(resolvedAdminDir)) {
|
|
188118
188007
|
res.writeHead(403, { "Content-Type": "text/html" });
|
|
188119
188008
|
res.end("<h1>Forbidden</h1>");
|
|
@@ -188124,11 +188013,11 @@ function serveStaticFile(res, pathname) {
|
|
|
188124
188013
|
if (fs16.existsSync(htmlPath)) {
|
|
188125
188014
|
return serveFile(res, htmlPath);
|
|
188126
188015
|
}
|
|
188127
|
-
const indexPath =
|
|
188016
|
+
const indexPath = path12.join(resolvedPath, "index.html");
|
|
188128
188017
|
if (fs16.existsSync(indexPath)) {
|
|
188129
188018
|
return serveFile(res, indexPath);
|
|
188130
188019
|
}
|
|
188131
|
-
const notFoundPath =
|
|
188020
|
+
const notFoundPath = path12.join(adminDir, "404.html");
|
|
188132
188021
|
if (fs16.existsSync(notFoundPath)) {
|
|
188133
188022
|
return serveFileContent(res, notFoundPath, "text/html", 404);
|
|
188134
188023
|
}
|
|
@@ -188139,7 +188028,7 @@ function serveStaticFile(res, pathname) {
|
|
|
188139
188028
|
serveFile(res, resolvedPath);
|
|
188140
188029
|
}
|
|
188141
188030
|
function serveFile(res, filePath) {
|
|
188142
|
-
const ext =
|
|
188031
|
+
const ext = path12.extname(filePath).toLowerCase();
|
|
188143
188032
|
const contentType = MIME_TYPES[ext] || "application/octet-stream";
|
|
188144
188033
|
serveFileContent(res, filePath, contentType, 200);
|
|
188145
188034
|
}
|
|
@@ -188202,6 +188091,101 @@ async function startAdminServer(getState) {
|
|
|
188202
188091
|
// src/lib/dev/electric-manager.ts
|
|
188203
188092
|
import * as net2 from "net";
|
|
188204
188093
|
import { spawn as spawn3 } from "child_process";
|
|
188094
|
+
|
|
188095
|
+
// src/lib/secrets/parser.ts
|
|
188096
|
+
import { readFile as readFile2, writeFile as writeFile2, mkdir } from "fs/promises";
|
|
188097
|
+
import { existsSync as existsSync13 } from "fs";
|
|
188098
|
+
import * as path13 from "path";
|
|
188099
|
+
import * as crypto2 from "crypto";
|
|
188100
|
+
var GENERATED_SECRETS_FILE = ".specific/generated-secrets.json";
|
|
188101
|
+
async function loadSecrets() {
|
|
188102
|
+
const { secrets } = await loadLocal();
|
|
188103
|
+
return secrets;
|
|
188104
|
+
}
|
|
188105
|
+
function generateRandomString(length = 64) {
|
|
188106
|
+
const chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
|
188107
|
+
const bytes = crypto2.randomBytes(length);
|
|
188108
|
+
let result = "";
|
|
188109
|
+
for (let i = 0; i < length; i++) {
|
|
188110
|
+
result += chars[bytes[i] % chars.length];
|
|
188111
|
+
}
|
|
188112
|
+
return result;
|
|
188113
|
+
}
|
|
188114
|
+
async function loadGeneratedSecrets() {
|
|
188115
|
+
if (!existsSync13(GENERATED_SECRETS_FILE)) {
|
|
188116
|
+
return /* @__PURE__ */ new Map();
|
|
188117
|
+
}
|
|
188118
|
+
const content = await readFile2(GENERATED_SECRETS_FILE, "utf-8");
|
|
188119
|
+
const parsed = JSON.parse(content);
|
|
188120
|
+
return new Map(Object.entries(parsed));
|
|
188121
|
+
}
|
|
188122
|
+
async function saveGeneratedSecret(name, value) {
|
|
188123
|
+
let secrets = {};
|
|
188124
|
+
if (existsSync13(GENERATED_SECRETS_FILE)) {
|
|
188125
|
+
const content = await readFile2(GENERATED_SECRETS_FILE, "utf-8");
|
|
188126
|
+
secrets = JSON.parse(content);
|
|
188127
|
+
}
|
|
188128
|
+
secrets[name] = value;
|
|
188129
|
+
const dir = path13.dirname(GENERATED_SECRETS_FILE);
|
|
188130
|
+
if (!existsSync13(dir)) {
|
|
188131
|
+
await mkdir(dir, { recursive: true });
|
|
188132
|
+
}
|
|
188133
|
+
await writeFile2(GENERATED_SECRETS_FILE, JSON.stringify(secrets, null, 2) + "\n");
|
|
188134
|
+
}
|
|
188135
|
+
async function prepareSecrets(secretsConfig, isDevMode = false) {
|
|
188136
|
+
const userSecrets = await loadSecrets();
|
|
188137
|
+
const generatedSecrets = await loadGeneratedSecrets();
|
|
188138
|
+
const finalSecrets = /* @__PURE__ */ new Map();
|
|
188139
|
+
for (const secretDef of secretsConfig) {
|
|
188140
|
+
const userValue = userSecrets.get(secretDef.name);
|
|
188141
|
+
if (userValue !== void 0) {
|
|
188142
|
+
finalSecrets.set(secretDef.name, userValue);
|
|
188143
|
+
continue;
|
|
188144
|
+
}
|
|
188145
|
+
if (secretDef.generated) {
|
|
188146
|
+
let generatedValue = generatedSecrets.get(secretDef.name);
|
|
188147
|
+
if (generatedValue === void 0) {
|
|
188148
|
+
generatedValue = generateRandomString(secretDef.length ?? 64);
|
|
188149
|
+
await saveGeneratedSecret(secretDef.name, generatedValue);
|
|
188150
|
+
}
|
|
188151
|
+
finalSecrets.set(secretDef.name, generatedValue);
|
|
188152
|
+
continue;
|
|
188153
|
+
}
|
|
188154
|
+
if (isDevMode && secretDef.dev?.required === false) {
|
|
188155
|
+
finalSecrets.set(secretDef.name, "");
|
|
188156
|
+
continue;
|
|
188157
|
+
}
|
|
188158
|
+
}
|
|
188159
|
+
return finalSecrets;
|
|
188160
|
+
}
|
|
188161
|
+
async function saveSecret(name, value) {
|
|
188162
|
+
await saveLocalSecret(name, value);
|
|
188163
|
+
}
|
|
188164
|
+
function findUsedSecrets(services, isDevMode) {
|
|
188165
|
+
const used = /* @__PURE__ */ new Set();
|
|
188166
|
+
for (const service of services) {
|
|
188167
|
+
const mergedEnv = isDevMode ? { ...service.env, ...service.dev?.env } : service.env;
|
|
188168
|
+
for (const value of Object.values(mergedEnv ?? {})) {
|
|
188169
|
+
if (typeof value === "object" && value.type === "secret") {
|
|
188170
|
+
used.add(value.name);
|
|
188171
|
+
}
|
|
188172
|
+
}
|
|
188173
|
+
}
|
|
188174
|
+
return used;
|
|
188175
|
+
}
|
|
188176
|
+
function findMissingSecrets(secretsDef, preparedSecrets, usedSecrets) {
|
|
188177
|
+
const missing = [];
|
|
188178
|
+
for (const secret of secretsDef) {
|
|
188179
|
+
if (secret.generated) continue;
|
|
188180
|
+
if (usedSecrets && !usedSecrets.has(secret.name)) continue;
|
|
188181
|
+
if (!preparedSecrets.has(secret.name)) {
|
|
188182
|
+
missing.push(secret.name);
|
|
188183
|
+
}
|
|
188184
|
+
}
|
|
188185
|
+
return missing;
|
|
188186
|
+
}
|
|
188187
|
+
|
|
188188
|
+
// src/lib/dev/electric-manager.ts
|
|
188205
188189
|
async function startElectric(postgres, port, options2) {
|
|
188206
188190
|
if (postgres.type !== "postgres") {
|
|
188207
188191
|
throw new Error(
|
|
@@ -188926,6 +188910,59 @@ var ProxyRegistryManager = class {
|
|
|
188926
188910
|
}
|
|
188927
188911
|
};
|
|
188928
188912
|
|
|
188913
|
+
// src/lib/config/parser.ts
|
|
188914
|
+
async function loadConfigs() {
|
|
188915
|
+
const { configs } = await loadLocal();
|
|
188916
|
+
return configs;
|
|
188917
|
+
}
|
|
188918
|
+
async function saveConfig(name, value) {
|
|
188919
|
+
await saveLocalConfig(name, value);
|
|
188920
|
+
}
|
|
188921
|
+
async function prepareConfigs(configsDef, environmentOverrides, isDevMode = false) {
|
|
188922
|
+
const userConfigs = await loadConfigs();
|
|
188923
|
+
const finalConfigs = /* @__PURE__ */ new Map();
|
|
188924
|
+
for (const configDef of configsDef) {
|
|
188925
|
+
const userValue = userConfigs.get(configDef.name);
|
|
188926
|
+
if (userValue !== void 0) {
|
|
188927
|
+
finalConfigs.set(configDef.name, userValue);
|
|
188928
|
+
continue;
|
|
188929
|
+
}
|
|
188930
|
+
const envOverride = environmentOverrides?.[configDef.name];
|
|
188931
|
+
if (envOverride !== void 0) {
|
|
188932
|
+
finalConfigs.set(configDef.name, envOverride);
|
|
188933
|
+
continue;
|
|
188934
|
+
}
|
|
188935
|
+
const effectiveDefault = isDevMode && configDef.dev?.default !== void 0 ? configDef.dev.default : configDef.default;
|
|
188936
|
+
if (effectiveDefault !== void 0) {
|
|
188937
|
+
finalConfigs.set(configDef.name, effectiveDefault);
|
|
188938
|
+
continue;
|
|
188939
|
+
}
|
|
188940
|
+
}
|
|
188941
|
+
return finalConfigs;
|
|
188942
|
+
}
|
|
188943
|
+
function findUsedConfigs(services, isDevMode) {
|
|
188944
|
+
const used = /* @__PURE__ */ new Set();
|
|
188945
|
+
for (const service of services) {
|
|
188946
|
+
const mergedEnv = isDevMode ? { ...service.env, ...service.dev?.env } : service.env;
|
|
188947
|
+
for (const value of Object.values(mergedEnv ?? {})) {
|
|
188948
|
+
if (typeof value === "object" && value.type === "config") {
|
|
188949
|
+
used.add(value.name);
|
|
188950
|
+
}
|
|
188951
|
+
}
|
|
188952
|
+
}
|
|
188953
|
+
return used;
|
|
188954
|
+
}
|
|
188955
|
+
function findMissingConfigs(configsDef, preparedConfigs, usedConfigs) {
|
|
188956
|
+
const missing = [];
|
|
188957
|
+
for (const config of configsDef) {
|
|
188958
|
+
if (usedConfigs && !usedConfigs.has(config.name)) continue;
|
|
188959
|
+
if (!preparedConfigs.has(config.name)) {
|
|
188960
|
+
missing.push(config.name);
|
|
188961
|
+
}
|
|
188962
|
+
}
|
|
188963
|
+
return missing;
|
|
188964
|
+
}
|
|
188965
|
+
|
|
188929
188966
|
// src/lib/ui/SecretInput.tsx
|
|
188930
188967
|
import React4, { useState as useState3 } from "react";
|
|
188931
188968
|
import { Box as Box4, Text as Text4, useInput as useInput2 } from "ink";
|
|
@@ -189450,11 +189487,11 @@ function DevUI({ instanceKey }) {
|
|
|
189450
189487
|
const errorParts = [];
|
|
189451
189488
|
if (missingSecrets.length > 0) {
|
|
189452
189489
|
errorParts.push(`Missing secrets: ${missingSecrets.join(", ")}
|
|
189453
|
-
Add them to specific.
|
|
189490
|
+
Add them to the secrets block in specific.local`);
|
|
189454
189491
|
}
|
|
189455
189492
|
if (missingConfigs.length > 0) {
|
|
189456
189493
|
errorParts.push(`Missing configs: ${missingConfigs.join(", ")}
|
|
189457
|
-
Add them to specific.
|
|
189494
|
+
Add them to the config block in specific.local`);
|
|
189458
189495
|
}
|
|
189459
189496
|
setState((s) => ({
|
|
189460
189497
|
...s,
|
|
@@ -189579,6 +189616,7 @@ Add them to specific.config`);
|
|
|
189579
189616
|
for (const s of services2) {
|
|
189580
189617
|
runningServicePorts.set(s.name, s.ports.get("default"));
|
|
189581
189618
|
}
|
|
189619
|
+
const projectId = hasProjectId() ? readProjectId() : void 0;
|
|
189582
189620
|
const getState = () => ({
|
|
189583
189621
|
status: "running",
|
|
189584
189622
|
services: config2.services.filter((svc) => runningServicePorts.has(svc.name) || svc.serve).map((svc) => ({
|
|
@@ -189593,7 +189631,8 @@ Add them to specific.config`);
|
|
|
189593
189631
|
port: r.port,
|
|
189594
189632
|
host: r.host,
|
|
189595
189633
|
syncEnabled: r.type === "postgres" && syncDatabases.has(name)
|
|
189596
|
-
}))
|
|
189634
|
+
})),
|
|
189635
|
+
projectId
|
|
189597
189636
|
});
|
|
189598
189637
|
const adminServer = await startAdminServer(getState);
|
|
189599
189638
|
adminServerRef.current = adminServer;
|
|
@@ -189982,7 +190021,7 @@ import * as path19 from "path";
|
|
|
189982
190021
|
// src/lib/deploy/build-tester.ts
|
|
189983
190022
|
import { spawn as spawn5 } from "child_process";
|
|
189984
190023
|
import { existsSync as existsSync17 } from "fs";
|
|
189985
|
-
import { join as join18
|
|
190024
|
+
import { join as join18 } from "path";
|
|
189986
190025
|
function getDependencyInstallCommand(build, projectDir) {
|
|
189987
190026
|
switch (build.base) {
|
|
189988
190027
|
case "node":
|
|
@@ -190071,12 +190110,12 @@ function runCommand2(command, projectDir, buildName) {
|
|
|
190071
190110
|
async function testBuild(build, projectDir) {
|
|
190072
190111
|
const startTime = Date.now();
|
|
190073
190112
|
const outputs = [];
|
|
190074
|
-
const
|
|
190075
|
-
writeLog("build-test", `Starting test for build "${build.name}" (base: ${build.base},
|
|
190076
|
-
const depsCommand = getDependencyInstallCommand(build,
|
|
190113
|
+
const workDir = projectDir;
|
|
190114
|
+
writeLog("build-test", `Starting test for build "${build.name}" (base: ${build.base}, workDir: ${workDir})`);
|
|
190115
|
+
const depsCommand = getDependencyInstallCommand(build, workDir);
|
|
190077
190116
|
if (depsCommand) {
|
|
190078
190117
|
writeLog("build-test", `[${build.name}] Installing dependencies...`);
|
|
190079
|
-
const depsResult = await runCommand2(depsCommand,
|
|
190118
|
+
const depsResult = await runCommand2(depsCommand, workDir, build.name);
|
|
190080
190119
|
outputs.push(`[${depsCommand}]
|
|
190081
190120
|
${depsResult.output}`);
|
|
190082
190121
|
if (!depsResult.success) {
|
|
@@ -190095,7 +190134,7 @@ ${depsResult.output}`);
|
|
|
190095
190134
|
}
|
|
190096
190135
|
if (build.command) {
|
|
190097
190136
|
writeLog("build-test", `[${build.name}] Running build command...`);
|
|
190098
|
-
const buildResult = await runCommand2(build.command,
|
|
190137
|
+
const buildResult = await runCommand2(build.command, workDir, build.name);
|
|
190099
190138
|
outputs.push(`[${build.command}]
|
|
190100
190139
|
${buildResult.output}`);
|
|
190101
190140
|
if (!buildResult.success) {
|
|
@@ -191405,232 +191444,6 @@ function cleanCommand(instanceKey) {
|
|
|
191405
191444
|
}
|
|
191406
191445
|
}
|
|
191407
191446
|
|
|
191408
|
-
// src/commands/secrets.tsx
|
|
191409
|
-
import React9, { useState as useState8, useEffect as useEffect6 } from "react";
|
|
191410
|
-
import { render as render7, Text as Text9, Box as Box9, useInput as useInput6, useApp as useApp4 } from "ink";
|
|
191411
|
-
function SetSecretUI({ secretName }) {
|
|
191412
|
-
const { exit } = useApp4();
|
|
191413
|
-
const [value, setValue] = useState8("");
|
|
191414
|
-
const [done, setDone] = useState8(false);
|
|
191415
|
-
const [saving, setSaving] = useState8(false);
|
|
191416
|
-
const [error, setError] = useState8(null);
|
|
191417
|
-
useInput6((input, key) => {
|
|
191418
|
-
if (done || saving) return;
|
|
191419
|
-
if (key.return) {
|
|
191420
|
-
if (value.trim() === "") {
|
|
191421
|
-
setError("Secret value cannot be empty");
|
|
191422
|
-
return;
|
|
191423
|
-
}
|
|
191424
|
-
setSaving(true);
|
|
191425
|
-
saveSecret(secretName, value).then(() => {
|
|
191426
|
-
setDone(true);
|
|
191427
|
-
}).catch((err) => {
|
|
191428
|
-
setError(err instanceof Error ? err.message : String(err));
|
|
191429
|
-
setSaving(false);
|
|
191430
|
-
});
|
|
191431
|
-
} else if (key.backspace || key.delete) {
|
|
191432
|
-
setValue((prev) => prev.slice(0, -1));
|
|
191433
|
-
} else if (key.escape) {
|
|
191434
|
-
exit();
|
|
191435
|
-
} else if (!key.ctrl && !key.meta && input) {
|
|
191436
|
-
setValue((prev) => prev + input);
|
|
191437
|
-
}
|
|
191438
|
-
});
|
|
191439
|
-
useEffect6(() => {
|
|
191440
|
-
if (done) {
|
|
191441
|
-
const timer = setTimeout(() => exit(), 50);
|
|
191442
|
-
return () => clearTimeout(timer);
|
|
191443
|
-
}
|
|
191444
|
-
}, [done, exit]);
|
|
191445
|
-
if (error) {
|
|
191446
|
-
return /* @__PURE__ */ React9.createElement(Text9, { color: "red" }, "Error: ", error);
|
|
191447
|
-
}
|
|
191448
|
-
if (done) {
|
|
191449
|
-
return /* @__PURE__ */ React9.createElement(Box9, { flexDirection: "column" }, /* @__PURE__ */ React9.createElement(Text9, { color: "green" }, "Secret '", secretName, "' saved to ", SECRETS_FILE));
|
|
191450
|
-
}
|
|
191451
|
-
return /* @__PURE__ */ React9.createElement(Box9, { flexDirection: "column" }, /* @__PURE__ */ React9.createElement(Text9, null, "Enter value for secret '", secretName, "':"), /* @__PURE__ */ React9.createElement(Box9, null, /* @__PURE__ */ React9.createElement(Text9, { color: "cyan" }, "> "), /* @__PURE__ */ React9.createElement(Text9, null, value.length > 0 ? "*".repeat(value.length) : ""), /* @__PURE__ */ React9.createElement(Text9, { color: "gray" }, "|")), /* @__PURE__ */ React9.createElement(Text9, { dimColor: true }, "(Press Enter to save, Esc to cancel)"));
|
|
191452
|
-
}
|
|
191453
|
-
async function secretsSetCommand(secretName) {
|
|
191454
|
-
if (!secretName) {
|
|
191455
|
-
console.error("Error: Secret name required");
|
|
191456
|
-
console.error("Usage: specific secrets set <name>");
|
|
191457
|
-
process.exit(1);
|
|
191458
|
-
}
|
|
191459
|
-
render7(/* @__PURE__ */ React9.createElement(SetSecretUI, { secretName }));
|
|
191460
|
-
}
|
|
191461
|
-
async function secretsCommand(action, secretName) {
|
|
191462
|
-
if (!action) {
|
|
191463
|
-
console.error("Usage: specific secrets <command>");
|
|
191464
|
-
console.error("");
|
|
191465
|
-
console.error("Commands:");
|
|
191466
|
-
console.error(" set <name> Set a secret value");
|
|
191467
|
-
process.exit(1);
|
|
191468
|
-
}
|
|
191469
|
-
if (action === "set") {
|
|
191470
|
-
if (!secretName) {
|
|
191471
|
-
console.error("Error: Secret name required");
|
|
191472
|
-
console.error("Usage: specific secrets set <name>");
|
|
191473
|
-
process.exit(1);
|
|
191474
|
-
}
|
|
191475
|
-
await secretsSetCommand(secretName);
|
|
191476
|
-
} else {
|
|
191477
|
-
console.error(`Unknown command: ${action}`);
|
|
191478
|
-
console.error("Usage: specific secrets set <name>");
|
|
191479
|
-
process.exit(1);
|
|
191480
|
-
}
|
|
191481
|
-
}
|
|
191482
|
-
|
|
191483
|
-
// src/commands/config.tsx
|
|
191484
|
-
import React10, { useState as useState9, useEffect as useEffect7 } from "react";
|
|
191485
|
-
import { render as render8, Text as Text10, Box as Box10, useInput as useInput7, useApp as useApp5 } from "ink";
|
|
191486
|
-
import * as fs24 from "fs";
|
|
191487
|
-
var HEADER_COMMENT2 = "# Configuration values for this project\n# These values override defaults defined in specific.hcl\n";
|
|
191488
|
-
function SetConfigUI({ configName, initialValue }) {
|
|
191489
|
-
const { exit } = useApp5();
|
|
191490
|
-
const [value, setValue] = useState9(initialValue ?? "");
|
|
191491
|
-
const [done, setDone] = useState9(false);
|
|
191492
|
-
const [error, setError] = useState9(null);
|
|
191493
|
-
useInput7((input, key) => {
|
|
191494
|
-
if (done) return;
|
|
191495
|
-
if (key.return) {
|
|
191496
|
-
if (value.trim() === "") {
|
|
191497
|
-
setError("Config value cannot be empty");
|
|
191498
|
-
return;
|
|
191499
|
-
}
|
|
191500
|
-
try {
|
|
191501
|
-
const escapedValue = value.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
191502
|
-
const hclLine = `${configName} = "${escapedValue}"`;
|
|
191503
|
-
let content = "";
|
|
191504
|
-
let hasHeader = false;
|
|
191505
|
-
if (fs24.existsSync(CONFIG_FILE)) {
|
|
191506
|
-
content = fs24.readFileSync(CONFIG_FILE, "utf-8");
|
|
191507
|
-
hasHeader = content.startsWith("#");
|
|
191508
|
-
const lines = content.split("\n");
|
|
191509
|
-
const newLines = [];
|
|
191510
|
-
let found = false;
|
|
191511
|
-
const pattern = new RegExp(`^${configName}\\s*=\\s*"`);
|
|
191512
|
-
for (const line of lines) {
|
|
191513
|
-
if (pattern.test(line.trim())) {
|
|
191514
|
-
newLines.push(hclLine);
|
|
191515
|
-
found = true;
|
|
191516
|
-
} else {
|
|
191517
|
-
newLines.push(line);
|
|
191518
|
-
}
|
|
191519
|
-
}
|
|
191520
|
-
if (found) {
|
|
191521
|
-
fs24.writeFileSync(CONFIG_FILE, newLines.join("\n"));
|
|
191522
|
-
setDone(true);
|
|
191523
|
-
return;
|
|
191524
|
-
}
|
|
191525
|
-
}
|
|
191526
|
-
let newContent = "";
|
|
191527
|
-
if (!hasHeader && !content) {
|
|
191528
|
-
newContent = HEADER_COMMENT2 + "\n";
|
|
191529
|
-
} else if (content) {
|
|
191530
|
-
newContent = content.endsWith("\n") ? content : content + "\n";
|
|
191531
|
-
}
|
|
191532
|
-
newContent += `${hclLine}
|
|
191533
|
-
`;
|
|
191534
|
-
fs24.writeFileSync(CONFIG_FILE, newContent);
|
|
191535
|
-
setDone(true);
|
|
191536
|
-
} catch (err) {
|
|
191537
|
-
setError(err instanceof Error ? err.message : String(err));
|
|
191538
|
-
}
|
|
191539
|
-
} else if (key.backspace || key.delete) {
|
|
191540
|
-
setValue((prev) => prev.slice(0, -1));
|
|
191541
|
-
} else if (key.escape) {
|
|
191542
|
-
exit();
|
|
191543
|
-
} else if (!key.ctrl && !key.meta && input) {
|
|
191544
|
-
setValue((prev) => prev + input);
|
|
191545
|
-
}
|
|
191546
|
-
});
|
|
191547
|
-
useEffect7(() => {
|
|
191548
|
-
if (done) {
|
|
191549
|
-
const timer = setTimeout(() => exit(), 50);
|
|
191550
|
-
return () => clearTimeout(timer);
|
|
191551
|
-
}
|
|
191552
|
-
}, [done, exit]);
|
|
191553
|
-
if (error) {
|
|
191554
|
-
return /* @__PURE__ */ React10.createElement(Text10, { color: "red" }, "Error: ", error);
|
|
191555
|
-
}
|
|
191556
|
-
if (done) {
|
|
191557
|
-
return /* @__PURE__ */ React10.createElement(Box10, { flexDirection: "column" }, /* @__PURE__ */ React10.createElement(Text10, { color: "green" }, "Config '", configName, "' saved to ", CONFIG_FILE));
|
|
191558
|
-
}
|
|
191559
|
-
return /* @__PURE__ */ React10.createElement(Box10, { flexDirection: "column" }, /* @__PURE__ */ React10.createElement(Text10, null, "Enter value for config '", configName, "':"), /* @__PURE__ */ React10.createElement(Box10, null, /* @__PURE__ */ React10.createElement(Text10, { color: "cyan" }, "> "), /* @__PURE__ */ React10.createElement(Text10, null, value), /* @__PURE__ */ React10.createElement(Text10, { color: "gray" }, "|")), /* @__PURE__ */ React10.createElement(Text10, { dimColor: true }, "(Press Enter to save, Esc to cancel)"));
|
|
191560
|
-
}
|
|
191561
|
-
async function configSetCommand(configName, configValue) {
|
|
191562
|
-
if (!configName) {
|
|
191563
|
-
console.error("Error: Config name required");
|
|
191564
|
-
console.error("Usage: specific config set <name> [value]");
|
|
191565
|
-
process.exit(1);
|
|
191566
|
-
}
|
|
191567
|
-
if (configValue !== void 0) {
|
|
191568
|
-
try {
|
|
191569
|
-
const escapedValue = configValue.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
191570
|
-
const hclLine = `${configName} = "${escapedValue}"`;
|
|
191571
|
-
let content = "";
|
|
191572
|
-
let hasHeader = false;
|
|
191573
|
-
if (fs24.existsSync(CONFIG_FILE)) {
|
|
191574
|
-
content = fs24.readFileSync(CONFIG_FILE, "utf-8");
|
|
191575
|
-
hasHeader = content.startsWith("#");
|
|
191576
|
-
const lines = content.split("\n");
|
|
191577
|
-
const newLines = [];
|
|
191578
|
-
let found = false;
|
|
191579
|
-
const pattern = new RegExp(`^${configName}\\s*=\\s*"`);
|
|
191580
|
-
for (const line of lines) {
|
|
191581
|
-
if (pattern.test(line.trim())) {
|
|
191582
|
-
newLines.push(hclLine);
|
|
191583
|
-
found = true;
|
|
191584
|
-
} else {
|
|
191585
|
-
newLines.push(line);
|
|
191586
|
-
}
|
|
191587
|
-
}
|
|
191588
|
-
if (found) {
|
|
191589
|
-
fs24.writeFileSync(CONFIG_FILE, newLines.join("\n"));
|
|
191590
|
-
console.log(`Config '${configName}' saved to ${CONFIG_FILE}`);
|
|
191591
|
-
return;
|
|
191592
|
-
}
|
|
191593
|
-
}
|
|
191594
|
-
let newContent = "";
|
|
191595
|
-
if (!hasHeader && !content) {
|
|
191596
|
-
newContent = HEADER_COMMENT2 + "\n";
|
|
191597
|
-
} else if (content) {
|
|
191598
|
-
newContent = content.endsWith("\n") ? content : content + "\n";
|
|
191599
|
-
}
|
|
191600
|
-
newContent += `${hclLine}
|
|
191601
|
-
`;
|
|
191602
|
-
fs24.writeFileSync(CONFIG_FILE, newContent);
|
|
191603
|
-
console.log(`Config '${configName}' saved to ${CONFIG_FILE}`);
|
|
191604
|
-
} catch (err) {
|
|
191605
|
-
console.error("Error:", err instanceof Error ? err.message : String(err));
|
|
191606
|
-
process.exit(1);
|
|
191607
|
-
}
|
|
191608
|
-
return;
|
|
191609
|
-
}
|
|
191610
|
-
render8(/* @__PURE__ */ React10.createElement(SetConfigUI, { configName }));
|
|
191611
|
-
}
|
|
191612
|
-
async function configCommand(action, configName, configValue) {
|
|
191613
|
-
if (!action) {
|
|
191614
|
-
console.error("Usage: specific config <command>");
|
|
191615
|
-
console.error("");
|
|
191616
|
-
console.error("Commands:");
|
|
191617
|
-
console.error(" set <name> [value] Set a config value");
|
|
191618
|
-
process.exit(1);
|
|
191619
|
-
}
|
|
191620
|
-
if (action === "set") {
|
|
191621
|
-
if (!configName) {
|
|
191622
|
-
console.error("Error: Config name required");
|
|
191623
|
-
console.error("Usage: specific config set <name> [value]");
|
|
191624
|
-
process.exit(1);
|
|
191625
|
-
}
|
|
191626
|
-
await configSetCommand(configName, configValue);
|
|
191627
|
-
} else {
|
|
191628
|
-
console.error(`Unknown command: ${action}`);
|
|
191629
|
-
console.error("Usage: specific config set <name> [value]");
|
|
191630
|
-
process.exit(1);
|
|
191631
|
-
}
|
|
191632
|
-
}
|
|
191633
|
-
|
|
191634
191447
|
// src/commands/login.tsx
|
|
191635
191448
|
async function loginCommand() {
|
|
191636
191449
|
if (isLoggedIn()) {
|
|
@@ -191644,14 +191457,14 @@ async function loginCommand() {
|
|
|
191644
191457
|
}
|
|
191645
191458
|
|
|
191646
191459
|
// src/commands/logout.tsx
|
|
191647
|
-
import
|
|
191648
|
-
import { render as
|
|
191460
|
+
import React9, { useState as useState8, useEffect as useEffect6 } from "react";
|
|
191461
|
+
import { render as render7, Text as Text9, useApp as useApp4 } from "ink";
|
|
191649
191462
|
function LogoutUI() {
|
|
191650
|
-
const { exit } =
|
|
191651
|
-
const [state, setState] =
|
|
191463
|
+
const { exit } = useApp4();
|
|
191464
|
+
const [state, setState] = useState8({
|
|
191652
191465
|
phase: "checking"
|
|
191653
191466
|
});
|
|
191654
|
-
|
|
191467
|
+
useEffect6(() => {
|
|
191655
191468
|
if (state.phase !== "checking") return;
|
|
191656
191469
|
if (!isLoggedIn()) {
|
|
191657
191470
|
setState({ phase: "not-logged-in" });
|
|
@@ -191660,29 +191473,29 @@ function LogoutUI() {
|
|
|
191660
191473
|
clearUserCredentials();
|
|
191661
191474
|
setState({ phase: "done" });
|
|
191662
191475
|
}, [state.phase]);
|
|
191663
|
-
|
|
191476
|
+
useEffect6(() => {
|
|
191664
191477
|
if (state.phase === "done" || state.phase === "not-logged-in") {
|
|
191665
191478
|
const timer = setTimeout(() => exit(), 100);
|
|
191666
191479
|
return () => clearTimeout(timer);
|
|
191667
191480
|
}
|
|
191668
191481
|
}, [state.phase, exit]);
|
|
191669
191482
|
if (state.phase === "not-logged-in") {
|
|
191670
|
-
return /* @__PURE__ */
|
|
191483
|
+
return /* @__PURE__ */ React9.createElement(Text9, { dimColor: true }, "Not logged in.");
|
|
191671
191484
|
}
|
|
191672
191485
|
if (state.phase === "done") {
|
|
191673
|
-
return /* @__PURE__ */
|
|
191486
|
+
return /* @__PURE__ */ React9.createElement(Text9, { color: "green" }, "Logged out successfully.");
|
|
191674
191487
|
}
|
|
191675
|
-
return /* @__PURE__ */
|
|
191488
|
+
return /* @__PURE__ */ React9.createElement(Text9, null, "Logging out...");
|
|
191676
191489
|
}
|
|
191677
191490
|
function logoutCommand() {
|
|
191678
|
-
|
|
191491
|
+
render7(/* @__PURE__ */ React9.createElement(LogoutUI, null));
|
|
191679
191492
|
}
|
|
191680
191493
|
|
|
191681
191494
|
// src/cli.tsx
|
|
191682
191495
|
var program = new Command();
|
|
191683
191496
|
var env = "production";
|
|
191684
191497
|
var envLabel = env !== "production" ? `[${env.toUpperCase()}] ` : "";
|
|
191685
|
-
program.name("specific").description(`${envLabel}Infrastructure-as-code for coding agents`).version("0.1.
|
|
191498
|
+
program.name("specific").description(`${envLabel}Infrastructure-as-code for coding agents`).version("0.1.45").enablePositionalOptions();
|
|
191686
191499
|
program.command("init").description("Initialize project for use with a coding agent").action(initCommand);
|
|
191687
191500
|
program.command("docs [topic]").description("Fetch LLM-optimized documentation").action(docsCommand);
|
|
191688
191501
|
program.command("check").description("Validate specific.hcl configuration").action(checkCommand);
|
|
@@ -191705,8 +191518,6 @@ program.command("psql [database]").description("Connect to a running Postgres da
|
|
|
191705
191518
|
program.command("clean").description("Remove .specific directory for a clean slate").option("-k, --key <key>", "Clean only the specified dev environment key").action((options2) => {
|
|
191706
191519
|
cleanCommand(options2.key);
|
|
191707
191520
|
});
|
|
191708
|
-
program.command("secrets [action] [name]").description("Manage secrets").action(secretsCommand);
|
|
191709
|
-
program.command("config [action] [name] [value]").description("Manage configuration values").action(configCommand);
|
|
191710
191521
|
program.command("login").description("Log in to Specific").action(loginCommand);
|
|
191711
191522
|
program.command("logout").description("Log out of Specific").action(logoutCommand);
|
|
191712
191523
|
var commandName = process.argv[2] || "help";
|