flowdular 0.6.0 → 0.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/distribution.js +173 -153
- package/dist/index.js +769 -596
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1861,7 +1861,7 @@ var EXPRESSIONS = new Map(
|
|
|
1861
1861
|
);
|
|
1862
1862
|
|
|
1863
1863
|
// ../contracts/src/index.ts
|
|
1864
|
-
var PLATFORM_API_VERSION = "0.2.
|
|
1864
|
+
var PLATFORM_API_VERSION = "0.2.4";
|
|
1865
1865
|
|
|
1866
1866
|
// src/module-templates.ts
|
|
1867
1867
|
function packageSuffix(id) {
|
|
@@ -4394,6 +4394,14 @@ import * as nodeCrypto2 from "node:crypto";
|
|
|
4394
4394
|
import * as nodeCrypto from "node:crypto";
|
|
4395
4395
|
var KEYRING_KEY_BYTES = 32;
|
|
4396
4396
|
var KEYRING_MAX_PREVIOUS_KEYS = 8;
|
|
4397
|
+
var KeyringError = class extends Error {
|
|
4398
|
+
code;
|
|
4399
|
+
constructor(code, message, options) {
|
|
4400
|
+
super(message, options);
|
|
4401
|
+
this.name = "KeyringError";
|
|
4402
|
+
this.code = code;
|
|
4403
|
+
}
|
|
4404
|
+
};
|
|
4397
4405
|
function keyFingerprint(key) {
|
|
4398
4406
|
return nodeCrypto.createHash("sha256").update(key).digest("hex").slice(0, 16);
|
|
4399
4407
|
}
|
|
@@ -4842,17 +4850,27 @@ function createModuleRegistry(input) {
|
|
|
4842
4850
|
});
|
|
4843
4851
|
}
|
|
4844
4852
|
|
|
4853
|
+
// ../kernel/src/variable-registry.ts
|
|
4854
|
+
var VariableResolutionError = class extends Error {
|
|
4855
|
+
constructor(code, message) {
|
|
4856
|
+
super(message);
|
|
4857
|
+
this.code = code;
|
|
4858
|
+
this.name = "VariableResolutionError";
|
|
4859
|
+
}
|
|
4860
|
+
code;
|
|
4861
|
+
};
|
|
4862
|
+
|
|
4845
4863
|
// src/module-install.ts
|
|
4846
4864
|
import {
|
|
4847
|
-
lstat
|
|
4865
|
+
lstat,
|
|
4848
4866
|
mkdir,
|
|
4849
|
-
readFile as
|
|
4867
|
+
readFile as readFile4,
|
|
4850
4868
|
readdir as readdir3,
|
|
4851
4869
|
rename,
|
|
4852
4870
|
rm,
|
|
4853
4871
|
writeFile
|
|
4854
4872
|
} from "node:fs/promises";
|
|
4855
|
-
import { dirname as dirname5, join as
|
|
4873
|
+
import { dirname as dirname5, join as join4, relative as relative5 } from "node:path";
|
|
4856
4874
|
|
|
4857
4875
|
// src/module-artifact.ts
|
|
4858
4876
|
import { parse as parseYaml2 } from "yaml";
|
|
@@ -5010,167 +5028,156 @@ function validateModuleArtifact(value) {
|
|
|
5010
5028
|
return artifact;
|
|
5011
5029
|
}
|
|
5012
5030
|
|
|
5013
|
-
// src/
|
|
5031
|
+
// ../kernel/src/module-manifests.ts
|
|
5032
|
+
import { lstatSync, readdirSync, readFileSync, realpathSync } from "node:fs";
|
|
5014
5033
|
import { createRequire } from "node:module";
|
|
5015
|
-
import {
|
|
5016
|
-
|
|
5017
|
-
var
|
|
5018
|
-
var
|
|
5019
|
-
|
|
5020
|
-
"
|
|
5021
|
-
"
|
|
5022
|
-
"contracts",
|
|
5023
|
-
"database",
|
|
5024
|
-
"database-pglite",
|
|
5025
|
-
"database-testing",
|
|
5026
|
-
"dev-console",
|
|
5027
|
-
"harness",
|
|
5028
|
-
"kernel",
|
|
5029
|
-
"server",
|
|
5030
|
-
"storage",
|
|
5031
|
-
"ui"
|
|
5034
|
+
import { dirname as dirname3, isAbsolute as isAbsolute2, join as join2, relative as relative3, resolve as resolve2 } from "node:path";
|
|
5035
|
+
var SDK_INDEX = "@flowdular/sdk/modules.json";
|
|
5036
|
+
var SDK_IMPORT = /^@flowdular\/sdk\/modules\/[a-z0-9-]+$/;
|
|
5037
|
+
var SDK_INDEX_LIMIT = 256;
|
|
5038
|
+
var UNRESOLVED = /* @__PURE__ */ new Set([
|
|
5039
|
+
"MODULE_NOT_FOUND",
|
|
5040
|
+
"ERR_PACKAGE_PATH_NOT_EXPORTED"
|
|
5032
5041
|
]);
|
|
5033
|
-
var
|
|
5034
|
-
"
|
|
5035
|
-
"
|
|
5036
|
-
"
|
|
5037
|
-
"
|
|
5038
|
-
"
|
|
5039
|
-
"system",
|
|
5040
|
-
"users",
|
|
5041
|
-
"workflows"
|
|
5042
|
+
var SKIPPED_DIRECTORIES2 = /* @__PURE__ */ new Set([
|
|
5043
|
+
".git",
|
|
5044
|
+
".flowdular",
|
|
5045
|
+
".vercel",
|
|
5046
|
+
"node_modules",
|
|
5047
|
+
"dist"
|
|
5042
5048
|
]);
|
|
5043
|
-
function
|
|
5044
|
-
|
|
5045
|
-
if (!name.startsWith("@flowdular/")) return name;
|
|
5046
|
-
if (LIBRARIES.has(suffix)) return `@flowdular/sdk/${suffix}`;
|
|
5047
|
-
if (suffix.startsWith("module-") && CORE_MODULES.has(suffix.slice(7)))
|
|
5048
|
-
return `@flowdular/sdk/modules/${suffix.slice(7)}`;
|
|
5049
|
-
return name;
|
|
5049
|
+
function errorCode(error) {
|
|
5050
|
+
return error.code ?? "";
|
|
5050
5051
|
}
|
|
5051
|
-
function
|
|
5052
|
-
|
|
5052
|
+
function insideRealPath(root, path, shown = path) {
|
|
5053
|
+
const canonicalRoot = realpathSync(root);
|
|
5054
|
+
const canonical2 = realpathSync(path);
|
|
5055
|
+
const fromRoot = relative3(canonicalRoot, canonical2);
|
|
5056
|
+
if (fromRoot.startsWith("..") || isAbsolute2(fromRoot)) {
|
|
5057
|
+
throw new Error(`Path escapes the workspace through a link: ${shown}`);
|
|
5058
|
+
}
|
|
5059
|
+
return canonical2;
|
|
5053
5060
|
}
|
|
5054
|
-
function
|
|
5055
|
-
|
|
5061
|
+
function manifestPackage(path) {
|
|
5062
|
+
try {
|
|
5063
|
+
const manifest2 = JSON.parse(readFileSync(path, "utf8"));
|
|
5064
|
+
return typeof manifest2.package === "string" ? manifest2.package : void 0;
|
|
5065
|
+
} catch {
|
|
5066
|
+
return void 0;
|
|
5067
|
+
}
|
|
5056
5068
|
}
|
|
5057
|
-
|
|
5058
|
-
const
|
|
5069
|
+
function moduleRootDirectories(workspaceRoot, roots2) {
|
|
5070
|
+
const configured = roots2 ?? ["modules"];
|
|
5071
|
+
if (!Array.isArray(configured) || configured.length === 0 || configured.some(
|
|
5072
|
+
(root) => typeof root !== "string" || !root || root.startsWith(".") || root.includes("\\") || root.split("/").some((part) => part === ".." || !part)
|
|
5073
|
+
)) {
|
|
5074
|
+
throw new Error(
|
|
5075
|
+
"Invalid modules.roots. Use relative workspace directories."
|
|
5076
|
+
);
|
|
5077
|
+
}
|
|
5078
|
+
return configured.map((root) => {
|
|
5079
|
+
const path = resolve2(workspaceRoot, root);
|
|
5080
|
+
if (!relative3(workspaceRoot, path)) {
|
|
5081
|
+
throw new Error("The workspace root cannot be a module root.");
|
|
5082
|
+
}
|
|
5083
|
+
return path;
|
|
5084
|
+
});
|
|
5085
|
+
}
|
|
5086
|
+
function sdkModuleManifests(workspaceRoot) {
|
|
5087
|
+
const require2 = createRequire(join2(workspaceRoot, "platform/package.json"));
|
|
5059
5088
|
let indexPath;
|
|
5060
5089
|
try {
|
|
5061
|
-
indexPath = require2.resolve(
|
|
5090
|
+
indexPath = require2.resolve(SDK_INDEX);
|
|
5062
5091
|
} catch (error) {
|
|
5063
|
-
if (
|
|
5064
|
-
error.code ?? ""
|
|
5065
|
-
))
|
|
5066
|
-
return /* @__PURE__ */ new Map();
|
|
5092
|
+
if (UNRESOLVED.has(errorCode(error))) return /* @__PURE__ */ new Map();
|
|
5067
5093
|
throw error;
|
|
5068
5094
|
}
|
|
5069
|
-
const index = JSON.parse(
|
|
5070
|
-
if (index.schemaVersion !== 1 || !Array.isArray(index.modules) || index.modules.length >
|
|
5095
|
+
const index = JSON.parse(readFileSync(indexPath, "utf8"));
|
|
5096
|
+
if (index.schemaVersion !== 1 || !Array.isArray(index.modules) || index.modules.length > SDK_INDEX_LIMIT) {
|
|
5071
5097
|
throw new Error("Invalid SDK module index.");
|
|
5098
|
+
}
|
|
5099
|
+
const sdkRoot = dirname3(indexPath);
|
|
5072
5100
|
const result2 = /* @__PURE__ */ new Map();
|
|
5073
5101
|
for (const entry of index.modules) {
|
|
5074
|
-
if (
|
|
5102
|
+
if (typeof entry?.import !== "string" || !SDK_IMPORT.test(entry.import)) {
|
|
5075
5103
|
throw new Error("Invalid SDK module entrypoint.");
|
|
5076
|
-
|
|
5077
|
-
|
|
5078
|
-
|
|
5079
|
-
|
|
5104
|
+
}
|
|
5105
|
+
if (typeof entry.manifest !== "string") {
|
|
5106
|
+
throw new Error("Invalid SDK module manifest path.");
|
|
5107
|
+
}
|
|
5108
|
+
const lexical = resolve2(sdkRoot, entry.manifest);
|
|
5109
|
+
const fromRoot = relative3(sdkRoot, lexical);
|
|
5110
|
+
if (fromRoot.startsWith("..") || isAbsolute2(fromRoot)) {
|
|
5111
|
+
throw new Error(`Path escapes the workspace: ${entry.manifest}`);
|
|
5112
|
+
}
|
|
5113
|
+
const path = insideRealPath(sdkRoot, lexical, entry.manifest);
|
|
5080
5114
|
if (result2.has(path)) throw new Error("Duplicate SDK module path.");
|
|
5081
5115
|
result2.set(path, entry.import);
|
|
5082
5116
|
}
|
|
5083
5117
|
return result2;
|
|
5084
5118
|
}
|
|
5085
|
-
function
|
|
5086
|
-
return new Map(
|
|
5087
|
-
[...files].map(([path, source]) => {
|
|
5088
|
-
if (path === "spec/module.yaml" || path === "module.json")
|
|
5089
|
-
return [path, source];
|
|
5090
|
-
if (path !== "package.json") return [path, sdkSource(source)];
|
|
5091
|
-
const pkg = JSON.parse(source);
|
|
5092
|
-
for (const section of [pkg.dependencies, pkg.devDependencies])
|
|
5093
|
-
if (section) {
|
|
5094
|
-
for (const name of Object.keys(section))
|
|
5095
|
-
if (sdkSpecifier(name) !== name) delete section[name];
|
|
5096
|
-
}
|
|
5097
|
-
pkg.dependencies ??= {};
|
|
5098
|
-
pkg.dependencies["@flowdular/sdk"] = SDK_VERSION;
|
|
5099
|
-
return [path, JSON.stringify(pkg, null, " ") + "\n"];
|
|
5100
|
-
})
|
|
5101
|
-
);
|
|
5102
|
-
}
|
|
5103
|
-
|
|
5104
|
-
// src/module-files.ts
|
|
5105
|
-
import { createRequire as createRequire2 } from "node:module";
|
|
5106
|
-
import { lstat, readFile as readFile4 } from "node:fs/promises";
|
|
5107
|
-
import { join as join3, relative as relative3 } from "node:path";
|
|
5108
|
-
function moduleRoots(workspace) {
|
|
5109
|
-
const roots2 = workspace.config.modules?.roots ?? ["modules"];
|
|
5110
|
-
if (!Array.isArray(roots2) || !roots2.length || roots2.some(
|
|
5111
|
-
(root) => typeof root !== "string" || !root || root.startsWith(".") || root.includes("\\") || root.split("/").some((part) => part === ".." || !part)
|
|
5112
|
-
))
|
|
5113
|
-
throw new Error(
|
|
5114
|
-
"Invalid modules.roots. Use relative workspace directories."
|
|
5115
|
-
);
|
|
5116
|
-
return roots2.map((root) => {
|
|
5117
|
-
const path = resolveInside(workspace.root, root);
|
|
5118
|
-
if (!relative3(workspace.root, path))
|
|
5119
|
-
throw new Error("The workspace root cannot be a module root.");
|
|
5120
|
-
return path;
|
|
5121
|
-
});
|
|
5122
|
-
}
|
|
5123
|
-
async function findModuleFiles(workspace) {
|
|
5119
|
+
function findModuleManifests(workspaceRoot, roots2) {
|
|
5124
5120
|
const files = /* @__PURE__ */ new Set();
|
|
5125
|
-
for (const root of
|
|
5121
|
+
for (const root of moduleRootDirectories(workspaceRoot, roots2)) {
|
|
5126
5122
|
try {
|
|
5127
|
-
|
|
5123
|
+
lstatSync(root);
|
|
5128
5124
|
} catch (error) {
|
|
5129
|
-
if (error
|
|
5125
|
+
if (errorCode(error) === "ENOENT") continue;
|
|
5130
5126
|
throw error;
|
|
5131
5127
|
}
|
|
5132
|
-
|
|
5133
|
-
for (const
|
|
5134
|
-
if (
|
|
5128
|
+
insideRealPath(workspaceRoot, root);
|
|
5129
|
+
for (const entry of readdirSync(root, { withFileTypes: true })) {
|
|
5130
|
+
if (!entry.isDirectory() || SKIPPED_DIRECTORIES2.has(entry.name)) continue;
|
|
5131
|
+
const path = join2(root, entry.name, "module.json");
|
|
5132
|
+
try {
|
|
5133
|
+
if (!lstatSync(path).isDirectory()) files.add(path);
|
|
5134
|
+
} catch (error) {
|
|
5135
|
+
if (errorCode(error) !== "ENOENT") throw error;
|
|
5136
|
+
}
|
|
5135
5137
|
}
|
|
5136
5138
|
}
|
|
5137
5139
|
const packages = /* @__PURE__ */ new Set();
|
|
5138
|
-
for (const file of files)
|
|
5139
|
-
|
|
5140
|
-
|
|
5141
|
-
|
|
5142
|
-
for (const file of (
|
|
5143
|
-
const
|
|
5144
|
-
if (!packages.has(
|
|
5140
|
+
for (const file of files) {
|
|
5141
|
+
const name = manifestPackage(file);
|
|
5142
|
+
if (name) packages.add(name);
|
|
5143
|
+
}
|
|
5144
|
+
for (const file of sdkModuleManifests(workspaceRoot).keys()) {
|
|
5145
|
+
const name = manifestPackage(file);
|
|
5146
|
+
if (!name || !packages.has(name)) files.add(file);
|
|
5145
5147
|
}
|
|
5146
|
-
const platformPackage =
|
|
5148
|
+
const platformPackage = join2(workspaceRoot, "platform/package.json");
|
|
5149
|
+
let dependencies = {};
|
|
5147
5150
|
try {
|
|
5148
|
-
|
|
5149
|
-
const require2 = createRequire2(platformPackage);
|
|
5150
|
-
for (const name of Object.keys(pkg.dependencies ?? {}).sort()) {
|
|
5151
|
-
if (!name.startsWith("@flowdular/module-") || packages.has(name))
|
|
5152
|
-
continue;
|
|
5153
|
-
let file;
|
|
5154
|
-
try {
|
|
5155
|
-
file = require2.resolve(name + "/module.json");
|
|
5156
|
-
} catch (error) {
|
|
5157
|
-
if (["MODULE_NOT_FOUND", "ERR_PACKAGE_PATH_NOT_EXPORTED"].includes(
|
|
5158
|
-
error.code ?? ""
|
|
5159
|
-
))
|
|
5160
|
-
continue;
|
|
5161
|
-
throw error;
|
|
5162
|
-
}
|
|
5163
|
-
files.add(file);
|
|
5164
|
-
}
|
|
5151
|
+
dependencies = JSON.parse(readFileSync(platformPackage, "utf8")).dependencies ?? {};
|
|
5165
5152
|
} catch (error) {
|
|
5166
|
-
if (error
|
|
5153
|
+
if (errorCode(error) !== "ENOENT") throw error;
|
|
5154
|
+
}
|
|
5155
|
+
const require2 = createRequire(platformPackage);
|
|
5156
|
+
for (const name of Object.keys(dependencies).sort()) {
|
|
5157
|
+
if (!name.startsWith("@flowdular/module-") || packages.has(name)) continue;
|
|
5158
|
+
try {
|
|
5159
|
+
files.add(require2.resolve(`${name}/module.json`));
|
|
5160
|
+
} catch (error) {
|
|
5161
|
+
if (!UNRESOLVED.has(errorCode(error))) throw error;
|
|
5162
|
+
}
|
|
5167
5163
|
}
|
|
5168
5164
|
return [...files].sort();
|
|
5169
5165
|
}
|
|
5170
5166
|
|
|
5167
|
+
// src/module-files.ts
|
|
5168
|
+
function configuredRoots(workspace) {
|
|
5169
|
+
return workspace.config.modules?.roots;
|
|
5170
|
+
}
|
|
5171
|
+
function moduleRoots(workspace) {
|
|
5172
|
+
return [...moduleRootDirectories(workspace.root, configuredRoots(workspace))];
|
|
5173
|
+
}
|
|
5174
|
+
async function findModuleFiles(workspace) {
|
|
5175
|
+
return [...findModuleManifests(workspace.root, configuredRoots(workspace))];
|
|
5176
|
+
}
|
|
5177
|
+
|
|
5171
5178
|
// src/module-validate.ts
|
|
5172
|
-
import { access as access2, readFile as
|
|
5173
|
-
import { dirname as dirname4, join as
|
|
5179
|
+
import { access as access2, readFile as readFile3, readdir as readdir2 } from "node:fs/promises";
|
|
5180
|
+
import { dirname as dirname4, join as join3, relative as relative4 } from "node:path";
|
|
5174
5181
|
import { parse as parseYaml3 } from "yaml";
|
|
5175
5182
|
|
|
5176
5183
|
// ../cli-protocol/src/index.ts
|
|
@@ -5887,8 +5894,8 @@ function migrationIdentifierIssues(sql) {
|
|
|
5887
5894
|
}
|
|
5888
5895
|
|
|
5889
5896
|
// ../kernel/src/runtime-config.ts
|
|
5890
|
-
import { lstatSync } from "node:fs";
|
|
5891
|
-
import { resolve as
|
|
5897
|
+
import { lstatSync as lstatSync2 } from "node:fs";
|
|
5898
|
+
import { resolve as resolve3 } from "node:path";
|
|
5892
5899
|
var UnsafeLocalStatePathError = class extends Error {
|
|
5893
5900
|
code = "UNSAFE_LOCAL_STATE_PATH";
|
|
5894
5901
|
constructor(path, expected) {
|
|
@@ -5897,9 +5904,9 @@ var UnsafeLocalStatePathError = class extends Error {
|
|
|
5897
5904
|
}
|
|
5898
5905
|
};
|
|
5899
5906
|
function flowdularStateDirectory(workspaceRoot) {
|
|
5900
|
-
const directory =
|
|
5907
|
+
const directory = resolve3(workspaceRoot, ".flowdular");
|
|
5901
5908
|
try {
|
|
5902
|
-
const info =
|
|
5909
|
+
const info = lstatSync2(directory);
|
|
5903
5910
|
if (info.isSymbolicLink() || !info.isDirectory()) {
|
|
5904
5911
|
throw new UnsafeLocalStatePathError(directory, "directory");
|
|
5905
5912
|
}
|
|
@@ -5910,8 +5917,8 @@ function flowdularStateDirectory(workspaceRoot) {
|
|
|
5910
5917
|
}
|
|
5911
5918
|
|
|
5912
5919
|
// ../database/src/provider.ts
|
|
5913
|
-
import { readFileSync } from "node:fs";
|
|
5914
|
-
import { resolve as
|
|
5920
|
+
import { readFileSync as readFileSync2 } from "node:fs";
|
|
5921
|
+
import { resolve as resolve4 } from "node:path";
|
|
5915
5922
|
|
|
5916
5923
|
// ../database/src/postgresql.ts
|
|
5917
5924
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
@@ -6409,7 +6416,7 @@ function postgresTlsAuthority(environment) {
|
|
|
6409
6416
|
if (!path) return inline || void 0;
|
|
6410
6417
|
let contents;
|
|
6411
6418
|
try {
|
|
6412
|
-
contents =
|
|
6419
|
+
contents = readFileSync2(path, "utf8");
|
|
6413
6420
|
} catch (error) {
|
|
6414
6421
|
throw new Error(
|
|
6415
6422
|
`FD_DATABASE_TLS_CA_FILE could not be read: ${error instanceof Error ? error.message : String(error)}`
|
|
@@ -6433,7 +6440,7 @@ function databaseProviderConfigFromEnvironment(environment = process.env, worksp
|
|
|
6433
6440
|
workspaceRoot,
|
|
6434
6441
|
environment,
|
|
6435
6442
|
pglite: {
|
|
6436
|
-
dataDirectory: environment.NODE_ENV === "test" ? void 0 : configured ??
|
|
6443
|
+
dataDirectory: environment.NODE_ENV === "test" ? void 0 : configured ?? resolve4(
|
|
6437
6444
|
flowdularStateDirectory(workspaceRoot),
|
|
6438
6445
|
"data",
|
|
6439
6446
|
"pglite"
|
|
@@ -6546,11 +6553,28 @@ function databaseProviderConfigFromEnvironment(environment = process.env, worksp
|
|
|
6546
6553
|
}
|
|
6547
6554
|
};
|
|
6548
6555
|
}
|
|
6556
|
+
function reportIdleConnectionError(error) {
|
|
6557
|
+
const code = error.code;
|
|
6558
|
+
console.warn(
|
|
6559
|
+
`An idle pooled PostgreSQL connection failed (${typeof code === "string" ? `${code}: ` : ""}${error.message}). The pool discards it and the next query opens a new one.`
|
|
6560
|
+
);
|
|
6561
|
+
}
|
|
6562
|
+
function ignoreLeasedClientError() {
|
|
6563
|
+
}
|
|
6549
6564
|
function postgresDriverPool(pool) {
|
|
6565
|
+
const guardedClients = /* @__PURE__ */ new WeakSet();
|
|
6566
|
+
const guard = (client) => {
|
|
6567
|
+
if (!client.on || guardedClients.has(client)) return;
|
|
6568
|
+
guardedClients.add(client);
|
|
6569
|
+
client.on("error", ignoreLeasedClientError);
|
|
6570
|
+
};
|
|
6571
|
+
pool.on?.("error", reportIdleConnectionError);
|
|
6572
|
+
pool.on?.("connect", guard);
|
|
6550
6573
|
return {
|
|
6551
6574
|
cancellation: "before-start",
|
|
6552
6575
|
async connect() {
|
|
6553
6576
|
const client = await pool.connect();
|
|
6577
|
+
guard(client);
|
|
6554
6578
|
return {
|
|
6555
6579
|
async query({ text, values: values2 }) {
|
|
6556
6580
|
const result2 = await client.query({
|
|
@@ -7038,15 +7062,15 @@ async function exists(path) {
|
|
|
7038
7062
|
}
|
|
7039
7063
|
}
|
|
7040
7064
|
async function readJson(path) {
|
|
7041
|
-
return JSON.parse(await
|
|
7065
|
+
return JSON.parse(await readFile3(path, "utf8"));
|
|
7042
7066
|
}
|
|
7043
7067
|
async function clientSourceFiles(moduleRoot) {
|
|
7044
|
-
const clientRoot =
|
|
7068
|
+
const clientRoot = join3(moduleRoot, "src/client");
|
|
7045
7069
|
if (!await exists(clientRoot)) return [];
|
|
7046
7070
|
return (await readdir2(clientRoot, {
|
|
7047
7071
|
recursive: true,
|
|
7048
7072
|
withFileTypes: true
|
|
7049
|
-
})).filter((entry) => entry.isFile() && /\.(?:ts|tsx|tsrx)$/.test(entry.name)).map((entry) =>
|
|
7073
|
+
})).filter((entry) => entry.isFile() && /\.(?:ts|tsx|tsrx)$/.test(entry.name)).map((entry) => join3(entry.parentPath, entry.name));
|
|
7050
7074
|
}
|
|
7051
7075
|
async function platformIssues(moduleRoot, manifest2) {
|
|
7052
7076
|
const issues = [];
|
|
@@ -7054,7 +7078,7 @@ async function platformIssues(moduleRoot, manifest2) {
|
|
|
7054
7078
|
let packageName;
|
|
7055
7079
|
let packageVersion;
|
|
7056
7080
|
try {
|
|
7057
|
-
const pkg = await readJson(
|
|
7081
|
+
const pkg = await readJson(join3(moduleRoot, "package.json"));
|
|
7058
7082
|
exports = pkg.exports ?? {};
|
|
7059
7083
|
packageName = pkg.name;
|
|
7060
7084
|
packageVersion = pkg.version;
|
|
@@ -7096,7 +7120,7 @@ async function platformIssues(moduleRoot, manifest2) {
|
|
|
7096
7120
|
);
|
|
7097
7121
|
}
|
|
7098
7122
|
if (manifest2.platform?.server === true) {
|
|
7099
|
-
if (!await exists(
|
|
7123
|
+
if (!await exists(join3(moduleRoot, "src/platform.ts"))) {
|
|
7100
7124
|
issues.push(
|
|
7101
7125
|
issue(
|
|
7102
7126
|
"PLATFORM_SERVER_ENTRY_MISSING",
|
|
@@ -7116,7 +7140,7 @@ async function platformIssues(moduleRoot, manifest2) {
|
|
|
7116
7140
|
}
|
|
7117
7141
|
}
|
|
7118
7142
|
if (manifest2.platform?.client === true) {
|
|
7119
|
-
if (!await exists(
|
|
7143
|
+
if (!await exists(join3(moduleRoot, "src/client/index.ts"))) {
|
|
7120
7144
|
issues.push(
|
|
7121
7145
|
issue(
|
|
7122
7146
|
"PLATFORM_CLIENT_ENTRY_MISSING",
|
|
@@ -7138,11 +7162,11 @@ async function platformIssues(moduleRoot, manifest2) {
|
|
|
7138
7162
|
return issues;
|
|
7139
7163
|
}
|
|
7140
7164
|
async function specIssues(moduleRoot, manifest2, specDirectory2) {
|
|
7141
|
-
const specPath =
|
|
7165
|
+
const specPath = join3(specDirectory2, "module.yaml");
|
|
7142
7166
|
let spec;
|
|
7143
7167
|
try {
|
|
7144
7168
|
spec = parseYaml3(
|
|
7145
|
-
await
|
|
7169
|
+
await readFile3(join3(moduleRoot, specPath), "utf8")
|
|
7146
7170
|
);
|
|
7147
7171
|
} catch (error) {
|
|
7148
7172
|
return [
|
|
@@ -7217,7 +7241,7 @@ async function translationIssues(moduleRoot, manifest2, projectLocales) {
|
|
|
7217
7241
|
const referenceBundleKeys = /* @__PURE__ */ new Set();
|
|
7218
7242
|
for (const locale of manifest2.locales) {
|
|
7219
7243
|
const path = `translations/${locale}.json`;
|
|
7220
|
-
if (!await exists(
|
|
7244
|
+
if (!await exists(join3(moduleRoot, path))) {
|
|
7221
7245
|
issues.push(
|
|
7222
7246
|
issue(
|
|
7223
7247
|
"TRANSLATION_FILE_MISSING",
|
|
@@ -7228,7 +7252,7 @@ async function translationIssues(moduleRoot, manifest2, projectLocales) {
|
|
|
7228
7252
|
continue;
|
|
7229
7253
|
}
|
|
7230
7254
|
try {
|
|
7231
|
-
const bundle = await readJson(
|
|
7255
|
+
const bundle = await readJson(join3(moduleRoot, path));
|
|
7232
7256
|
if (!bundle || typeof bundle !== "object" || Array.isArray(bundle)) {
|
|
7233
7257
|
throw new Error("Expected a JSON object.");
|
|
7234
7258
|
}
|
|
@@ -7283,7 +7307,7 @@ async function translationIssues(moduleRoot, manifest2, projectLocales) {
|
|
|
7283
7307
|
const missing = /* @__PURE__ */ new Map();
|
|
7284
7308
|
const pattern = /\bt\s*\(\s*(['"])([a-zA-Z0-9._-]+)\1/g;
|
|
7285
7309
|
for (const file of files) {
|
|
7286
|
-
const source = await
|
|
7310
|
+
const source = await readFile3(file, "utf8");
|
|
7287
7311
|
for (const match of source.matchAll(pattern)) {
|
|
7288
7312
|
const fullKey = match[2];
|
|
7289
7313
|
if (!fullKey.startsWith(prefix) || fullKey.endsWith(".")) continue;
|
|
@@ -7325,7 +7349,7 @@ function filtersTags(source) {
|
|
|
7325
7349
|
async function userInterfaceIssues(moduleRoot) {
|
|
7326
7350
|
const issues = [];
|
|
7327
7351
|
for (const file of await clientSourceFiles(moduleRoot)) {
|
|
7328
|
-
const source = await
|
|
7352
|
+
const source = await readFile3(file, "utf8");
|
|
7329
7353
|
const path = relative4(moduleRoot, file);
|
|
7330
7354
|
if (/<table\b/.test(source)) {
|
|
7331
7355
|
issues.push(
|
|
@@ -7370,11 +7394,11 @@ async function userInterfaceIssues(moduleRoot) {
|
|
|
7370
7394
|
return issues;
|
|
7371
7395
|
}
|
|
7372
7396
|
async function migrationIssues(moduleRoot) {
|
|
7373
|
-
const directory =
|
|
7397
|
+
const directory = join3(moduleRoot, "migrations");
|
|
7374
7398
|
if (!await exists(directory)) return [];
|
|
7375
7399
|
const issues = [];
|
|
7376
7400
|
for (const name of (await readdir2(directory)).filter((entry) => entry.endsWith(".up.sql")).sort()) {
|
|
7377
|
-
const sql = await
|
|
7401
|
+
const sql = await readFile3(join3(directory, name), "utf8");
|
|
7378
7402
|
for (const found of migrationIdentifierIssues(sql))
|
|
7379
7403
|
issues.push(issue(found.code, found.message, `migrations/${name}`));
|
|
7380
7404
|
}
|
|
@@ -7479,7 +7503,7 @@ var LOCK = "flowdular.modules.lock.json";
|
|
|
7479
7503
|
var TRANSACTION = ".flowdular-module-install";
|
|
7480
7504
|
async function exists2(path) {
|
|
7481
7505
|
try {
|
|
7482
|
-
await
|
|
7506
|
+
await lstat(path);
|
|
7483
7507
|
return true;
|
|
7484
7508
|
} catch (error) {
|
|
7485
7509
|
if (error.code === "ENOENT") return false;
|
|
@@ -7493,10 +7517,10 @@ async function safeParents(workspace, path) {
|
|
|
7493
7517
|
).split("/");
|
|
7494
7518
|
let current = workspace.root;
|
|
7495
7519
|
for (const part of parts) {
|
|
7496
|
-
current =
|
|
7520
|
+
current = join4(current, part);
|
|
7497
7521
|
if (!await exists2(current)) break;
|
|
7498
7522
|
distributionAssert(
|
|
7499
|
-
!(await
|
|
7523
|
+
!(await lstat(current)).isSymbolicLink(),
|
|
7500
7524
|
"MODULE_DESTINATION_LINK",
|
|
7501
7525
|
"Module installation paths cannot contain links."
|
|
7502
7526
|
);
|
|
@@ -7536,11 +7560,11 @@ function validateLock(workspace, value) {
|
|
|
7536
7560
|
return lock;
|
|
7537
7561
|
}
|
|
7538
7562
|
async function readLock(workspace) {
|
|
7539
|
-
const path =
|
|
7563
|
+
const path = join4(workspace.root, LOCK);
|
|
7540
7564
|
await safeParents(workspace, path);
|
|
7541
7565
|
if (!await exists2(path))
|
|
7542
7566
|
return { lock: { schemaVersion: 1, modules: [] }, raw: null };
|
|
7543
|
-
const raw = await
|
|
7567
|
+
const raw = await readFile4(path, "utf8");
|
|
7544
7568
|
return { lock: validateLock(workspace, JSON.parse(raw)), raw };
|
|
7545
7569
|
}
|
|
7546
7570
|
async function directoryHashes(root) {
|
|
@@ -7556,14 +7580,14 @@ async function directoryHashes(root) {
|
|
|
7556
7580
|
);
|
|
7557
7581
|
const path = prefix + entry.name;
|
|
7558
7582
|
if (entry.isDirectory())
|
|
7559
|
-
await visit(
|
|
7583
|
+
await visit(join4(directory, entry.name), path + "/");
|
|
7560
7584
|
else {
|
|
7561
7585
|
distributionAssert(
|
|
7562
7586
|
entry.isFile(),
|
|
7563
7587
|
"MODULE_LOCAL_CHANGES",
|
|
7564
7588
|
"Installed module contains a special file."
|
|
7565
7589
|
);
|
|
7566
|
-
hashes[path] = hashBytes(await
|
|
7590
|
+
hashes[path] = hashBytes(await readFile4(join4(directory, entry.name)));
|
|
7567
7591
|
}
|
|
7568
7592
|
}
|
|
7569
7593
|
}
|
|
@@ -7592,8 +7616,8 @@ async function validateInstalledModules(workspace) {
|
|
|
7592
7616
|
for (const entry of lock.modules) {
|
|
7593
7617
|
await assertUnmodified(workspace, entry);
|
|
7594
7618
|
const manifest2 = JSON.parse(
|
|
7595
|
-
await
|
|
7596
|
-
|
|
7619
|
+
await readFile4(
|
|
7620
|
+
join4(workspace.root, entry.directory, "module.json"),
|
|
7597
7621
|
"utf8"
|
|
7598
7622
|
)
|
|
7599
7623
|
);
|
|
@@ -7606,7 +7630,7 @@ async function validateInstalledModules(workspace) {
|
|
|
7606
7630
|
return lock;
|
|
7607
7631
|
}
|
|
7608
7632
|
async function rollback(workspace, journal) {
|
|
7609
|
-
const transaction =
|
|
7633
|
+
const transaction = join4(workspace.root, TRANSACTION);
|
|
7610
7634
|
validateLock(workspace, {
|
|
7611
7635
|
schemaVersion: 1,
|
|
7612
7636
|
modules: journal.entries.map((entry) => entry.installed)
|
|
@@ -7617,8 +7641,8 @@ async function rollback(workspace, journal) {
|
|
|
7617
7641
|
entry.installed.directory
|
|
7618
7642
|
);
|
|
7619
7643
|
await safeParents(workspace, destination);
|
|
7620
|
-
const backup =
|
|
7621
|
-
const moved = !await exists2(
|
|
7644
|
+
const backup = join4(transaction, `backup-${index}`);
|
|
7645
|
+
const moved = !await exists2(join4(transaction, `stage-${index}`));
|
|
7622
7646
|
if (moved && await exists2(destination)) {
|
|
7623
7647
|
const hashes = await directoryHashes(destination);
|
|
7624
7648
|
if (equalHashes(hashes, entry.installed.files))
|
|
@@ -7640,9 +7664,9 @@ async function rollback(workspace, journal) {
|
|
|
7640
7664
|
await rename(backup, destination);
|
|
7641
7665
|
}
|
|
7642
7666
|
}
|
|
7643
|
-
const lockPath =
|
|
7667
|
+
const lockPath = join4(workspace.root, LOCK);
|
|
7644
7668
|
await safeParents(workspace, lockPath);
|
|
7645
|
-
const current = await exists2(lockPath) ? await
|
|
7669
|
+
const current = await exists2(lockPath) ? await readFile4(lockPath, "utf8") : null;
|
|
7646
7670
|
distributionAssert(
|
|
7647
7671
|
current === journal.previous || current === journal.next,
|
|
7648
7672
|
"MODULE_RECOVERY_CONFLICT",
|
|
@@ -7652,13 +7676,13 @@ async function rollback(workspace, journal) {
|
|
|
7652
7676
|
else await writeFile(lockPath, journal.previous);
|
|
7653
7677
|
}
|
|
7654
7678
|
async function recoverModuleInstall(workspace, apply) {
|
|
7655
|
-
const transaction =
|
|
7679
|
+
const transaction = join4(workspace.root, TRANSACTION);
|
|
7656
7680
|
await safeParents(workspace, transaction);
|
|
7657
7681
|
if (!await exists2(transaction)) return { recovered: false, pending: false };
|
|
7658
|
-
const hasJournal = await exists2(
|
|
7682
|
+
const hasJournal = await exists2(join4(transaction, "journal.json"));
|
|
7659
7683
|
const journal = JSON.parse(
|
|
7660
|
-
await
|
|
7661
|
-
|
|
7684
|
+
await readFile4(
|
|
7685
|
+
join4(transaction, hasJournal ? "journal.json" : "owner.json"),
|
|
7662
7686
|
"utf8"
|
|
7663
7687
|
)
|
|
7664
7688
|
);
|
|
@@ -7684,7 +7708,7 @@ async function recoverModuleInstall(workspace, apply) {
|
|
|
7684
7708
|
return { recovered: true, pending: false };
|
|
7685
7709
|
}
|
|
7686
7710
|
async function installPlannedModule(workspace, options) {
|
|
7687
|
-
const transaction =
|
|
7711
|
+
const transaction = join4(workspace.root, TRANSACTION);
|
|
7688
7712
|
await safeParents(workspace, transaction);
|
|
7689
7713
|
distributionAssert(
|
|
7690
7714
|
!await exists2(transaction),
|
|
@@ -7701,7 +7725,7 @@ async function installPlannedModule(workspace, options) {
|
|
|
7701
7725
|
for (const root of moduleRoots(workspace)) await safeParents(workspace, root);
|
|
7702
7726
|
const files = await findModuleFiles(workspace);
|
|
7703
7727
|
for (const file of files)
|
|
7704
|
-
manifests.push(JSON.parse(await
|
|
7728
|
+
manifests.push(JSON.parse(await readFile4(file, "utf8")));
|
|
7705
7729
|
const id = options.target.split("@")[0];
|
|
7706
7730
|
const previous = snapshot.lock.modules.find((entry) => entry.id === id);
|
|
7707
7731
|
distributionAssert(
|
|
@@ -7764,7 +7788,7 @@ async function installPlannedModule(workspace, options) {
|
|
|
7764
7788
|
"Catalog and artifact manifest differ."
|
|
7765
7789
|
);
|
|
7766
7790
|
const old = snapshot.lock.modules.find((entry) => entry.id === release.manifest.id) ?? null;
|
|
7767
|
-
const destination = old ? resolveInside(workspace.root, old.directory) :
|
|
7791
|
+
const destination = old ? resolveInside(workspace.root, old.directory) : join4(
|
|
7768
7792
|
moduleRoots(workspace)[0],
|
|
7769
7793
|
release.manifest.package.replace("@flowdular/module-", "")
|
|
7770
7794
|
);
|
|
@@ -7839,14 +7863,14 @@ async function installPlannedModule(workspace, options) {
|
|
|
7839
7863
|
let journalWritten = false;
|
|
7840
7864
|
try {
|
|
7841
7865
|
await writeFile(
|
|
7842
|
-
|
|
7866
|
+
join4(transaction, "owner.json"),
|
|
7843
7867
|
JSON.stringify({ schemaVersion: 1, pid: process.pid })
|
|
7844
7868
|
);
|
|
7845
7869
|
for (const [index, entry] of entries.entries()) {
|
|
7846
|
-
const stage =
|
|
7870
|
+
const stage = join4(transaction, `stage-${index}`);
|
|
7847
7871
|
await mkdir(stage);
|
|
7848
7872
|
for (const file of entry.artifact.files) {
|
|
7849
|
-
const path =
|
|
7873
|
+
const path = join4(stage, file.path);
|
|
7850
7874
|
await mkdir(dirname5(path), { recursive: true });
|
|
7851
7875
|
await writeFile(path, Buffer.from(file.content, "base64"), {
|
|
7852
7876
|
flag: "wx"
|
|
@@ -7859,10 +7883,10 @@ async function installPlannedModule(workspace, options) {
|
|
|
7859
7883
|
`Invalid module layout: ${issues.map((issue2) => issue2.message).join("; ")}`
|
|
7860
7884
|
);
|
|
7861
7885
|
}
|
|
7862
|
-
await writeFile(
|
|
7886
|
+
await writeFile(join4(transaction, "journal.tmp"), JSON.stringify(journal));
|
|
7863
7887
|
await rename(
|
|
7864
|
-
|
|
7865
|
-
|
|
7888
|
+
join4(transaction, "journal.tmp"),
|
|
7889
|
+
join4(transaction, "journal.json")
|
|
7866
7890
|
);
|
|
7867
7891
|
journalWritten = true;
|
|
7868
7892
|
distributionAssert(
|
|
@@ -7878,7 +7902,7 @@ async function installPlannedModule(workspace, options) {
|
|
|
7878
7902
|
await safeParents(workspace, destination);
|
|
7879
7903
|
if (entry.previous) {
|
|
7880
7904
|
await assertUnmodified(workspace, entry.previous);
|
|
7881
|
-
await rename(destination,
|
|
7905
|
+
await rename(destination, join4(transaction, `backup-${index}`));
|
|
7882
7906
|
} else
|
|
7883
7907
|
distributionAssert(
|
|
7884
7908
|
!await exists2(destination),
|
|
@@ -7886,43 +7910,325 @@ async function installPlannedModule(workspace, options) {
|
|
|
7886
7910
|
`Destination appeared during installation: ${entry.installed.directory}`
|
|
7887
7911
|
);
|
|
7888
7912
|
await mkdir(dirname5(destination), { recursive: true });
|
|
7889
|
-
await rename(
|
|
7913
|
+
await rename(join4(transaction, `stage-${index}`), destination);
|
|
7890
7914
|
}
|
|
7891
|
-
await writeFile(
|
|
7915
|
+
await writeFile(join4(transaction, "next-lock.json"), journal.next);
|
|
7892
7916
|
await rename(
|
|
7893
|
-
|
|
7894
|
-
|
|
7917
|
+
join4(transaction, "next-lock.json"),
|
|
7918
|
+
join4(workspace.root, LOCK)
|
|
7919
|
+
);
|
|
7920
|
+
} catch (error) {
|
|
7921
|
+
if (journalWritten) await rollback(workspace, journal);
|
|
7922
|
+
await rm(transaction, { recursive: true });
|
|
7923
|
+
throw error;
|
|
7924
|
+
}
|
|
7925
|
+
await rm(transaction, { recursive: true });
|
|
7926
|
+
return {
|
|
7927
|
+
applied: true,
|
|
7928
|
+
modules: entries.map((entry) => entry.installed),
|
|
7929
|
+
activationRequired: true
|
|
7930
|
+
};
|
|
7931
|
+
}
|
|
7932
|
+
|
|
7933
|
+
// ../database-pglite/src/driver.ts
|
|
7934
|
+
import { PGlite } from "@electric-sql/pglite";
|
|
7935
|
+
import { mkdir as mkdir2, readFile as readFile5, rm as rm2, writeFile as writeFile2 } from "node:fs/promises";
|
|
7936
|
+
import { join as join5, resolve as resolve5 } from "node:path";
|
|
7937
|
+
var ROLE = /^[a-z_][a-z0-9_]{0,62}$/;
|
|
7938
|
+
var LOCK_FILE = "flowdular.lock";
|
|
7939
|
+
var LocalDatabaseLockedError = class extends Error {
|
|
7940
|
+
constructor(directory, pid) {
|
|
7941
|
+
super(
|
|
7942
|
+
`The local database in ${directory} is already open in process ${pid}. Stop that Flowdular first, or point this one at another directory with FD_DATABASE_PGLITE_DIRECTORY.`
|
|
7943
|
+
);
|
|
7944
|
+
this.directory = directory;
|
|
7945
|
+
this.pid = pid;
|
|
7946
|
+
this.name = "LocalDatabaseLockedError";
|
|
7947
|
+
}
|
|
7948
|
+
directory;
|
|
7949
|
+
pid;
|
|
7950
|
+
code = "LOCAL_DATABASE_LOCKED";
|
|
7951
|
+
};
|
|
7952
|
+
var LocalDatabaseUnreadableError = class extends Error {
|
|
7953
|
+
constructor(directory, cause) {
|
|
7954
|
+
super(
|
|
7955
|
+
`The local database in ${directory} could not be opened. A process killed mid write leaves it this way. Restore a backup of that directory, recreate the workspace with "pnpm flowdular setup quick --apply --confirm reset-local-auth", or point somewhere else with FD_DATABASE_PGLITE_DIRECTORY.`,
|
|
7956
|
+
{ cause }
|
|
7957
|
+
);
|
|
7958
|
+
this.directory = directory;
|
|
7959
|
+
this.name = "LocalDatabaseUnreadableError";
|
|
7960
|
+
}
|
|
7961
|
+
directory;
|
|
7962
|
+
code = "LOCAL_DATABASE_UNREADABLE";
|
|
7963
|
+
};
|
|
7964
|
+
function running(pid) {
|
|
7965
|
+
try {
|
|
7966
|
+
process.kill(pid, 0);
|
|
7967
|
+
return true;
|
|
7968
|
+
} catch (error) {
|
|
7969
|
+
return error.code === "EPERM";
|
|
7970
|
+
}
|
|
7971
|
+
}
|
|
7972
|
+
async function claimDirectory(directory) {
|
|
7973
|
+
const path = join5(directory, LOCK_FILE);
|
|
7974
|
+
let held;
|
|
7975
|
+
try {
|
|
7976
|
+
held = await readFile5(path, "utf8");
|
|
7977
|
+
} catch (error) {
|
|
7978
|
+
if (error.code !== "ENOENT") throw error;
|
|
7979
|
+
}
|
|
7980
|
+
const pid = Number(held?.split("\n")[0]);
|
|
7981
|
+
if (Number.isInteger(pid) && pid > 0 && pid !== process.pid && running(pid)) {
|
|
7982
|
+
throw new LocalDatabaseLockedError(directory, pid);
|
|
7983
|
+
}
|
|
7984
|
+
await writeFile2(path, `${process.pid}
|
|
7985
|
+
${(/* @__PURE__ */ new Date()).toISOString()}
|
|
7986
|
+
`, {
|
|
7987
|
+
mode: 384
|
|
7988
|
+
});
|
|
7989
|
+
}
|
|
7990
|
+
async function releaseDirectory(directory) {
|
|
7991
|
+
const path = join5(directory, LOCK_FILE);
|
|
7992
|
+
try {
|
|
7993
|
+
const held = await readFile5(path, "utf8");
|
|
7994
|
+
if (Number(held.split("\n")[0]) !== process.pid) return;
|
|
7995
|
+
await rm2(path, { force: true });
|
|
7996
|
+
} catch (error) {
|
|
7997
|
+
const code = error.code;
|
|
7998
|
+
if (code === "ENOENT" || code === "ENOTDIR" || code === "EACCES") return;
|
|
7999
|
+
throw error;
|
|
8000
|
+
}
|
|
8001
|
+
}
|
|
8002
|
+
var INT8_OID = 20;
|
|
8003
|
+
var SERVER_PARSERS = Object.freeze({ [INT8_OID]: (value) => value });
|
|
8004
|
+
var ConnectionQueue = class {
|
|
8005
|
+
#tail = Promise.resolve();
|
|
8006
|
+
acquire() {
|
|
8007
|
+
let release;
|
|
8008
|
+
const held = new Promise((resolve11) => {
|
|
8009
|
+
release = resolve11;
|
|
8010
|
+
});
|
|
8011
|
+
const waited = this.#tail.then(() => release);
|
|
8012
|
+
this.#tail = this.#tail.then(() => held);
|
|
8013
|
+
return waited;
|
|
8014
|
+
}
|
|
8015
|
+
};
|
|
8016
|
+
function result(rows, affected) {
|
|
8017
|
+
return {
|
|
8018
|
+
rows,
|
|
8019
|
+
rowCount: rows.length > 0 ? rows.length : affected
|
|
8020
|
+
};
|
|
8021
|
+
}
|
|
8022
|
+
async function openDatabase(directory, bootstrap) {
|
|
8023
|
+
if (directory) {
|
|
8024
|
+
await mkdir2(directory, { recursive: true, mode: 448 });
|
|
8025
|
+
await claimDirectory(directory);
|
|
8026
|
+
}
|
|
8027
|
+
let created;
|
|
8028
|
+
try {
|
|
8029
|
+
created = directory ? await PGlite.create({
|
|
8030
|
+
dataDir: directory,
|
|
8031
|
+
parsers: SERVER_PARSERS
|
|
8032
|
+
}) : await PGlite.create({ parsers: SERVER_PARSERS });
|
|
8033
|
+
} catch (error) {
|
|
8034
|
+
if (!directory) throw error;
|
|
8035
|
+
await releaseDirectory(directory);
|
|
8036
|
+
throw new LocalDatabaseUnreadableError(directory, error);
|
|
8037
|
+
}
|
|
8038
|
+
try {
|
|
8039
|
+
if (bootstrap) await created.exec(bootstrap);
|
|
8040
|
+
} catch (error) {
|
|
8041
|
+
try {
|
|
8042
|
+
await created.close();
|
|
8043
|
+
} catch (closeError) {
|
|
8044
|
+
throw new AggregateError(
|
|
8045
|
+
[error, closeError],
|
|
8046
|
+
"PGlite bootstrap failed and cleanup also failed."
|
|
8047
|
+
);
|
|
8048
|
+
}
|
|
8049
|
+
throw error;
|
|
8050
|
+
}
|
|
8051
|
+
return created;
|
|
8052
|
+
}
|
|
8053
|
+
var OPEN_DIRECTORIES = /* @__PURE__ */ Symbol.for("flowdular.database-pglite.directories");
|
|
8054
|
+
function openDirectories() {
|
|
8055
|
+
const host = globalThis;
|
|
8056
|
+
host[OPEN_DIRECTORIES] ??= { open: /* @__PURE__ */ new Map(), closing: /* @__PURE__ */ new Map() };
|
|
8057
|
+
return host[OPEN_DIRECTORIES];
|
|
8058
|
+
}
|
|
8059
|
+
function attachDatabase(directory, bootstrap) {
|
|
8060
|
+
if (!directory) {
|
|
8061
|
+
return {
|
|
8062
|
+
queue: new ConnectionQueue(),
|
|
8063
|
+
instance: openDatabase(void 0, bootstrap),
|
|
8064
|
+
holders: 1
|
|
8065
|
+
};
|
|
8066
|
+
}
|
|
8067
|
+
const key = resolve5(directory);
|
|
8068
|
+
const directories = openDirectories();
|
|
8069
|
+
let database = directories.open.get(key);
|
|
8070
|
+
if (!database) {
|
|
8071
|
+
const previousClose = directories.closing.get(key) ?? Promise.resolve();
|
|
8072
|
+
const opening = {
|
|
8073
|
+
queue: new ConnectionQueue(),
|
|
8074
|
+
instance: previousClose.then(() => openDatabase(directory, bootstrap)),
|
|
8075
|
+
holders: 0
|
|
8076
|
+
};
|
|
8077
|
+
opening.instance.catch(() => {
|
|
8078
|
+
if (directories.open.get(key) === opening) directories.open.delete(key);
|
|
8079
|
+
});
|
|
8080
|
+
directories.open.set(key, opening);
|
|
8081
|
+
database = opening;
|
|
8082
|
+
}
|
|
8083
|
+
database.holders += 1;
|
|
8084
|
+
return database;
|
|
8085
|
+
}
|
|
8086
|
+
async function detachDatabase(directory, database) {
|
|
8087
|
+
database.holders -= 1;
|
|
8088
|
+
if (database.holders > 0) return;
|
|
8089
|
+
const directories = openDirectories();
|
|
8090
|
+
const key = directory ? resolve5(directory) : void 0;
|
|
8091
|
+
const current = key ? directories.open.get(key) : void 0;
|
|
8092
|
+
if (key && current === database) directories.open.delete(key);
|
|
8093
|
+
const ownsDirectory = directory !== void 0 && (current === void 0 || current === database);
|
|
8094
|
+
const closed = (async () => {
|
|
8095
|
+
const instance = await database.instance.catch(() => void 0);
|
|
8096
|
+
await instance?.close();
|
|
8097
|
+
if (ownsDirectory) await releaseDirectory(directory);
|
|
8098
|
+
})();
|
|
8099
|
+
if (key && ownsDirectory) {
|
|
8100
|
+
const settled = closed.catch(() => void 0);
|
|
8101
|
+
directories.closing.set(key, settled);
|
|
8102
|
+
void settled.then(() => {
|
|
8103
|
+
if (directories.closing.get(key) === settled)
|
|
8104
|
+
directories.closing.delete(key);
|
|
8105
|
+
});
|
|
8106
|
+
}
|
|
8107
|
+
await closed;
|
|
8108
|
+
}
|
|
8109
|
+
function createPgliteCluster(options = {}) {
|
|
8110
|
+
let database;
|
|
8111
|
+
let closing;
|
|
8112
|
+
let issued = 0;
|
|
8113
|
+
let ended = 0;
|
|
8114
|
+
const close = () => {
|
|
8115
|
+
const attached = database;
|
|
8116
|
+
if (!attached) return closing ?? Promise.resolve();
|
|
8117
|
+
database = void 0;
|
|
8118
|
+
closing = detachDatabase(options.dataDirectory, attached);
|
|
8119
|
+
return closing;
|
|
8120
|
+
};
|
|
8121
|
+
const pool = (role) => {
|
|
8122
|
+
if (role !== void 0 && !ROLE.test(role)) {
|
|
8123
|
+
throw new Error(`"${role}" is not a usable PostgreSQL role name.`);
|
|
8124
|
+
}
|
|
8125
|
+
issued += 1;
|
|
8126
|
+
return {
|
|
8127
|
+
cancellation: "before-start",
|
|
8128
|
+
async connect() {
|
|
8129
|
+
database ??= attachDatabase(options.dataDirectory, options.bootstrap);
|
|
8130
|
+
const attached = database;
|
|
8131
|
+
const release = await attached.queue.acquire();
|
|
8132
|
+
let instance;
|
|
8133
|
+
try {
|
|
8134
|
+
instance = await attached.instance;
|
|
8135
|
+
if (role) await instance.exec(`SET ROLE ${role}`);
|
|
8136
|
+
} catch (error) {
|
|
8137
|
+
release();
|
|
8138
|
+
throw error;
|
|
8139
|
+
}
|
|
8140
|
+
let released = false;
|
|
8141
|
+
const run = async ({
|
|
8142
|
+
text,
|
|
8143
|
+
values: values2
|
|
8144
|
+
}) => {
|
|
8145
|
+
if (values2 === void 0 || values2.length === 0) {
|
|
8146
|
+
const answers = await instance.exec(text);
|
|
8147
|
+
const last = answers[answers.length - 1];
|
|
8148
|
+
return last ? result(last.rows, last.affectedRows ?? 0) : result([], 0);
|
|
8149
|
+
}
|
|
8150
|
+
const answer = await instance.query(text, [...values2]);
|
|
8151
|
+
return result(answer.rows, answer.affectedRows ?? 0);
|
|
8152
|
+
};
|
|
8153
|
+
return {
|
|
8154
|
+
query: run,
|
|
8155
|
+
release() {
|
|
8156
|
+
if (released) return;
|
|
8157
|
+
released = true;
|
|
8158
|
+
const reset = role ? instance.exec("RESET ROLE").catch(() => void 0) : Promise.resolve();
|
|
8159
|
+
void reset.finally(release);
|
|
8160
|
+
}
|
|
8161
|
+
};
|
|
8162
|
+
},
|
|
8163
|
+
async end() {
|
|
8164
|
+
ended += 1;
|
|
8165
|
+
if (ended < issued) return;
|
|
8166
|
+
await close();
|
|
8167
|
+
}
|
|
8168
|
+
};
|
|
8169
|
+
};
|
|
8170
|
+
return { pool, close };
|
|
8171
|
+
}
|
|
8172
|
+
|
|
8173
|
+
// ../kernel/src/legacy-local-state.ts
|
|
8174
|
+
var LEGACY_DATA_DIRECTORY = ".octane-erp";
|
|
8175
|
+
var LegacyLocalStateError = class extends Error {
|
|
8176
|
+
constructor(fileName) {
|
|
8177
|
+
super(
|
|
8178
|
+
`Legacy local state exists for ${fileName}. Stop Flowdular and run "flowdular setup migrate-state" before starting it again.`
|
|
7895
8179
|
);
|
|
7896
|
-
|
|
7897
|
-
|
|
7898
|
-
await rm(transaction, { recursive: true });
|
|
7899
|
-
throw error;
|
|
8180
|
+
this.fileName = fileName;
|
|
8181
|
+
this.name = "LegacyLocalStateError";
|
|
7900
8182
|
}
|
|
7901
|
-
|
|
7902
|
-
|
|
7903
|
-
|
|
7904
|
-
|
|
7905
|
-
|
|
7906
|
-
|
|
8183
|
+
fileName;
|
|
8184
|
+
code = "LEGACY_LOCAL_STATE_REQUIRES_MIGRATION";
|
|
8185
|
+
};
|
|
8186
|
+
|
|
8187
|
+
// src/command-failure.ts
|
|
8188
|
+
var STABLE_CODE = /^[A-Z][A-Z0-9_]{0,63}$/;
|
|
8189
|
+
var PLATFORM_ERRORS = [
|
|
8190
|
+
ModuleDistributionError,
|
|
8191
|
+
RegistryError,
|
|
8192
|
+
KeyringError,
|
|
8193
|
+
LegacyLocalStateError,
|
|
8194
|
+
UnsafeLocalStatePathError,
|
|
8195
|
+
VariableResolutionError,
|
|
8196
|
+
DatabaseMigrationError,
|
|
8197
|
+
DatabaseError,
|
|
8198
|
+
LocalDatabaseLockedError,
|
|
8199
|
+
LocalDatabaseUnreadableError
|
|
8200
|
+
];
|
|
8201
|
+
function isModuleRefusal(error) {
|
|
8202
|
+
return typeof error.status === "number";
|
|
8203
|
+
}
|
|
8204
|
+
function commandFailure(error) {
|
|
8205
|
+
if (!(error instanceof Error))
|
|
8206
|
+
return failure("COMMAND_FAILED", String(error));
|
|
8207
|
+
const code = error.code;
|
|
8208
|
+
const known = PLATFORM_ERRORS.some((type) => error instanceof type) || isModuleRefusal(error);
|
|
8209
|
+
return failure(
|
|
8210
|
+
known && typeof code === "string" && STABLE_CODE.test(code) ? code : "COMMAND_FAILED",
|
|
8211
|
+
error.message
|
|
8212
|
+
);
|
|
7907
8213
|
}
|
|
7908
8214
|
|
|
7909
8215
|
// src/module-plans.ts
|
|
7910
8216
|
import {
|
|
7911
|
-
readFile as
|
|
8217
|
+
readFile as readFile8,
|
|
7912
8218
|
readdir as readdir4,
|
|
7913
|
-
mkdir as
|
|
8219
|
+
mkdir as mkdir4,
|
|
7914
8220
|
rename as rename3,
|
|
7915
|
-
writeFile as
|
|
7916
|
-
rm as
|
|
7917
|
-
lstat as
|
|
8221
|
+
writeFile as writeFile4,
|
|
8222
|
+
rm as rm4,
|
|
8223
|
+
lstat as lstat3
|
|
7918
8224
|
} from "node:fs/promises";
|
|
7919
8225
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
7920
8226
|
import { join as join7, relative as relative6 } from "node:path";
|
|
7921
8227
|
import { parse as parseYaml4 } from "yaml";
|
|
7922
8228
|
|
|
7923
8229
|
// src/module-catalog.ts
|
|
7924
|
-
import { readFile as
|
|
7925
|
-
import { dirname as dirname6, resolve as
|
|
8230
|
+
import { readFile as readFile6, stat } from "node:fs/promises";
|
|
8231
|
+
import { dirname as dirname6, resolve as resolve6 } from "node:path";
|
|
7926
8232
|
function platformAdmits(manifest2) {
|
|
7927
8233
|
try {
|
|
7928
8234
|
assertModuleCompatibility(manifest2);
|
|
@@ -7938,7 +8244,7 @@ async function boundedRead(location, limit, fetcher = fetch) {
|
|
|
7938
8244
|
"MODULE_DOWNLOAD_LIMIT",
|
|
7939
8245
|
"Module metadata/artifact exceeds the size limit."
|
|
7940
8246
|
);
|
|
7941
|
-
const result2 = await
|
|
8247
|
+
const result2 = await readFile6(location);
|
|
7942
8248
|
distributionAssert(
|
|
7943
8249
|
result2.length <= limit,
|
|
7944
8250
|
"MODULE_DOWNLOAD_LIMIT",
|
|
@@ -8030,7 +8336,7 @@ async function releaseLocation(source, release) {
|
|
|
8030
8336
|
"An offline catalog must use local artifacts."
|
|
8031
8337
|
);
|
|
8032
8338
|
return resolveExistingInside(
|
|
8033
|
-
dirname6(
|
|
8339
|
+
dirname6(resolve6(source.location)),
|
|
8034
8340
|
release.artifact
|
|
8035
8341
|
);
|
|
8036
8342
|
}
|
|
@@ -8141,16 +8447,16 @@ async function readRelease(source, release, fetcher = fetch) {
|
|
|
8141
8447
|
import { execFile } from "node:child_process";
|
|
8142
8448
|
import { randomUUID } from "node:crypto";
|
|
8143
8449
|
import {
|
|
8144
|
-
lstat as
|
|
8145
|
-
mkdir as
|
|
8450
|
+
lstat as lstat2,
|
|
8451
|
+
mkdir as mkdir3,
|
|
8146
8452
|
mkdtemp,
|
|
8147
|
-
readFile as
|
|
8453
|
+
readFile as readFile7,
|
|
8148
8454
|
rename as rename2,
|
|
8149
|
-
rm as
|
|
8150
|
-
writeFile as
|
|
8455
|
+
rm as rm3,
|
|
8456
|
+
writeFile as writeFile3
|
|
8151
8457
|
} from "node:fs/promises";
|
|
8152
8458
|
import { tmpdir } from "node:os";
|
|
8153
|
-
import { isAbsolute as
|
|
8459
|
+
import { isAbsolute as isAbsolute3, join as join6, resolve as resolve7 } from "node:path";
|
|
8154
8460
|
import { promisify } from "node:util";
|
|
8155
8461
|
var exec = promisify(execFile);
|
|
8156
8462
|
var SOURCES_FILE = "flowdular.module-sources.json";
|
|
@@ -8188,13 +8494,13 @@ function validateSource(source) {
|
|
|
8188
8494
|
async function readModuleSources(workspace) {
|
|
8189
8495
|
let raw;
|
|
8190
8496
|
try {
|
|
8191
|
-
const info = await
|
|
8497
|
+
const info = await lstat2(sourcePath(workspace));
|
|
8192
8498
|
distributionAssert(
|
|
8193
8499
|
info.isFile() && !info.isSymbolicLink() && info.size <= 64 * 1024,
|
|
8194
8500
|
"MODULE_SOURCE_INVALID",
|
|
8195
8501
|
"Module source list is not a bounded regular file."
|
|
8196
8502
|
);
|
|
8197
|
-
raw = await
|
|
8503
|
+
raw = await readFile7(sourcePath(workspace), "utf8");
|
|
8198
8504
|
} catch (error) {
|
|
8199
8505
|
if (error.code === "ENOENT") return [];
|
|
8200
8506
|
throw error;
|
|
@@ -8252,7 +8558,7 @@ async function updateSources(workspace, apply, change) {
|
|
|
8252
8558
|
const destination = sourcePath(workspace);
|
|
8253
8559
|
const lock = destination + ".lock";
|
|
8254
8560
|
try {
|
|
8255
|
-
await
|
|
8561
|
+
await mkdir3(lock);
|
|
8256
8562
|
} catch (error) {
|
|
8257
8563
|
if (error.code === "EEXIST")
|
|
8258
8564
|
distributionAssert(
|
|
@@ -8265,7 +8571,7 @@ async function updateSources(workspace, apply, change) {
|
|
|
8265
8571
|
try {
|
|
8266
8572
|
const sources = change(await readModuleSources(workspace));
|
|
8267
8573
|
const temp = destination + "." + randomUUID() + ".tmp";
|
|
8268
|
-
await
|
|
8574
|
+
await writeFile3(
|
|
8269
8575
|
temp,
|
|
8270
8576
|
JSON.stringify({ schemaVersion: 1, sources }, null, " ") + "\n",
|
|
8271
8577
|
{ flag: "wx" }
|
|
@@ -8273,11 +8579,11 @@ async function updateSources(workspace, apply, change) {
|
|
|
8273
8579
|
try {
|
|
8274
8580
|
await rename2(temp, destination);
|
|
8275
8581
|
} finally {
|
|
8276
|
-
await
|
|
8582
|
+
await rm3(temp, { force: true });
|
|
8277
8583
|
}
|
|
8278
8584
|
return { sources, applied: true };
|
|
8279
8585
|
} finally {
|
|
8280
|
-
await
|
|
8586
|
+
await rm3(lock, { recursive: true, force: true });
|
|
8281
8587
|
}
|
|
8282
8588
|
}
|
|
8283
8589
|
async function git(directory, ...arguments_) {
|
|
@@ -8295,12 +8601,12 @@ async function git(directory, ...arguments_) {
|
|
|
8295
8601
|
async function withModuleSource(workspace, source, work) {
|
|
8296
8602
|
validateSource(source);
|
|
8297
8603
|
if (source.kind === "catalog") {
|
|
8298
|
-
const location = source.location.startsWith("https://") ? source.location :
|
|
8604
|
+
const location = source.location.startsWith("https://") ? source.location : resolve7(workspace.root, source.location);
|
|
8299
8605
|
return work(await loadModuleCatalog(location));
|
|
8300
8606
|
}
|
|
8301
8607
|
const checkout = await mkdtemp(join6(tmpdir(), "flowdular-module-source-"));
|
|
8302
8608
|
try {
|
|
8303
|
-
const location = source.location.startsWith("https://") ? source.location :
|
|
8609
|
+
const location = source.location.startsWith("https://") ? source.location : isAbsolute3(source.location) ? source.location : resolve7(workspace.root, source.location);
|
|
8304
8610
|
await git(checkout, "init", "-q");
|
|
8305
8611
|
await git(
|
|
8306
8612
|
checkout,
|
|
@@ -8322,7 +8628,7 @@ async function withModuleSource(workspace, source, work) {
|
|
|
8322
8628
|
);
|
|
8323
8629
|
return await work(await loadModuleCatalog(catalogPath));
|
|
8324
8630
|
} finally {
|
|
8325
|
-
await
|
|
8631
|
+
await rm3(checkout, { recursive: true, force: true });
|
|
8326
8632
|
}
|
|
8327
8633
|
}
|
|
8328
8634
|
|
|
@@ -8347,7 +8653,7 @@ function checkedPlanFiles(files) {
|
|
|
8347
8653
|
async function planCollectionBytes(directory, files) {
|
|
8348
8654
|
let total = 0;
|
|
8349
8655
|
for (const file of files) {
|
|
8350
|
-
const info = await
|
|
8656
|
+
const info = await lstat3(join7(directory, file));
|
|
8351
8657
|
distributionAssert(
|
|
8352
8658
|
info.isFile() && !info.isSymbolicLink() && info.size <= MAX_PLAN_BYTES,
|
|
8353
8659
|
"MODULE_PLAN_INVALID",
|
|
@@ -8359,7 +8665,7 @@ async function planCollectionBytes(directory, files) {
|
|
|
8359
8665
|
}
|
|
8360
8666
|
async function checkedPlanDirectory(workspace) {
|
|
8361
8667
|
const directory = planDirectory(workspace);
|
|
8362
|
-
const info = await
|
|
8668
|
+
const info = await lstat3(directory);
|
|
8363
8669
|
distributionAssert(
|
|
8364
8670
|
info.isDirectory() && !info.isSymbolicLink(),
|
|
8365
8671
|
"MODULE_PLAN_INVALID",
|
|
@@ -8370,7 +8676,7 @@ async function checkedPlanDirectory(workspace) {
|
|
|
8370
8676
|
async function lockDigest(workspace) {
|
|
8371
8677
|
try {
|
|
8372
8678
|
return hashBytes(
|
|
8373
|
-
await
|
|
8679
|
+
await readFile8(join7(workspace.root, "flowdular.modules.lock.json"))
|
|
8374
8680
|
);
|
|
8375
8681
|
} catch (error) {
|
|
8376
8682
|
if (error.code === "ENOENT") return null;
|
|
@@ -8383,7 +8689,7 @@ async function workspaceDigest(workspace) {
|
|
|
8383
8689
|
for (const file of files)
|
|
8384
8690
|
manifests.push([
|
|
8385
8691
|
relative6(workspace.root, file),
|
|
8386
|
-
hashBytes(await
|
|
8692
|
+
hashBytes(await readFile8(file))
|
|
8387
8693
|
]);
|
|
8388
8694
|
return hashBytes(
|
|
8389
8695
|
JSON.stringify(manifests.sort(([a], [b]) => a.localeCompare(b)))
|
|
@@ -8416,7 +8722,7 @@ function permissions(artifact) {
|
|
|
8416
8722
|
async function plannedReleases(workspace, source, target, update) {
|
|
8417
8723
|
const manifests = [];
|
|
8418
8724
|
for (const file of await findModuleFiles(workspace))
|
|
8419
|
-
manifests.push(JSON.parse(await
|
|
8725
|
+
manifests.push(JSON.parse(await readFile8(file, "utf8")));
|
|
8420
8726
|
const targetId = target.split("@")[0];
|
|
8421
8727
|
if (update) {
|
|
8422
8728
|
const lock = await validateInstalledModules(workspace);
|
|
@@ -8531,7 +8837,7 @@ async function createModulePlan(workspace, options) {
|
|
|
8531
8837
|
);
|
|
8532
8838
|
const lock = planDirectory(workspace) + ".lock";
|
|
8533
8839
|
try {
|
|
8534
|
-
await
|
|
8840
|
+
await mkdir4(lock);
|
|
8535
8841
|
} catch (error) {
|
|
8536
8842
|
if (error.code === "EEXIST")
|
|
8537
8843
|
distributionAssert(
|
|
@@ -8543,7 +8849,7 @@ async function createModulePlan(workspace, options) {
|
|
|
8543
8849
|
}
|
|
8544
8850
|
try {
|
|
8545
8851
|
const directory = planDirectory(workspace);
|
|
8546
|
-
await
|
|
8852
|
+
await mkdir4(directory, { recursive: true });
|
|
8547
8853
|
await checkedPlanDirectory(workspace);
|
|
8548
8854
|
const files = await readdir4(directory);
|
|
8549
8855
|
checkedPlanFiles(files);
|
|
@@ -8560,10 +8866,10 @@ async function createModulePlan(workspace, options) {
|
|
|
8560
8866
|
"The workspace has 8 MiB of module plans. Remove an obsolete plan first."
|
|
8561
8867
|
);
|
|
8562
8868
|
const temp = join7(lock, `${randomUUID2()}.tmp`);
|
|
8563
|
-
await
|
|
8869
|
+
await writeFile4(temp, serialized, { flag: "wx" });
|
|
8564
8870
|
await rename3(temp, join7(directory, name));
|
|
8565
8871
|
} finally {
|
|
8566
|
-
await
|
|
8872
|
+
await rm4(lock, { recursive: true, force: true });
|
|
8567
8873
|
}
|
|
8568
8874
|
}
|
|
8569
8875
|
return plan;
|
|
@@ -8575,13 +8881,13 @@ async function readModulePlan(workspace, id) {
|
|
|
8575
8881
|
"Invalid module plan id."
|
|
8576
8882
|
);
|
|
8577
8883
|
const path = join7(await checkedPlanDirectory(workspace), `${id}.json`);
|
|
8578
|
-
const info = await
|
|
8884
|
+
const info = await lstat3(path);
|
|
8579
8885
|
distributionAssert(
|
|
8580
8886
|
info.isFile() && !info.isSymbolicLink() && info.size <= MAX_PLAN_BYTES,
|
|
8581
8887
|
"MODULE_PLAN_INVALID",
|
|
8582
8888
|
"Module plan is not a bounded regular file."
|
|
8583
8889
|
);
|
|
8584
|
-
const raw = await
|
|
8890
|
+
const raw = await readFile8(path, "utf8");
|
|
8585
8891
|
const plan = JSON.parse(raw);
|
|
8586
8892
|
distributionAssert(
|
|
8587
8893
|
plan && typeof plan === "object",
|
|
@@ -8620,7 +8926,7 @@ async function listModulePlans(workspace) {
|
|
|
8620
8926
|
}
|
|
8621
8927
|
async function removeModulePlan(workspace, id, apply) {
|
|
8622
8928
|
await readModulePlan(workspace, id);
|
|
8623
|
-
if (apply) await
|
|
8929
|
+
if (apply) await rm4(join7(planDirectory(workspace), `${id}.json`));
|
|
8624
8930
|
return { id, applied: apply };
|
|
8625
8931
|
}
|
|
8626
8932
|
async function applyModulePlan(workspace, id, apply) {
|
|
@@ -8657,15 +8963,78 @@ async function applyModulePlan(workspace, id, apply) {
|
|
|
8657
8963
|
}
|
|
8658
8964
|
|
|
8659
8965
|
// src/web-mounts.ts
|
|
8660
|
-
import { readFile as
|
|
8966
|
+
import { readFile as readFile10 } from "node:fs/promises";
|
|
8967
|
+
|
|
8968
|
+
// src/sdk.ts
|
|
8969
|
+
var SDK_VERSION = "0.6.2";
|
|
8970
|
+
var LIBRARIES = /* @__PURE__ */ new Set([
|
|
8971
|
+
"ai-provider",
|
|
8972
|
+
"cli-protocol",
|
|
8973
|
+
"client",
|
|
8974
|
+
"contracts",
|
|
8975
|
+
"database",
|
|
8976
|
+
"database-pglite",
|
|
8977
|
+
"database-testing",
|
|
8978
|
+
"dev-console",
|
|
8979
|
+
"harness",
|
|
8980
|
+
"kernel",
|
|
8981
|
+
"server",
|
|
8982
|
+
"storage",
|
|
8983
|
+
"ui"
|
|
8984
|
+
]);
|
|
8985
|
+
var CORE_MODULES = /* @__PURE__ */ new Set([
|
|
8986
|
+
"agents",
|
|
8987
|
+
"auth",
|
|
8988
|
+
"automations",
|
|
8989
|
+
"profile",
|
|
8990
|
+
"sandbox",
|
|
8991
|
+
"system",
|
|
8992
|
+
"users",
|
|
8993
|
+
"workflows"
|
|
8994
|
+
]);
|
|
8995
|
+
function sdkSpecifier(name) {
|
|
8996
|
+
const suffix = name.slice("@flowdular/".length);
|
|
8997
|
+
if (!name.startsWith("@flowdular/")) return name;
|
|
8998
|
+
if (LIBRARIES.has(suffix)) return `@flowdular/sdk/${suffix}`;
|
|
8999
|
+
if (suffix.startsWith("module-") && CORE_MODULES.has(suffix.slice(7)))
|
|
9000
|
+
return `@flowdular/sdk/modules/${suffix.slice(7)}`;
|
|
9001
|
+
return name;
|
|
9002
|
+
}
|
|
9003
|
+
function sdkSource(source) {
|
|
9004
|
+
return source.replace(/@flowdular\/[a-z0-9-]+/g, sdkSpecifier);
|
|
9005
|
+
}
|
|
9006
|
+
function npmPackage(specifier) {
|
|
9007
|
+
return specifier.startsWith("@") ? specifier.split("/").slice(0, 2).join("/") : specifier.split("/")[0];
|
|
9008
|
+
}
|
|
9009
|
+
async function sdkModules(workspace) {
|
|
9010
|
+
return sdkModuleManifests(workspace.root);
|
|
9011
|
+
}
|
|
9012
|
+
function sdkScaffold(files) {
|
|
9013
|
+
return new Map(
|
|
9014
|
+
[...files].map(([path, source]) => {
|
|
9015
|
+
if (path === "spec/module.yaml" || path === "module.json")
|
|
9016
|
+
return [path, source];
|
|
9017
|
+
if (path !== "package.json") return [path, sdkSource(source)];
|
|
9018
|
+
const pkg = JSON.parse(source);
|
|
9019
|
+
for (const section of [pkg.dependencies, pkg.devDependencies])
|
|
9020
|
+
if (section) {
|
|
9021
|
+
for (const name of Object.keys(section))
|
|
9022
|
+
if (sdkSpecifier(name) !== name) delete section[name];
|
|
9023
|
+
}
|
|
9024
|
+
pkg.dependencies ??= {};
|
|
9025
|
+
pkg.dependencies["@flowdular/sdk"] = SDK_VERSION;
|
|
9026
|
+
return [path, JSON.stringify(pkg, null, " ") + "\n"];
|
|
9027
|
+
})
|
|
9028
|
+
);
|
|
9029
|
+
}
|
|
8661
9030
|
|
|
8662
9031
|
// src/module-sync.ts
|
|
8663
9032
|
import { spawnSync } from "node:child_process";
|
|
8664
|
-
import { access as access3, mkdir as
|
|
9033
|
+
import { access as access3, mkdir as mkdir5, readFile as readFile9, rm as rm5, writeFile as writeFile5 } from "node:fs/promises";
|
|
8665
9034
|
import { dirname as dirname7, join as join9 } from "node:path";
|
|
8666
9035
|
|
|
8667
9036
|
// src/format.ts
|
|
8668
|
-
import { createRequire as
|
|
9037
|
+
import { createRequire as createRequire2 } from "node:module";
|
|
8669
9038
|
import { join as join8 } from "node:path";
|
|
8670
9039
|
import { pathToFileURL } from "node:url";
|
|
8671
9040
|
var DEFAULT_OPTIONS = {
|
|
@@ -8677,7 +9046,7 @@ var TSRX_PLUGIN = "@tsrx/prettier-plugin";
|
|
|
8677
9046
|
function resolveFrom(workspaceRoot, specifier) {
|
|
8678
9047
|
for (const base of [join8(workspaceRoot, "package.json"), import.meta.url]) {
|
|
8679
9048
|
try {
|
|
8680
|
-
return
|
|
9049
|
+
return createRequire2(base).resolve(specifier);
|
|
8681
9050
|
} catch {
|
|
8682
9051
|
}
|
|
8683
9052
|
}
|
|
@@ -8721,7 +9090,7 @@ async function writeProjectConfig(workspace, config) {
|
|
|
8721
9090
|
const raw = JSON.stringify(config, null, " ") + "\n";
|
|
8722
9091
|
const formatter = await loadWorkspaceFormatter(workspace.root);
|
|
8723
9092
|
const output = formatter ? await formatter.format(workspace.configPath, raw) : raw;
|
|
8724
|
-
await
|
|
9093
|
+
await writeFile5(workspace.configPath, output);
|
|
8725
9094
|
}
|
|
8726
9095
|
var PROTECTED_MODULES = ["system.core", "auth.core"];
|
|
8727
9096
|
var GENERATED_FILES = {
|
|
@@ -8793,7 +9162,7 @@ async function loadManifests(workspace) {
|
|
|
8793
9162
|
const descriptors = /* @__PURE__ */ new Map();
|
|
8794
9163
|
for (const file of files) {
|
|
8795
9164
|
const manifest2 = JSON.parse(
|
|
8796
|
-
await
|
|
9165
|
+
await readFile9(file, "utf8")
|
|
8797
9166
|
);
|
|
8798
9167
|
if (!validators.module(manifest2))
|
|
8799
9168
|
throw new Error(`Invalid module manifest: ${file}`);
|
|
@@ -8898,7 +9267,7 @@ async function takeSnapshots(paths) {
|
|
|
8898
9267
|
return Promise.all(
|
|
8899
9268
|
paths.map(async (path) => {
|
|
8900
9269
|
try {
|
|
8901
|
-
return { path, content: await
|
|
9270
|
+
return { path, content: await readFile9(path, "utf8") };
|
|
8902
9271
|
} catch (error) {
|
|
8903
9272
|
if (error.code === "ENOENT") {
|
|
8904
9273
|
return { path, content: void 0 };
|
|
@@ -8911,11 +9280,11 @@ async function takeSnapshots(paths) {
|
|
|
8911
9280
|
async function restoreSnapshots(snapshots) {
|
|
8912
9281
|
for (const snapshot of [...snapshots].reverse()) {
|
|
8913
9282
|
if (snapshot.content === void 0) {
|
|
8914
|
-
await
|
|
9283
|
+
await rm5(snapshot.path, { force: true });
|
|
8915
9284
|
continue;
|
|
8916
9285
|
}
|
|
8917
|
-
await
|
|
8918
|
-
await
|
|
9286
|
+
await mkdir5(dirname7(snapshot.path), { recursive: true });
|
|
9287
|
+
await writeFile5(snapshot.path, snapshot.content);
|
|
8919
9288
|
}
|
|
8920
9289
|
}
|
|
8921
9290
|
async function syncPlatformModules(workspace, apply, enabledOverride) {
|
|
@@ -8956,13 +9325,13 @@ async function syncPlatformModules(workspace, apply, enabledOverride) {
|
|
|
8956
9325
|
const absolute = join9(workspace.root, target.path);
|
|
8957
9326
|
let current = "";
|
|
8958
9327
|
try {
|
|
8959
|
-
current = await
|
|
9328
|
+
current = await readFile9(absolute, "utf8");
|
|
8960
9329
|
} catch {
|
|
8961
9330
|
}
|
|
8962
9331
|
const changed = current !== target.content;
|
|
8963
9332
|
if (apply && changed) {
|
|
8964
|
-
await
|
|
8965
|
-
await
|
|
9333
|
+
await mkdir5(dirname7(absolute), { recursive: true });
|
|
9334
|
+
await writeFile5(absolute, target.content);
|
|
8966
9335
|
}
|
|
8967
9336
|
files.push({ path: target.path, changed });
|
|
8968
9337
|
}
|
|
@@ -8987,7 +9356,7 @@ async function enableModule(workspace, id, apply) {
|
|
|
8987
9356
|
const configChanged = !equalIds(current, enabled);
|
|
8988
9357
|
const platformPackagePath = join9(workspace.root, "platform/package.json");
|
|
8989
9358
|
const platformPackage = JSON.parse(
|
|
8990
|
-
await
|
|
9359
|
+
await readFile9(platformPackagePath, "utf8")
|
|
8991
9360
|
);
|
|
8992
9361
|
const dependencies = platformPackage.dependencies ?? {};
|
|
8993
9362
|
const platformDependenciesAdded = modules.map((module) => npmPackage(module.package)).filter((packageName) => !(packageName in dependencies)).sort((left, right) => left.localeCompare(right));
|
|
@@ -9032,7 +9401,7 @@ async function enableModule(workspace, id, apply) {
|
|
|
9032
9401
|
try {
|
|
9033
9402
|
if (configChanged) {
|
|
9034
9403
|
const config = JSON.parse(
|
|
9035
|
-
await
|
|
9404
|
+
await readFile9(workspace.configPath, "utf8")
|
|
9036
9405
|
);
|
|
9037
9406
|
const configModules = config.modules ?? {};
|
|
9038
9407
|
configModules.enabled = enabled;
|
|
@@ -9040,7 +9409,7 @@ async function enableModule(workspace, id, apply) {
|
|
|
9040
9409
|
await writeProjectConfig(workspace, config);
|
|
9041
9410
|
}
|
|
9042
9411
|
if (platformDependencyAdded) {
|
|
9043
|
-
await
|
|
9412
|
+
await writeFile5(
|
|
9044
9413
|
platformPackagePath,
|
|
9045
9414
|
JSON.stringify(platformPackage, null, " ") + "\n"
|
|
9046
9415
|
);
|
|
@@ -9114,7 +9483,7 @@ async function disableModule(workspace, id, apply) {
|
|
|
9114
9483
|
const enabled = orderedCurrent.filter((module) => module.id !== id).map((module) => module.id);
|
|
9115
9484
|
const platformPackagePath = join9(workspace.root, "platform/package.json");
|
|
9116
9485
|
const platformPackage = JSON.parse(
|
|
9117
|
-
await
|
|
9486
|
+
await readFile9(platformPackagePath, "utf8")
|
|
9118
9487
|
);
|
|
9119
9488
|
const packageName = npmPackage(manifests.get(id).package);
|
|
9120
9489
|
const dependencyRemoved = Boolean(
|
|
@@ -9133,14 +9502,14 @@ async function disableModule(workspace, id, apply) {
|
|
|
9133
9502
|
]);
|
|
9134
9503
|
try {
|
|
9135
9504
|
const config = JSON.parse(
|
|
9136
|
-
await
|
|
9505
|
+
await readFile9(workspace.configPath, "utf8")
|
|
9137
9506
|
);
|
|
9138
9507
|
const modules = config.modules ?? {};
|
|
9139
9508
|
modules.enabled = enabled;
|
|
9140
9509
|
config.modules = modules;
|
|
9141
9510
|
await writeProjectConfig(workspace, config);
|
|
9142
9511
|
if (dependencyRemoved)
|
|
9143
|
-
await
|
|
9512
|
+
await writeFile5(
|
|
9144
9513
|
platformPackagePath,
|
|
9145
9514
|
JSON.stringify(platformPackage, null, " ") + "\n"
|
|
9146
9515
|
);
|
|
@@ -9237,7 +9606,7 @@ function planUnmount(workspace, id) {
|
|
|
9237
9606
|
}
|
|
9238
9607
|
async function writeMounts(workspace, mounts) {
|
|
9239
9608
|
const config = JSON.parse(
|
|
9240
|
-
await
|
|
9609
|
+
await readFile10(workspace.configPath, "utf8")
|
|
9241
9610
|
);
|
|
9242
9611
|
if (mounts.length === 0) delete config.web;
|
|
9243
9612
|
else config.web = { ...config.web, mounts };
|
|
@@ -9246,8 +9615,8 @@ async function writeMounts(workspace, mounts) {
|
|
|
9246
9615
|
}
|
|
9247
9616
|
|
|
9248
9617
|
// src/runner.ts
|
|
9249
|
-
import { readFile as
|
|
9250
|
-
import { join as
|
|
9618
|
+
import { readFile as readFile22 } from "node:fs/promises";
|
|
9619
|
+
import { join as join20, relative as relative14 } from "node:path";
|
|
9251
9620
|
import { parse as parseYaml7 } from "yaml";
|
|
9252
9621
|
|
|
9253
9622
|
// src/capabilities.ts
|
|
@@ -9481,196 +9850,6 @@ function capability(id) {
|
|
|
9481
9850
|
return capabilities.find((entry) => entry.id === id);
|
|
9482
9851
|
}
|
|
9483
9852
|
|
|
9484
|
-
// ../database-pglite/src/driver.ts
|
|
9485
|
-
import { PGlite } from "@electric-sql/pglite";
|
|
9486
|
-
import { mkdir as mkdir5, readFile as readFile12, rm as rm5, writeFile as writeFile5 } from "node:fs/promises";
|
|
9487
|
-
import { join as join10 } from "node:path";
|
|
9488
|
-
var ROLE = /^[a-z_][a-z0-9_]{0,62}$/;
|
|
9489
|
-
var LOCK_FILE = "flowdular.lock";
|
|
9490
|
-
var LocalDatabaseLockedError = class extends Error {
|
|
9491
|
-
constructor(directory, pid) {
|
|
9492
|
-
super(
|
|
9493
|
-
`The local database in ${directory} is already open in process ${pid}. Stop that Flowdular first, or point this one at another directory with FD_DATABASE_PGLITE_DIRECTORY.`
|
|
9494
|
-
);
|
|
9495
|
-
this.directory = directory;
|
|
9496
|
-
this.pid = pid;
|
|
9497
|
-
this.name = "LocalDatabaseLockedError";
|
|
9498
|
-
}
|
|
9499
|
-
directory;
|
|
9500
|
-
pid;
|
|
9501
|
-
code = "LOCAL_DATABASE_LOCKED";
|
|
9502
|
-
};
|
|
9503
|
-
var LocalDatabaseUnreadableError = class extends Error {
|
|
9504
|
-
constructor(directory, cause) {
|
|
9505
|
-
super(
|
|
9506
|
-
`The local database in ${directory} could not be opened. A process killed mid write leaves it this way. Restore a backup of that directory, recreate the workspace with "pnpm flowdular setup quick --apply --confirm reset-local-auth", or point somewhere else with FD_DATABASE_PGLITE_DIRECTORY.`,
|
|
9507
|
-
{ cause }
|
|
9508
|
-
);
|
|
9509
|
-
this.directory = directory;
|
|
9510
|
-
this.name = "LocalDatabaseUnreadableError";
|
|
9511
|
-
}
|
|
9512
|
-
directory;
|
|
9513
|
-
code = "LOCAL_DATABASE_UNREADABLE";
|
|
9514
|
-
};
|
|
9515
|
-
function running(pid) {
|
|
9516
|
-
try {
|
|
9517
|
-
process.kill(pid, 0);
|
|
9518
|
-
return true;
|
|
9519
|
-
} catch (error) {
|
|
9520
|
-
return error.code === "EPERM";
|
|
9521
|
-
}
|
|
9522
|
-
}
|
|
9523
|
-
async function claimDirectory(directory) {
|
|
9524
|
-
const path = join10(directory, LOCK_FILE);
|
|
9525
|
-
let held;
|
|
9526
|
-
try {
|
|
9527
|
-
held = await readFile12(path, "utf8");
|
|
9528
|
-
} catch (error) {
|
|
9529
|
-
if (error.code !== "ENOENT") throw error;
|
|
9530
|
-
}
|
|
9531
|
-
const pid = Number(held?.split("\n")[0]);
|
|
9532
|
-
if (Number.isInteger(pid) && pid > 0 && pid !== process.pid && running(pid)) {
|
|
9533
|
-
throw new LocalDatabaseLockedError(directory, pid);
|
|
9534
|
-
}
|
|
9535
|
-
await writeFile5(path, `${process.pid}
|
|
9536
|
-
${(/* @__PURE__ */ new Date()).toISOString()}
|
|
9537
|
-
`, {
|
|
9538
|
-
mode: 384
|
|
9539
|
-
});
|
|
9540
|
-
}
|
|
9541
|
-
async function releaseDirectory(directory) {
|
|
9542
|
-
const path = join10(directory, LOCK_FILE);
|
|
9543
|
-
try {
|
|
9544
|
-
const held = await readFile12(path, "utf8");
|
|
9545
|
-
if (Number(held.split("\n")[0]) !== process.pid) return;
|
|
9546
|
-
await rm5(path, { force: true });
|
|
9547
|
-
} catch (error) {
|
|
9548
|
-
const code = error.code;
|
|
9549
|
-
if (code === "ENOENT" || code === "ENOTDIR" || code === "EACCES") return;
|
|
9550
|
-
throw error;
|
|
9551
|
-
}
|
|
9552
|
-
}
|
|
9553
|
-
var INT8_OID = 20;
|
|
9554
|
-
var SERVER_PARSERS = Object.freeze({ [INT8_OID]: (value) => value });
|
|
9555
|
-
var ConnectionQueue = class {
|
|
9556
|
-
#tail = Promise.resolve();
|
|
9557
|
-
acquire() {
|
|
9558
|
-
let release;
|
|
9559
|
-
const held = new Promise((resolve9) => {
|
|
9560
|
-
release = resolve9;
|
|
9561
|
-
});
|
|
9562
|
-
const waited = this.#tail.then(() => release);
|
|
9563
|
-
this.#tail = this.#tail.then(() => held);
|
|
9564
|
-
return waited;
|
|
9565
|
-
}
|
|
9566
|
-
};
|
|
9567
|
-
function result(rows, affected) {
|
|
9568
|
-
return {
|
|
9569
|
-
rows,
|
|
9570
|
-
rowCount: rows.length > 0 ? rows.length : affected
|
|
9571
|
-
};
|
|
9572
|
-
}
|
|
9573
|
-
function createPgliteCluster(options = {}) {
|
|
9574
|
-
const queue = new ConnectionQueue();
|
|
9575
|
-
let databasePromise;
|
|
9576
|
-
let closePromise;
|
|
9577
|
-
let issued = 0;
|
|
9578
|
-
let ended = 0;
|
|
9579
|
-
const close = () => {
|
|
9580
|
-
closePromise ??= (async () => {
|
|
9581
|
-
if (!databasePromise) return;
|
|
9582
|
-
const instance = await databasePromise.catch(() => void 0);
|
|
9583
|
-
databasePromise = void 0;
|
|
9584
|
-
await instance?.close();
|
|
9585
|
-
if (options.dataDirectory) await releaseDirectory(options.dataDirectory);
|
|
9586
|
-
})();
|
|
9587
|
-
return closePromise;
|
|
9588
|
-
};
|
|
9589
|
-
const database = async () => {
|
|
9590
|
-
databasePromise ??= (async () => {
|
|
9591
|
-
const directory = options.dataDirectory;
|
|
9592
|
-
if (directory) {
|
|
9593
|
-
await mkdir5(directory, { recursive: true, mode: 448 });
|
|
9594
|
-
await claimDirectory(directory);
|
|
9595
|
-
}
|
|
9596
|
-
let created;
|
|
9597
|
-
try {
|
|
9598
|
-
created = directory ? await PGlite.create({
|
|
9599
|
-
dataDir: directory,
|
|
9600
|
-
parsers: SERVER_PARSERS
|
|
9601
|
-
}) : await PGlite.create({ parsers: SERVER_PARSERS });
|
|
9602
|
-
} catch (error) {
|
|
9603
|
-
if (!directory) throw error;
|
|
9604
|
-
await releaseDirectory(directory);
|
|
9605
|
-
throw new LocalDatabaseUnreadableError(directory, error);
|
|
9606
|
-
}
|
|
9607
|
-
try {
|
|
9608
|
-
if (options.bootstrap) await created.exec(options.bootstrap);
|
|
9609
|
-
} catch (error) {
|
|
9610
|
-
try {
|
|
9611
|
-
await created.close();
|
|
9612
|
-
} catch (closeError) {
|
|
9613
|
-
throw new AggregateError(
|
|
9614
|
-
[error, closeError],
|
|
9615
|
-
"PGlite bootstrap failed and cleanup also failed."
|
|
9616
|
-
);
|
|
9617
|
-
}
|
|
9618
|
-
throw error;
|
|
9619
|
-
}
|
|
9620
|
-
return created;
|
|
9621
|
-
})();
|
|
9622
|
-
return databasePromise;
|
|
9623
|
-
};
|
|
9624
|
-
const pool = (role) => {
|
|
9625
|
-
if (role !== void 0 && !ROLE.test(role)) {
|
|
9626
|
-
throw new Error(`"${role}" is not a usable PostgreSQL role name.`);
|
|
9627
|
-
}
|
|
9628
|
-
issued += 1;
|
|
9629
|
-
return {
|
|
9630
|
-
cancellation: "before-start",
|
|
9631
|
-
async connect() {
|
|
9632
|
-
const release = await queue.acquire();
|
|
9633
|
-
let instance;
|
|
9634
|
-
try {
|
|
9635
|
-
instance = await database();
|
|
9636
|
-
if (role) await instance.exec(`SET ROLE ${role}`);
|
|
9637
|
-
} catch (error) {
|
|
9638
|
-
release();
|
|
9639
|
-
throw error;
|
|
9640
|
-
}
|
|
9641
|
-
let released = false;
|
|
9642
|
-
const run = async ({
|
|
9643
|
-
text,
|
|
9644
|
-
values: values2
|
|
9645
|
-
}) => {
|
|
9646
|
-
if (values2 === void 0 || values2.length === 0) {
|
|
9647
|
-
const answers = await instance.exec(text);
|
|
9648
|
-
const last = answers[answers.length - 1];
|
|
9649
|
-
return last ? result(last.rows, last.affectedRows ?? 0) : result([], 0);
|
|
9650
|
-
}
|
|
9651
|
-
const answer = await instance.query(text, [...values2]);
|
|
9652
|
-
return result(answer.rows, answer.affectedRows ?? 0);
|
|
9653
|
-
};
|
|
9654
|
-
return {
|
|
9655
|
-
query: run,
|
|
9656
|
-
release() {
|
|
9657
|
-
if (released) return;
|
|
9658
|
-
released = true;
|
|
9659
|
-
const reset = role ? instance.exec("RESET ROLE").catch(() => void 0) : Promise.resolve();
|
|
9660
|
-
void reset.finally(release);
|
|
9661
|
-
}
|
|
9662
|
-
};
|
|
9663
|
-
},
|
|
9664
|
-
async end() {
|
|
9665
|
-
ended += 1;
|
|
9666
|
-
if (ended < issued) return;
|
|
9667
|
-
await close();
|
|
9668
|
-
}
|
|
9669
|
-
};
|
|
9670
|
-
};
|
|
9671
|
-
return { pool, close };
|
|
9672
|
-
}
|
|
9673
|
-
|
|
9674
9853
|
// src/database.ts
|
|
9675
9854
|
import { Pool } from "pg";
|
|
9676
9855
|
function enabledNamespaces(workspace) {
|
|
@@ -9762,14 +9941,14 @@ import {
|
|
|
9762
9941
|
cp,
|
|
9763
9942
|
mkdir as mkdir6,
|
|
9764
9943
|
mkdtemp as mkdtemp2,
|
|
9765
|
-
readFile as
|
|
9944
|
+
readFile as readFile11,
|
|
9766
9945
|
readdir as readdir5,
|
|
9767
9946
|
rename as rename4,
|
|
9768
9947
|
rm as rm6,
|
|
9769
9948
|
writeFile as writeFile6
|
|
9770
9949
|
} from "node:fs/promises";
|
|
9771
9950
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
9772
|
-
import { delimiter, dirname as dirname8, isAbsolute as
|
|
9951
|
+
import { delimiter, dirname as dirname8, isAbsolute as isAbsolute4, join as join10, resolve as resolve8 } from "node:path";
|
|
9773
9952
|
import { promisify as promisify2 } from "node:util";
|
|
9774
9953
|
var POSTGRES_DUMP_FILE = "database.dump";
|
|
9775
9954
|
var PGLITE_PAYLOAD_DIRECTORY = "pglite";
|
|
@@ -9797,12 +9976,12 @@ function platformVersion(workspace) {
|
|
|
9797
9976
|
return typeof declared === "string" ? declared : "unknown";
|
|
9798
9977
|
}
|
|
9799
9978
|
function backupDirectory(workspace, value) {
|
|
9800
|
-
return
|
|
9979
|
+
return isAbsolute4(value) ? resolve8(value) : resolve8(workspace.root, value);
|
|
9801
9980
|
}
|
|
9802
9981
|
async function resolveTool(name, environment) {
|
|
9803
9982
|
for (const directory of (environment.PATH ?? "").split(delimiter)) {
|
|
9804
9983
|
if (!directory) continue;
|
|
9805
|
-
const candidate =
|
|
9984
|
+
const candidate = resolve8(directory, name);
|
|
9806
9985
|
try {
|
|
9807
9986
|
await access4(candidate, constants.X_OK);
|
|
9808
9987
|
return candidate;
|
|
@@ -9839,11 +10018,11 @@ async function withPostgresConnection(config, run) {
|
|
|
9839
10018
|
"\\n",
|
|
9840
10019
|
"\n"
|
|
9841
10020
|
).trim();
|
|
9842
|
-
const temporaryDirectory = !authorityFile && inlineAuthority ? await mkdtemp2(
|
|
10021
|
+
const temporaryDirectory = !authorityFile && inlineAuthority ? await mkdtemp2(join10(tmpdir2(), "flowdular-backup-")) : void 0;
|
|
9843
10022
|
try {
|
|
9844
10023
|
let certificate = authorityFile;
|
|
9845
10024
|
if (temporaryDirectory) {
|
|
9846
|
-
certificate =
|
|
10025
|
+
certificate = join10(temporaryDirectory, "ca.pem");
|
|
9847
10026
|
await writeFile6(certificate, `${inlineAuthority}
|
|
9848
10027
|
`, {
|
|
9849
10028
|
encoding: "utf8",
|
|
@@ -9912,7 +10091,7 @@ async function databaseBackup(workspace, output, apply) {
|
|
|
9912
10091
|
return failure("DATABASE_CONFIGURATION_INVALID", reason(error));
|
|
9913
10092
|
}
|
|
9914
10093
|
const directory = backupDirectory(workspace, output);
|
|
9915
|
-
const manifestPath =
|
|
10094
|
+
const manifestPath = join10(directory, BACKUP_MANIFEST_FILE);
|
|
9916
10095
|
if (await exists3(manifestPath)) {
|
|
9917
10096
|
return failure(
|
|
9918
10097
|
"BACKUP_TARGET_EXISTS",
|
|
@@ -9937,7 +10116,7 @@ async function databaseBackup(workspace, output, apply) {
|
|
|
9937
10116
|
"pg_dump was not found on PATH. Install the PostgreSQL client tools matching the server version."
|
|
9938
10117
|
);
|
|
9939
10118
|
}
|
|
9940
|
-
const payload2 =
|
|
10119
|
+
const payload2 = join10(directory, POSTGRES_DUMP_FILE);
|
|
9941
10120
|
const plan2 = {
|
|
9942
10121
|
adapter: config.adapter,
|
|
9943
10122
|
applied: apply,
|
|
@@ -9975,7 +10154,7 @@ async function databaseBackup(workspace, output, apply) {
|
|
|
9975
10154
|
source ? `The embedded database directory ${source} does not exist yet.` : "The embedded database runs in memory under NODE_ENV=test, so there is nothing to copy."
|
|
9976
10155
|
);
|
|
9977
10156
|
}
|
|
9978
|
-
const payload =
|
|
10157
|
+
const payload = join10(directory, PGLITE_PAYLOAD_DIRECTORY);
|
|
9979
10158
|
const plan = {
|
|
9980
10159
|
adapter: config.adapter,
|
|
9981
10160
|
applied: apply,
|
|
@@ -10002,7 +10181,7 @@ async function databaseBackup(workspace, output, apply) {
|
|
|
10002
10181
|
async function restrictTree(root) {
|
|
10003
10182
|
await chmod(root, 448);
|
|
10004
10183
|
for (const entry of await readdir5(root, { withFileTypes: true })) {
|
|
10005
|
-
const path =
|
|
10184
|
+
const path = join10(root, entry.name);
|
|
10006
10185
|
if (entry.isDirectory()) await restrictTree(path);
|
|
10007
10186
|
else if (entry.isFile()) await chmod(path, 384);
|
|
10008
10187
|
}
|
|
@@ -10013,7 +10192,7 @@ function restoreTarget(config) {
|
|
|
10013
10192
|
return decodeURIComponent(url.pathname.slice(1));
|
|
10014
10193
|
}
|
|
10015
10194
|
const directory = config.pglite?.dataDirectory;
|
|
10016
|
-
return directory === void 0 ? void 0 :
|
|
10195
|
+
return directory === void 0 ? void 0 : resolve8(config.workspaceRoot, directory);
|
|
10017
10196
|
}
|
|
10018
10197
|
function describeKeyMismatch(divergent) {
|
|
10019
10198
|
return divergent.map((key) => `${key.variable} (${key.status})`).join(", ");
|
|
@@ -10072,7 +10251,7 @@ function productionRefusal(options, config) {
|
|
|
10072
10251
|
);
|
|
10073
10252
|
}
|
|
10074
10253
|
const expected = restoreTarget(config);
|
|
10075
|
-
const target = config.adapter === "pglite" ?
|
|
10254
|
+
const target = config.adapter === "pglite" ? resolve8(config.workspaceRoot, options.target) : options.target;
|
|
10076
10255
|
if (target !== expected) {
|
|
10077
10256
|
return failure(
|
|
10078
10257
|
"RESTORE_TARGET_MISMATCH",
|
|
@@ -10107,11 +10286,11 @@ async function databaseRestore(workspace, input, apply, production) {
|
|
|
10107
10286
|
return failure("DATABASE_CONFIGURATION_INVALID", reason(error));
|
|
10108
10287
|
}
|
|
10109
10288
|
const directory = backupDirectory(workspace, input);
|
|
10110
|
-
const manifestPath =
|
|
10289
|
+
const manifestPath = join10(directory, BACKUP_MANIFEST_FILE);
|
|
10111
10290
|
let manifest2;
|
|
10112
10291
|
try {
|
|
10113
10292
|
manifest2 = parseBackupManifest(
|
|
10114
|
-
JSON.parse(await
|
|
10293
|
+
JSON.parse(await readFile11(manifestPath, "utf8"))
|
|
10115
10294
|
);
|
|
10116
10295
|
} catch (error) {
|
|
10117
10296
|
return error.code === "ENOENT" ? failure(
|
|
@@ -10156,7 +10335,7 @@ async function databaseRestore(workspace, input, apply, production) {
|
|
|
10156
10335
|
"pg_restore was not found on PATH. Install the PostgreSQL client tools matching the server version."
|
|
10157
10336
|
);
|
|
10158
10337
|
}
|
|
10159
|
-
const payload2 =
|
|
10338
|
+
const payload2 = join10(directory, POSTGRES_DUMP_FILE);
|
|
10160
10339
|
if (!await exists3(payload2)) {
|
|
10161
10340
|
return failure(
|
|
10162
10341
|
"BACKUP_PAYLOAD_MISSING",
|
|
@@ -10194,7 +10373,7 @@ async function databaseRestore(workspace, input, apply, production) {
|
|
|
10194
10373
|
}
|
|
10195
10374
|
return success(plan2, { evidence: [manifestPath, payload2], warnings });
|
|
10196
10375
|
}
|
|
10197
|
-
const payload =
|
|
10376
|
+
const payload = join10(directory, PGLITE_PAYLOAD_DIRECTORY);
|
|
10198
10377
|
if (!await exists3(payload)) {
|
|
10199
10378
|
return failure(
|
|
10200
10379
|
"BACKUP_PAYLOAD_MISSING",
|
|
@@ -10230,12 +10409,12 @@ async function databaseRestore(workspace, input, apply, production) {
|
|
|
10230
10409
|
}
|
|
10231
10410
|
|
|
10232
10411
|
// src/migration-new.ts
|
|
10233
|
-
import { readFile as
|
|
10412
|
+
import { readFile as readFile12 } from "node:fs/promises";
|
|
10234
10413
|
import { dirname as dirname9 } from "node:path";
|
|
10235
10414
|
|
|
10236
10415
|
// src/migration-scaffold.ts
|
|
10237
10416
|
import { mkdir as mkdir7, readdir as readdir6, writeFile as writeFile7 } from "node:fs/promises";
|
|
10238
|
-
import { join as
|
|
10417
|
+
import { join as join11 } from "node:path";
|
|
10239
10418
|
var NAME = /^[a-z][a-z0-9_]{2,48}$/;
|
|
10240
10419
|
function nextNumber(existing) {
|
|
10241
10420
|
const highest = existing.filter((entry) => entry.endsWith(".up.sql")).map((entry) => Number.parseInt(entry.slice(0, 4), 10)).filter((value) => Number.isSafeInteger(value)).reduce((left, right) => Math.max(left, right), 0);
|
|
@@ -10262,7 +10441,7 @@ async function scaffoldMigration(moduleDirectory, moduleStem, name, apply) {
|
|
|
10262
10441
|
`"${name}" must be lowercase letters, digits and underscores, 3 to 49 characters.`
|
|
10263
10442
|
);
|
|
10264
10443
|
}
|
|
10265
|
-
const directory =
|
|
10444
|
+
const directory = join11(moduleDirectory, "migrations");
|
|
10266
10445
|
let existing = [];
|
|
10267
10446
|
try {
|
|
10268
10447
|
existing = await readdir6(directory);
|
|
@@ -10273,11 +10452,11 @@ async function scaffoldMigration(moduleDirectory, moduleStem, name, apply) {
|
|
|
10273
10452
|
const table = `${moduleStem}_${name}`;
|
|
10274
10453
|
const files = [
|
|
10275
10454
|
{
|
|
10276
|
-
path:
|
|
10455
|
+
path: join11(directory, `${id}.up.sql`),
|
|
10277
10456
|
body: tenantTable(table)
|
|
10278
10457
|
},
|
|
10279
10458
|
{
|
|
10280
|
-
path:
|
|
10459
|
+
path: join11(directory, `${id}.down.sql`),
|
|
10281
10460
|
body: `DROP POLICY IF EXISTS ${table}_tenant_policy ON ${table};
|
|
10282
10461
|
DROP INDEX IF EXISTS ${table}_tenant_created_idx;
|
|
10283
10462
|
DROP TABLE IF EXISTS ${table};
|
|
@@ -10298,7 +10477,7 @@ async function migrationScaffold(workspace, moduleId, name, apply) {
|
|
|
10298
10477
|
const manifests = await findModuleFiles(workspace);
|
|
10299
10478
|
for (const manifestPath of manifests) {
|
|
10300
10479
|
const manifest2 = JSON.parse(
|
|
10301
|
-
await
|
|
10480
|
+
await readFile12(manifestPath, "utf8")
|
|
10302
10481
|
);
|
|
10303
10482
|
if (manifest2.id !== moduleId) continue;
|
|
10304
10483
|
const stem = moduleId.split(".")[0].replaceAll("-", "_");
|
|
@@ -10328,8 +10507,8 @@ async function migrationScaffold(workspace, moduleId, name, apply) {
|
|
|
10328
10507
|
}
|
|
10329
10508
|
|
|
10330
10509
|
// src/doctor.ts
|
|
10331
|
-
import { access as access5, readFile as
|
|
10332
|
-
import { join as
|
|
10510
|
+
import { access as access5, readFile as readFile13 } from "node:fs/promises";
|
|
10511
|
+
import { join as join12, relative as relative7 } from "node:path";
|
|
10333
10512
|
async function exists4(path) {
|
|
10334
10513
|
try {
|
|
10335
10514
|
await access5(path);
|
|
@@ -10358,20 +10537,20 @@ async function runDoctor(workspace) {
|
|
|
10358
10537
|
["policy.capabilities", agentResource(workspace, "policy")],
|
|
10359
10538
|
["policy.model-routing", agentResource(workspace, "modelRouting")],
|
|
10360
10539
|
["blueprints.root", agentResource(workspace, "blueprints")],
|
|
10361
|
-
["modules.root",
|
|
10362
|
-
...(await sdkModules(workspace)).size ? [] : [["packages.root",
|
|
10363
|
-
["platform.root",
|
|
10540
|
+
["modules.root", join12(workspace.root, "modules")],
|
|
10541
|
+
...(await sdkModules(workspace)).size ? [] : [["packages.root", join12(workspace.root, "packages")]],
|
|
10542
|
+
["platform.root", join12(workspace.root, "platform")]
|
|
10364
10543
|
]) {
|
|
10365
10544
|
const path = relative7(workspace.root, resource);
|
|
10366
10545
|
checks.push({
|
|
10367
10546
|
id,
|
|
10368
|
-
status: await exists4(
|
|
10369
|
-
message: await exists4(
|
|
10547
|
+
status: await exists4(join12(workspace.root, path)) ? "pass" : "fail",
|
|
10548
|
+
message: await exists4(join12(workspace.root, path)) ? `${path} is present.` : `${path} is missing.`,
|
|
10370
10549
|
evidence: path
|
|
10371
10550
|
});
|
|
10372
10551
|
}
|
|
10373
10552
|
const packageJson2 = JSON.parse(
|
|
10374
|
-
await
|
|
10553
|
+
await readFile13(join12(workspace.root, "package.json"), "utf8")
|
|
10375
10554
|
);
|
|
10376
10555
|
checks.push({
|
|
10377
10556
|
id: "workspace.pnpm",
|
|
@@ -10386,11 +10565,11 @@ async function runDoctor(workspace) {
|
|
|
10386
10565
|
message: blueprints.length > 0 ? `${blueprints.length} blueprint(s) discoverable.` : 'No blueprint.json was found; "blueprint validate --all" would pass vacuously.',
|
|
10387
10566
|
evidence: blueprints.map((file) => relative7(workspace.root, file)).join(", ")
|
|
10388
10567
|
});
|
|
10389
|
-
const entryPath =
|
|
10568
|
+
const entryPath = join12(workspace.root, "platform/src/App.tsrx");
|
|
10390
10569
|
if (await exists4(entryPath)) {
|
|
10391
|
-
const entry = await
|
|
10392
|
-
const pagePath =
|
|
10393
|
-
const page = await exists4(pagePath) ? await
|
|
10570
|
+
const entry = await readFile13(entryPath, "utf8");
|
|
10571
|
+
const pagePath = join12(workspace.root, "platform/index.html");
|
|
10572
|
+
const page = await exists4(pagePath) ? await readFile13(pagePath, "utf8") : "";
|
|
10394
10573
|
const renders = entry.includes("configureBrandingFromPage");
|
|
10395
10574
|
const staticHead = /<meta[^>]+name="theme-color"|<link[^>]+rel="icon"/.test(
|
|
10396
10575
|
page
|
|
@@ -10426,16 +10605,16 @@ async function runDoctor(workspace) {
|
|
|
10426
10605
|
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
10427
10606
|
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
10428
10607
|
import {
|
|
10429
|
-
lstat as
|
|
10608
|
+
lstat as lstat5,
|
|
10430
10609
|
mkdir as mkdir9,
|
|
10431
10610
|
open as open2,
|
|
10432
|
-
readFile as
|
|
10611
|
+
readFile as readFile15,
|
|
10433
10612
|
realpath as realpath2,
|
|
10434
10613
|
rename as rename6,
|
|
10435
10614
|
rm as rm8,
|
|
10436
10615
|
writeFile as writeFile9
|
|
10437
10616
|
} from "node:fs/promises";
|
|
10438
|
-
import { isAbsolute as
|
|
10617
|
+
import { isAbsolute as isAbsolute5, join as join14, relative as relative9 } from "node:path";
|
|
10439
10618
|
import { parse as parseYaml5 } from "yaml";
|
|
10440
10619
|
|
|
10441
10620
|
// src/vercel-launch.ts
|
|
@@ -10444,17 +10623,17 @@ import { createHash as createHash6, randomBytes as randomBytes2, randomUUID as r
|
|
|
10444
10623
|
import {
|
|
10445
10624
|
chmod as chmod2,
|
|
10446
10625
|
copyFile,
|
|
10447
|
-
lstat as
|
|
10626
|
+
lstat as lstat4,
|
|
10448
10627
|
mkdir as mkdir8,
|
|
10449
10628
|
mkdtemp as mkdtemp3,
|
|
10450
10629
|
open,
|
|
10451
|
-
readFile as
|
|
10630
|
+
readFile as readFile14,
|
|
10452
10631
|
rename as rename5,
|
|
10453
10632
|
rm as rm7,
|
|
10454
10633
|
writeFile as writeFile8
|
|
10455
10634
|
} from "node:fs/promises";
|
|
10456
10635
|
import { tmpdir as tmpdir3 } from "node:os";
|
|
10457
|
-
import { dirname as dirname10, join as
|
|
10636
|
+
import { dirname as dirname10, join as join13, relative as relative8 } from "node:path";
|
|
10458
10637
|
import { Client } from "pg";
|
|
10459
10638
|
|
|
10460
10639
|
// src/database-roles.ts
|
|
@@ -10699,7 +10878,7 @@ ${run.stdout}`.split("\n").map((line) => line.trim()).filter(Boolean);
|
|
|
10699
10878
|
}
|
|
10700
10879
|
function runVercel(context, args, mode = {}) {
|
|
10701
10880
|
const fullArgs = context.options.scope ? [...args, "--scope", context.options.scope] : [...args];
|
|
10702
|
-
return new Promise((
|
|
10881
|
+
return new Promise((resolve11, reject) => {
|
|
10703
10882
|
const child = spawn("vercel", fullArgs, {
|
|
10704
10883
|
cwd: mode.cwd ?? context.root,
|
|
10705
10884
|
stdio: mode.interactive ? "inherit" : [mode.input === void 0 ? "ignore" : "pipe", "pipe", "pipe"]
|
|
@@ -10726,7 +10905,7 @@ function runVercel(context, args, mode = {}) {
|
|
|
10726
10905
|
if (rest) process.stderr.write(`${redact(context, rest)}
|
|
10727
10906
|
`);
|
|
10728
10907
|
}
|
|
10729
|
-
|
|
10908
|
+
resolve11({ status: code ?? 1, ...captured });
|
|
10730
10909
|
});
|
|
10731
10910
|
});
|
|
10732
10911
|
}
|
|
@@ -10737,17 +10916,17 @@ function unexpected(command) {
|
|
|
10737
10916
|
);
|
|
10738
10917
|
}
|
|
10739
10918
|
async function readProjectLink(root) {
|
|
10740
|
-
const path =
|
|
10919
|
+
const path = join13(root, ".vercel/project.json");
|
|
10741
10920
|
let link;
|
|
10742
10921
|
try {
|
|
10743
|
-
const entry = await
|
|
10922
|
+
const entry = await lstat4(path);
|
|
10744
10923
|
if (!entry.isFile() || entry.size > 16 * 1024) {
|
|
10745
10924
|
throw new LaunchError(
|
|
10746
10925
|
"VERCEL_LINK_INVALID",
|
|
10747
10926
|
".vercel/project.json must be a regular file. Remove .vercel and rerun to link again."
|
|
10748
10927
|
);
|
|
10749
10928
|
}
|
|
10750
|
-
link = JSON.parse(await
|
|
10929
|
+
link = JSON.parse(await readFile14(path, "utf8"));
|
|
10751
10930
|
} catch (error) {
|
|
10752
10931
|
if (error.code === "ENOENT") return null;
|
|
10753
10932
|
if (error instanceof LaunchError) throw error;
|
|
@@ -10834,14 +11013,14 @@ async function setProductionVariable(context, name, value, exists5) {
|
|
|
10834
11013
|
}
|
|
10835
11014
|
async function readPrivateFile(root, path, maxKiB, code) {
|
|
10836
11015
|
try {
|
|
10837
|
-
const entry = await
|
|
11016
|
+
const entry = await lstat4(path);
|
|
10838
11017
|
if (!entry.isFile() || entry.size > maxKiB * 1024) {
|
|
10839
11018
|
throw new LaunchError(
|
|
10840
11019
|
code,
|
|
10841
11020
|
`${relative8(root, path)} must be a regular file of at most ${maxKiB} KiB.`
|
|
10842
11021
|
);
|
|
10843
11022
|
}
|
|
10844
|
-
const text = await
|
|
11023
|
+
const text = await readFile14(path, "utf8");
|
|
10845
11024
|
await chmod2(path, 384);
|
|
10846
11025
|
return text;
|
|
10847
11026
|
} catch (error) {
|
|
@@ -10850,7 +11029,7 @@ async function readPrivateFile(root, path, maxKiB, code) {
|
|
|
10850
11029
|
}
|
|
10851
11030
|
}
|
|
10852
11031
|
async function readKeyBackup(root, project) {
|
|
10853
|
-
const path =
|
|
11032
|
+
const path = join13(root, ".flowdular/deploy", `vercel-${project.id}.env`);
|
|
10854
11033
|
const values2 = /* @__PURE__ */ new Map();
|
|
10855
11034
|
const text = await readPrivateFile(root, path, 64, "KEY_BACKUP_INVALID");
|
|
10856
11035
|
for (const line of text?.split("\n") ?? []) {
|
|
@@ -10874,8 +11053,8 @@ async function writeKeyBackup(root, project, backup) {
|
|
|
10874
11053
|
async function writePrivateFile(root, path, contents) {
|
|
10875
11054
|
const directory = dirname10(path);
|
|
10876
11055
|
await mkdir8(directory, { recursive: true, mode: 448 });
|
|
10877
|
-
for (const path2 of [
|
|
10878
|
-
if (!(await
|
|
11056
|
+
for (const path2 of [join13(root, ".flowdular"), directory]) {
|
|
11057
|
+
if (!(await lstat4(path2)).isDirectory()) {
|
|
10879
11058
|
throw new LaunchError(
|
|
10880
11059
|
"KEY_BACKUP_INVALID",
|
|
10881
11060
|
`${relative8(root, path2)} must be a directory inside the workspace.`
|
|
@@ -10898,7 +11077,7 @@ async function writePrivateFile(root, path, contents) {
|
|
|
10898
11077
|
}
|
|
10899
11078
|
}
|
|
10900
11079
|
function setupTokenPath(root, project) {
|
|
10901
|
-
return
|
|
11080
|
+
return join13(root, ".flowdular/deploy", `vercel-${project.id}.setup-token`);
|
|
10902
11081
|
}
|
|
10903
11082
|
async function saveSetupToken(context, project) {
|
|
10904
11083
|
const path = setupTokenPath(context.root, project);
|
|
@@ -10971,9 +11150,9 @@ function roleUrl(owner, role, password) {
|
|
|
10971
11150
|
return `postgresql://${encodeURIComponent(APPLICATION_ROLES[role])}:${encodeURIComponent(password)}@${owner.host}${owner.pathname}`;
|
|
10972
11151
|
}
|
|
10973
11152
|
async function pullProductionValue(context, name) {
|
|
10974
|
-
const directory = await mkdtemp3(
|
|
11153
|
+
const directory = await mkdtemp3(join13(tmpdir3(), "flowdular-vercel-env-"));
|
|
10975
11154
|
try {
|
|
10976
|
-
const file =
|
|
11155
|
+
const file = join13(directory, "production.env");
|
|
10977
11156
|
await writeFile8(file, "", { mode: 384, flag: "wx" });
|
|
10978
11157
|
const run = await runVercel(context, [
|
|
10979
11158
|
"env",
|
|
@@ -10990,7 +11169,7 @@ async function pullProductionValue(context, name) {
|
|
|
10990
11169
|
);
|
|
10991
11170
|
}
|
|
10992
11171
|
const prefix = `${name}="`;
|
|
10993
|
-
const line = (await
|
|
11172
|
+
const line = (await readFile14(file, "utf8")).split("\n").find((entry) => entry.startsWith(prefix) && entry.endsWith('"'));
|
|
10994
11173
|
const value = line?.slice(prefix.length, -1);
|
|
10995
11174
|
return value && value !== "[SENSITIVE]" ? remember(context, value) : void 0;
|
|
10996
11175
|
} finally {
|
|
@@ -10999,12 +11178,12 @@ async function pullProductionValue(context, name) {
|
|
|
10999
11178
|
}
|
|
11000
11179
|
async function provisionNeon(context) {
|
|
11001
11180
|
progress("Provisioning Neon PostgreSQL through the Vercel Marketplace");
|
|
11002
|
-
const directory = await mkdtemp3(
|
|
11181
|
+
const directory = await mkdtemp3(join13(tmpdir3(), "flowdular-vercel-neon-"));
|
|
11003
11182
|
try {
|
|
11004
|
-
await mkdir8(
|
|
11183
|
+
await mkdir8(join13(directory, ".vercel"), { mode: 448 });
|
|
11005
11184
|
await copyFile(
|
|
11006
|
-
|
|
11007
|
-
|
|
11185
|
+
join13(context.root, ".vercel/project.json"),
|
|
11186
|
+
join13(directory, ".vercel/project.json")
|
|
11008
11187
|
);
|
|
11009
11188
|
const run = await runVercel(
|
|
11010
11189
|
context,
|
|
@@ -11519,6 +11698,8 @@ function defaultVercelHost() {
|
|
|
11519
11698
|
application_name: "flowdular-deploy",
|
|
11520
11699
|
connectionTimeoutMillis: 15e3
|
|
11521
11700
|
});
|
|
11701
|
+
client.on("error", () => {
|
|
11702
|
+
});
|
|
11522
11703
|
await client.connect();
|
|
11523
11704
|
return {
|
|
11524
11705
|
query: (text) => client.query(text),
|
|
@@ -11534,7 +11715,7 @@ function defaultVercelHost() {
|
|
|
11534
11715
|
)
|
|
11535
11716
|
);
|
|
11536
11717
|
}
|
|
11537
|
-
return new Promise((
|
|
11718
|
+
return new Promise((resolve11, reject) => {
|
|
11538
11719
|
const child = spawn(
|
|
11539
11720
|
process.execPath,
|
|
11540
11721
|
[...process.execArgv, entry, ...args, "--json"],
|
|
@@ -11550,7 +11731,7 @@ function defaultVercelHost() {
|
|
|
11550
11731
|
child.once("error", reject);
|
|
11551
11732
|
child.once("close", () => {
|
|
11552
11733
|
try {
|
|
11553
|
-
|
|
11734
|
+
resolve11(JSON.parse(stdout));
|
|
11554
11735
|
} catch {
|
|
11555
11736
|
reject(
|
|
11556
11737
|
new Error("The flowdular child command printed no envelope.")
|
|
@@ -11560,7 +11741,7 @@ function defaultVercelHost() {
|
|
|
11560
11741
|
});
|
|
11561
11742
|
},
|
|
11562
11743
|
fetch: (url, init) => fetch(url, init),
|
|
11563
|
-
wait: (ms) => new Promise((
|
|
11744
|
+
wait: (ms) => new Promise((resolve11) => setTimeout(resolve11, ms))
|
|
11564
11745
|
};
|
|
11565
11746
|
}
|
|
11566
11747
|
|
|
@@ -11604,23 +11785,23 @@ var deploymentAdapters = [
|
|
|
11604
11785
|
];
|
|
11605
11786
|
var DEPLOYMENT_HISTORY_LIMIT = 64;
|
|
11606
11787
|
async function recordDeployment(root, record) {
|
|
11607
|
-
const directory =
|
|
11788
|
+
const directory = join14(root, ".flowdular");
|
|
11608
11789
|
await mkdir9(directory, { recursive: true, mode: 448 });
|
|
11609
|
-
if (!(await
|
|
11790
|
+
if (!(await lstat5(directory)).isDirectory()) {
|
|
11610
11791
|
throw new Error(
|
|
11611
11792
|
"Deployment audit directory must be a directory inside the workspace."
|
|
11612
11793
|
);
|
|
11613
11794
|
}
|
|
11614
|
-
const path =
|
|
11795
|
+
const path = join14(directory, "deployments.json");
|
|
11615
11796
|
let history = [];
|
|
11616
11797
|
try {
|
|
11617
|
-
const entry = await
|
|
11798
|
+
const entry = await lstat5(path);
|
|
11618
11799
|
if (!entry.isFile() || entry.size > 128 * 1024) {
|
|
11619
11800
|
throw new Error(
|
|
11620
11801
|
"Deployment audit journal is not a bounded regular file."
|
|
11621
11802
|
);
|
|
11622
11803
|
}
|
|
11623
|
-
history = JSON.parse(await
|
|
11804
|
+
history = JSON.parse(await readFile15(path, "utf8"));
|
|
11624
11805
|
if (!Array.isArray(history))
|
|
11625
11806
|
throw new Error("Deployment audit journal is invalid.");
|
|
11626
11807
|
} catch (error) {
|
|
@@ -11645,12 +11826,12 @@ async function recordDeployment(root, record) {
|
|
|
11645
11826
|
}
|
|
11646
11827
|
async function workspaceFile(root, path) {
|
|
11647
11828
|
try {
|
|
11648
|
-
const file =
|
|
11649
|
-
if (!(await
|
|
11829
|
+
const file = join14(root, path);
|
|
11830
|
+
if (!(await lstat5(file)).isFile()) return false;
|
|
11650
11831
|
const canonicalRoot = await realpath2(root);
|
|
11651
11832
|
const canonicalFile = await realpath2(file);
|
|
11652
11833
|
const pathFromRoot = relative9(canonicalRoot, canonicalFile);
|
|
11653
|
-
return pathFromRoot !== "" && !pathFromRoot.startsWith("..") && !
|
|
11834
|
+
return pathFromRoot !== "" && !pathFromRoot.startsWith("..") && !isAbsolute5(pathFromRoot);
|
|
11654
11835
|
} catch {
|
|
11655
11836
|
return false;
|
|
11656
11837
|
}
|
|
@@ -11682,9 +11863,9 @@ async function renderBlueprintIssue(root) {
|
|
|
11682
11863
|
return "render.yaml must be a regular file at the repository root.";
|
|
11683
11864
|
let blueprint;
|
|
11684
11865
|
try {
|
|
11685
|
-
if ((await
|
|
11866
|
+
if ((await lstat5(join14(root, path))).size > 128 * 1024)
|
|
11686
11867
|
return "render.yaml exceeds the 128 KiB preflight limit.";
|
|
11687
|
-
blueprint = parseYaml5(await
|
|
11868
|
+
blueprint = parseYaml5(await readFile15(join14(root, path), "utf8"));
|
|
11688
11869
|
} catch {
|
|
11689
11870
|
return "render.yaml must contain valid YAML.";
|
|
11690
11871
|
}
|
|
@@ -11840,10 +12021,10 @@ async function vercelArtifactIssue(root) {
|
|
|
11840
12021
|
}
|
|
11841
12022
|
let config;
|
|
11842
12023
|
try {
|
|
11843
|
-
const path =
|
|
11844
|
-
if ((await
|
|
12024
|
+
const path = join14(root, "vercel.json");
|
|
12025
|
+
if ((await lstat5(path)).size > 16 * 1024)
|
|
11845
12026
|
return "vercel.json exceeds the 16 KiB preflight limit.";
|
|
11846
|
-
config = JSON.parse(await
|
|
12027
|
+
config = JSON.parse(await readFile15(path, "utf8"));
|
|
11847
12028
|
} catch {
|
|
11848
12029
|
return "vercel.json must contain valid JSON.";
|
|
11849
12030
|
}
|
|
@@ -11852,15 +12033,15 @@ async function vercelArtifactIssue(root) {
|
|
|
11852
12033
|
return null;
|
|
11853
12034
|
}
|
|
11854
12035
|
async function vercelUploadIgnoreIssue(root) {
|
|
11855
|
-
const path =
|
|
12036
|
+
const path = join14(root, ".vercelignore");
|
|
11856
12037
|
if (!await workspaceFile(root, ".vercelignore"))
|
|
11857
12038
|
return ".vercelignore must exist so vercel deploy does not upload .env files or the key backup under .flowdular.";
|
|
11858
12039
|
let patterns;
|
|
11859
12040
|
try {
|
|
11860
|
-
if ((await
|
|
12041
|
+
if ((await lstat5(path)).size > 16 * 1024)
|
|
11861
12042
|
return ".vercelignore exceeds the 16 KiB preflight limit.";
|
|
11862
12043
|
patterns = new Set(
|
|
11863
|
-
(await
|
|
12044
|
+
(await readFile15(path, "utf8")).split("\n").map((line) => line.trim().replace(/^\*\*\//, ""))
|
|
11864
12045
|
);
|
|
11865
12046
|
} catch {
|
|
11866
12047
|
return ".vercelignore must be readable.";
|
|
@@ -12032,15 +12213,15 @@ async function runDeployment(workspace, action, target, arguments_, terminal = {
|
|
|
12032
12213
|
}
|
|
12033
12214
|
);
|
|
12034
12215
|
}
|
|
12035
|
-
const directory =
|
|
12216
|
+
const directory = join14(workspace.root, ".flowdular");
|
|
12036
12217
|
await mkdir9(directory, { recursive: true, mode: 448 });
|
|
12037
|
-
if (!(await
|
|
12218
|
+
if (!(await lstat5(directory)).isDirectory()) {
|
|
12038
12219
|
return failure(
|
|
12039
12220
|
"DEPLOY_AUDIT_FAILED",
|
|
12040
12221
|
"The local audit directory is invalid."
|
|
12041
12222
|
);
|
|
12042
12223
|
}
|
|
12043
|
-
const lockPath =
|
|
12224
|
+
const lockPath = join14(directory, "deployment.lock");
|
|
12044
12225
|
let lock;
|
|
12045
12226
|
try {
|
|
12046
12227
|
lock = await open2(lockPath, "wx", 384);
|
|
@@ -12082,7 +12263,7 @@ async function launchDocker(workspace, arguments_, record) {
|
|
|
12082
12263
|
);
|
|
12083
12264
|
const result2 = spawnSync3(
|
|
12084
12265
|
process.execPath,
|
|
12085
|
-
[
|
|
12266
|
+
[join14(workspace.root, "infra/docker/start.mjs"), ...flags],
|
|
12086
12267
|
{
|
|
12087
12268
|
cwd: workspace.root,
|
|
12088
12269
|
stdio: "inherit"
|
|
@@ -12111,13 +12292,13 @@ async function launchDocker(workspace, arguments_, record) {
|
|
|
12111
12292
|
}
|
|
12112
12293
|
|
|
12113
12294
|
// src/extensions.ts
|
|
12114
|
-
import { readFile as
|
|
12295
|
+
import { readFile as readFile16 } from "node:fs/promises";
|
|
12115
12296
|
import { dirname as dirname12, relative as relative10 } from "node:path";
|
|
12116
12297
|
|
|
12117
12298
|
// src/module-import.ts
|
|
12118
|
-
import { readFileSync as
|
|
12299
|
+
import { readFileSync as readFileSync3, realpathSync as realpathSync2 } from "node:fs";
|
|
12119
12300
|
import {
|
|
12120
|
-
createRequire as
|
|
12301
|
+
createRequire as createRequire3,
|
|
12121
12302
|
registerHooks,
|
|
12122
12303
|
stripTypeScriptTypes
|
|
12123
12304
|
} from "node:module";
|
|
@@ -12126,11 +12307,11 @@ import { fileURLToPath, pathToFileURL as pathToFileURL2 } from "node:url";
|
|
|
12126
12307
|
var roots = /* @__PURE__ */ new Set();
|
|
12127
12308
|
var registered = false;
|
|
12128
12309
|
async function importModuleSource(entry, moduleRoot) {
|
|
12129
|
-
roots.add(
|
|
12310
|
+
roots.add(realpathSync2(moduleRoot));
|
|
12130
12311
|
try {
|
|
12131
|
-
const require2 =
|
|
12312
|
+
const require2 = createRequire3(pathToFileURL2(entry));
|
|
12132
12313
|
roots.add(
|
|
12133
|
-
|
|
12314
|
+
realpathSync2(dirname11(require2.resolve("@flowdular/sdk/package.json")))
|
|
12134
12315
|
);
|
|
12135
12316
|
} catch (error) {
|
|
12136
12317
|
if (!["MODULE_NOT_FOUND", "ERR_PACKAGE_PATH_NOT_EXPORTED"].includes(
|
|
@@ -12143,12 +12324,12 @@ async function importModuleSource(entry, moduleRoot) {
|
|
|
12143
12324
|
load(url, context, nextLoad) {
|
|
12144
12325
|
if (!url.startsWith("file:") || !fileURLToPath(url).endsWith(".ts"))
|
|
12145
12326
|
return nextLoad(url, context);
|
|
12146
|
-
const path =
|
|
12327
|
+
const path = realpathSync2(fileURLToPath(url));
|
|
12147
12328
|
if (![...roots].some((root) => path.startsWith(root + sep2)))
|
|
12148
12329
|
return nextLoad(url, context);
|
|
12149
12330
|
return {
|
|
12150
12331
|
format: "module",
|
|
12151
|
-
source: stripTypeScriptTypes(
|
|
12332
|
+
source: stripTypeScriptTypes(readFileSync3(path, "utf8"), {
|
|
12152
12333
|
mode: "transform",
|
|
12153
12334
|
sourceUrl: url
|
|
12154
12335
|
}),
|
|
@@ -12252,7 +12433,7 @@ async function loadCliExtensions(workspace) {
|
|
|
12252
12433
|
const loaded = [];
|
|
12253
12434
|
for (const manifestPath of manifests) {
|
|
12254
12435
|
const manifest2 = JSON.parse(
|
|
12255
|
-
await
|
|
12436
|
+
await readFile16(manifestPath, "utf8")
|
|
12256
12437
|
);
|
|
12257
12438
|
if (!enabled.has(manifest2.id) || !manifest2.cli) continue;
|
|
12258
12439
|
const moduleRoot = dirname12(manifestPath);
|
|
@@ -12268,7 +12449,7 @@ async function loadCliExtensions(workspace) {
|
|
|
12268
12449
|
);
|
|
12269
12450
|
}
|
|
12270
12451
|
const catalog = JSON.parse(
|
|
12271
|
-
await
|
|
12452
|
+
await readFile16(catalogPath, "utf8")
|
|
12272
12453
|
);
|
|
12273
12454
|
validateCliCatalog(catalog, manifest2);
|
|
12274
12455
|
for (const command of catalog.commands) {
|
|
@@ -12292,12 +12473,12 @@ async function loadCliExtensions(workspace) {
|
|
|
12292
12473
|
}
|
|
12293
12474
|
|
|
12294
12475
|
// src/migration.ts
|
|
12295
|
-
import { readFile as
|
|
12296
|
-
import { dirname as dirname13, join as
|
|
12476
|
+
import { readFile as readFile18, stat as stat2 } from "node:fs/promises";
|
|
12477
|
+
import { dirname as dirname13, join as join16 } from "node:path";
|
|
12297
12478
|
|
|
12298
12479
|
// src/migration-audit.ts
|
|
12299
|
-
import { readdir as readdir7, readFile as
|
|
12300
|
-
import { join as
|
|
12480
|
+
import { readdir as readdir7, readFile as readFile17 } from "node:fs/promises";
|
|
12481
|
+
import { join as join15 } from "node:path";
|
|
12301
12482
|
function statementsOf2(sql) {
|
|
12302
12483
|
return sql.replace(/\/\*[\s\S]*?\*\//g, " ").replace(/--[^\n]*\n/g, "\n");
|
|
12303
12484
|
}
|
|
@@ -12368,13 +12549,13 @@ async function scripts(directory) {
|
|
|
12368
12549
|
for (const entry of entries.filter((name) => name.endsWith(".up.sql"))) {
|
|
12369
12550
|
found.set(
|
|
12370
12551
|
entry.slice(0, -".up.sql".length),
|
|
12371
|
-
await
|
|
12552
|
+
await readFile17(join15(directory, entry), "utf8")
|
|
12372
12553
|
);
|
|
12373
12554
|
}
|
|
12374
12555
|
return found;
|
|
12375
12556
|
}
|
|
12376
12557
|
async function moduleMigrationAudit(moduleId, moduleDirectory, declared) {
|
|
12377
|
-
const found = await scripts(
|
|
12558
|
+
const found = await scripts(join15(moduleDirectory, "migrations"));
|
|
12378
12559
|
const issues = [];
|
|
12379
12560
|
const declaredIds = new Set(declared.map((migration) => migration.id));
|
|
12380
12561
|
for (const migrationId of [...declaredIds].sort()) {
|
|
@@ -12458,11 +12639,11 @@ async function loadMigrationModules(workspace, moduleId) {
|
|
|
12458
12639
|
const unmanaged = [];
|
|
12459
12640
|
for (const manifestPath of manifests) {
|
|
12460
12641
|
const manifest2 = JSON.parse(
|
|
12461
|
-
await
|
|
12642
|
+
await readFile18(manifestPath, "utf8")
|
|
12462
12643
|
);
|
|
12463
12644
|
if (!enabled.has(manifest2.id)) continue;
|
|
12464
12645
|
if (moduleId && manifest2.id !== moduleId) continue;
|
|
12465
|
-
const entry =
|
|
12646
|
+
const entry = join16(dirname13(manifestPath), "src/services/migration.ts");
|
|
12466
12647
|
try {
|
|
12467
12648
|
await stat2(entry);
|
|
12468
12649
|
} catch (error) {
|
|
@@ -12704,12 +12885,12 @@ import {
|
|
|
12704
12885
|
access as access6,
|
|
12705
12886
|
mkdir as mkdir10,
|
|
12706
12887
|
readdir as readdir8,
|
|
12707
|
-
readFile as
|
|
12888
|
+
readFile as readFile19,
|
|
12708
12889
|
realpath as realpath3,
|
|
12709
12890
|
rm as rm9,
|
|
12710
12891
|
writeFile as writeFile10
|
|
12711
12892
|
} from "node:fs/promises";
|
|
12712
|
-
import { dirname as dirname14, join as
|
|
12893
|
+
import { dirname as dirname14, join as join17, relative as relative11, resolve as resolve9 } from "node:path";
|
|
12713
12894
|
import { parse as parseYaml6 } from "yaml";
|
|
12714
12895
|
var IGNORED_ENTRIES = /* @__PURE__ */ new Set(["node_modules", "dist"]);
|
|
12715
12896
|
function ownedByAuthor(path) {
|
|
@@ -12719,7 +12900,7 @@ async function listFiles(directory) {
|
|
|
12719
12900
|
const files = [];
|
|
12720
12901
|
for (const entry of await readdir8(directory, { withFileTypes: true })) {
|
|
12721
12902
|
if (IGNORED_ENTRIES.has(entry.name)) continue;
|
|
12722
|
-
const path =
|
|
12903
|
+
const path = join17(directory, entry.name);
|
|
12723
12904
|
if (entry.isDirectory()) files.push(...await listFiles(path));
|
|
12724
12905
|
else files.push(path);
|
|
12725
12906
|
}
|
|
@@ -12746,9 +12927,9 @@ async function inspectTarget(workspaceRoot, moduleDirectory, specPath, specSourc
|
|
|
12746
12927
|
);
|
|
12747
12928
|
}
|
|
12748
12929
|
if (present.has("spec/module.yaml")) {
|
|
12749
|
-
const existingSpecPath =
|
|
12750
|
-
const sameFile =
|
|
12751
|
-
if (!sameFile && await
|
|
12930
|
+
const existingSpecPath = join17(moduleDirectory, "spec/module.yaml");
|
|
12931
|
+
const sameFile = resolve9(specPath) === await realpath3(existingSpecPath);
|
|
12932
|
+
if (!sameFile && await readFile19(existingSpecPath, "utf8") !== specSource) {
|
|
12752
12933
|
throw new Error(
|
|
12753
12934
|
`${relative11(workspaceRoot, existingSpecPath)} holds a different specification than ${relative11(workspaceRoot, specPath)}.`
|
|
12754
12935
|
);
|
|
@@ -12762,7 +12943,7 @@ async function writeScaffold(moduleDirectory, files, target) {
|
|
|
12762
12943
|
try {
|
|
12763
12944
|
for (const [path, source] of files) {
|
|
12764
12945
|
if (target.present.has(path)) continue;
|
|
12765
|
-
const absolute =
|
|
12946
|
+
const absolute = join17(moduleDirectory, path);
|
|
12766
12947
|
const created = await mkdir10(dirname14(absolute), { recursive: true });
|
|
12767
12948
|
if (created) createdDirectories.push(created);
|
|
12768
12949
|
await writeFile10(absolute, source, { encoding: "utf8", flag: "wx" });
|
|
@@ -12796,7 +12977,7 @@ async function scaffoldModule(workspace, request) {
|
|
|
12796
12977
|
`Module specification is invalid: ${specReport.issues.filter((issue2) => issue2.severity === "error").map((issue2) => issue2.message).join("; ")}`
|
|
12797
12978
|
);
|
|
12798
12979
|
}
|
|
12799
|
-
const specSource = await
|
|
12980
|
+
const specSource = await readFile19(specPath, "utf8");
|
|
12800
12981
|
const spec = parseYaml6(specSource);
|
|
12801
12982
|
if (spec.id !== request.id)
|
|
12802
12983
|
throw new Error(
|
|
@@ -12808,7 +12989,7 @@ async function scaffoldModule(workspace, request) {
|
|
|
12808
12989
|
);
|
|
12809
12990
|
const existingManifests = (await findNamedFiles(workspace.root, "module.json")).filter((path) => path.includes("/modules/"));
|
|
12810
12991
|
for (const path of existingManifests) {
|
|
12811
|
-
const existing = JSON.parse(await
|
|
12992
|
+
const existing = JSON.parse(await readFile19(path, "utf8"));
|
|
12812
12993
|
if (existing.id === request.id) {
|
|
12813
12994
|
throw new Error(
|
|
12814
12995
|
`Module id "${request.id}" is already registered by ${relative11(workspace.root, path)}.`
|
|
@@ -12817,7 +12998,7 @@ async function scaffoldModule(workspace, request) {
|
|
|
12817
12998
|
}
|
|
12818
12999
|
const moduleDirectory = resolveInside(
|
|
12819
13000
|
workspace.root,
|
|
12820
|
-
|
|
13001
|
+
join17("modules", packageSuffix(request.id))
|
|
12821
13002
|
);
|
|
12822
13003
|
const target = await inspectTarget(
|
|
12823
13004
|
workspace.root,
|
|
@@ -12839,8 +13020,8 @@ async function scaffoldModule(workspace, request) {
|
|
|
12839
13020
|
applied: request.apply,
|
|
12840
13021
|
formatted,
|
|
12841
13022
|
moduleDirectory: moduleRelative,
|
|
12842
|
-
files: [...planned.keys()].map((path) =>
|
|
12843
|
-
skipped: [...planned.keys()].filter((path) => target.present.has(path)).map((path) =>
|
|
13023
|
+
files: [...planned.keys()].map((path) => join17(moduleRelative, path)),
|
|
13024
|
+
skipped: [...planned.keys()].filter((path) => target.present.has(path)).map((path) => join17(moduleRelative, path))
|
|
12844
13025
|
};
|
|
12845
13026
|
}
|
|
12846
13027
|
async function formatFiles(moduleDirectory, files, formatter) {
|
|
@@ -12848,7 +13029,7 @@ async function formatFiles(moduleDirectory, files, formatter) {
|
|
|
12848
13029
|
for (const [path, source] of files) {
|
|
12849
13030
|
formatted.set(
|
|
12850
13031
|
path,
|
|
12851
|
-
await formatter.format(
|
|
13032
|
+
await formatter.format(join17(moduleDirectory, path), source)
|
|
12852
13033
|
);
|
|
12853
13034
|
}
|
|
12854
13035
|
return formatted;
|
|
@@ -12859,20 +13040,15 @@ import { constants as constants2 } from "node:fs";
|
|
|
12859
13040
|
import {
|
|
12860
13041
|
chmod as chmod3,
|
|
12861
13042
|
copyFile as copyFile2,
|
|
12862
|
-
lstat as
|
|
13043
|
+
lstat as lstat6,
|
|
12863
13044
|
mkdir as mkdir11,
|
|
12864
13045
|
readdir as readdir9,
|
|
12865
|
-
readFile as
|
|
13046
|
+
readFile as readFile20,
|
|
12866
13047
|
rm as rm10,
|
|
12867
13048
|
stat as stat3
|
|
12868
13049
|
} from "node:fs/promises";
|
|
12869
|
-
import { dirname as dirname15, join as
|
|
13050
|
+
import { dirname as dirname15, join as join18, relative as relative12 } from "node:path";
|
|
12870
13051
|
import { createHash as createHash7 } from "node:crypto";
|
|
12871
|
-
|
|
12872
|
-
// ../kernel/src/legacy-local-state.ts
|
|
12873
|
-
var LEGACY_DATA_DIRECTORY = ".octane-erp";
|
|
12874
|
-
|
|
12875
|
-
// src/state-migration.ts
|
|
12876
13052
|
var STATE_FILES = [
|
|
12877
13053
|
"agent-credential.key",
|
|
12878
13054
|
"agent-run-grant.key",
|
|
@@ -12886,7 +13062,7 @@ function isMissing(error) {
|
|
|
12886
13062
|
}
|
|
12887
13063
|
async function pathState(path) {
|
|
12888
13064
|
try {
|
|
12889
|
-
return await
|
|
13065
|
+
return await lstat6(path);
|
|
12890
13066
|
} catch (error) {
|
|
12891
13067
|
if (isMissing(error)) return void 0;
|
|
12892
13068
|
throw error;
|
|
@@ -12896,9 +13072,9 @@ function relativePath(workspace, path) {
|
|
|
12896
13072
|
return relative12(workspace.root, path);
|
|
12897
13073
|
}
|
|
12898
13074
|
async function migrationPlan(workspace) {
|
|
12899
|
-
const sourceDirectory =
|
|
13075
|
+
const sourceDirectory = join18(workspace.root, LEGACY_DATA_DIRECTORY);
|
|
12900
13076
|
const stateDirectory = flowdularStateDirectory(workspace.root);
|
|
12901
|
-
const destinationDirectory =
|
|
13077
|
+
const destinationDirectory = join18(stateDirectory, "data");
|
|
12902
13078
|
const destinationLabel = relativePath(workspace, destinationDirectory);
|
|
12903
13079
|
const blockers = [];
|
|
12904
13080
|
const missing = [];
|
|
@@ -12936,8 +13112,8 @@ async function migrationPlan(workspace) {
|
|
|
12936
13112
|
if (isLegacyDatabase(name)) unsupported.push(name);
|
|
12937
13113
|
}
|
|
12938
13114
|
for (const name of STATE_FILES) {
|
|
12939
|
-
const source =
|
|
12940
|
-
const destination =
|
|
13115
|
+
const source = join18(sourceDirectory, name);
|
|
13116
|
+
const destination = join18(destinationDirectory, name);
|
|
12941
13117
|
const sourceFile = await pathState(source);
|
|
12942
13118
|
if (!sourceFile) {
|
|
12943
13119
|
missing.push(name);
|
|
@@ -12963,7 +13139,7 @@ async function migrationPlan(workspace) {
|
|
|
12963
13139
|
};
|
|
12964
13140
|
}
|
|
12965
13141
|
async function digest(path) {
|
|
12966
|
-
return createHash7("sha256").update(await
|
|
13142
|
+
return createHash7("sha256").update(await readFile20(path)).digest("hex");
|
|
12967
13143
|
}
|
|
12968
13144
|
async function ensurePrivateDirectory(path) {
|
|
12969
13145
|
try {
|
|
@@ -12972,7 +13148,7 @@ async function ensurePrivateDirectory(path) {
|
|
|
12972
13148
|
if (!(error instanceof Error && "code" in error && error.code === "EEXIST"))
|
|
12973
13149
|
throw error;
|
|
12974
13150
|
}
|
|
12975
|
-
const state = await
|
|
13151
|
+
const state = await lstat6(path);
|
|
12976
13152
|
if (state.isSymbolicLink() || !state.isDirectory()) {
|
|
12977
13153
|
throw new Error(`${path} is not a safe local state directory.`);
|
|
12978
13154
|
}
|
|
@@ -12984,7 +13160,7 @@ async function copyPlan(plan) {
|
|
|
12984
13160
|
const created = [];
|
|
12985
13161
|
try {
|
|
12986
13162
|
for (const file of plan.files) {
|
|
12987
|
-
const sourceState = await
|
|
13163
|
+
const sourceState = await lstat6(file.source);
|
|
12988
13164
|
if (sourceState.isSymbolicLink() || !sourceState.isFile()) {
|
|
12989
13165
|
throw new Error(`${file.name} is no longer a regular file.`);
|
|
12990
13166
|
}
|
|
@@ -13064,7 +13240,7 @@ async function migrateLegacyState(workspace, apply) {
|
|
|
13064
13240
|
}
|
|
13065
13241
|
return success(data(plan, true), {
|
|
13066
13242
|
evidence: plan.files.map(
|
|
13067
|
-
(file) => relativePath(workspace,
|
|
13243
|
+
(file) => relativePath(workspace, join18(plan.destinationDirectory, file.name))
|
|
13068
13244
|
),
|
|
13069
13245
|
warnings: [
|
|
13070
13246
|
...unsupportedWarnings(plan),
|
|
@@ -13074,8 +13250,8 @@ async function migrateLegacyState(workspace, apply) {
|
|
|
13074
13250
|
}
|
|
13075
13251
|
|
|
13076
13252
|
// src/module-version.ts
|
|
13077
|
-
import { readFile as
|
|
13078
|
-
import { dirname as dirname16, join as
|
|
13253
|
+
import { readFile as readFile21, writeFile as writeFile11 } from "node:fs/promises";
|
|
13254
|
+
import { dirname as dirname16, join as join19, relative as relative13 } from "node:path";
|
|
13079
13255
|
var LOCK2 = "flowdular.modules.lock.json";
|
|
13080
13256
|
var LEVELS = ["patch", "minor", "major"];
|
|
13081
13257
|
function specDirectory(workspace) {
|
|
@@ -13085,7 +13261,7 @@ function specDirectory(workspace) {
|
|
|
13085
13261
|
async function loadModules(workspace) {
|
|
13086
13262
|
const modules = [];
|
|
13087
13263
|
for (const file of await findModuleFiles(workspace)) {
|
|
13088
|
-
const manifest2 = JSON.parse(await
|
|
13264
|
+
const manifest2 = JSON.parse(await readFile21(file, "utf8"));
|
|
13089
13265
|
modules.push({ file, root: dirname16(file), manifest: manifest2 });
|
|
13090
13266
|
}
|
|
13091
13267
|
return modules;
|
|
@@ -13093,7 +13269,7 @@ async function loadModules(workspace) {
|
|
|
13093
13269
|
async function installerManaged(workspace, id) {
|
|
13094
13270
|
try {
|
|
13095
13271
|
const lock = JSON.parse(
|
|
13096
|
-
await
|
|
13272
|
+
await readFile21(join19(workspace.root, LOCK2), "utf8")
|
|
13097
13273
|
);
|
|
13098
13274
|
return (lock.modules ?? []).some((entry) => entry.id === id);
|
|
13099
13275
|
} catch (error) {
|
|
@@ -13136,7 +13312,7 @@ function specRangeEdit(source, id, range) {
|
|
|
13136
13312
|
}
|
|
13137
13313
|
async function readOptional(path) {
|
|
13138
13314
|
try {
|
|
13139
|
-
return await
|
|
13315
|
+
return await readFile21(path, "utf8");
|
|
13140
13316
|
} catch (error) {
|
|
13141
13317
|
if (error.code === "ENOENT") return null;
|
|
13142
13318
|
throw error;
|
|
@@ -13168,7 +13344,7 @@ async function bumpModuleVersion(workspace, options) {
|
|
|
13168
13344
|
const files = [];
|
|
13169
13345
|
const manual = [];
|
|
13170
13346
|
const rel = (path) => relative13(workspace.root, path);
|
|
13171
|
-
const manifestSource = await
|
|
13347
|
+
const manifestSource = await readFile21(target.file, "utf8");
|
|
13172
13348
|
const manifestNext = versionKeyEdit(manifestSource, previous, next);
|
|
13173
13349
|
if (!manifestNext)
|
|
13174
13350
|
return failure(
|
|
@@ -13180,7 +13356,7 @@ async function bumpModuleVersion(workspace, options) {
|
|
|
13180
13356
|
path: rel(target.file),
|
|
13181
13357
|
change: `version ${previous} -> ${next}`
|
|
13182
13358
|
});
|
|
13183
|
-
const packagePath =
|
|
13359
|
+
const packagePath = join19(target.root, "package.json");
|
|
13184
13360
|
const packageSource = await readOptional(packagePath);
|
|
13185
13361
|
if (packageSource) {
|
|
13186
13362
|
const edited = versionKeyEdit(packageSource, previous, next);
|
|
@@ -13192,7 +13368,7 @@ async function bumpModuleVersion(workspace, options) {
|
|
|
13192
13368
|
});
|
|
13193
13369
|
} else manual.push(`${rel(packagePath)}: version is not ${previous}`);
|
|
13194
13370
|
}
|
|
13195
|
-
const specPath =
|
|
13371
|
+
const specPath = join19(target.root, spec, "module.yaml");
|
|
13196
13372
|
const specSource = await readOptional(specPath);
|
|
13197
13373
|
if (specSource) {
|
|
13198
13374
|
const edited = specVersionEdit(specSource, previous, next);
|
|
@@ -13221,7 +13397,7 @@ async function bumpModuleVersion(workspace, options) {
|
|
|
13221
13397
|
continue;
|
|
13222
13398
|
}
|
|
13223
13399
|
if (range === dependency.range) continue;
|
|
13224
|
-
const source = await
|
|
13400
|
+
const source = await readFile21(dependent.file, "utf8");
|
|
13225
13401
|
const edited = manifestRangeEdit(source, options.id, range);
|
|
13226
13402
|
if (!edited) {
|
|
13227
13403
|
manual.push(
|
|
@@ -13234,7 +13410,7 @@ async function bumpModuleVersion(workspace, options) {
|
|
|
13234
13410
|
path: rel(dependent.file),
|
|
13235
13411
|
change: `${options.id} ${dependency.range} -> ${range}`
|
|
13236
13412
|
});
|
|
13237
|
-
const dependentSpecPath =
|
|
13413
|
+
const dependentSpecPath = join19(dependent.root, spec, "module.yaml");
|
|
13238
13414
|
const dependentSpec = await readOptional(dependentSpecPath);
|
|
13239
13415
|
if (!dependentSpec) continue;
|
|
13240
13416
|
const specEdited = specRangeEdit(dependentSpec, options.id, range);
|
|
@@ -13379,7 +13555,7 @@ async function runExtensionCommand(workspace, extension, arguments_) {
|
|
|
13379
13555
|
{ report }
|
|
13380
13556
|
);
|
|
13381
13557
|
}
|
|
13382
|
-
const spec = parseYaml7(await
|
|
13558
|
+
const spec = parseYaml7(await readFile22(specPath, "utf8"));
|
|
13383
13559
|
if (spec.status !== "approved") {
|
|
13384
13560
|
return failure(
|
|
13385
13561
|
"SPEC_NOT_APPROVED",
|
|
@@ -13595,7 +13771,7 @@ async function runCommand(arguments_) {
|
|
|
13595
13771
|
if (arguments_.flags.has("all")) {
|
|
13596
13772
|
const platformRoot = workspace.config.specs?.platformRoot ?? "specs";
|
|
13597
13773
|
const platformSpecs = await listPlatformSpecs(
|
|
13598
|
-
|
|
13774
|
+
join20(workspace.root, platformRoot)
|
|
13599
13775
|
);
|
|
13600
13776
|
reports.push(
|
|
13601
13777
|
...await Promise.all(
|
|
@@ -14012,7 +14188,7 @@ async function runCommand(arguments_) {
|
|
|
14012
14188
|
["apply", true]
|
|
14013
14189
|
])
|
|
14014
14190
|
}
|
|
14015
|
-
);
|
|
14191
|
+
).catch(commandFailure);
|
|
14016
14192
|
if (!granted.ok) {
|
|
14017
14193
|
return failure(
|
|
14018
14194
|
"MODULE_SCOPES_SYNC_FAILED",
|
|
@@ -14088,23 +14264,20 @@ async function runCommand(arguments_) {
|
|
|
14088
14264
|
`Unknown command: ${arguments_.positionals.join(" ")}`
|
|
14089
14265
|
);
|
|
14090
14266
|
} catch (error) {
|
|
14091
|
-
return
|
|
14092
|
-
error instanceof ModuleDistributionError || error instanceof RegistryError || error instanceof DatabaseMigrationError ? error.code : "COMMAND_FAILED",
|
|
14093
|
-
error instanceof Error ? error.message : String(error)
|
|
14094
|
-
);
|
|
14267
|
+
return commandFailure(error);
|
|
14095
14268
|
}
|
|
14096
14269
|
}
|
|
14097
14270
|
|
|
14098
14271
|
// src/program.ts
|
|
14099
14272
|
import { loadEnvFile } from "node:process";
|
|
14100
|
-
import { resolve as
|
|
14273
|
+
import { resolve as resolve10 } from "node:path";
|
|
14101
14274
|
async function runProgram(arguments_) {
|
|
14102
14275
|
try {
|
|
14103
14276
|
const workspace = await findWorkspace(
|
|
14104
14277
|
stringFlag(arguments_, "root") ?? process.cwd()
|
|
14105
14278
|
);
|
|
14106
14279
|
try {
|
|
14107
|
-
loadEnvFile(
|
|
14280
|
+
loadEnvFile(resolve10(workspace.root, ".env"));
|
|
14108
14281
|
} catch (error) {
|
|
14109
14282
|
if (error.code !== "ENOENT")
|
|
14110
14283
|
return failure(
|
|
@@ -14126,20 +14299,20 @@ import { stat as stat4 } from "node:fs/promises";
|
|
|
14126
14299
|
|
|
14127
14300
|
// src/setup-environment.ts
|
|
14128
14301
|
import { randomUUID as randomUUID6 } from "node:crypto";
|
|
14129
|
-
import { lstat as
|
|
14130
|
-
import { join as
|
|
14302
|
+
import { lstat as lstat7, open as open3, readFile as readFile23, rename as rename7, rm as rm11, writeFile as writeFile12 } from "node:fs/promises";
|
|
14303
|
+
import { join as join21 } from "node:path";
|
|
14131
14304
|
async function readSetupEnvironment(root) {
|
|
14132
14305
|
try {
|
|
14133
|
-
return await
|
|
14306
|
+
return await readFile23(join21(root, ".env"), "utf8");
|
|
14134
14307
|
} catch (error) {
|
|
14135
14308
|
if (error.code === "ENOENT") return "";
|
|
14136
14309
|
throw error;
|
|
14137
14310
|
}
|
|
14138
14311
|
}
|
|
14139
14312
|
async function saveSetupEnvironment(root, before, updates) {
|
|
14140
|
-
const path =
|
|
14313
|
+
const path = join21(root, ".env");
|
|
14141
14314
|
try {
|
|
14142
|
-
if (!(await
|
|
14315
|
+
if (!(await lstat7(path)).isFile())
|
|
14143
14316
|
throw new Error("Setup requires .env to be a regular file.");
|
|
14144
14317
|
} catch (error) {
|
|
14145
14318
|
if (error.code !== "ENOENT") throw error;
|
|
@@ -14161,8 +14334,8 @@ async function saveSetupEnvironment(root, before, updates) {
|
|
|
14161
14334
|
return false;
|
|
14162
14335
|
});
|
|
14163
14336
|
const source = lines.join("\n").trimEnd() + "\n" + Object.entries(updates).map(([key, value]) => `${key}='${value}'`).join("\n") + "\n";
|
|
14164
|
-
const temporary =
|
|
14165
|
-
const lockPath =
|
|
14337
|
+
const temporary = join21(root, `.env.setup-${randomUUID6()}.tmp`);
|
|
14338
|
+
const lockPath = join21(root, ".env.setup.lock");
|
|
14166
14339
|
const lock = await open3(lockPath, "wx", 384);
|
|
14167
14340
|
try {
|
|
14168
14341
|
await writeFile12(temporary, source, { mode: 384, flag: "wx" });
|