@supacloud/cli 0.63.0 → 0.64.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -3
- package/dist/index.js +633 -759
- package/package.json +4 -2
package/dist/index.js
CHANGED
|
@@ -206727,7 +206727,7 @@ var ACTION_POLICY = {
|
|
|
206727
206727
|
},
|
|
206728
206728
|
ai: { local: ["show_skill", "install_skill"] },
|
|
206729
206729
|
app: {
|
|
206730
|
-
local: ["init", "generate", "dev", "compile", "check", "graph", "explain", "export-tools", "context", "doctor", "fix", "plan", "build"],
|
|
206730
|
+
local: ["init", "generate", "dev", "watch", "verify-plan", "compile", "check", "graph", "explain", "export-tools", "context", "doctor", "fix", "plan", "build"],
|
|
206731
206731
|
read: ["status"],
|
|
206732
206732
|
write: ["upload", "configure", "deploy", "rollback", "reconcile", "retire"]
|
|
206733
206733
|
},
|
|
@@ -221520,8 +221520,8 @@ function registerAiTools(server2) {
|
|
|
221520
221520
|
|
|
221521
221521
|
// src/shared/tools/app-tools.ts
|
|
221522
221522
|
import { existsSync as existsSync12, readFileSync as readFileSync9 } from "node:fs";
|
|
221523
|
-
import { mkdir as mkdir6, readFile as
|
|
221524
|
-
import { basename as basename8, dirname as
|
|
221523
|
+
import { mkdir as mkdir6, readFile as readFile9, readdir as readdir6, writeFile as writeFile5 } from "node:fs/promises";
|
|
221524
|
+
import { basename as basename8, dirname as dirname13, join as join17, relative as relative13, resolve as resolve21 } from "node:path";
|
|
221525
221525
|
|
|
221526
221526
|
// node_modules/@supacloud/compiler/dist/index.js
|
|
221527
221527
|
import { dirname as dirname22, relative as relative6, sep as sep4 } from "node:path";
|
|
@@ -246660,6 +246660,46 @@ function buildToolDefinitions(manifest) {
|
|
|
246660
246660
|
}
|
|
246661
246661
|
return { openai, mcp };
|
|
246662
246662
|
}
|
|
246663
|
+
// src/shared/tools/starter-metadata.json
|
|
246664
|
+
var starter_metadata_default = {
|
|
246665
|
+
schemaVersion: 1,
|
|
246666
|
+
generatedBy: "supacloud/starter-metadata-v1",
|
|
246667
|
+
packages: {
|
|
246668
|
+
compiler: {
|
|
246669
|
+
version: "0.31.2"
|
|
246670
|
+
},
|
|
246671
|
+
app: {
|
|
246672
|
+
version: "0.22.0",
|
|
246673
|
+
dependencies: {
|
|
246674
|
+
rxjs: "7.8.2"
|
|
246675
|
+
}
|
|
246676
|
+
},
|
|
246677
|
+
elysia: {
|
|
246678
|
+
version: "0.23.1"
|
|
246679
|
+
},
|
|
246680
|
+
commands: {
|
|
246681
|
+
version: "0.9.0"
|
|
246682
|
+
},
|
|
246683
|
+
contracts: {
|
|
246684
|
+
version: "0.8.0"
|
|
246685
|
+
},
|
|
246686
|
+
db: {
|
|
246687
|
+
version: "0.13.0",
|
|
246688
|
+
peerDependencies: {
|
|
246689
|
+
"drizzle-orm": "1.0.0-rc.4"
|
|
246690
|
+
},
|
|
246691
|
+
devDependencies: {
|
|
246692
|
+
"drizzle-kit": "1.0.0-rc.4"
|
|
246693
|
+
}
|
|
246694
|
+
},
|
|
246695
|
+
sdk: {
|
|
246696
|
+
version: "0.36.1",
|
|
246697
|
+
peerDependencies: {
|
|
246698
|
+
"@supabase/supabase-js": "^2.115.0"
|
|
246699
|
+
}
|
|
246700
|
+
}
|
|
246701
|
+
}
|
|
246702
|
+
};
|
|
246663
246703
|
|
|
246664
246704
|
// src/shared/tools/app-starter-reactive.ts
|
|
246665
246705
|
var STARTER_REACTIVE_GUIDE = `# Reactive development / 响应式开发
|
|
@@ -246885,259 +246925,9 @@ test("partial and untagged inherited remote profiles cannot mix with selected fi
|
|
|
246885
246925
|
expect(() => loadEnvironment("staging", root, {})).toThrow("Each remote file profile");
|
|
246886
246926
|
});
|
|
246887
246927
|
`;
|
|
246888
|
-
// ../compiler/package.json
|
|
246889
|
-
var package_default = {
|
|
246890
|
-
name: "@supacloud/compiler",
|
|
246891
|
-
version: "0.31.1",
|
|
246892
|
-
description: "Static compiler for @supacloud/app metadata: builds the application graph from AST, validates it, and generates reflection-free factory code",
|
|
246893
|
-
type: "module",
|
|
246894
|
-
main: "./dist/index.js",
|
|
246895
|
-
module: "./dist/index.js",
|
|
246896
|
-
types: "./dist/index.d.ts",
|
|
246897
|
-
bin: {
|
|
246898
|
-
"supacloud-compiler": "./dist/cli.js"
|
|
246899
|
-
},
|
|
246900
|
-
exports: {
|
|
246901
|
-
".": {
|
|
246902
|
-
types: "./dist/index.d.ts",
|
|
246903
|
-
import: "./dist/index.js",
|
|
246904
|
-
default: "./dist/index.js"
|
|
246905
|
-
},
|
|
246906
|
-
"./diagnostics": {
|
|
246907
|
-
types: "./dist/diagnostics.d.ts",
|
|
246908
|
-
import: "./dist/diagnostics.js",
|
|
246909
|
-
default: "./dist/diagnostics.js"
|
|
246910
|
-
}
|
|
246911
|
-
},
|
|
246912
|
-
files: [
|
|
246913
|
-
"NOTICE",
|
|
246914
|
-
"LICENSE-APACHE-2.0.txt",
|
|
246915
|
-
"dist",
|
|
246916
|
-
"README.md",
|
|
246917
|
-
"DELIVERY.md"
|
|
246918
|
-
],
|
|
246919
|
-
scripts: {
|
|
246920
|
-
build: "bun run clean && bun run build:js && bun run build:types",
|
|
246921
|
-
"build:js": "bun build src/index.ts src/diagnostics.ts src/cli.ts src/delivery-bundle-worker.ts --outdir dist --target node --conditions=supacloud-source --external @typescript/typescript6 --external graphql --external '@graphql-codegen/*'",
|
|
246922
|
-
"build:types": "tsc -p tsconfig.json --emitDeclarationOnly",
|
|
246923
|
-
clean: "rm -rf dist",
|
|
246924
|
-
prepublishOnly: "bun run build && bun run test:package",
|
|
246925
|
-
test: "bun test",
|
|
246926
|
-
"test:package": 'SUPACLOUD_COMPILER_TEST_CLI="$PWD/dist/cli.js" bun test src/graphql-package.test.ts',
|
|
246927
|
-
benchmark: "bun run src/benchmark.ts",
|
|
246928
|
-
typecheck: "tsc -p tsconfig.json --noEmit",
|
|
246929
|
-
"typecheck:test": "tsc -p tsconfig.test.json --noEmit"
|
|
246930
|
-
},
|
|
246931
|
-
keywords: [
|
|
246932
|
-
"supacloud",
|
|
246933
|
-
"compiler",
|
|
246934
|
-
"di",
|
|
246935
|
-
"codegen",
|
|
246936
|
-
"elysia"
|
|
246937
|
-
],
|
|
246938
|
-
license: "Apache-2.0",
|
|
246939
|
-
repository: {
|
|
246940
|
-
type: "git",
|
|
246941
|
-
url: "https://github.com/vibeunion/supacloud.git",
|
|
246942
|
-
directory: "packages/compiler"
|
|
246943
|
-
},
|
|
246944
|
-
dependencies: {
|
|
246945
|
-
"@supacloud/delivery": "0.4.0",
|
|
246946
|
-
typebox: "1.3.34",
|
|
246947
|
-
"@graphql-codegen/core": "^6.2.0",
|
|
246948
|
-
"@graphql-codegen/typed-document-node": "^7.1.0",
|
|
246949
|
-
"@graphql-codegen/typescript-operations": "^6.1.6",
|
|
246950
|
-
"@graphql-typed-document-node/core": "^3.2.0",
|
|
246951
|
-
"@typescript/typescript6": "^6.0.2",
|
|
246952
|
-
graphql: "^16"
|
|
246953
|
-
},
|
|
246954
|
-
devDependencies: {
|
|
246955
|
-
"@supabase/supabase-js": "2.115.0",
|
|
246956
|
-
"drizzle-orm": "1.0.0-rc.4",
|
|
246957
|
-
"@types/bun": "^1.4.2",
|
|
246958
|
-
typescript: "^7.0.2"
|
|
246959
|
-
}
|
|
246960
|
-
};
|
|
246961
|
-
// ../app/package.json
|
|
246962
|
-
var package_default2 = {
|
|
246963
|
-
name: "@supacloud/app",
|
|
246964
|
-
version: "0.21.1",
|
|
246965
|
-
description: "Angular-style application metadata for SupaCloud: modules, DI tokens, providers, scopes, controllers and commands",
|
|
246966
|
-
type: "module",
|
|
246967
|
-
main: "./dist/index.js",
|
|
246968
|
-
module: "./dist/index.js",
|
|
246969
|
-
types: "./dist/index.d.ts",
|
|
246970
|
-
exports: {
|
|
246971
|
-
"./contracts": {
|
|
246972
|
-
types: "./dist/contract_client.d.ts",
|
|
246973
|
-
import: "./dist/contract_client.js",
|
|
246974
|
-
default: "./dist/contract_client.js"
|
|
246975
|
-
},
|
|
246976
|
-
"./browser": {
|
|
246977
|
-
types: "./dist/browser.d.ts",
|
|
246978
|
-
import: "./dist/browser.js",
|
|
246979
|
-
default: "./dist/browser.js"
|
|
246980
|
-
},
|
|
246981
|
-
".": {
|
|
246982
|
-
types: "./dist/index.d.ts",
|
|
246983
|
-
import: "./dist/index.js",
|
|
246984
|
-
default: "./dist/index.js"
|
|
246985
|
-
},
|
|
246986
|
-
"./execution": {
|
|
246987
|
-
types: "./dist/execution.d.ts",
|
|
246988
|
-
import: "./dist/execution.js",
|
|
246989
|
-
default: "./dist/execution.js"
|
|
246990
|
-
},
|
|
246991
|
-
"./reactive": {
|
|
246992
|
-
types: "./dist/reactive.d.ts",
|
|
246993
|
-
import: "./dist/reactive.js",
|
|
246994
|
-
default: "./dist/reactive.js"
|
|
246995
|
-
},
|
|
246996
|
-
"./rxjs": {
|
|
246997
|
-
types: "./dist/rxjs.d.ts",
|
|
246998
|
-
import: "./dist/rxjs.js",
|
|
246999
|
-
default: "./dist/rxjs.js"
|
|
247000
|
-
},
|
|
247001
|
-
"./angular": {
|
|
247002
|
-
types: "./dist/angular.d.ts",
|
|
247003
|
-
import: "./dist/angular.js",
|
|
247004
|
-
default: "./dist/angular.js"
|
|
247005
|
-
},
|
|
247006
|
-
"./http": {
|
|
247007
|
-
types: "./dist/http.d.ts",
|
|
247008
|
-
import: "./dist/http.js",
|
|
247009
|
-
default: "./dist/http.js"
|
|
247010
|
-
},
|
|
247011
|
-
"./runtime": {
|
|
247012
|
-
types: "./dist/runtime.d.ts",
|
|
247013
|
-
import: "./dist/runtime.js",
|
|
247014
|
-
default: "./dist/runtime.js"
|
|
247015
|
-
}
|
|
247016
|
-
},
|
|
247017
|
-
files: [
|
|
247018
|
-
"NOTICE",
|
|
247019
|
-
"LICENSE-APACHE-2.0.txt",
|
|
247020
|
-
"dist",
|
|
247021
|
-
"README.md",
|
|
247022
|
-
"EXECUTION.md",
|
|
247023
|
-
"REACTIVE.md",
|
|
247024
|
-
"ANGULAR.md"
|
|
247025
|
-
],
|
|
247026
|
-
scripts: {
|
|
247027
|
-
build: "bun run clean && bun run build:js && bun run build:types",
|
|
247028
|
-
"build:js": "bun build src/index.ts src/execution.ts --outdir dist --target node --external @supacloud/contracts --external '@angular/*' --external rxjs --format esm && bun build src/contract_client.ts src/browser.ts --outdir dist --target browser --external @supacloud/contracts --format esm && bun build src/reactive.ts --outdir dist --target browser --external rxjs --format esm && bun build src/angular.ts src/rxjs.ts --outdir dist --target browser --external '@angular/*' --external rxjs --format esm && bun build src/http.ts --outdir dist --target node --external @supacloud/app --format esm && bun build src/runtime.ts --outdir dist --target browser --format esm",
|
|
247029
|
-
"build:types": "tsc -p tsconfig.json --emitDeclarationOnly",
|
|
247030
|
-
clean: "rm -rf dist",
|
|
247031
|
-
"check:package": "node ../../.github/scripts/esm-package-policy.mjs --pack .",
|
|
247032
|
-
prepublishOnly: "bun run build && bun run check:package",
|
|
247033
|
-
test: "bun test",
|
|
247034
|
-
typecheck: "tsc -p tsconfig.json --noEmit",
|
|
247035
|
-
"typecheck:test": "tsc -p tsconfig.test.json --noEmit"
|
|
247036
|
-
},
|
|
247037
|
-
keywords: [
|
|
247038
|
-
"supacloud",
|
|
247039
|
-
"di",
|
|
247040
|
-
"dependency-injection",
|
|
247041
|
-
"module",
|
|
247042
|
-
"elysia"
|
|
247043
|
-
],
|
|
247044
|
-
license: "Apache-2.0",
|
|
247045
|
-
repository: {
|
|
247046
|
-
type: "git",
|
|
247047
|
-
url: "https://github.com/vibeunion/supacloud.git",
|
|
247048
|
-
directory: "packages/app"
|
|
247049
|
-
},
|
|
247050
|
-
dependencies: {
|
|
247051
|
-
"@angular/core": "^22.1.5",
|
|
247052
|
-
"@supacloud/contracts": "file:../contracts",
|
|
247053
|
-
rxjs: "7.8.2",
|
|
247054
|
-
typebox: "1.3.34"
|
|
247055
|
-
},
|
|
247056
|
-
devDependencies: {
|
|
247057
|
-
"@types/bun": "^1.4.2",
|
|
247058
|
-
"@types/node": "^26.5.0",
|
|
247059
|
-
typescript: "^7.0.2",
|
|
247060
|
-
"@angular/compiler": "22.1.5"
|
|
247061
|
-
}
|
|
247062
|
-
};
|
|
247063
|
-
// ../elysia/package.json
|
|
247064
|
-
var package_default3 = {
|
|
247065
|
-
name: "@supacloud/elysia",
|
|
247066
|
-
version: "0.23.1",
|
|
247067
|
-
description: "Elysia runtime adapter for SupaCloud compiled modules: application/request scopes, route registration and validation",
|
|
247068
|
-
type: "module",
|
|
247069
|
-
main: "./dist/index.js",
|
|
247070
|
-
module: "./dist/index.js",
|
|
247071
|
-
types: "./dist/index.d.ts",
|
|
247072
|
-
exports: {
|
|
247073
|
-
".": {
|
|
247074
|
-
types: "./dist/index.d.ts",
|
|
247075
|
-
import: "./dist/index.js",
|
|
247076
|
-
default: "./dist/index.js"
|
|
247077
|
-
}
|
|
247078
|
-
},
|
|
247079
|
-
files: [
|
|
247080
|
-
"NOTICE",
|
|
247081
|
-
"LICENSE-APACHE-2.0.txt",
|
|
247082
|
-
"dist",
|
|
247083
|
-
"README.md",
|
|
247084
|
-
"compatibility.json"
|
|
247085
|
-
],
|
|
247086
|
-
scripts: {
|
|
247087
|
-
"generate:example": "bun src/generate-webhook-example.ts",
|
|
247088
|
-
build: "bun run clean && bun run build:js && bun run build:types",
|
|
247089
|
-
"build:js": "bun build src/index.ts --outdir dist --target node --external elysia --external jose --external @supacloud/app --external @supacloud/db --external @supacloud/contracts",
|
|
247090
|
-
"build:types": "tsc -p tsconfig.json --emitDeclarationOnly",
|
|
247091
|
-
clean: "rm -rf dist",
|
|
247092
|
-
prepublishOnly: "bun run build",
|
|
247093
|
-
test: "bun test",
|
|
247094
|
-
"test:conformance": "bun test src/conformance.test.ts src/application-execution.test.ts ../app/src/execution.test.ts ../app/src/execution_bundle.test.ts",
|
|
247095
|
-
"test:runtime-safety": "SUPACLOUD_REQUIRE_RUNTIME_SAFETY=1 bun test src/runtime-safety.test.ts",
|
|
247096
|
-
"test:contract-upgrade": "bun test src/contract-upgrade.test.ts",
|
|
247097
|
-
"bench:http-policy": "bun bench/http-policy.ts",
|
|
247098
|
-
typecheck: "tsc -p tsconfig.json --noEmit",
|
|
247099
|
-
"typecheck:test": "tsc -p tsconfig.test.json --noEmit"
|
|
247100
|
-
},
|
|
247101
|
-
keywords: [
|
|
247102
|
-
"supacloud",
|
|
247103
|
-
"elysia",
|
|
247104
|
-
"adapter",
|
|
247105
|
-
"dependency-injection",
|
|
247106
|
-
"module"
|
|
247107
|
-
],
|
|
247108
|
-
license: "Apache-2.0",
|
|
247109
|
-
repository: {
|
|
247110
|
-
type: "git",
|
|
247111
|
-
url: "https://github.com/vibeunion/supacloud.git",
|
|
247112
|
-
directory: "packages/elysia"
|
|
247113
|
-
},
|
|
247114
|
-
dependencies: {
|
|
247115
|
-
"@supacloud/app": "file:../app",
|
|
247116
|
-
"@supacloud/contracts": "file:../contracts",
|
|
247117
|
-
"exact-mirror": "1.2.6",
|
|
247118
|
-
jose: "^6.2.11",
|
|
247119
|
-
typebox: "1.3.34"
|
|
247120
|
-
},
|
|
247121
|
-
overrides: {
|
|
247122
|
-
"@supacloud/delivery": "file:../delivery",
|
|
247123
|
-
"@supacloud/contracts": "file:../contracts",
|
|
247124
|
-
"@supacloud/commands": "file:../commands"
|
|
247125
|
-
},
|
|
247126
|
-
peerDependencies: {
|
|
247127
|
-
elysia: "2.0.0-beta.19"
|
|
247128
|
-
},
|
|
247129
|
-
devDependencies: {
|
|
247130
|
-
"@supacloud/compiler": "file:../compiler",
|
|
247131
|
-
"@supacloud/delivery": "file:../delivery",
|
|
247132
|
-
"@supacloud/commands": "file:../commands",
|
|
247133
|
-
"@supacloud/db": "file:../db",
|
|
247134
|
-
"@types/bun": "^1.4.2",
|
|
247135
|
-
elysia: "2.0.0-beta.19",
|
|
247136
|
-
typescript: "^7.0.2"
|
|
247137
|
-
}
|
|
247138
|
-
};
|
|
247139
246928
|
|
|
247140
246929
|
// src/shared/tools/app-starter-templates.ts
|
|
246930
|
+
var { compiler: compilerMetadata, app: appMetadata, elysia: elysiaMetadata } = starter_metadata_default.packages;
|
|
247141
246931
|
var json = (value) => `${JSON.stringify(value, null, 2)}
|
|
247142
246932
|
`;
|
|
247143
246933
|
var DEV_SCRIPT = `import { watchProject, compileOptionsFromConfig, loadSupacloudConfig } from "@supacloud/compiler";
|
|
@@ -247213,7 +247003,8 @@ export function createCompiledModules(): never {
|
|
|
247213
247003
|
throw new Error("Run bun run compile before starting the application");
|
|
247214
247004
|
}
|
|
247215
247005
|
`;
|
|
247216
|
-
function baseFiles(name) {
|
|
247006
|
+
function baseFiles(name, sdkDependencies) {
|
|
247007
|
+
const minimal = sdkDependencies !== undefined;
|
|
247217
247008
|
return {
|
|
247218
247009
|
"package.json": json({
|
|
247219
247010
|
name,
|
|
@@ -247236,13 +247027,13 @@ function baseFiles(name) {
|
|
|
247236
247027
|
"env:production": "bun --no-env-file scripts/environment.ts production"
|
|
247237
247028
|
},
|
|
247238
247029
|
dependencies: {
|
|
247239
|
-
"@supacloud/app": `^${
|
|
247240
|
-
"@supacloud/elysia": `^${
|
|
247030
|
+
"@supacloud/app": `^${appMetadata.version}`,
|
|
247031
|
+
"@supacloud/elysia": `^${elysiaMetadata.version}`,
|
|
247241
247032
|
elysia: "2.0.0-beta.19",
|
|
247242
|
-
rxjs:
|
|
247033
|
+
...sdkDependencies ?? { rxjs: appMetadata.dependencies.rxjs }
|
|
247243
247034
|
},
|
|
247244
247035
|
devDependencies: {
|
|
247245
|
-
"@supacloud/compiler": `^${
|
|
247036
|
+
"@supacloud/compiler": `^${compilerMetadata.version}`,
|
|
247246
247037
|
"@types/bun": "^1.4.2",
|
|
247247
247038
|
typescript: "^7.0.2"
|
|
247248
247039
|
}
|
|
@@ -247290,9 +247081,11 @@ export default defineSupacloudConfig({
|
|
|
247290
247081
|
`,
|
|
247291
247082
|
"src/application.ts": APPLICATION_SOURCE(name),
|
|
247292
247083
|
"generated/application.ts": GENERATED_BOOTSTRAP,
|
|
247293
|
-
|
|
247294
|
-
|
|
247295
|
-
|
|
247084
|
+
...minimal ? {} : {
|
|
247085
|
+
"REACTIVE.md": STARTER_REACTIVE_GUIDE,
|
|
247086
|
+
"AGENTS.md": STARTER_REACTIVE_AGENTS,
|
|
247087
|
+
"tests/reactive.test.ts": STARTER_REACTIVE_TEST
|
|
247088
|
+
},
|
|
247296
247089
|
"scripts/environment.ts": STARTER_ENVIRONMENT,
|
|
247297
247090
|
"tests/environment.test.ts": STARTER_ENVIRONMENT_TEST,
|
|
247298
247091
|
"scripts/dev.ts": DEV_SCRIPT,
|
|
@@ -247488,7 +247281,111 @@ supacloud doctor --root .
|
|
|
247488
247281
|
`
|
|
247489
247282
|
};
|
|
247490
247283
|
}
|
|
247491
|
-
function
|
|
247284
|
+
function minimalTemplate(name, sdkDependencies) {
|
|
247285
|
+
return {
|
|
247286
|
+
...baseFiles(name, sdkDependencies),
|
|
247287
|
+
"src/features/health/health.ts": `import { Controller, Get, Module } from "@supacloud/app/core";
|
|
247288
|
+
import { t } from "elysia";
|
|
247289
|
+
|
|
247290
|
+
export const HealthResult = t.Object({ ok: t.Boolean() });
|
|
247291
|
+
|
|
247292
|
+
@Controller("/health")
|
|
247293
|
+
export class HealthController {
|
|
247294
|
+
@Get("/", { responses: { 200: HealthResult } })
|
|
247295
|
+
health(): { ok: boolean } { return { ok: true }; }
|
|
247296
|
+
}
|
|
247297
|
+
|
|
247298
|
+
@Module({ name: "health", tags: ["type:feature"], controllers: [HealthController] })
|
|
247299
|
+
export class HealthModule {}
|
|
247300
|
+
`,
|
|
247301
|
+
"src/features/health/health.test.ts": `import { expect, test } from "bun:test";
|
|
247302
|
+
import { HealthController } from "./health";
|
|
247303
|
+
|
|
247304
|
+
test("health is a public, side-effect-free operation", () => {
|
|
247305
|
+
expect(new HealthController().health()).toEqual({ ok: true });
|
|
247306
|
+
});
|
|
247307
|
+
`,
|
|
247308
|
+
"src/app.module.ts": `import { Module } from "@supacloud/app/core";
|
|
247309
|
+
import { HealthModule } from "./features/health/health";
|
|
247310
|
+
|
|
247311
|
+
@Module({ name: "application-root", tags: ["type:app"], imports: [HealthModule] })
|
|
247312
|
+
export class AppModule {}
|
|
247313
|
+
`,
|
|
247314
|
+
"scripts/sandbox.ts": `import { createMemorySandbox } from "@supacloud/elysia";
|
|
247315
|
+
import { createCompiledModules } from "../generated/application";
|
|
247316
|
+
|
|
247317
|
+
export function createDemo() {
|
|
247318
|
+
if (process.env.APP_ENV !== "development" && process.env.APP_ENV !== "test") {
|
|
247319
|
+
throw new Error("Local adapters are restricted to development and test");
|
|
247320
|
+
}
|
|
247321
|
+
return createMemorySandbox({ modules: createCompiledModules() });
|
|
247322
|
+
}
|
|
247323
|
+
`,
|
|
247324
|
+
"AGENTS.md": `# Application changes
|
|
247325
|
+
|
|
247326
|
+
- Business code and its tests belong in src/features/<feature>.
|
|
247327
|
+
- Use @supacloud/app/core for metadata; keep UI in the selected frontend framework.
|
|
247328
|
+
- Reuse @supacloud/js and the existing Supabase session for platform access.
|
|
247329
|
+
- Ordinary reads use the RLS-protected Supabase client. GraphQL is opt-in.
|
|
247330
|
+
- Cross-table business writes require trusted authorization, transactions,
|
|
247331
|
+
idempotency and audit. Never put service-role or Management tokens in a browser.
|
|
247332
|
+
- Do not edit generated/. Do not rewrite historical migrations.
|
|
247333
|
+
- Run the directly related single test file and git diff --check for daily changes.
|
|
247334
|
+
- Use app verify-plan --target <module> to inspect the focused verification plan.
|
|
247335
|
+
- Do not introduce another workflow engine, DI container or session store.
|
|
247336
|
+
`,
|
|
247337
|
+
"README.md": `# ${name}
|
|
247338
|
+
|
|
247339
|
+
## Local development
|
|
247340
|
+
|
|
247341
|
+
\`\`\`sh
|
|
247342
|
+
bun install
|
|
247343
|
+
bun run compile
|
|
247344
|
+
bun test src/features/health/health.test.ts
|
|
247345
|
+
bun run dev
|
|
247346
|
+
\`\`\`
|
|
247347
|
+
|
|
247348
|
+
The local server binds to 127.0.0.1:3000 and exposes GET /health.
|
|
247349
|
+
The dev script compiles, watches and restarts after successful compilation.
|
|
247350
|
+
Memory adapters are local-only; this is not production identity or persistence.
|
|
247351
|
+
|
|
247352
|
+
## Add a feature
|
|
247353
|
+
|
|
247354
|
+
Keep code, contracts and tests in src/features/<feature>; register modules in
|
|
247355
|
+
src/app.module.ts. Use @supacloud/app/core, not a frontend compatibility API.
|
|
247356
|
+
Use app generate --kind resource for an authorized read-port skeleton.
|
|
247357
|
+
It fails closed until the application supplies its data adapter.
|
|
247358
|
+
|
|
247359
|
+
## Frontend and database
|
|
247360
|
+
|
|
247361
|
+
@supacloud/js wraps your existing @supabase/supabase-js client. Reuse its session,
|
|
247362
|
+
Storage and RLS-protected PostgREST reads. Generated business clients can use
|
|
247363
|
+
createAuthenticatedFetch from @supacloud/js/contracts with that same session.
|
|
247364
|
+
Use fixed trusted HTTPS endpoints and never retry an uncertain write.
|
|
247365
|
+
|
|
247366
|
+
GraphQL is optional; this starter has no synthetic GraphQL schema.
|
|
247367
|
+
For a complete persistent command/attachment example, create a separate reference
|
|
247368
|
+
project with app init --template command. The http and edge recipes also remain
|
|
247369
|
+
explicit options; do not install every recipe into this application.
|
|
247370
|
+
|
|
247371
|
+
## Integration and delivery
|
|
247372
|
+
|
|
247373
|
+
createApp requires application-owned trusted identity and durable adapters.
|
|
247374
|
+
Database migrations and seed data require an explicitly selected development
|
|
247375
|
+
database and a reviewed application script; the CLI never infers a production target.
|
|
247376
|
+
Commit generated/ after compilation. At release, check generated drift before
|
|
247377
|
+
regeneration, then validate types, database permissions and authenticated behavior.
|
|
247378
|
+
`
|
|
247379
|
+
};
|
|
247380
|
+
}
|
|
247381
|
+
function appTemplateFiles(name, template, sdkDependencies) {
|
|
247382
|
+
if (template === "minimal") {
|
|
247383
|
+
if (!sdkDependencies)
|
|
247384
|
+
throw new Error("Minimal template requires the initializer's SDK dependency versions");
|
|
247385
|
+
return minimalTemplate(name, sdkDependencies);
|
|
247386
|
+
}
|
|
247387
|
+
if (template !== "http" && template !== "edge")
|
|
247388
|
+
throw new Error("Use appStarterFiles for the command recipe");
|
|
247492
247389
|
const files = template === "http" ? httpTemplate(name) : edgeTemplate(name);
|
|
247493
247390
|
const feature = template === "http" ? "OrdersFeature" : "SyncFeature";
|
|
247494
247391
|
const source = template === "http" ? "./orders/orders" : "./sync/sync";
|
|
@@ -248522,330 +248419,6 @@ export async function createDeliveryApplication(modules: CompiledModule[], lifec
|
|
|
248522
248419
|
}
|
|
248523
248420
|
}
|
|
248524
248421
|
`;
|
|
248525
|
-
// ../commands/package.json
|
|
248526
|
-
var package_default4 = {
|
|
248527
|
-
name: "@supacloud/commands",
|
|
248528
|
-
version: "0.9.0",
|
|
248529
|
-
description: "Storage-independent durable command execution and recovery",
|
|
248530
|
-
type: "module",
|
|
248531
|
-
main: "./dist/index.js",
|
|
248532
|
-
types: "./dist/index.d.ts",
|
|
248533
|
-
exports: {
|
|
248534
|
-
"./typebox": {
|
|
248535
|
-
types: "./dist/typebox.d.ts",
|
|
248536
|
-
import: "./dist/typebox.js"
|
|
248537
|
-
},
|
|
248538
|
-
".": {
|
|
248539
|
-
types: "./dist/index.d.ts",
|
|
248540
|
-
import: "./dist/index.js"
|
|
248541
|
-
}
|
|
248542
|
-
},
|
|
248543
|
-
files: [
|
|
248544
|
-
"NOTICE",
|
|
248545
|
-
"LICENSE-APACHE-2.0.txt",
|
|
248546
|
-
"dist",
|
|
248547
|
-
"README.md"
|
|
248548
|
-
],
|
|
248549
|
-
scripts: {
|
|
248550
|
-
build: "bun run build:js && bun run build:types",
|
|
248551
|
-
"build:js": "bun build src/index.ts src/typebox.ts --outdir dist --target node --external @supacloud/contracts --external @sinclair/typebox",
|
|
248552
|
-
"build:types": "tsc -p tsconfig.json --emitDeclarationOnly",
|
|
248553
|
-
typecheck: "tsc -p tsconfig.json --noEmit",
|
|
248554
|
-
"typecheck:test": "tsc -p tsconfig.test.json --noEmit",
|
|
248555
|
-
test: "bun test",
|
|
248556
|
-
prepublishOnly: "bun run build"
|
|
248557
|
-
},
|
|
248558
|
-
dependencies: {
|
|
248559
|
-
"@supacloud/contracts": "file:../contracts"
|
|
248560
|
-
},
|
|
248561
|
-
devDependencies: {
|
|
248562
|
-
"@sinclair/typebox": "0.34.52",
|
|
248563
|
-
"@types/bun": "1.4.2",
|
|
248564
|
-
typescript: "7.0.2"
|
|
248565
|
-
},
|
|
248566
|
-
peerDependencies: {
|
|
248567
|
-
"@sinclair/typebox": "0.34.52"
|
|
248568
|
-
},
|
|
248569
|
-
peerDependenciesMeta: {
|
|
248570
|
-
"@sinclair/typebox": {
|
|
248571
|
-
optional: true
|
|
248572
|
-
}
|
|
248573
|
-
},
|
|
248574
|
-
license: "Apache-2.0",
|
|
248575
|
-
repository: {
|
|
248576
|
-
type: "git",
|
|
248577
|
-
url: "https://github.com/vibeunion/supacloud.git",
|
|
248578
|
-
directory: "packages/commands"
|
|
248579
|
-
}
|
|
248580
|
-
};
|
|
248581
|
-
// ../contracts/package.json
|
|
248582
|
-
var package_default5 = {
|
|
248583
|
-
name: "@supacloud/contracts",
|
|
248584
|
-
version: "0.8.0",
|
|
248585
|
-
description: "SupaCloud command protocol with optional client and browser entrypoints",
|
|
248586
|
-
type: "module",
|
|
248587
|
-
main: "./dist/index.cjs",
|
|
248588
|
-
types: "./dist/index.d.mts",
|
|
248589
|
-
exports: {
|
|
248590
|
-
".": {
|
|
248591
|
-
import: {
|
|
248592
|
-
types: "./dist/index.d.mts",
|
|
248593
|
-
default: "./dist/index.mjs"
|
|
248594
|
-
},
|
|
248595
|
-
require: {
|
|
248596
|
-
types: "./dist/index.d.cts",
|
|
248597
|
-
default: "./dist/index.cjs"
|
|
248598
|
-
}
|
|
248599
|
-
},
|
|
248600
|
-
"./client": {
|
|
248601
|
-
import: {
|
|
248602
|
-
types: "./dist/client.d.mts",
|
|
248603
|
-
default: "./dist/client.mjs"
|
|
248604
|
-
},
|
|
248605
|
-
require: {
|
|
248606
|
-
types: "./dist/client.d.cts",
|
|
248607
|
-
default: "./dist/client.cjs"
|
|
248608
|
-
}
|
|
248609
|
-
},
|
|
248610
|
-
"./browser": {
|
|
248611
|
-
import: {
|
|
248612
|
-
types: "./dist/browser.d.mts",
|
|
248613
|
-
default: "./dist/browser.mjs"
|
|
248614
|
-
},
|
|
248615
|
-
require: {
|
|
248616
|
-
types: "./dist/browser.d.cts",
|
|
248617
|
-
default: "./dist/browser.cjs"
|
|
248618
|
-
}
|
|
248619
|
-
}
|
|
248620
|
-
},
|
|
248621
|
-
files: [
|
|
248622
|
-
"NOTICE",
|
|
248623
|
-
"LICENSE-APACHE-2.0.txt",
|
|
248624
|
-
"dist",
|
|
248625
|
-
"README.md"
|
|
248626
|
-
],
|
|
248627
|
-
scripts: {
|
|
248628
|
-
build: "bun run clean && bun run build:js && bun run build:types",
|
|
248629
|
-
"build:js": "bun run build:js:esm && bun run build:js:cjs",
|
|
248630
|
-
"build:types": "tsc -p tsconfig.json --emitDeclarationOnly && node ../../scripts/copy-dual-declarations.mjs dist",
|
|
248631
|
-
typecheck: "tsc -p tsconfig.json --noEmit",
|
|
248632
|
-
"typecheck:test": "tsc -p tsconfig.test.json --noEmit",
|
|
248633
|
-
test: "bun test",
|
|
248634
|
-
prepublishOnly: "bun run build",
|
|
248635
|
-
"build:js:esm": 'bun build src/index.ts src/client.ts src/browser.ts --outdir dist --format esm --entry-naming "[name].mjs" --chunk-naming "[name]-[hash].mjs" --target browser --splitting',
|
|
248636
|
-
"build:js:cjs": 'bun build src/index.ts src/client.ts src/browser.ts --outdir dist --format cjs --entry-naming "[name].cjs" --chunk-naming "[name]-[hash].cjs" --target browser',
|
|
248637
|
-
clean: "rm -rf dist"
|
|
248638
|
-
},
|
|
248639
|
-
devDependencies: {
|
|
248640
|
-
"@types/bun": "1.4.2",
|
|
248641
|
-
typescript: "7.0.2"
|
|
248642
|
-
},
|
|
248643
|
-
license: "Apache-2.0",
|
|
248644
|
-
repository: {
|
|
248645
|
-
type: "git",
|
|
248646
|
-
url: "https://github.com/vibeunion/supacloud.git",
|
|
248647
|
-
directory: "packages/contracts"
|
|
248648
|
-
},
|
|
248649
|
-
module: "./dist/index.mjs"
|
|
248650
|
-
};
|
|
248651
|
-
// ../db/package.json
|
|
248652
|
-
var package_default6 = {
|
|
248653
|
-
name: "@supacloud/db",
|
|
248654
|
-
version: "0.12.0",
|
|
248655
|
-
description: "Database governance layer for SupaCloud: RLS policies, RPC functions and grants as first-class resources, with manifest/catalog reconciliation",
|
|
248656
|
-
type: "module",
|
|
248657
|
-
main: "./dist/index.js",
|
|
248658
|
-
module: "./dist/index.js",
|
|
248659
|
-
types: "./dist/index.d.ts",
|
|
248660
|
-
bin: {
|
|
248661
|
-
"supacloud-sql-impact": "./dist/sql-impact-cli.js",
|
|
248662
|
-
"supacloud-db": "./dist/source-contracts-cli.js"
|
|
248663
|
-
},
|
|
248664
|
-
exports: {
|
|
248665
|
-
"./source-contracts": {
|
|
248666
|
-
types: "./dist/source-contracts.d.ts",
|
|
248667
|
-
import: "./dist/source-contracts.js"
|
|
248668
|
-
},
|
|
248669
|
-
"./source-contracts-cli": "./dist/source-contracts-cli.js",
|
|
248670
|
-
"./sql-analysis": {
|
|
248671
|
-
types: "./dist/sql-analysis.d.ts",
|
|
248672
|
-
import: "./dist/sql-analysis.js"
|
|
248673
|
-
},
|
|
248674
|
-
"./drizzle": {
|
|
248675
|
-
types: "./dist/drizzle.d.ts",
|
|
248676
|
-
import: "./dist/drizzle.js"
|
|
248677
|
-
},
|
|
248678
|
-
"./drizzle-bun": {
|
|
248679
|
-
types: "./dist/drizzle-bun.d.ts",
|
|
248680
|
-
import: "./dist/drizzle-bun.js"
|
|
248681
|
-
},
|
|
248682
|
-
"./bun": {
|
|
248683
|
-
types: "./dist/command-bun.d.ts",
|
|
248684
|
-
import: "./dist/command-bun.js"
|
|
248685
|
-
},
|
|
248686
|
-
".": {
|
|
248687
|
-
types: "./dist/index.d.ts",
|
|
248688
|
-
import: "./dist/index.js",
|
|
248689
|
-
default: "./dist/index.js"
|
|
248690
|
-
}
|
|
248691
|
-
},
|
|
248692
|
-
files: [
|
|
248693
|
-
"NOTICE",
|
|
248694
|
-
"LICENSE-APACHE-2.0.txt",
|
|
248695
|
-
"dist",
|
|
248696
|
-
"README.md",
|
|
248697
|
-
"MIGRATION_BINDINGS.md"
|
|
248698
|
-
],
|
|
248699
|
-
scripts: {
|
|
248700
|
-
build: "bun run clean && bun run build:js && bun run build:types",
|
|
248701
|
-
"build:js": "bun build src/index.ts src/command-bun.ts src/drizzle.ts src/drizzle-bun.ts src/sql-analysis.ts src/sql-impact-cli.ts src/source-contracts.ts src/source-contracts-cli.ts --outdir dist --target node --external bun --external @supacloud/contracts --external drizzle-orm --external libpg-query --external @typescript/typescript6",
|
|
248702
|
-
"build:types": "tsc -p tsconfig.json --emitDeclarationOnly",
|
|
248703
|
-
clean: "rm -rf dist",
|
|
248704
|
-
prepublishOnly: "bun run build",
|
|
248705
|
-
test: "bun test",
|
|
248706
|
-
typecheck: "tsc -p tsconfig.json --noEmit",
|
|
248707
|
-
"typecheck:test": "tsc -p tsconfig.test.json --noEmit",
|
|
248708
|
-
"typecheck:drizzle": "tsc -p tsconfig.drizzle.json --noEmit"
|
|
248709
|
-
},
|
|
248710
|
-
keywords: [
|
|
248711
|
-
"supacloud",
|
|
248712
|
-
"database",
|
|
248713
|
-
"governance",
|
|
248714
|
-
"rls",
|
|
248715
|
-
"postgresql"
|
|
248716
|
-
],
|
|
248717
|
-
license: "Apache-2.0",
|
|
248718
|
-
repository: {
|
|
248719
|
-
type: "git",
|
|
248720
|
-
url: "https://github.com/vibeunion/supacloud.git",
|
|
248721
|
-
directory: "packages/db"
|
|
248722
|
-
},
|
|
248723
|
-
devDependencies: {
|
|
248724
|
-
"@sinclair/typebox": "0.34.52",
|
|
248725
|
-
"drizzle-orm": "1.0.0-rc.4",
|
|
248726
|
-
"drizzle-kit": "1.0.0-rc.4",
|
|
248727
|
-
"@types/bun": "^1.4.2",
|
|
248728
|
-
typescript: "^7.0.2"
|
|
248729
|
-
},
|
|
248730
|
-
dependencies: {
|
|
248731
|
-
"@typescript/typescript6": "^6.0.2",
|
|
248732
|
-
"libpg-query": "18.1.4",
|
|
248733
|
-
"@supacloud/contracts": "0.8.0"
|
|
248734
|
-
},
|
|
248735
|
-
peerDependencies: {
|
|
248736
|
-
"drizzle-orm": "1.0.0-rc.4"
|
|
248737
|
-
},
|
|
248738
|
-
peerDependenciesMeta: {
|
|
248739
|
-
"drizzle-orm": {
|
|
248740
|
-
optional: true
|
|
248741
|
-
}
|
|
248742
|
-
},
|
|
248743
|
-
overrides: {
|
|
248744
|
-
"@supacloud/contracts": "0.8.0"
|
|
248745
|
-
}
|
|
248746
|
-
};
|
|
248747
|
-
// ../supacloud-js/package.json
|
|
248748
|
-
var package_default7 = {
|
|
248749
|
-
name: "@supacloud/js",
|
|
248750
|
-
version: "0.36.1",
|
|
248751
|
-
description: "Platform SDK for SupaCloud, built on top of supabase-js",
|
|
248752
|
-
type: "module",
|
|
248753
|
-
main: "./dist/index.cjs",
|
|
248754
|
-
module: "./dist/index.mjs",
|
|
248755
|
-
types: "./dist/index.d.mts",
|
|
248756
|
-
exports: {
|
|
248757
|
-
".": {
|
|
248758
|
-
import: {
|
|
248759
|
-
types: "./dist/index.d.mts",
|
|
248760
|
-
default: "./dist/index.mjs"
|
|
248761
|
-
},
|
|
248762
|
-
require: {
|
|
248763
|
-
types: "./dist/index.d.cts",
|
|
248764
|
-
default: "./dist/index.cjs"
|
|
248765
|
-
}
|
|
248766
|
-
},
|
|
248767
|
-
"./task-events": {
|
|
248768
|
-
import: {
|
|
248769
|
-
types: "./dist/task-events.d.mts",
|
|
248770
|
-
default: "./dist/task-events.mjs"
|
|
248771
|
-
},
|
|
248772
|
-
require: {
|
|
248773
|
-
types: "./dist/task-events.d.cts",
|
|
248774
|
-
default: "./dist/task-events.cjs"
|
|
248775
|
-
}
|
|
248776
|
-
},
|
|
248777
|
-
"./contracts": {
|
|
248778
|
-
import: {
|
|
248779
|
-
types: "./dist/contracts.d.mts",
|
|
248780
|
-
default: "./dist/contracts.mjs"
|
|
248781
|
-
},
|
|
248782
|
-
require: {
|
|
248783
|
-
types: "./dist/contracts.d.cts",
|
|
248784
|
-
default: "./dist/contracts.cjs"
|
|
248785
|
-
}
|
|
248786
|
-
},
|
|
248787
|
-
"./reactive": {
|
|
248788
|
-
import: {
|
|
248789
|
-
types: "./dist/reactive.d.mts",
|
|
248790
|
-
default: "./dist/reactive.mjs"
|
|
248791
|
-
},
|
|
248792
|
-
require: {
|
|
248793
|
-
types: "./dist/reactive.d.cts",
|
|
248794
|
-
default: "./dist/reactive.cjs"
|
|
248795
|
-
}
|
|
248796
|
-
}
|
|
248797
|
-
},
|
|
248798
|
-
files: [
|
|
248799
|
-
"NOTICE",
|
|
248800
|
-
"LICENSE-APACHE-2.0.txt",
|
|
248801
|
-
"dist",
|
|
248802
|
-
"README.md",
|
|
248803
|
-
"COMPATIBILITY.md",
|
|
248804
|
-
"REACTIVE.md"
|
|
248805
|
-
],
|
|
248806
|
-
scripts: {
|
|
248807
|
-
test: "bun test",
|
|
248808
|
-
build: "bun run clean && bun run build:js && bun run build:types",
|
|
248809
|
-
"build:js": "bun run build:js:esm && bun run build:js:cjs",
|
|
248810
|
-
"build:types": "tsc -p tsconfig.json --emitDeclarationOnly && node ../../scripts/copy-dual-declarations.mjs dist",
|
|
248811
|
-
clean: "rm -rf dist",
|
|
248812
|
-
prepublishOnly: "bun run build && bun run check:package",
|
|
248813
|
-
"typecheck:consumer": "tsc -p tsconfig.consumer.json --noEmit",
|
|
248814
|
-
typecheck: "tsc -p tsconfig.json --noEmit",
|
|
248815
|
-
"typecheck:test": "tsc -p tsconfig.test.json --noEmit",
|
|
248816
|
-
"check:package": "node ../../.github/scripts/esm-package-policy.mjs --pack .",
|
|
248817
|
-
"build:js:esm": 'bun build src/index.ts src/task-events.ts --outdir dist --format esm --entry-naming "[name].mjs" --chunk-naming "[name]-[hash].mjs" --target node --external @supabase/supabase-js --external @supacloud/contracts && bun build src/contracts.ts --outdir dist --format esm --entry-naming "[name].mjs" --chunk-naming "[name]-[hash].mjs" --target browser --external @supacloud/contracts && bun build src/reactive.ts --outdir dist --format esm --entry-naming "[name].mjs" --chunk-naming "[name]-[hash].mjs" --target browser --external rxjs',
|
|
248818
|
-
"build:js:cjs": 'bun build src/index.ts src/task-events.ts --outdir dist --format cjs --entry-naming "[name].cjs" --chunk-naming "[name]-[hash].cjs" --target node --external @supabase/supabase-js --external @supacloud/contracts && bun build src/contracts.ts --outdir dist --format cjs --entry-naming "[name].cjs" --chunk-naming "[name]-[hash].cjs" --target browser --external @supacloud/contracts && bun build src/reactive.ts --outdir dist --format cjs --entry-naming "[name].cjs" --chunk-naming "[name]-[hash].cjs" --target browser --external rxjs'
|
|
248819
|
-
},
|
|
248820
|
-
keywords: [
|
|
248821
|
-
"supacloud",
|
|
248822
|
-
"supabase",
|
|
248823
|
-
"sdk",
|
|
248824
|
-
"background-tasks",
|
|
248825
|
-
"realtime"
|
|
248826
|
-
],
|
|
248827
|
-
license: "Apache-2.0",
|
|
248828
|
-
repository: {
|
|
248829
|
-
type: "git",
|
|
248830
|
-
url: "https://github.com/vibeunion/supacloud.git",
|
|
248831
|
-
directory: "packages/supacloud-js"
|
|
248832
|
-
},
|
|
248833
|
-
peerDependencies: {
|
|
248834
|
-
"@supabase/supabase-js": "^2.115.0"
|
|
248835
|
-
},
|
|
248836
|
-
dependencies: {
|
|
248837
|
-
"@supacloud/contracts": "0.8.0",
|
|
248838
|
-
rxjs: "7.8.2"
|
|
248839
|
-
},
|
|
248840
|
-
devDependencies: {
|
|
248841
|
-
"@types/bun": "^1.4.2",
|
|
248842
|
-
"@supabase/supabase-js": "^2.115.0",
|
|
248843
|
-
typescript: "^7.0.2"
|
|
248844
|
-
},
|
|
248845
|
-
engines: {
|
|
248846
|
-
node: ">=22.12.0"
|
|
248847
|
-
}
|
|
248848
|
-
};
|
|
248849
248422
|
|
|
248850
248423
|
// src/shared/tools/app-starter-database.ts
|
|
248851
248424
|
var STARTER_DATABASE_CONFIG = {
|
|
@@ -248969,6 +248542,7 @@ export default defineConfig({
|
|
|
248969
248542
|
}
|
|
248970
248543
|
|
|
248971
248544
|
// src/shared/tools/app-starter.ts
|
|
248545
|
+
var { compiler: compilerMetadata2, app: appMetadata2, elysia: elysiaMetadata2, commands: commandsMetadata, contracts: contractsMetadata, db: dbMetadata, sdk: sdkMetadata } = starter_metadata_default.packages;
|
|
248972
248546
|
var json2 = (value) => `${JSON.stringify(value, null, 2)}
|
|
248973
248547
|
`;
|
|
248974
248548
|
function appStarterFiles(name) {
|
|
@@ -248992,6 +248566,7 @@ function appStarterFiles(name) {
|
|
|
248992
248566
|
check: "bun run db:check && bun run compile && bun run check:generated && bun run typecheck && bun run test",
|
|
248993
248567
|
test: "bun run compile && bun --no-env-file scripts/environment.ts test bun test",
|
|
248994
248568
|
dev: "bun --no-env-file scripts/environment.ts development bun scripts/dev.ts",
|
|
248569
|
+
"dev:integration": "bun --no-env-file scripts/environment.ts development bun scripts/integration.ts",
|
|
248995
248570
|
build: "bun run db:check && bun run compile && bun run typecheck && bun build src/application.ts --target bun --minify --outdir dist",
|
|
248996
248571
|
"env:development": "bun --no-env-file scripts/environment.ts development",
|
|
248997
248572
|
"env:test": "bun --no-env-file scripts/environment.ts test",
|
|
@@ -248999,20 +248574,20 @@ function appStarterFiles(name) {
|
|
|
248999
248574
|
"env:production": "bun --no-env-file scripts/environment.ts production"
|
|
249000
248575
|
},
|
|
249001
248576
|
dependencies: {
|
|
249002
|
-
"@supacloud/app": `^${
|
|
249003
|
-
"@supacloud/elysia": `^${
|
|
249004
|
-
"@supacloud/commands": `^${
|
|
249005
|
-
"@supacloud/contracts": `^${
|
|
249006
|
-
"@supacloud/db": `^${
|
|
249007
|
-
"drizzle-orm":
|
|
249008
|
-
"@supacloud/js": `^${
|
|
249009
|
-
"@supabase/supabase-js":
|
|
248577
|
+
"@supacloud/app": `^${appMetadata2.version}`,
|
|
248578
|
+
"@supacloud/elysia": `^${elysiaMetadata2.version}`,
|
|
248579
|
+
"@supacloud/commands": `^${commandsMetadata.version}`,
|
|
248580
|
+
"@supacloud/contracts": `^${contractsMetadata.version}`,
|
|
248581
|
+
"@supacloud/db": `^${dbMetadata.version}`,
|
|
248582
|
+
"drizzle-orm": dbMetadata.peerDependencies["drizzle-orm"],
|
|
248583
|
+
"@supacloud/js": `^${sdkMetadata.version}`,
|
|
248584
|
+
"@supabase/supabase-js": sdkMetadata.peerDependencies["@supabase/supabase-js"],
|
|
249010
248585
|
elysia: "2.0.0-beta.19",
|
|
249011
|
-
rxjs:
|
|
248586
|
+
rxjs: appMetadata2.dependencies.rxjs
|
|
249012
248587
|
},
|
|
249013
248588
|
devDependencies: {
|
|
249014
|
-
"@supacloud/compiler": `^${
|
|
249015
|
-
"drizzle-kit":
|
|
248589
|
+
"@supacloud/compiler": `^${compilerMetadata2.version}`,
|
|
248590
|
+
"drizzle-kit": dbMetadata.devDependencies["drizzle-kit"],
|
|
249016
248591
|
"@types/bun": "^1.4.2",
|
|
249017
248592
|
typescript: "^7.0.2"
|
|
249018
248593
|
}
|
|
@@ -249144,7 +248719,8 @@ const watcher = watchProject({
|
|
|
249144
248719
|
restarts = restarts.then(async () => {
|
|
249145
248720
|
if (server) { server.kill(); await server.exited; }
|
|
249146
248721
|
if (closing) return;
|
|
249147
|
-
|
|
248722
|
+
const entry = process.env.SUPACLOUD_DEV_PROFILE === "integration" ? "scripts/serve-integration.ts" : "scripts/serve.ts";
|
|
248723
|
+
server = Bun.spawn([process.execPath, "--no-env-file", entry], {
|
|
249148
248724
|
stdin: "inherit", stdout: "inherit", stderr: "inherit", env: process.env,
|
|
249149
248725
|
});
|
|
249150
248726
|
}).catch((error) => { console.error(error); process.exitCode = 1; });
|
|
@@ -249160,6 +248736,48 @@ const close = async () => {
|
|
|
249160
248736
|
process.once("SIGINT", close);
|
|
249161
248737
|
process.once("SIGTERM", close);
|
|
249162
248738
|
await watcher.ready;
|
|
248739
|
+
`,
|
|
248740
|
+
"scripts/integration.ts": `if (process.env.APP_ENV !== "development") throw new Error("Integration is development-only");
|
|
248741
|
+
process.env.SUPACLOUD_DEV_PROFILE = "integration";
|
|
248742
|
+
await import("./dev");
|
|
248743
|
+
export {};
|
|
248744
|
+
`,
|
|
248745
|
+
"scripts/serve-integration.ts": `import { createCompiledModules } from "../generated/application";
|
|
248746
|
+
import { createDeliveryApplication } from "../src/delivery-host";
|
|
248747
|
+
|
|
248748
|
+
if (process.env.APP_ENV !== "development") throw new Error("Integration is development-only");
|
|
248749
|
+
const databaseUrl = process.env.SUPACLOUD_DEV_DATABASE_URL;
|
|
248750
|
+
try {
|
|
248751
|
+
if (!databaseUrl) throw new Error();
|
|
248752
|
+
const url = new URL(databaseUrl);
|
|
248753
|
+
if (!["postgres:", "postgresql:"].includes(url.protocol)
|
|
248754
|
+
|| !["127.0.0.1", "localhost", "[::1]"].includes(url.hostname)
|
|
248755
|
+
|| url.pathname.length <= 1 || url.search || url.hash) throw new Error();
|
|
248756
|
+
} catch {
|
|
248757
|
+
throw new Error("Integration requires an explicit loopback PostgreSQL database");
|
|
248758
|
+
}
|
|
248759
|
+
if (process.env.DATABASE_SOCKET_PATH
|
|
248760
|
+
|| (process.env.DATABASE_URL && process.env.DATABASE_URL !== databaseUrl)) {
|
|
248761
|
+
throw new Error("Conflicting integration database settings");
|
|
248762
|
+
}
|
|
248763
|
+
process.env.DATABASE_URL = databaseUrl;
|
|
248764
|
+
const port = Number(process.env.PORT ?? "3000");
|
|
248765
|
+
if (!Number.isInteger(port) || port < 0 || port > 65535) throw new Error("Invalid PORT");
|
|
248766
|
+
const abort = new AbortController();
|
|
248767
|
+
const stopStartup = () => abort.abort();
|
|
248768
|
+
process.once("SIGINT", stopStartup);
|
|
248769
|
+
process.once("SIGTERM", stopStartup);
|
|
248770
|
+
const application = await createDeliveryApplication(createCompiledModules(), { signal: abort.signal });
|
|
248771
|
+
if (abort.signal.aborted) { await application.close(); throw new Error("Integration startup cancelled"); }
|
|
248772
|
+
const server = Bun.serve({ hostname: "127.0.0.1", port, fetch: application.fetch });
|
|
248773
|
+
const close = async () => {
|
|
248774
|
+
abort.abort();
|
|
248775
|
+
server.stop(true);
|
|
248776
|
+
await application.close();
|
|
248777
|
+
};
|
|
248778
|
+
process.once("SIGINT", close);
|
|
248779
|
+
process.once("SIGTERM", close);
|
|
248780
|
+
console.log("Local integration: " + server.url);
|
|
249163
248781
|
`,
|
|
249164
248782
|
"scripts/serve.ts": `import { createDemo } from "./sandbox";
|
|
249165
248783
|
|
|
@@ -249729,8 +249347,11 @@ async function initializeAppProject(options) {
|
|
|
249729
249347
|
if ((await readdir4(root)).some((entry) => entry !== ".git")) {
|
|
249730
249348
|
throw new Error("app init requires an empty directory (an existing .git directory is allowed)");
|
|
249731
249349
|
}
|
|
249732
|
-
const template = options.template ?? "
|
|
249733
|
-
const files = template === "command" ? appStarterFiles(name) : appTemplateFiles(name, template
|
|
249350
|
+
const template = options.template ?? "minimal";
|
|
249351
|
+
const files = template === "command" ? appStarterFiles(name) : appTemplateFiles(name, template, {
|
|
249352
|
+
"@supacloud/js": `^${sdkMetadata.version}`,
|
|
249353
|
+
"@supabase/supabase-js": sdkMetadata.peerDependencies["@supabase/supabase-js"]
|
|
249354
|
+
});
|
|
249734
249355
|
for (const [relativePath, content] of Object.entries(files)) {
|
|
249735
249356
|
const path = join13(root, relativePath);
|
|
249736
249357
|
await mkdir4(dirname10(path), { recursive: true });
|
|
@@ -249792,22 +249413,30 @@ function checkAppDatabaseSources(projectRoot) {
|
|
|
249792
249413
|
function resourceScaffold(name, className) {
|
|
249793
249414
|
return {
|
|
249794
249415
|
[`${name}.model.ts`]: `import { t } from "elysia";
|
|
249795
|
-
import type
|
|
249416
|
+
import { InjectionToken, type RouteHandlerOutput } from "@supacloud/app";
|
|
249796
249417
|
|
|
249797
249418
|
// HTTP contracts are the single source of field types. Services import types only.
|
|
249798
249419
|
export const ${className}Params = t.Object({ id: t.String({ minLength: 1, maxLength: 128, pattern: "^[A-Za-z0-9_-]+$" }) });
|
|
249799
249420
|
export const ${className}Response = t.Object({ id: t.String() });
|
|
249800
249421
|
export type ${className}Result = RouteHandlerOutput<{ responses: { 200: typeof ${className}Response } }>;
|
|
249422
|
+
|
|
249423
|
+
// Bind a request-scoped adapter using the verified user and RLS. It must reject
|
|
249424
|
+
// denied/not-found reads; never bind a browser-supplied identity or service-role fallback.
|
|
249425
|
+
export interface ${className}ReadPort {
|
|
249426
|
+
readAuthorized(id: string): Promise<${className}Result>;
|
|
249427
|
+
}
|
|
249428
|
+
export const ${className}Reader = new InjectionToken<${className}ReadPort>("${name}.reader", { scope: "request" });
|
|
249801
249429
|
`,
|
|
249802
|
-
[`${name}.service.ts`]: `import { Injectable } from "@supacloud/app";
|
|
249803
|
-
import type { ${className}Result } from "./${name}.model";
|
|
249430
|
+
[`${name}.service.ts`]: `import { Inject, Injectable, Optional } from "@supacloud/app";
|
|
249431
|
+
import { ${className}Reader, type ${className}ReadPort, type ${className}Result } from "./${name}.model";
|
|
249804
249432
|
|
|
249805
|
-
@Injectable()
|
|
249433
|
+
@Injectable({ scope: "request" })
|
|
249806
249434
|
export class ${className}Service {
|
|
249807
|
-
|
|
249808
|
-
|
|
249809
|
-
|
|
249810
|
-
throw new Error("
|
|
249435
|
+
constructor(@Inject(${className}Reader) @Optional() readonly reader?: ${className}ReadPort) {}
|
|
249436
|
+
|
|
249437
|
+
async find(id: string): Promise<${className}Result> {
|
|
249438
|
+
if (!this.reader) throw new Error("Bind ${className}Reader before exposing this resource");
|
|
249439
|
+
return this.reader.readAuthorized(id);
|
|
249811
249440
|
}
|
|
249812
249441
|
}
|
|
249813
249442
|
`,
|
|
@@ -249817,7 +249446,7 @@ import { ${className}Service } from "./${name}.service";
|
|
|
249817
249446
|
|
|
249818
249447
|
@Controller("/${name}")
|
|
249819
249448
|
export class ${className}Controller {
|
|
249820
|
-
constructor(@Inject(${className}Service) readonly service:
|
|
249449
|
+
constructor(@Inject(${className}Service) readonly service: Pick<${className}Service, "find">) {}
|
|
249821
249450
|
|
|
249822
249451
|
@Get("/:id", { params: ${className}Params, responses: { 200: ${className}Response } })
|
|
249823
249452
|
find(@Param("id") id: string): Promise<${className}Result> {
|
|
@@ -249842,7 +249471,18 @@ import { ${className}Service } from "./${name}.service";
|
|
|
249842
249471
|
|
|
249843
249472
|
test("${name} does not claim a read adapter has been implemented", async () => {
|
|
249844
249473
|
await expect(new ${className}Service().find("example"))
|
|
249845
|
-
.rejects.toThrow("
|
|
249474
|
+
.rejects.toThrow("Bind ${className}Reader");
|
|
249475
|
+
});
|
|
249476
|
+
|
|
249477
|
+
test("${name} returns only the supplied authorized read result", async () => {
|
|
249478
|
+
const service = new ${className}Service({ readAuthorized: async id => ({ id }) });
|
|
249479
|
+
expect(await service.find("example")).toEqual({ id: "example" });
|
|
249480
|
+
});
|
|
249481
|
+
|
|
249482
|
+
test("${name} preserves permission denial without a privileged fallback", async () => {
|
|
249483
|
+
const denied = new Error("denied");
|
|
249484
|
+
const service = new ${className}Service({ readAuthorized: async () => { throw denied; } });
|
|
249485
|
+
await expect(service.find("example")).rejects.toBe(denied);
|
|
249846
249486
|
});
|
|
249847
249487
|
`,
|
|
249848
249488
|
[`${name}.controller.test.ts`]: `import { expect, test } from "bun:test";
|
|
@@ -249863,10 +249503,220 @@ test("${name} controller preserves an asynchronous read failure", async () => {
|
|
|
249863
249503
|
};
|
|
249864
249504
|
}
|
|
249865
249505
|
|
|
249506
|
+
// src/shared/tools/app-local-dev.ts
|
|
249507
|
+
import { execFile as execFile2, spawn as spawn3 } from "node:child_process";
|
|
249508
|
+
import { readFile as readFile4 } from "node:fs/promises";
|
|
249509
|
+
import { join as join15, resolve as resolve17 } from "node:path";
|
|
249510
|
+
function localDatabaseUrl(value) {
|
|
249511
|
+
try {
|
|
249512
|
+
if (!value || /[\x00-\x20\x7f]/.test(value))
|
|
249513
|
+
throw new Error;
|
|
249514
|
+
const url = new URL(value);
|
|
249515
|
+
if (!["postgres:", "postgresql:"].includes(url.protocol) || !["127.0.0.1", "localhost", "[::1]"].includes(url.hostname) || url.pathname.length <= 1 || url.search || url.hash)
|
|
249516
|
+
throw new Error;
|
|
249517
|
+
return value;
|
|
249518
|
+
} catch {
|
|
249519
|
+
throw new Error("Integration requires an explicit loopback PostgreSQL URL with a database name and no query or fragment");
|
|
249520
|
+
}
|
|
249521
|
+
}
|
|
249522
|
+
async function probeDatabase(url, signal) {
|
|
249523
|
+
const source = `const database = new Bun.SQL(process.env.SUPACLOUD_DEV_DATABASE_URL, {
|
|
249524
|
+
max: 1, connectionTimeout: 5,
|
|
249525
|
+
});
|
|
249526
|
+
try {
|
|
249527
|
+
const rows = await database\`SELECT current_database() AS name,
|
|
249528
|
+
r.rolsuper AS superuser, r.rolbypassrls AS bypass_rls
|
|
249529
|
+
FROM pg_roles r WHERE r.rolname = current_user\`;
|
|
249530
|
+
console.log(JSON.stringify(rows));
|
|
249531
|
+
} finally {
|
|
249532
|
+
await database.close({ timeout: 1 });
|
|
249533
|
+
}`;
|
|
249534
|
+
try {
|
|
249535
|
+
const stdout = await new Promise((resolveOutput, reject) => {
|
|
249536
|
+
execFile2(process.versions.bun ? process.execPath : "bun", ["--no-env-file", "-e", source], {
|
|
249537
|
+
env: { ...process.env, SUPACLOUD_DEV_DATABASE_URL: url },
|
|
249538
|
+
timeout: 12000,
|
|
249539
|
+
killSignal: "SIGKILL",
|
|
249540
|
+
maxBuffer: 4096,
|
|
249541
|
+
encoding: "utf8",
|
|
249542
|
+
signal
|
|
249543
|
+
}, (error, output) => error ? reject(error) : resolveOutput(output));
|
|
249544
|
+
});
|
|
249545
|
+
const rows = JSON.parse(stdout);
|
|
249546
|
+
const expected = decodeURIComponent(new URL(url).pathname.slice(1));
|
|
249547
|
+
if (!Array.isArray(rows) || rows.length !== 1)
|
|
249548
|
+
throw new Error;
|
|
249549
|
+
const row = rows[0];
|
|
249550
|
+
if (!row || typeof row !== "object" || !("name" in row) || row.name !== expected || !("superuser" in row) || row.superuser !== false || !("bypass_rls" in row) || row.bypass_rls !== false)
|
|
249551
|
+
throw new Error;
|
|
249552
|
+
} catch {
|
|
249553
|
+
throw new Error("Integration database verification failed; check connectivity, database identity and non-privileged application role");
|
|
249554
|
+
}
|
|
249555
|
+
}
|
|
249556
|
+
async function runLocalDevelopment(options) {
|
|
249557
|
+
const root = resolve17(options.root);
|
|
249558
|
+
const profile = options.profile ?? "fast";
|
|
249559
|
+
if (profile !== "fast" && profile !== "integration")
|
|
249560
|
+
throw new Error("Unknown development profile");
|
|
249561
|
+
if (["production", "staging"].includes(process.env.APP_ENV ?? "") || process.env.SUPACLOUD_ENV === "production") {
|
|
249562
|
+
throw new Error("Local development refuses production or staging environment selectors");
|
|
249563
|
+
}
|
|
249564
|
+
const remoteKeys = ["SUPACLOUD_API_URL", "SUPACLOUD_API_TOKEN", "SUPACLOUD_PROJECT_REF"];
|
|
249565
|
+
if (remoteKeys.some((key) => process.env[key] !== undefined) && (process.env.SUPACLOUD_ENV !== "test" || remoteKeys.some((key) => !process.env[key]?.trim()))) {
|
|
249566
|
+
throw new Error("Inherited remote context must be complete and explicitly tagged with SUPACLOUD_ENV=test");
|
|
249567
|
+
}
|
|
249568
|
+
const script = profile === "integration" ? "dev:integration" : "dev";
|
|
249569
|
+
const manifest = JSON.parse(await readFile4(join15(root, "package.json"), "utf8"));
|
|
249570
|
+
const scripts = manifest && typeof manifest === "object" && "scripts" in manifest ? manifest.scripts : undefined;
|
|
249571
|
+
const command = scripts && typeof scripts === "object" ? Reflect.get(scripts, script) : undefined;
|
|
249572
|
+
if (typeof command !== "string" || !command.trim()) {
|
|
249573
|
+
throw new Error(`Project must declare ${script}; use app watch for compile-only inspection`);
|
|
249574
|
+
}
|
|
249575
|
+
let databaseUrl;
|
|
249576
|
+
if (profile === "integration") {
|
|
249577
|
+
databaseUrl = localDatabaseUrl(options.databaseUrl ?? process.env.SUPACLOUD_DEV_DATABASE_URL);
|
|
249578
|
+
} else if (options.databaseUrl !== undefined) {
|
|
249579
|
+
throw new Error("A database URL requires the integration profile");
|
|
249580
|
+
}
|
|
249581
|
+
if (options.signal?.aborted)
|
|
249582
|
+
return { profile, script, exitCode: 0, state: "stopped" };
|
|
249583
|
+
if (databaseUrl)
|
|
249584
|
+
await probeDatabase(databaseUrl, options.signal);
|
|
249585
|
+
if (options.signal?.aborted)
|
|
249586
|
+
return { profile, script, exitCode: 0, state: "stopped" };
|
|
249587
|
+
const env = {
|
|
249588
|
+
...process.env,
|
|
249589
|
+
APP_ENV: "development",
|
|
249590
|
+
SUPACLOUD_ENV: "test",
|
|
249591
|
+
SUPACLOUD_DEV_PROFILE: profile
|
|
249592
|
+
};
|
|
249593
|
+
delete env.SUPACLOUD_DEV_DATABASE_URL;
|
|
249594
|
+
if (databaseUrl)
|
|
249595
|
+
env.SUPACLOUD_DEV_DATABASE_URL = databaseUrl;
|
|
249596
|
+
const executable = process.versions.bun ? process.execPath : "bun";
|
|
249597
|
+
const child = spawn3(executable, ["--no-env-file", "run", script], {
|
|
249598
|
+
cwd: root,
|
|
249599
|
+
env,
|
|
249600
|
+
detached: process.platform !== "win32",
|
|
249601
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
249602
|
+
});
|
|
249603
|
+
let timer;
|
|
249604
|
+
let outputError;
|
|
249605
|
+
let stopping = false;
|
|
249606
|
+
const kill = (signal) => {
|
|
249607
|
+
try {
|
|
249608
|
+
if (process.platform !== "win32" && child.pid)
|
|
249609
|
+
process.kill(-child.pid, signal);
|
|
249610
|
+
else
|
|
249611
|
+
child.kill(signal);
|
|
249612
|
+
} catch (error) {
|
|
249613
|
+
if (!(error instanceof Error) || !("code" in error) || error.code !== "ESRCH")
|
|
249614
|
+
throw error;
|
|
249615
|
+
}
|
|
249616
|
+
};
|
|
249617
|
+
const stop = () => {
|
|
249618
|
+
if (stopping)
|
|
249619
|
+
return;
|
|
249620
|
+
stopping = true;
|
|
249621
|
+
kill("SIGTERM");
|
|
249622
|
+
timer = setTimeout(() => kill("SIGKILL"), 1500);
|
|
249623
|
+
};
|
|
249624
|
+
const output = (chunk) => {
|
|
249625
|
+
try {
|
|
249626
|
+
options.onOutput?.(chunk.toString("utf8"));
|
|
249627
|
+
} catch (error) {
|
|
249628
|
+
outputError = { error };
|
|
249629
|
+
stop();
|
|
249630
|
+
}
|
|
249631
|
+
};
|
|
249632
|
+
child.stdout.on("data", output);
|
|
249633
|
+
child.stderr.on("data", output);
|
|
249634
|
+
options.signal?.addEventListener("abort", stop, { once: true });
|
|
249635
|
+
process.once("SIGINT", stop);
|
|
249636
|
+
process.once("SIGTERM", stop);
|
|
249637
|
+
if (options.signal?.aborted)
|
|
249638
|
+
stop();
|
|
249639
|
+
try {
|
|
249640
|
+
const exitCode = await new Promise((resolveExit, reject) => {
|
|
249641
|
+
child.once("error", reject);
|
|
249642
|
+
child.once("close", (code) => resolveExit(stopping ? 0 : code ?? 1));
|
|
249643
|
+
});
|
|
249644
|
+
if (outputError)
|
|
249645
|
+
throw outputError.error;
|
|
249646
|
+
return { profile, script, exitCode, state: "stopped" };
|
|
249647
|
+
} finally {
|
|
249648
|
+
if (timer)
|
|
249649
|
+
clearTimeout(timer);
|
|
249650
|
+
options.signal?.removeEventListener("abort", stop);
|
|
249651
|
+
process.removeListener("SIGINT", stop);
|
|
249652
|
+
process.removeListener("SIGTERM", stop);
|
|
249653
|
+
}
|
|
249654
|
+
}
|
|
249655
|
+
|
|
249656
|
+
// src/shared/tools/app-verification-plan.ts
|
|
249657
|
+
import { readdir as readdir5, realpath as realpath5 } from "node:fs/promises";
|
|
249658
|
+
import { dirname as dirname11, isAbsolute as isAbsolute6, relative as relative11, resolve as resolve18 } from "node:path";
|
|
249659
|
+
function inside3(root, file) {
|
|
249660
|
+
const path = relative11(root, file).replaceAll("\\", "/");
|
|
249661
|
+
return path !== ".." && !path.startsWith("../") && !isAbsolute6(path);
|
|
249662
|
+
}
|
|
249663
|
+
async function createVerificationPlan(root, graph, target, sourceRoot = root) {
|
|
249664
|
+
const owners = graph.modules.filter((module) => module.name === target || module.className === target || [...module.providers, ...module.controllers, ...module.commands, ...module.jobs ?? [], ...module.queries ?? []].some((item) => ("className" in item) && item.className === target || ("name" in item) && item.name === target || ("token" in item) && item.token === target || ("useClass" in item) && item.useClass === target));
|
|
249665
|
+
if (owners.length !== 1)
|
|
249666
|
+
throw new Error("Select one unambiguous module or owned symbol for verification");
|
|
249667
|
+
const owner = owners[0];
|
|
249668
|
+
const project = await realpath5(root);
|
|
249669
|
+
const requestedRoot = resolve18(root);
|
|
249670
|
+
const sources = [
|
|
249671
|
+
owner.file,
|
|
249672
|
+
...owner.providers.map((item) => item.file),
|
|
249673
|
+
...owner.controllers.map((item) => item.file)
|
|
249674
|
+
].filter((file) => typeof file === "string");
|
|
249675
|
+
const directories = [...new Set(sources.map((file) => dirname11(resolve18(sourceRoot, file))))].sort();
|
|
249676
|
+
const tests = new Set;
|
|
249677
|
+
const manual = [];
|
|
249678
|
+
for (const directory of directories) {
|
|
249679
|
+
if (!inside3(requestedRoot, directory)) {
|
|
249680
|
+
manual.push("A source directory is outside the project; select its owning project explicitly");
|
|
249681
|
+
continue;
|
|
249682
|
+
}
|
|
249683
|
+
const actual = await realpath5(directory);
|
|
249684
|
+
if (!inside3(project, actual)) {
|
|
249685
|
+
manual.push("A source directory is outside the project; select its owning project explicitly");
|
|
249686
|
+
continue;
|
|
249687
|
+
}
|
|
249688
|
+
for (const entry of await readdir5(actual, { withFileTypes: true })) {
|
|
249689
|
+
if (entry.isFile() && /\.(test|spec)\.[cm]?[jt]sx?$/.test(entry.name)) {
|
|
249690
|
+
tests.add(relative11(project, resolve18(actual, entry.name)).replaceAll("\\", "/"));
|
|
249691
|
+
}
|
|
249692
|
+
}
|
|
249693
|
+
}
|
|
249694
|
+
const selected = [...tests].sort();
|
|
249695
|
+
if (!selected.length)
|
|
249696
|
+
manual.push("No colocated tests found; declare a focused test before changing this module");
|
|
249697
|
+
if (selected.length > 32)
|
|
249698
|
+
manual.push("More than 32 local tests; narrow module ownership before execution");
|
|
249699
|
+
return {
|
|
249700
|
+
version: 1,
|
|
249701
|
+
source: "declaration",
|
|
249702
|
+
target: owner.name,
|
|
249703
|
+
ready: manual.length === 0,
|
|
249704
|
+
files: [...new Set(sources.map((file) => relative11(requestedRoot, resolve18(sourceRoot, file)).replaceAll("\\", "/")))].sort(),
|
|
249705
|
+
tests: selected.slice(0, 32),
|
|
249706
|
+
commands: selected.length <= 32 ? [
|
|
249707
|
+
...selected.map((file) => ["bun", "test", `./${file}`]),
|
|
249708
|
+
["git", "diff", "--check"]
|
|
249709
|
+
] : [],
|
|
249710
|
+
manual,
|
|
249711
|
+
releaseOnly: ["generated artifact drift", "consumer types", "database/RLS and authenticated integration", "delivery read-back"],
|
|
249712
|
+
executed: false
|
|
249713
|
+
};
|
|
249714
|
+
}
|
|
249715
|
+
|
|
249866
249716
|
// src/shared/tools/app-scaffold-writes.ts
|
|
249867
249717
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
249868
|
-
import { link, lstat as lstat4, mkdir as mkdir5, open as open4, readFile as
|
|
249869
|
-
import { dirname as
|
|
249718
|
+
import { link, lstat as lstat4, mkdir as mkdir5, open as open4, readFile as readFile8, realpath as realpath6, rename as rename5, rmdir, unlink as unlink3 } from "node:fs/promises";
|
|
249719
|
+
import { dirname as dirname12, isAbsolute as isAbsolute7, join as join16, relative as relative12, resolve as resolve20, sep as sep11, win32 } from "node:path";
|
|
249870
249720
|
|
|
249871
249721
|
class ScaffoldError extends Error {
|
|
249872
249722
|
code;
|
|
@@ -249880,26 +249730,26 @@ function fsCode(error) {
|
|
|
249880
249730
|
return error instanceof Error && "code" in error && typeof error.code === "string" ? error.code : undefined;
|
|
249881
249731
|
}
|
|
249882
249732
|
function scaffoldPath(root, path) {
|
|
249883
|
-
if (!path || path.includes("\x00") || path.includes("\\") ||
|
|
249733
|
+
if (!path || path.includes("\x00") || path.includes("\\") || isAbsolute7(path) || win32.isAbsolute(path)) {
|
|
249884
249734
|
throw new ScaffoldError("SCAFFOLD_PATH_INVALID", "Scaffold paths must be relative to the project root");
|
|
249885
249735
|
}
|
|
249886
249736
|
const parts = path.split("/");
|
|
249887
249737
|
if (parts.some((part) => /[<>:"|?*\u0000-\u001f]/.test(part) || /[ .]$/.test(part) && part !== "." && part !== ".." || /^(con|prn|aux|nul|com[1-9]|lpt[1-9])(?:\.|$)/i.test(part) || part.toLowerCase() === ".git" || part.toLowerCase() === ".supacloud-generate.lock")) {
|
|
249888
249738
|
throw new ScaffoldError("SCAFFOLD_PATH_INVALID", "Scaffold path is reserved or not portable");
|
|
249889
249739
|
}
|
|
249890
|
-
const target =
|
|
249891
|
-
const local =
|
|
249892
|
-
if (!local || local === ".." || local.startsWith(`..${sep11}`) ||
|
|
249740
|
+
const target = resolve20(root, path);
|
|
249741
|
+
const local = relative12(root, target);
|
|
249742
|
+
if (!local || local === ".." || local.startsWith(`..${sep11}`) || isAbsolute7(local)) {
|
|
249893
249743
|
throw new ScaffoldError("SCAFFOLD_PATH_INVALID", "Scaffold path is outside the project root");
|
|
249894
249744
|
}
|
|
249895
249745
|
return target;
|
|
249896
249746
|
}
|
|
249897
249747
|
async function snapshot(root, path) {
|
|
249898
249748
|
const target = scaffoldPath(root, path);
|
|
249899
|
-
const parts =
|
|
249749
|
+
const parts = relative12(root, target).split(sep11);
|
|
249900
249750
|
let current = root;
|
|
249901
249751
|
for (const [index, part] of parts.entries()) {
|
|
249902
|
-
current =
|
|
249752
|
+
current = join16(current, part);
|
|
249903
249753
|
let stat;
|
|
249904
249754
|
try {
|
|
249905
249755
|
stat = await lstat4(current);
|
|
@@ -249917,7 +249767,7 @@ async function snapshot(root, path) {
|
|
|
249917
249767
|
if (!stat.isFile() || stat.nlink !== 1) {
|
|
249918
249768
|
throw new ScaffoldError("SCAFFOLD_PATH_INVALID", `Scaffold target must be a regular, unlinked file: ${current}`);
|
|
249919
249769
|
}
|
|
249920
|
-
return { content: await
|
|
249770
|
+
return { content: await readFile8(current, "utf8"), mode: stat.mode, dev: stat.dev, ino: stat.ino };
|
|
249921
249771
|
}
|
|
249922
249772
|
}
|
|
249923
249773
|
return null;
|
|
@@ -249926,7 +249776,7 @@ function sameFile(a, b) {
|
|
|
249926
249776
|
return a === null ? b === null : b !== null && a.content === b.content && a.dev === b.dev && a.ino === b.ino && a.mode === b.mode;
|
|
249927
249777
|
}
|
|
249928
249778
|
async function planScaffoldWrites(root, writes) {
|
|
249929
|
-
const canonical = await
|
|
249779
|
+
const canonical = await realpath6(resolve20(root));
|
|
249930
249780
|
const targets = new Set;
|
|
249931
249781
|
const planned = [];
|
|
249932
249782
|
for (const write of writes) {
|
|
@@ -249949,7 +249799,7 @@ async function planScaffoldWrites(root, writes) {
|
|
|
249949
249799
|
return Object.freeze({ root: canonical, writes: Object.freeze(planned) });
|
|
249950
249800
|
}
|
|
249951
249801
|
async function applyScaffoldWrites(plan) {
|
|
249952
|
-
const lockPath =
|
|
249802
|
+
const lockPath = join16(plan.root, ".supacloud-generate.lock");
|
|
249953
249803
|
const lock = await open4(lockPath, "wx").catch((error) => {
|
|
249954
249804
|
if (fsCode(error) === "EEXIST")
|
|
249955
249805
|
throw new ScaffoldError("SCAFFOLD_BUSY", "Another generator owns .supacloud-generate.lock; no files written");
|
|
@@ -249959,7 +249809,7 @@ async function applyScaffoldWrites(plan) {
|
|
|
249959
249809
|
const applied = [];
|
|
249960
249810
|
const temporary = [];
|
|
249961
249811
|
try {
|
|
249962
|
-
if (await
|
|
249812
|
+
if (await realpath6(plan.root) !== plan.root)
|
|
249963
249813
|
throw new ScaffoldError("SCAFFOLD_CHANGED", "Project root changed");
|
|
249964
249814
|
for (const write of plan.writes) {
|
|
249965
249815
|
if (!sameFile(write.before, await snapshot(plan.root, write.path))) {
|
|
@@ -249969,8 +249819,8 @@ async function applyScaffoldWrites(plan) {
|
|
|
249969
249819
|
for (const write of plan.writes) {
|
|
249970
249820
|
const target = scaffoldPath(plan.root, write.path);
|
|
249971
249821
|
let current = plan.root;
|
|
249972
|
-
for (const part of
|
|
249973
|
-
current =
|
|
249822
|
+
for (const part of relative12(plan.root, dirname12(target)).split(sep11).filter(Boolean)) {
|
|
249823
|
+
current = join16(current, part);
|
|
249974
249824
|
try {
|
|
249975
249825
|
await mkdir5(current);
|
|
249976
249826
|
directories.push(current);
|
|
@@ -250073,7 +249923,7 @@ var REMOTE_APP_SCHEMA = Object.fromEntries(Object.entries(APPLICATION_TOOL_SCHEM
|
|
|
250073
249923
|
async function initProject(args) {
|
|
250074
249924
|
if (args.force)
|
|
250075
249925
|
throw new Error("app init never overwrites files; choose an empty directory");
|
|
250076
|
-
const template = args.template ?? "
|
|
249926
|
+
const template = args.template ?? "minimal";
|
|
250077
249927
|
const { root, name, files } = await initializeAppProject({ root: args.root, name: args.name, template });
|
|
250078
249928
|
return textResult([
|
|
250079
249929
|
`Initialized ${name} in ${root} (${files.length} files, template: ${template}).`,
|
|
@@ -250186,7 +250036,7 @@ async function generateScaffold(args) {
|
|
|
250186
250036
|
throw new ScaffoldError("SCAFFOLD_OPTION_INVALID", `--${flag.replaceAll("_", "-")} must be boolean`);
|
|
250187
250037
|
}
|
|
250188
250038
|
}
|
|
250189
|
-
const root =
|
|
250039
|
+
const root = resolve21(args.root || process.cwd());
|
|
250190
250040
|
const dir = args.dir ?? "src/features";
|
|
250191
250041
|
if (dir !== ".")
|
|
250192
250042
|
scaffoldPath(root, dir);
|
|
@@ -250202,19 +250052,19 @@ async function generateScaffold(args) {
|
|
|
250202
250052
|
let contractName;
|
|
250203
250053
|
if (kind === "module" || kind === "resource") {
|
|
250204
250054
|
const name = requireIdentifier(args.name, "name");
|
|
250205
|
-
modulePath =
|
|
250055
|
+
modulePath = join17(dir, name, `${name}.module.ts`).replaceAll("\\", "/");
|
|
250206
250056
|
moduleSymbol = `${pascalName2(name)}Module`;
|
|
250207
250057
|
if (kind === "module")
|
|
250208
250058
|
writes.push({ path: modulePath, content: moduleScaffold(name), overwrite: args.force === true });
|
|
250209
250059
|
else
|
|
250210
250060
|
for (const [file, content] of Object.entries(resourceScaffold(name, pascalName2(name)))) {
|
|
250211
|
-
writes.push({ path:
|
|
250061
|
+
writes.push({ path: join17(dir, name, file).replaceAll("\\", "/"), content });
|
|
250212
250062
|
}
|
|
250213
250063
|
} else {
|
|
250214
250064
|
const moduleName = requireIdentifier(args.module, "module");
|
|
250215
250065
|
const name = kind === "controller" ? moduleName : requireIdentifier(args.name, "name");
|
|
250216
250066
|
const subdir = kind === "command" ? "commands" : kind === "query" ? "queries" : kind === "job" ? "jobs" : kind === "contract" ? "contracts" : "";
|
|
250217
|
-
const path =
|
|
250067
|
+
const path = join17(dir, moduleName, subdir, `${name}.${kind}.ts`).replaceAll("\\", "/");
|
|
250218
250068
|
if (kind === "controller" && existsSync12(scaffoldPath(root, path))) {
|
|
250219
250069
|
throw new ScaffoldError("SCAFFOLD_EXISTS", `Controller already exists: ${path}(请手工合并路由到现有 controller)`);
|
|
250220
250070
|
}
|
|
@@ -250233,7 +250083,7 @@ async function generateScaffold(args) {
|
|
|
250233
250083
|
if (new RegExp(`\\b${moduleSymbol}\\b`).test(original)) {
|
|
250234
250084
|
throw new ScaffoldError("SCAFFOLD_REGISTRATION_CONFLICT", `Registration target already references ${moduleSymbol}; review the import manually`);
|
|
250235
250085
|
}
|
|
250236
|
-
let importPath =
|
|
250086
|
+
let importPath = relative13(dirname13(target), resolve21(root, modulePath)).replaceAll("\\", "/").replace(/\.ts$/, "");
|
|
250237
250087
|
if (!importPath.startsWith("."))
|
|
250238
250088
|
importPath = `./${importPath}`;
|
|
250239
250089
|
const edit = await applyDiagnosticFix({
|
|
@@ -250243,7 +250093,7 @@ async function generateScaffold(args) {
|
|
|
250243
250093
|
importPath,
|
|
250244
250094
|
symbol: moduleSymbol
|
|
250245
250095
|
}, { rootDir: root, dryRun: true });
|
|
250246
|
-
if (await
|
|
250096
|
+
if (await readFile9(target, "utf8") !== original)
|
|
250247
250097
|
throw new ScaffoldError("SCAFFOLD_CHANGED", "Registration source changed during planning");
|
|
250248
250098
|
writes.push({ path: args.register_in, content: edit.content, expected: original });
|
|
250249
250099
|
}
|
|
@@ -250264,7 +250114,7 @@ async function generateScaffold(args) {
|
|
|
250264
250114
|
written: !args.dry_run,
|
|
250265
250115
|
changes
|
|
250266
250116
|
}, null, 2));
|
|
250267
|
-
const lines = changes.map((change) => `${args.dry_run ? "PREVIEW" : "✅"} ${change.action}: ${
|
|
250117
|
+
const lines = changes.map((change) => `${args.dry_run ? "PREVIEW" : "✅"} ${change.action}: ${join17(plan.root, change.path)}`);
|
|
250268
250118
|
if (args.dry_run)
|
|
250269
250119
|
lines.push("No files written. Omit --dry-run to apply this generation.");
|
|
250270
250120
|
if (kind === "resource")
|
|
@@ -250300,32 +250150,33 @@ function parseInclude(include) {
|
|
|
250300
250150
|
return patterns && patterns.length > 0 ? patterns : undefined;
|
|
250301
250151
|
}
|
|
250302
250152
|
function sourceRoot(args, root, configured) {
|
|
250303
|
-
const hasConfig = ["ts", "mts", "js", "mjs"].some((extension) => existsSync12(
|
|
250153
|
+
const hasConfig = ["ts", "mts", "js", "mjs"].some((extension) => existsSync12(join17(root, `supacloud.config.${extension}`)));
|
|
250304
250154
|
return args.root && !hasConfig ? "." : configured;
|
|
250305
250155
|
}
|
|
250306
250156
|
async function projectCompileConfig(args) {
|
|
250307
|
-
const root =
|
|
250308
|
-
const configFile = ["ts", "mts", "js", "mjs"].map((extension) =>
|
|
250157
|
+
const root = resolve21(args.root || process.cwd());
|
|
250158
|
+
const configFile = ["ts", "mts", "js", "mjs"].map((extension) => join17(root, `supacloud.config.${extension}`)).find((candidate) => existsSync12(candidate)) ?? null;
|
|
250309
250159
|
const loadedConfig = await loadSupacloudConfig(root);
|
|
250310
250160
|
const defaults = resolveSupacloudConfig(loadedConfig, root);
|
|
250311
250161
|
const configuredRoot = sourceRoot(args, root, loadedConfig.root);
|
|
250312
250162
|
const include = parseInclude(args.include) ?? loadedConfig.include;
|
|
250313
|
-
const outDir = args.out_dir ?
|
|
250314
|
-
const
|
|
250163
|
+
const outDir = args.out_dir ? resolve21(root, args.out_dir) : defaults.outDir;
|
|
250164
|
+
const compileOptions = compileOptionsFromConfig({
|
|
250315
250165
|
...loadedConfig,
|
|
250316
250166
|
...configuredRoot === undefined ? {} : { root: configuredRoot },
|
|
250317
250167
|
outDir,
|
|
250318
250168
|
...include === undefined ? {} : { include },
|
|
250319
250169
|
strict: args.strict ?? loadedConfig.strict ?? false
|
|
250320
|
-
}, root)
|
|
250321
|
-
|
|
250170
|
+
}, root);
|
|
250171
|
+
const result = await checkProject(compileOptions);
|
|
250172
|
+
return { root, sourceDir: compileOptions.rootDir, configFile, outDir, result };
|
|
250322
250173
|
}
|
|
250323
250174
|
async function readAllowedDependencies(root) {
|
|
250324
|
-
const path =
|
|
250175
|
+
const path = join17(root, "package.json");
|
|
250325
250176
|
if (!existsSync12(path))
|
|
250326
250177
|
return { dependencies: [], devDependencies: [] };
|
|
250327
250178
|
try {
|
|
250328
|
-
const parsed = JSON.parse(await
|
|
250179
|
+
const parsed = JSON.parse(await readFile9(path, "utf8"));
|
|
250329
250180
|
return {
|
|
250330
250181
|
dependencies: Object.keys(parsed.dependencies ?? {}).sort(),
|
|
250331
250182
|
devDependencies: Object.keys(parsed.devDependencies ?? {}).sort()
|
|
@@ -250402,14 +250253,14 @@ async function findUnwiredContracts(rootDir) {
|
|
|
250402
250253
|
async function walk(directory) {
|
|
250403
250254
|
let entries;
|
|
250404
250255
|
try {
|
|
250405
|
-
entries = await
|
|
250256
|
+
entries = await readdir6(directory, { withFileTypes: true });
|
|
250406
250257
|
} catch {
|
|
250407
250258
|
return;
|
|
250408
250259
|
}
|
|
250409
250260
|
for (const entry of entries) {
|
|
250410
250261
|
if (skip.has(entry.name))
|
|
250411
250262
|
continue;
|
|
250412
|
-
const path =
|
|
250263
|
+
const path = join17(directory, entry.name);
|
|
250413
250264
|
if (entry.isDirectory())
|
|
250414
250265
|
await walk(path);
|
|
250415
250266
|
else if (entry.isFile() && entry.name.endsWith(".ts"))
|
|
@@ -250420,17 +250271,17 @@ async function findUnwiredContracts(rootDir) {
|
|
|
250420
250271
|
const contracts = files.filter((file) => file.endsWith(".contract.ts"));
|
|
250421
250272
|
if (contracts.length === 0)
|
|
250422
250273
|
return [];
|
|
250423
|
-
const otherSources = await Promise.all(files.filter((file) => !contracts.includes(file)).map(async (file) => await
|
|
250274
|
+
const otherSources = await Promise.all(files.filter((file) => !contracts.includes(file)).map(async (file) => await readFile9(file, "utf8").catch(() => "")));
|
|
250424
250275
|
const unwired = [];
|
|
250425
250276
|
for (const contract of contracts) {
|
|
250426
|
-
const source = await
|
|
250277
|
+
const source = await readFile9(contract, "utf8").catch(() => "");
|
|
250427
250278
|
const symbols = [...source.matchAll(/export\s+const\s+([A-Za-z_$][A-Za-z0-9_$]*)/g)].map((match) => match[1]);
|
|
250428
250279
|
if (symbols.length === 0)
|
|
250429
250280
|
continue;
|
|
250430
250281
|
const moduleName = basename8(contract).replace(/\.ts$/, "");
|
|
250431
250282
|
const wired = otherSources.some((text) => text.includes(moduleName) || symbols.some((symbol) => new RegExp(`\\b${symbol}\\b`).test(text)));
|
|
250432
250283
|
if (!wired)
|
|
250433
|
-
unwired.push({ file:
|
|
250284
|
+
unwired.push({ file: relative13(rootDir, contract), symbols });
|
|
250434
250285
|
}
|
|
250435
250286
|
return unwired;
|
|
250436
250287
|
}
|
|
@@ -250473,11 +250324,11 @@ async function runDoctor(args) {
|
|
|
250473
250324
|
`), doctor.errors > 0);
|
|
250474
250325
|
}
|
|
250475
250326
|
async function runFix(args) {
|
|
250476
|
-
const root =
|
|
250327
|
+
const root = resolve21(args.root || process.cwd());
|
|
250477
250328
|
const fixPath = args.fix?.trim();
|
|
250478
250329
|
if (!fixPath)
|
|
250479
250330
|
throw new Error("app fix requires --fix <path-to-diagnostic-fix.json>");
|
|
250480
|
-
const parsed = JSON.parse(await
|
|
250331
|
+
const parsed = JSON.parse(await readFile9(resolve21(root, fixPath), "utf8"));
|
|
250481
250332
|
const write = args.write === true;
|
|
250482
250333
|
const applied = await applyDiagnosticFix(parsed, { rootDir: root, dryRun: !write });
|
|
250483
250334
|
return textResult(JSON.stringify({
|
|
@@ -250520,7 +250371,7 @@ function devDatabase(profile, explicit) {
|
|
|
250520
250371
|
}
|
|
250521
250372
|
function readManifestModules(outDir) {
|
|
250522
250373
|
try {
|
|
250523
|
-
const parsed = JSON.parse(readFileSync9(
|
|
250374
|
+
const parsed = JSON.parse(readFileSync9(join17(outDir, "app.manifest.json"), "utf8"));
|
|
250524
250375
|
return Array.isArray(parsed.modules) ? parsed.modules.map((module) => module.name) : [];
|
|
250525
250376
|
} catch {
|
|
250526
250377
|
return [];
|
|
@@ -250548,17 +250399,27 @@ function shutdownWaiter(signal) {
|
|
|
250548
250399
|
return { done, stop, dispose };
|
|
250549
250400
|
}
|
|
250550
250401
|
async function runAppDev(args, options) {
|
|
250402
|
+
if (args.action === "dev" && args.once !== true && args.watch !== false) {
|
|
250403
|
+
const result = await runLocalDevelopment({
|
|
250404
|
+
root: args.root || process.cwd(),
|
|
250405
|
+
profile: args.profile,
|
|
250406
|
+
databaseUrl: args.database_url,
|
|
250407
|
+
signal: options.signal,
|
|
250408
|
+
onOutput: (text) => options.onDevProgress?.(textResult(args.format === "json" ? JSON.stringify({ version: 1, source: "application", output: text }) : text))
|
|
250409
|
+
});
|
|
250410
|
+
return textResult(JSON.stringify({ version: 1, ok: result.exitCode === 0, ...result }), result.exitCode !== 0);
|
|
250411
|
+
}
|
|
250551
250412
|
const profile = args.profile ?? "fast";
|
|
250552
250413
|
if (profile !== "fast" && profile !== "integration") {
|
|
250553
250414
|
throw new ScaffoldError("SCAFFOLD_OPTION_INVALID", "app dev --profile must be fast or integration");
|
|
250554
250415
|
}
|
|
250555
250416
|
const database = devDatabase(profile, args.database_url);
|
|
250556
|
-
const root =
|
|
250417
|
+
const root = resolve21(args.root || process.cwd());
|
|
250557
250418
|
const loadedConfig = await loadSupacloudConfig(root);
|
|
250558
250419
|
const defaults = resolveSupacloudConfig(loadedConfig, root);
|
|
250559
250420
|
const configuredRoot = sourceRoot(args, root, loadedConfig.root);
|
|
250560
250421
|
const include = parseInclude(args.include) ?? loadedConfig.include;
|
|
250561
|
-
const outDir = args.out_dir ?
|
|
250422
|
+
const outDir = args.out_dir ? resolve21(root, args.out_dir) : defaults.outDir;
|
|
250562
250423
|
const watch = args.once !== true && args.watch !== false;
|
|
250563
250424
|
const compileOptions = compileOptionsFromConfig({
|
|
250564
250425
|
...loadedConfig,
|
|
@@ -250590,7 +250451,7 @@ async function runAppDev(args, options) {
|
|
|
250590
250451
|
}, null, progress ? undefined : 2), hasError);
|
|
250591
250452
|
}
|
|
250592
250453
|
return textResult([
|
|
250593
|
-
`app
|
|
250454
|
+
`app watch (compile-only, profile: ${profile}, watch: ${watch ? "on" : "off"}, state: ${state})`,
|
|
250594
250455
|
` root: ${root}`,
|
|
250595
250456
|
` outDir: ${outDir}`,
|
|
250596
250457
|
` database: ${profile === "fast" ? "local profile (no database provisioned or connected)" : `explicit ${database.url} (credentials omitted; not connected)`}`,
|
|
@@ -250644,7 +250505,7 @@ async function runAppDev(args, options) {
|
|
|
250644
250505
|
return report(lastEvent, "stopped");
|
|
250645
250506
|
}
|
|
250646
250507
|
async function runCompile(args) {
|
|
250647
|
-
const root =
|
|
250508
|
+
const root = resolve21(args.root || process.cwd());
|
|
250648
250509
|
const loadedConfig = await loadSupacloudConfig(root);
|
|
250649
250510
|
const defaults = resolveSupacloudConfig(loadedConfig, root);
|
|
250650
250511
|
const configuredRoot = sourceRoot(args, root, loadedConfig.root);
|
|
@@ -250653,7 +250514,7 @@ async function runCompile(args) {
|
|
|
250653
250514
|
...compileOptionsFromConfig({
|
|
250654
250515
|
...loadedConfig,
|
|
250655
250516
|
...configuredRoot === undefined ? {} : { root: configuredRoot },
|
|
250656
|
-
outDir: args.out_dir ?
|
|
250517
|
+
outDir: args.out_dir ? resolve21(root, args.out_dir) : defaults.outDir,
|
|
250657
250518
|
...include === undefined ? {} : { include },
|
|
250658
250519
|
strict: args.strict ?? loadedConfig.strict ?? false
|
|
250659
250520
|
}, root),
|
|
@@ -250677,7 +250538,7 @@ async function runCompile(args) {
|
|
|
250677
250538
|
return textResult(text, hasError);
|
|
250678
250539
|
}
|
|
250679
250540
|
async function runCheck(args) {
|
|
250680
|
-
const root =
|
|
250541
|
+
const root = resolve21(args.root || process.cwd());
|
|
250681
250542
|
const database = checkAppDatabaseSources(root);
|
|
250682
250543
|
const loadedConfig = await loadSupacloudConfig(root);
|
|
250683
250544
|
const defaults = resolveSupacloudConfig(loadedConfig, root);
|
|
@@ -250686,7 +250547,7 @@ async function runCheck(args) {
|
|
|
250686
250547
|
const config = compileOptionsFromConfig({
|
|
250687
250548
|
...loadedConfig,
|
|
250688
250549
|
...configuredRoot === undefined ? {} : { root: configuredRoot },
|
|
250689
|
-
outDir: args.out_dir ?
|
|
250550
|
+
outDir: args.out_dir ? resolve21(root, args.out_dir) : defaults.outDir,
|
|
250690
250551
|
...include === undefined ? {} : { include },
|
|
250691
250552
|
strict: args.strict ?? loadedConfig.strict ?? false
|
|
250692
250553
|
}, root);
|
|
@@ -250716,12 +250577,12 @@ async function runCheck(args) {
|
|
|
250716
250577
|
}
|
|
250717
250578
|
async function readManifest(root, args) {
|
|
250718
250579
|
const config = await loadSupacloudConfig(root);
|
|
250719
|
-
const outDir = args.out_dir ?
|
|
250720
|
-
const manifestPath =
|
|
250580
|
+
const outDir = args.out_dir ? resolve21(root, args.out_dir) : resolveSupacloudConfig(config, root).outDir;
|
|
250581
|
+
const manifestPath = join17(outDir, "app.manifest.json");
|
|
250721
250582
|
if (!existsSync12(manifestPath)) {
|
|
250722
250583
|
throw new Error(`Manifest not found: ${manifestPath}(先运行 app compile 生成)`);
|
|
250723
250584
|
}
|
|
250724
|
-
const parsed = JSON.parse(await
|
|
250585
|
+
const parsed = JSON.parse(await readFile9(manifestPath, "utf8"));
|
|
250725
250586
|
if (!Array.isArray(parsed.modules)) {
|
|
250726
250587
|
throw new Error(`Invalid manifest: ${manifestPath}`);
|
|
250727
250588
|
}
|
|
@@ -250761,7 +250622,7 @@ function formatGraphText(manifest) {
|
|
|
250761
250622
|
`);
|
|
250762
250623
|
}
|
|
250763
250624
|
async function runGraph(args) {
|
|
250764
|
-
const root =
|
|
250625
|
+
const root = resolve21(args.root || process.cwd());
|
|
250765
250626
|
const manifest = await readManifest(root, args);
|
|
250766
250627
|
if (args.format === "json")
|
|
250767
250628
|
return textResult(JSON.stringify(manifest, null, 2));
|
|
@@ -250829,7 +250690,7 @@ async function runExplain(args) {
|
|
|
250829
250690
|
const target = args.target?.trim();
|
|
250830
250691
|
if (!target)
|
|
250831
250692
|
throw new Error("app explain requires --target(provider 类名 / token 名 / command 名 / job 名)");
|
|
250832
|
-
const root =
|
|
250693
|
+
const root = resolve21(args.root || process.cwd());
|
|
250833
250694
|
const manifest = await readManifest(root, args);
|
|
250834
250695
|
for (const module of manifest.modules) {
|
|
250835
250696
|
const job = module.jobs?.find((entry) => entry.name === target || entry.className === target);
|
|
@@ -250904,16 +250765,16 @@ async function runExplain(args) {
|
|
|
250904
250765
|
return textResult(`未找到对象: ${target}`, true);
|
|
250905
250766
|
}
|
|
250906
250767
|
async function runExportTools(args) {
|
|
250907
|
-
const root =
|
|
250768
|
+
const root = resolve21(args.root || process.cwd());
|
|
250908
250769
|
const manifest = await readManifest(root, { ...args, out_dir: undefined });
|
|
250909
250770
|
const definitions = buildToolDefinitions(manifest);
|
|
250910
|
-
const outDir =
|
|
250771
|
+
const outDir = resolve21(args.out_dir || join17(root, "generated"));
|
|
250911
250772
|
if (args.format === "json") {
|
|
250912
250773
|
return textResult(JSON.stringify(definitions, null, 2));
|
|
250913
250774
|
}
|
|
250914
250775
|
await mkdir6(outDir, { recursive: true });
|
|
250915
|
-
const openaiPath =
|
|
250916
|
-
const mcpPath =
|
|
250776
|
+
const openaiPath = join17(outDir, "tool-definitions.openai.json");
|
|
250777
|
+
const mcpPath = join17(outDir, "tool-definitions.mcp.json");
|
|
250917
250778
|
await writeFile5(openaiPath, JSON.stringify(definitions.openai, null, 2), "utf8");
|
|
250918
250779
|
await writeFile5(mcpPath, JSON.stringify(definitions.mcp, null, 2), "utf8");
|
|
250919
250780
|
const summary = [
|
|
@@ -250928,7 +250789,7 @@ async function runExportTools(args) {
|
|
|
250928
250789
|
return textResult(summary);
|
|
250929
250790
|
}
|
|
250930
250791
|
async function runDelivery(args) {
|
|
250931
|
-
const root =
|
|
250792
|
+
const root = resolve21(args.root || process.cwd());
|
|
250932
250793
|
if (args.action === "build") {
|
|
250933
250794
|
const database = checkAppDatabaseSources(root);
|
|
250934
250795
|
if (database && !database.ok) {
|
|
@@ -250938,7 +250799,7 @@ async function runDelivery(args) {
|
|
|
250938
250799
|
const loaded = await loadSupacloudConfig(root);
|
|
250939
250800
|
const options = compileOptionsFromConfig({
|
|
250940
250801
|
...loaded,
|
|
250941
|
-
...args.out_dir === undefined ? {} : { outDir:
|
|
250802
|
+
...args.out_dir === undefined ? {} : { outDir: resolve21(root, args.out_dir) },
|
|
250942
250803
|
...args.include === undefined ? {} : { include: parseInclude(args.include) },
|
|
250943
250804
|
...args.strict === undefined ? {} : { strict: args.strict }
|
|
250944
250805
|
}, root);
|
|
@@ -250962,7 +250823,7 @@ async function runAppTool(request, options = {}) {
|
|
|
250962
250823
|
if ((request.dry_run !== undefined || request.register_in !== undefined) && request.action !== "generate") {
|
|
250963
250824
|
throw new ScaffoldError("SCAFFOLD_OPTION_INVALID", "--dry-run and --register-in apply only to app generate");
|
|
250964
250825
|
}
|
|
250965
|
-
if (request.database_url !== undefined && request.action !== "dev") {
|
|
250826
|
+
if (request.database_url !== undefined && request.action !== "dev" && request.action !== "watch") {
|
|
250966
250827
|
throw new ScaffoldError("SCAFFOLD_OPTION_INVALID", "--database-url applies only to app dev --profile integration");
|
|
250967
250828
|
}
|
|
250968
250829
|
if (Object.hasOwn(REMOTE_APP_ACTIONS, request.action)) {
|
|
@@ -250978,7 +250839,16 @@ async function runAppTool(request, options = {}) {
|
|
|
250978
250839
|
return delegate(args);
|
|
250979
250840
|
}
|
|
250980
250841
|
switch (request.action) {
|
|
250842
|
+
case "verify-plan": {
|
|
250843
|
+
if (!request.target?.trim())
|
|
250844
|
+
throw new Error("verify-plan requires --target; it never defaults to a full test suite");
|
|
250845
|
+
const { root, sourceDir, result } = await projectCompileConfig(request);
|
|
250846
|
+
const plan = await createVerificationPlan(root, result.graph, request.target.trim(), sourceDir);
|
|
250847
|
+
const ready = plan.ready && !result.diagnostics.some((item) => item.severity === "error");
|
|
250848
|
+
return textResult(JSON.stringify({ ...plan, ready, diagnostics: result.diagnostics }, null, 2), !ready);
|
|
250849
|
+
}
|
|
250981
250850
|
case "dev":
|
|
250851
|
+
case "watch":
|
|
250982
250852
|
return runAppDev(request, options);
|
|
250983
250853
|
case "plan":
|
|
250984
250854
|
case "build":
|
|
@@ -251026,6 +250896,8 @@ function registerAppTools(server2, options = {}) {
|
|
|
251026
250896
|
"init",
|
|
251027
250897
|
"generate",
|
|
251028
250898
|
"dev",
|
|
250899
|
+
"watch",
|
|
250900
|
+
"verify-plan",
|
|
251029
250901
|
"compile",
|
|
251030
250902
|
"check",
|
|
251031
250903
|
"graph",
|
|
@@ -251045,7 +250917,7 @@ function registerAppTools(server2, options = {}) {
|
|
|
251045
250917
|
"retire"
|
|
251046
250918
|
]), "App action; upload/configure only prepare, rollback activates an explicit old release without schema downgrade"),
|
|
251047
250919
|
kind: optional(stringEnum(["module", "command", "query", "controller", "job", "contract", "resource"]), "[generate] Scaffold kind"),
|
|
251048
|
-
template: optional(stringEnum(["http", "command", "edge"]), "[init]
|
|
250920
|
+
template: optional(stringEnum(["minimal", "http", "command", "edge"]), "[init] Minimal application by default; explicit http/command/edge recipes"),
|
|
251049
250921
|
name: optional(Type.String(), "[init/generate] Project or object name"),
|
|
251050
250922
|
module: optional(Type.String(), "[generate] Target feature module (required for command/query/controller)"),
|
|
251051
250923
|
dir: optional(Type.String(), "[generate] Feature root directory (default: src/features)"),
|
|
@@ -251059,12 +250931,12 @@ function registerAppTools(server2, options = {}) {
|
|
|
251059
250931
|
out_dir: optional(Type.String(), "[dev/compile/plan/build/export-tools] Output directory (default: configured outDir)"),
|
|
251060
250932
|
strict: optional(Type.Boolean(), "[dev/compile/check] Promote warnings to errors"),
|
|
251061
250933
|
format: optional(stringEnum(["text", "json"]), "[dev/generate/compile/check/plan/graph/export-tools] Output format (default: text)"),
|
|
251062
|
-
profile: optional(stringEnum(["fast", "integration"]), "[dev]
|
|
250934
|
+
profile: optional(stringEnum(["fast", "integration"]), "[dev] Run dev or dev:integration; integration verifies an explicit loopback database"),
|
|
251063
250935
|
once: optional(Type.Boolean(), "[dev] Validate and report once without watching"),
|
|
251064
250936
|
watch: optional(Type.Boolean(), "[dev] Watch for changes (default: true; --once disables)"),
|
|
251065
|
-
database_url: optional(Type.String(), "[dev] Explicit integration
|
|
250937
|
+
database_url: optional(Type.String(), "[dev] Explicit loopback integration URL; watch/once only inspect its shape"),
|
|
251066
250938
|
"database-url": optional(Type.String(), "[dev] CLI alias of database_url"),
|
|
251067
|
-
target: optional(Type.String(), "[explain/context] Provider class name / token name / command name / job name / module name"),
|
|
250939
|
+
target: optional(Type.String(), "[explain/context/verify-plan] Provider class name / token name / command name / job name / module name"),
|
|
251068
250940
|
fix: optional(Type.String(), "[fix] Path to a DiagnosticFix JSON file produced by `doctor --format json`"),
|
|
251069
250941
|
write: optional(Type.Boolean(), "[fix] Write the fix to disk (default: preview only)")
|
|
251070
250942
|
}, (request) => runAppTool(request, options));
|
|
@@ -251097,7 +250969,7 @@ function registerAppAliases(server2) {
|
|
|
251097
250969
|
|
|
251098
250970
|
// src/shared/tools/db-governance-tools.ts
|
|
251099
250971
|
import { existsSync as existsSync13 } from "node:fs";
|
|
251100
|
-
import { join as
|
|
250972
|
+
import { join as join18, resolve as resolve23 } from "node:path";
|
|
251101
250973
|
|
|
251102
250974
|
// node_modules/@supacloud/db/dist/index.js
|
|
251103
250975
|
var TABLES_SQL = `
|
|
@@ -251549,7 +251421,7 @@ function normalizeModule(candidate, sourcePath) {
|
|
|
251549
251421
|
};
|
|
251550
251422
|
}
|
|
251551
251423
|
async function loadDatabaseModules(root, moduleFile) {
|
|
251552
|
-
const filePath = moduleFile ?
|
|
251424
|
+
const filePath = moduleFile ? resolve23(root, moduleFile) : join18(root, "db", "modules.ts");
|
|
251553
251425
|
if (!existsSync13(filePath)) {
|
|
251554
251426
|
throw new Error(moduleFile ? `Module file not found: ${filePath}` : `Module file not found: ${filePath}(用 --module_file 指定一个导出 defineDatabaseModule(...) 的文件)`);
|
|
251555
251427
|
}
|
|
@@ -251598,7 +251470,7 @@ async function runLint(args, root) {
|
|
|
251598
251470
|
const issues = [];
|
|
251599
251471
|
for (const module of selected) {
|
|
251600
251472
|
const readSqlFile = async (path) => {
|
|
251601
|
-
const absolute =
|
|
251473
|
+
const absolute = resolve23(root, path);
|
|
251602
251474
|
try {
|
|
251603
251475
|
return await Bun.file(absolute).text();
|
|
251604
251476
|
} catch (error) {
|
|
@@ -251634,14 +251506,14 @@ var defaultLiteSpawn = async (command, cwd) => {
|
|
|
251634
251506
|
return { exitCode, stdout, stderr };
|
|
251635
251507
|
};
|
|
251636
251508
|
async function runModuleCheckLite(args, root, spawn, liteBinary) {
|
|
251637
|
-
const projectDir =
|
|
251509
|
+
const projectDir = resolve23(args.project_dir?.trim() || root);
|
|
251638
251510
|
const binary = liteBinary === undefined ? Bun.which("supacloud-lite") : liteBinary;
|
|
251639
251511
|
if (!binary) {
|
|
251640
251512
|
throw new Error("db module_check --lite 需要本机可用的 supacloud-lite(npm i -g @supacloud/lite,或加入 PATH)");
|
|
251641
251513
|
}
|
|
251642
251514
|
const command = [binary, "db", "check", "--project-dir", projectDir];
|
|
251643
251515
|
if (args.module_file?.trim())
|
|
251644
|
-
command.push("--module-file",
|
|
251516
|
+
command.push("--module-file", resolve23(root, args.module_file.trim()));
|
|
251645
251517
|
const result = await spawn(command, projectDir);
|
|
251646
251518
|
const output = [result.stdout.trim(), result.stderr.trim()].filter(Boolean).join(`
|
|
251647
251519
|
`);
|
|
@@ -251692,7 +251564,7 @@ function registerDbGovernanceTools(server2, options = {}) {
|
|
|
251692
251564
|
lite: optional(Type.Boolean(), "[module_check] Reconcile against a local SupaCloud Lite project (runs supacloud-lite db check)"),
|
|
251693
251565
|
project_dir: optional(Type.String(), "[module_check] Lite project directory (with --lite; default: --root)")
|
|
251694
251566
|
}, async (request) => {
|
|
251695
|
-
const root =
|
|
251567
|
+
const root = resolve23(request.root || fallbackRoot);
|
|
251696
251568
|
switch (request.action) {
|
|
251697
251569
|
case "lint":
|
|
251698
251570
|
return runLint(request, root);
|
|
@@ -251709,7 +251581,7 @@ function registerDbGovernanceTools(server2, options = {}) {
|
|
|
251709
251581
|
// src/shared/tools/scheduled-function-tools.ts
|
|
251710
251582
|
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
251711
251583
|
import { readFileSync as readFileSync10, statSync as statSync7 } from "node:fs";
|
|
251712
|
-
import { resolve as
|
|
251584
|
+
import { resolve as resolve24 } from "node:path";
|
|
251713
251585
|
import { isDeepStrictEqual } from "node:util";
|
|
251714
251586
|
var HEADER_NAME_PATTERN = /^[!#$%&'*+.^_`|~0-9A-Za-z-]{1,128}$/;
|
|
251715
251587
|
var ENVIRONMENT_NAME_PATTERN2 = /^[A-Za-z_][A-Za-z0-9_]{0,255}$/;
|
|
@@ -251793,7 +251665,7 @@ function validScheduledFunctionCron(expression) {
|
|
|
251793
251665
|
function readScheduleBodyFile(bodyPathInput) {
|
|
251794
251666
|
if (!bodyPathInput.trim())
|
|
251795
251667
|
throw new Error("'body_file' must be a path");
|
|
251796
|
-
const bodyPath =
|
|
251668
|
+
const bodyPath = resolve24(bodyPathInput);
|
|
251797
251669
|
const bodyStat = statSync7(bodyPath);
|
|
251798
251670
|
if (!bodyStat.isFile() || bodyStat.size > MAX_BODY_FILE_BYTES) {
|
|
251799
251671
|
throw new Error("Scheduled Function body file must be a regular file no larger than 1 MiB");
|
|
@@ -252377,7 +252249,7 @@ var MUTATION_TOOL_SCHEMA = {
|
|
|
252377
252249
|
import { execFileSync } from "node:child_process";
|
|
252378
252250
|
import { createHash as createHash10 } from "node:crypto";
|
|
252379
252251
|
import { existsSync as existsSync14, mkdirSync as mkdirSync4, readdirSync as readdirSync4, readFileSync as readFileSync11, writeFileSync as writeFileSync3 } from "node:fs";
|
|
252380
|
-
import { dirname as
|
|
252252
|
+
import { dirname as dirname14, join as join19, relative as relative14, resolve as resolve25 } from "node:path";
|
|
252381
252253
|
var SAFE_PROJECT_REF = /^[A-Za-z0-9_-]{1,64}$/;
|
|
252382
252254
|
var BACKUP_ID = /^logical-full_[A-Za-z0-9_-]{1,64}_[a-f0-9]{32}$/;
|
|
252383
252255
|
var SHA256 = /^[a-f0-9]{64}$/;
|
|
@@ -252671,13 +252543,13 @@ function collectScopeFiles(cwd, file, files, dir, task) {
|
|
|
252671
252543
|
const results = [];
|
|
252672
252544
|
const resolvePathWithFallbacks = (filePath) => {
|
|
252673
252545
|
const trimmed = filePath.trim();
|
|
252674
|
-
const resolved =
|
|
252546
|
+
const resolved = resolve25(cwd, trimmed);
|
|
252675
252547
|
if (existsSync14(resolved))
|
|
252676
252548
|
return resolved;
|
|
252677
252549
|
const candidates = [
|
|
252678
|
-
|
|
252679
|
-
|
|
252680
|
-
|
|
252550
|
+
resolve25(cwd, "supacloud/fa/release-scopes", trimmed),
|
|
252551
|
+
resolve25(cwd, "release-scopes", trimmed),
|
|
252552
|
+
resolve25(cwd, "scopes", trimmed)
|
|
252681
252553
|
];
|
|
252682
252554
|
const found = candidates.find(existsSync14);
|
|
252683
252555
|
if (found)
|
|
@@ -252700,10 +252572,10 @@ function collectScopeFiles(cwd, file, files, dir, task) {
|
|
|
252700
252572
|
if (!taskFilter && (!dir || typeof dir !== "string" || !dir.trim())) {
|
|
252701
252573
|
throw new Error("At least one of --file, --files, or --task is required for scope_rebind");
|
|
252702
252574
|
}
|
|
252703
|
-
const candidates = typeof dir === "string" && dir.trim() ? [
|
|
252704
|
-
|
|
252705
|
-
|
|
252706
|
-
|
|
252575
|
+
const candidates = typeof dir === "string" && dir.trim() ? [resolve25(cwd, dir.trim())] : [
|
|
252576
|
+
resolve25(cwd, "supacloud/fa/release-scopes"),
|
|
252577
|
+
resolve25(cwd, "release-scopes"),
|
|
252578
|
+
resolve25(cwd, "scopes")
|
|
252707
252579
|
];
|
|
252708
252580
|
for (const directory of candidates) {
|
|
252709
252581
|
if (existsSync14(directory)) {
|
|
@@ -252711,7 +252583,7 @@ function collectScopeFiles(cwd, file, files, dir, task) {
|
|
|
252711
252583
|
const entries = readdirSync4(directory, { withFileTypes: true });
|
|
252712
252584
|
for (const entry of entries) {
|
|
252713
252585
|
if (entry.isFile() && entry.name.endsWith(".json")) {
|
|
252714
|
-
const fullPath =
|
|
252586
|
+
const fullPath = join19(directory, entry.name);
|
|
252715
252587
|
if (!taskFilter) {
|
|
252716
252588
|
results.push(fullPath);
|
|
252717
252589
|
} else if (entry.name.toLowerCase().includes(taskFilter)) {
|
|
@@ -252737,7 +252609,7 @@ function collectScopeFiles(cwd, file, files, dir, task) {
|
|
|
252737
252609
|
return [...new Set(results)];
|
|
252738
252610
|
}
|
|
252739
252611
|
function handleScopeRebind(args) {
|
|
252740
|
-
const cwd = typeof args.cwd === "string" && args.cwd.trim() ?
|
|
252612
|
+
const cwd = typeof args.cwd === "string" && args.cwd.trim() ? resolve25(args.cwd.trim()) : process.cwd();
|
|
252741
252613
|
const targetBaseCommit = resolveGitBaseCommit(cwd, args.base_commit);
|
|
252742
252614
|
const scopeFiles = collectScopeFiles(cwd, args.file, args.files, args.dir, args.task);
|
|
252743
252615
|
const dryRun = args.dry_run === true;
|
|
@@ -252771,7 +252643,7 @@ function handleScopeRebind(args) {
|
|
|
252771
252643
|
writeFileSync3(filePath, formatted, "utf8");
|
|
252772
252644
|
}
|
|
252773
252645
|
scopes.push({
|
|
252774
|
-
file:
|
|
252646
|
+
file: relative14(cwd, filePath),
|
|
252775
252647
|
task_id: typeof parsed.taskId === "string" ? parsed.taskId : "",
|
|
252776
252648
|
target_project_ref: typeof parsed.targetProjectRef === "string" ? parsed.targetProjectRef : "",
|
|
252777
252649
|
previous_base_commit: previousBaseCommit,
|
|
@@ -252789,17 +252661,17 @@ function handleScopeRebind(args) {
|
|
|
252789
252661
|
});
|
|
252790
252662
|
}
|
|
252791
252663
|
function handleScopeInspect(args) {
|
|
252792
|
-
const cwd = typeof args.cwd === "string" && args.cwd.trim() ?
|
|
252664
|
+
const cwd = typeof args.cwd === "string" && args.cwd.trim() ? resolve25(args.cwd.trim()) : process.cwd();
|
|
252793
252665
|
if (typeof args.file !== "string" || !args.file.trim()) {
|
|
252794
252666
|
throw new Error("'file' is required for scope_inspect");
|
|
252795
252667
|
}
|
|
252796
252668
|
const trimmed = args.file.trim();
|
|
252797
|
-
let filePath =
|
|
252669
|
+
let filePath = resolve25(cwd, trimmed);
|
|
252798
252670
|
if (!existsSync14(filePath)) {
|
|
252799
252671
|
const candidates = [
|
|
252800
|
-
|
|
252801
|
-
|
|
252802
|
-
|
|
252672
|
+
resolve25(cwd, "supacloud/fa/release-scopes", trimmed),
|
|
252673
|
+
resolve25(cwd, "release-scopes", trimmed),
|
|
252674
|
+
resolve25(cwd, "scopes", trimmed)
|
|
252803
252675
|
];
|
|
252804
252676
|
const found = candidates.find(existsSync14);
|
|
252805
252677
|
if (found)
|
|
@@ -252825,7 +252697,7 @@ function handleScopeInspect(args) {
|
|
|
252825
252697
|
const scopeSha256 = genericScopedReleaseScopeSha256(parsed);
|
|
252826
252698
|
const git = gitCommitInfo(cwd);
|
|
252827
252699
|
return releaseControlSuccess("release.scope_inspect", {
|
|
252828
|
-
file:
|
|
252700
|
+
file: relative14(cwd, filePath),
|
|
252829
252701
|
scope: {
|
|
252830
252702
|
task_id: parsed.taskId,
|
|
252831
252703
|
target_project_ref: parsed.targetProjectRef,
|
|
@@ -252859,7 +252731,7 @@ function parseCommaList(value) {
|
|
|
252859
252731
|
return [];
|
|
252860
252732
|
}
|
|
252861
252733
|
function handleScopeCreate(args, fallbackRef) {
|
|
252862
|
-
const cwd = typeof args.cwd === "string" && args.cwd.trim() ?
|
|
252734
|
+
const cwd = typeof args.cwd === "string" && args.cwd.trim() ? resolve25(args.cwd.trim()) : process.cwd();
|
|
252863
252735
|
if (typeof args.file !== "string" || !args.file.trim()) {
|
|
252864
252736
|
throw new Error("'file' is required for scope_create");
|
|
252865
252737
|
}
|
|
@@ -252874,8 +252746,8 @@ function handleScopeCreate(args, fallbackRef) {
|
|
|
252874
252746
|
throw new Error("'ref' is invalid for release controls");
|
|
252875
252747
|
}
|
|
252876
252748
|
const targetBaseCommit = resolveGitBaseCommit(cwd, args.base_commit);
|
|
252877
|
-
const filePath =
|
|
252878
|
-
mkdirSync4(
|
|
252749
|
+
const filePath = resolve25(cwd, args.file.trim());
|
|
252750
|
+
mkdirSync4(dirname14(filePath), { recursive: true });
|
|
252879
252751
|
const scope = {
|
|
252880
252752
|
baseCommit: targetBaseCommit,
|
|
252881
252753
|
excludedFunctions: parseCommaList(args.excluded_functions),
|
|
@@ -252891,7 +252763,7 @@ function handleScopeCreate(args, fallbackRef) {
|
|
|
252891
252763
|
`;
|
|
252892
252764
|
writeFileSync3(filePath, formatted, "utf8");
|
|
252893
252765
|
return releaseControlSuccess("release.scope_create", {
|
|
252894
|
-
file:
|
|
252766
|
+
file: relative14(cwd, filePath),
|
|
252895
252767
|
task_id: scope.taskId,
|
|
252896
252768
|
target_project_ref: projectRef,
|
|
252897
252769
|
base_commit: targetBaseCommit,
|
|
@@ -253096,11 +252968,11 @@ function registerReleaseTools(server2, http, options = {}) {
|
|
|
253096
252968
|
}
|
|
253097
252969
|
|
|
253098
252970
|
// src/shared/tools/deploy-tools.ts
|
|
253099
|
-
import { access as access4, lstat as lstat5, mkdtemp as mkdtemp2, opendir, readFile as
|
|
252971
|
+
import { access as access4, lstat as lstat5, mkdtemp as mkdtemp2, opendir, readFile as readFile10, rm as rm3, writeFile as writeFile6 } from "node:fs/promises";
|
|
253100
252972
|
import { createHash as createHash11 } from "node:crypto";
|
|
253101
252973
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
253102
|
-
import { basename as basename9, dirname as
|
|
253103
|
-
import { spawn as
|
|
252974
|
+
import { basename as basename9, dirname as dirname15, join as join20, relative as relative15, resolve as resolve26, sep as sep12 } from "node:path";
|
|
252975
|
+
import { spawn as spawn4 } from "node:child_process";
|
|
253104
252976
|
|
|
253105
252977
|
// node_modules/fflate/esm/index.mjs
|
|
253106
252978
|
import { createRequire as createRequire3 } from "module";
|
|
@@ -253783,7 +253655,7 @@ function frontendDeployment(candidate) {
|
|
|
253783
253655
|
}
|
|
253784
253656
|
async function readJson(path) {
|
|
253785
253657
|
try {
|
|
253786
|
-
return JSON.parse(await
|
|
253658
|
+
return JSON.parse(await readFile10(path, "utf8"));
|
|
253787
253659
|
} catch (error) {
|
|
253788
253660
|
if (error instanceof Error && "code" in error && error.code === "ENOENT")
|
|
253789
253661
|
return null;
|
|
@@ -253791,13 +253663,13 @@ async function readJson(path) {
|
|
|
253791
253663
|
}
|
|
253792
253664
|
}
|
|
253793
253665
|
async function findDeployConfigRoot(startDirectory) {
|
|
253794
|
-
let directory =
|
|
253666
|
+
let directory = resolve26(startDirectory);
|
|
253795
253667
|
while (true) {
|
|
253796
|
-
if (await pathExists(
|
|
253668
|
+
if (await pathExists(join20(directory, "supacloud.json")))
|
|
253797
253669
|
return directory;
|
|
253798
|
-
const parent =
|
|
253670
|
+
const parent = dirname15(directory);
|
|
253799
253671
|
if (parent === directory)
|
|
253800
|
-
return
|
|
253672
|
+
return resolve26(startDirectory);
|
|
253801
253673
|
directory = parent;
|
|
253802
253674
|
}
|
|
253803
253675
|
}
|
|
@@ -253840,7 +253712,7 @@ function deployTargetConfig(candidate, name) {
|
|
|
253840
253712
|
};
|
|
253841
253713
|
}
|
|
253842
253714
|
async function readDeployConfig(configRoot) {
|
|
253843
|
-
const configPath =
|
|
253715
|
+
const configPath = join20(configRoot, "supacloud.json");
|
|
253844
253716
|
const candidate = await readJson(configPath);
|
|
253845
253717
|
if (candidate === null)
|
|
253846
253718
|
return {};
|
|
@@ -253862,29 +253734,29 @@ async function readDeployConfig(configRoot) {
|
|
|
253862
253734
|
};
|
|
253863
253735
|
}
|
|
253864
253736
|
async function packageName(projectDirectory) {
|
|
253865
|
-
const candidate = record4(await readJson(
|
|
253737
|
+
const candidate = record4(await readJson(join20(projectDirectory, "package.json")));
|
|
253866
253738
|
return typeof candidate?.name === "string" && candidate.name.trim() ? candidate.name.trim() : null;
|
|
253867
253739
|
}
|
|
253868
253740
|
async function pathExists(path) {
|
|
253869
253741
|
return access4(path).then(() => true, () => false);
|
|
253870
253742
|
}
|
|
253871
253743
|
async function defaultBuildCommand(projectDirectory, configRoot) {
|
|
253872
|
-
const packageJson = record4(await readJson(
|
|
253744
|
+
const packageJson = record4(await readJson(join20(projectDirectory, "package.json")));
|
|
253873
253745
|
const scripts = record4(packageJson?.scripts);
|
|
253874
253746
|
if (typeof scripts?.build !== "string" || !scripts.build.trim()) {
|
|
253875
253747
|
throw new Error("No build command was configured and package.json has no build script");
|
|
253876
253748
|
}
|
|
253877
253749
|
let directory = projectDirectory;
|
|
253878
253750
|
while (true) {
|
|
253879
|
-
if (await pathExists(
|
|
253751
|
+
if (await pathExists(join20(directory, "bun.lock")) || await pathExists(join20(directory, "bun.lockb")))
|
|
253880
253752
|
return "bun run build";
|
|
253881
|
-
if (await pathExists(
|
|
253753
|
+
if (await pathExists(join20(directory, "pnpm-lock.yaml")))
|
|
253882
253754
|
return "pnpm run build";
|
|
253883
|
-
if (await pathExists(
|
|
253755
|
+
if (await pathExists(join20(directory, "yarn.lock")))
|
|
253884
253756
|
return "yarn build";
|
|
253885
253757
|
if (directory === configRoot)
|
|
253886
253758
|
break;
|
|
253887
|
-
const parent =
|
|
253759
|
+
const parent = dirname15(directory);
|
|
253888
253760
|
if (parent === directory || !directory.startsWith(`${configRoot}${sep12}`))
|
|
253889
253761
|
break;
|
|
253890
253762
|
directory = parent;
|
|
@@ -253915,9 +253787,9 @@ function selectDeployment(deployments, requestedId, projectName) {
|
|
|
253915
253787
|
throw new Error(deployments.length === 0 ? "No frontend deployments exist for this project" : `Multiple frontend deployments found (${ids}). Set frontend.id in supacloud.json or pass --id`);
|
|
253916
253788
|
}
|
|
253917
253789
|
function targetRoot(configRoot, target, name) {
|
|
253918
|
-
const root =
|
|
253919
|
-
const prefix = `${
|
|
253920
|
-
if (root !==
|
|
253790
|
+
const root = resolve26(configRoot, target.root || (name === "frontend" ? "." : name));
|
|
253791
|
+
const prefix = `${resolve26(configRoot)}${sep12}`;
|
|
253792
|
+
if (root !== resolve26(configRoot) && !root.startsWith(prefix)) {
|
|
253921
253793
|
throw new Error(`Deploy target '${name}' root must stay inside the repository root`);
|
|
253922
253794
|
}
|
|
253923
253795
|
return root;
|
|
@@ -253968,8 +253840,8 @@ function defaultOutputDirectory(framework) {
|
|
|
253968
253840
|
}
|
|
253969
253841
|
}
|
|
253970
253842
|
function resolveInsideProject(projectDirectory, candidate, allowRoot = false) {
|
|
253971
|
-
const resolved =
|
|
253972
|
-
const projectRoot =
|
|
253843
|
+
const resolved = resolve26(projectDirectory, candidate);
|
|
253844
|
+
const projectRoot = resolve26(projectDirectory);
|
|
253973
253845
|
const projectPrefix = `${projectRoot}${sep12}`;
|
|
253974
253846
|
if (!allowRoot && resolved === projectRoot || resolved !== projectRoot && !resolved.startsWith(projectPrefix)) {
|
|
253975
253847
|
throw new Error("Frontend output directory must stay inside the project directory");
|
|
@@ -253978,7 +253850,7 @@ function resolveInsideProject(projectDirectory, candidate, allowRoot = false) {
|
|
|
253978
253850
|
}
|
|
253979
253851
|
async function runBuild(command, cwd) {
|
|
253980
253852
|
await new Promise((resolvePromise, reject) => {
|
|
253981
|
-
const child =
|
|
253853
|
+
const child = spawn4(command, { cwd, env: process.env, shell: true, stdio: "inherit" });
|
|
253982
253854
|
child.once("error", reject);
|
|
253983
253855
|
child.once("exit", (code, signal) => {
|
|
253984
253856
|
if (code === 0)
|
|
@@ -254000,7 +253872,7 @@ async function collectArchiveFiles(root) {
|
|
|
254000
253872
|
entries.push(entry);
|
|
254001
253873
|
entries.sort((left, right) => left.name.localeCompare(right.name, "en"));
|
|
254002
253874
|
for (const entry of entries) {
|
|
254003
|
-
const path =
|
|
253875
|
+
const path = join20(directory, entry.name);
|
|
254004
253876
|
const stats = await lstat5(path);
|
|
254005
253877
|
if (stats.isSymbolicLink())
|
|
254006
253878
|
throw new Error(`Frontend output cannot contain symbolic links: ${path}`);
|
|
@@ -254018,19 +253890,19 @@ async function collectArchiveFiles(root) {
|
|
|
254018
253890
|
let bytes = 0;
|
|
254019
253891
|
const files = {};
|
|
254020
253892
|
for (const path of paths) {
|
|
254021
|
-
const data = new Uint8Array(await
|
|
253893
|
+
const data = new Uint8Array(await readFile10(path));
|
|
254022
253894
|
bytes += data.byteLength;
|
|
254023
253895
|
if (bytes > MAX_SOURCE_BYTES)
|
|
254024
253896
|
throw new Error(`Frontend output exceeds ${MAX_SOURCE_BYTES} bytes`);
|
|
254025
|
-
const archivePath =
|
|
253897
|
+
const archivePath = relative15(root, path).split(sep12).join("/");
|
|
254026
253898
|
files[archivePath] = [data, { mtime: FIXED_ZIP_MTIME }];
|
|
254027
253899
|
}
|
|
254028
253900
|
return { files, bytes, count: paths.length };
|
|
254029
253901
|
}
|
|
254030
253902
|
async function createFrontendArchive(outputDirectory) {
|
|
254031
253903
|
const collected = await collectArchiveFiles(outputDirectory);
|
|
254032
|
-
const temporaryDirectory = await mkdtemp2(
|
|
254033
|
-
const archivePath =
|
|
253904
|
+
const temporaryDirectory = await mkdtemp2(join20(tmpdir2(), "supacloud-deploy-"));
|
|
253905
|
+
const archivePath = join20(temporaryDirectory, `${basename9(outputDirectory)}.zip`);
|
|
254034
253906
|
try {
|
|
254035
253907
|
const archiveBytes = zipSync(collected.files, { level: 6, mtime: FIXED_ZIP_MTIME });
|
|
254036
253908
|
await writeFile6(archivePath, archiveBytes);
|
|
@@ -254080,7 +253952,7 @@ function deployResponse(result, json) {
|
|
|
254080
253952
|
}
|
|
254081
253953
|
function registerDeployTools(server2, http, options = {}) {
|
|
254082
253954
|
server2.tool("deploy", "Build and publish the linked frontend with one command", deployToolSchema, async (args) => {
|
|
254083
|
-
const invocationDirectory =
|
|
253955
|
+
const invocationDirectory = resolve26(String(args.cwd || options.cwd || process.cwd()));
|
|
254084
253956
|
const projectRef = String(args.ref || options.projectRef || "").trim();
|
|
254085
253957
|
if (!projectRef)
|
|
254086
253958
|
throw new Error("A linked project ref is required. Set SUPACLOUD_PROJECT_REF or pass --ref");
|
|
@@ -254194,7 +254066,7 @@ function registerDeployTools(server2, http, options = {}) {
|
|
|
254194
254066
|
} else {
|
|
254195
254067
|
report("build", "skipped");
|
|
254196
254068
|
}
|
|
254197
|
-
report("package",
|
|
254069
|
+
report("package", relative15(projectDirectory, outputDirectory) || ".");
|
|
254198
254070
|
const archive = await createFrontendArchive(outputDirectory);
|
|
254199
254071
|
try {
|
|
254200
254072
|
const inventory = payload(await listFrontendReleases(http, projectRef, selected.id, undefined, 100));
|
|
@@ -254252,12 +254124,12 @@ function registerDeployTools(server2, http, options = {}) {
|
|
|
254252
254124
|
}
|
|
254253
254125
|
|
|
254254
254126
|
// src/shared/tools/remote-dev-tools.ts
|
|
254255
|
-
import { spawn as
|
|
254127
|
+
import { spawn as spawn5 } from "node:child_process";
|
|
254256
254128
|
import { existsSync as existsSync15 } from "node:fs";
|
|
254257
|
-
import { readFile as
|
|
254258
|
-
import { readdir as
|
|
254129
|
+
import { readFile as readFile11 } from "node:fs/promises";
|
|
254130
|
+
import { readdir as readdir7 } from "node:fs/promises";
|
|
254259
254131
|
import { createHash as createHash12 } from "node:crypto";
|
|
254260
|
-
import { join as
|
|
254132
|
+
import { join as join21, resolve as resolve27 } from "node:path";
|
|
254261
254133
|
var SAFE_TOKEN = /^[A-Za-z0-9._:@/+,-]+$/;
|
|
254262
254134
|
var SAFE_REMOTE_ROOT = /^\/(?:[A-Za-z0-9._-]+\/)*[A-Za-z0-9._-]+\/?$/;
|
|
254263
254135
|
var remoteDevToolSchema = {
|
|
@@ -254281,7 +254153,7 @@ var remoteDevToolSchema = {
|
|
|
254281
254153
|
};
|
|
254282
254154
|
function runProcess(executable, args, cwd) {
|
|
254283
254155
|
return new Promise((resolveResult, reject) => {
|
|
254284
|
-
const child =
|
|
254156
|
+
const child = spawn5(executable, args, { cwd, shell: false, stdio: ["ignore", "pipe", "pipe"] });
|
|
254285
254157
|
let stdout = "";
|
|
254286
254158
|
let stderr = "";
|
|
254287
254159
|
child.stdout?.setEncoding("utf8");
|
|
@@ -254299,19 +254171,19 @@ function runProcess(executable, args, cwd) {
|
|
|
254299
254171
|
function resolveDrizzleCommand(root, configured) {
|
|
254300
254172
|
if (configured?.trim())
|
|
254301
254173
|
return configured.trim();
|
|
254302
|
-
const local =
|
|
254174
|
+
const local = join21(root, "node_modules", ".bin", "drizzle-kit");
|
|
254303
254175
|
return existsSync15(local) ? local : "drizzle-kit";
|
|
254304
254176
|
}
|
|
254305
254177
|
function toolFailed(value) {
|
|
254306
254178
|
return value?.isError === true || value?.content?.some((chunk) => typeof chunk?.text === "string" && chunk.text.trimStart().startsWith("❌"));
|
|
254307
254179
|
}
|
|
254308
254180
|
async function migrateDatabase(args, options) {
|
|
254309
|
-
const root =
|
|
254181
|
+
const root = resolve27(String(args.project_dir || options.cwd || process.cwd()));
|
|
254310
254182
|
const projectConfig = await readProjectConfig3(root);
|
|
254311
254183
|
const config = projectConfig.dev || {};
|
|
254312
254184
|
const database = config.database || {};
|
|
254313
254185
|
const execute = options.execute || ((command, commandArgs, cwd) => runProcess(command, commandArgs, cwd));
|
|
254314
|
-
const drizzleConfig =
|
|
254186
|
+
const drizzleConfig = resolve27(root, String(args.drizzle_config || database.drizzleConfig || "drizzle.config.ts"));
|
|
254315
254187
|
const migrationsDir = String(args.migrations_dir || database.migrationsDir || "supabase/migrations");
|
|
254316
254188
|
if (!existsSync15(drizzleConfig))
|
|
254317
254189
|
throw new Error(`Drizzle config not found: ${drizzleConfig}`);
|
|
@@ -254331,11 +254203,11 @@ async function migrateDatabase(args, options) {
|
|
|
254331
254203
|
return { ok: true, mode: "dev", action: "migrate", generated: true, applied: true, migrations_dir: migrationsDir, result: applied };
|
|
254332
254204
|
}
|
|
254333
254205
|
async function readProjectConfig3(root) {
|
|
254334
|
-
const file =
|
|
254206
|
+
const file = join21(root, "supacloud.json");
|
|
254335
254207
|
if (!existsSync15(file))
|
|
254336
254208
|
return {};
|
|
254337
254209
|
try {
|
|
254338
|
-
const parsed = JSON.parse(await
|
|
254210
|
+
const parsed = JSON.parse(await readFile11(file, "utf8"));
|
|
254339
254211
|
return parsed && typeof parsed === "object" ? parsed : {};
|
|
254340
254212
|
} catch (error) {
|
|
254341
254213
|
throw new Error(`Invalid supacloud.json: ${error instanceof Error ? error.message : String(error)}`);
|
|
@@ -254348,9 +254220,9 @@ async function readDevConfig(root) {
|
|
|
254348
254220
|
async function sourceFingerprint(root) {
|
|
254349
254221
|
const files = [];
|
|
254350
254222
|
const visit = async (directory) => {
|
|
254351
|
-
const entries = await
|
|
254223
|
+
const entries = await readdir7(directory, { withFileTypes: true });
|
|
254352
254224
|
for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
254353
|
-
const path =
|
|
254225
|
+
const path = join21(directory, entry.name);
|
|
254354
254226
|
if (entry.isDirectory() && ![".git", "node_modules", "dist", "generated", ".supacloud"].includes(entry.name))
|
|
254355
254227
|
await visit(path);
|
|
254356
254228
|
else if (entry.isFile())
|
|
@@ -254361,7 +254233,7 @@ async function sourceFingerprint(root) {
|
|
|
254361
254233
|
const hash = createHash12("sha256");
|
|
254362
254234
|
for (const file of files) {
|
|
254363
254235
|
hash.update(file.slice(root.length).replace(/\\/g, "/"));
|
|
254364
|
-
hash.update(await
|
|
254236
|
+
hash.update(await readFile11(file));
|
|
254365
254237
|
}
|
|
254366
254238
|
return hash.digest("hex");
|
|
254367
254239
|
}
|
|
@@ -254378,17 +254250,17 @@ function remoteRoot(value) {
|
|
|
254378
254250
|
}
|
|
254379
254251
|
function targetDirectory(root, target, functionSlug, config = {}) {
|
|
254380
254252
|
if (target === "db")
|
|
254381
|
-
return
|
|
254253
|
+
return join21(root, "supabase", "migrations");
|
|
254382
254254
|
if (target === "functions") {
|
|
254383
254255
|
const targets = config.targets && typeof config.targets === "object" ? config.targets : {};
|
|
254384
254256
|
const match = Object.values(targets).find((entry) => entry?.type === "edge_function" && (!functionSlug || String(entry.slug || "") === functionSlug));
|
|
254385
|
-
const base = match?.root ?
|
|
254386
|
-
return match?.root ? base : functionSlug ?
|
|
254257
|
+
const base = match?.root ? resolve27(root, String(match.root)) : join21(root, "supabase", "functions");
|
|
254258
|
+
return match?.root ? base : functionSlug ? join21(base, safeToken(functionSlug, "function")) : base;
|
|
254387
254259
|
}
|
|
254388
254260
|
if (target === "frontend") {
|
|
254389
254261
|
const targets = config.targets && typeof config.targets === "object" ? config.targets : {};
|
|
254390
254262
|
const match = Object.values(targets).find((entry) => entry?.type === "frontend");
|
|
254391
|
-
return match?.root ?
|
|
254263
|
+
return match?.root ? resolve27(root, String(match.root)) : join21(root, "apps", "web");
|
|
254392
254264
|
}
|
|
254393
254265
|
return root;
|
|
254394
254266
|
}
|
|
@@ -254427,10 +254299,10 @@ function reloadCommand(config, target, projectRef, functionSlug) {
|
|
|
254427
254299
|
return [...command.split(" "), "--project-ref", safeToken(projectRef || "test", "project_ref"), "--target", targetConfigPath(target), ...functionSlug ? ["--function", safeToken(functionSlug, "function")] : []];
|
|
254428
254300
|
}
|
|
254429
254301
|
function sshArgs(connection, remoteCommand) {
|
|
254430
|
-
return ["-p", String(connection.port), "-i",
|
|
254302
|
+
return ["-p", String(connection.port), "-i", resolve27(connection.key), "-o", "BatchMode=yes", "-o", "StrictHostKeyChecking=yes", `${connection.user}@${connection.host}`, ...remoteCommand];
|
|
254431
254303
|
}
|
|
254432
254304
|
function rsyncArgs(connection, source, destination, excludes, deleteRemote) {
|
|
254433
|
-
const args = ["-az", "--checksum", "--partial", "--protect-args", "-e", `ssh -p ${connection.port} -i ${
|
|
254305
|
+
const args = ["-az", "--checksum", "--partial", "--protect-args", "-e", `ssh -p ${connection.port} -i ${resolve27(connection.key)} -o BatchMode=yes -o StrictHostKeyChecking=yes`];
|
|
254434
254306
|
if (deleteRemote)
|
|
254435
254307
|
args.push("--delete-delay");
|
|
254436
254308
|
for (const exclude of excludes) {
|
|
@@ -254442,7 +254314,7 @@ function rsyncArgs(connection, source, destination, excludes, deleteRemote) {
|
|
|
254442
254314
|
return args;
|
|
254443
254315
|
}
|
|
254444
254316
|
async function syncOnce(args, options) {
|
|
254445
|
-
const root =
|
|
254317
|
+
const root = resolve27(String(args.project_dir || options.cwd || process.cwd()));
|
|
254446
254318
|
const projectConfig = await readProjectConfig3(root);
|
|
254447
254319
|
const config = projectConfig.dev || {};
|
|
254448
254320
|
const target = String(args.target || "project");
|
|
@@ -254451,8 +254323,8 @@ async function syncOnce(args, options) {
|
|
|
254451
254323
|
throw new Error(`Dev source directory not found: ${source}`);
|
|
254452
254324
|
let compiled = false;
|
|
254453
254325
|
if (config.compile === true && target !== "db") {
|
|
254454
|
-
const compileRoot =
|
|
254455
|
-
const compileOutDir =
|
|
254326
|
+
const compileRoot = resolve27(root, config.compileRoot || ".");
|
|
254327
|
+
const compileOutDir = resolve27(root, config.compileOutDir || "generated");
|
|
254456
254328
|
const compilation = await compileProject({
|
|
254457
254329
|
rootDir: compileRoot,
|
|
254458
254330
|
outDir: compileOutDir,
|
|
@@ -254490,7 +254362,7 @@ function registerRemoteDevTools(server2, options = {}) {
|
|
|
254490
254362
|
if (["production", "prod"].includes((options.environment || "").toLowerCase()))
|
|
254491
254363
|
throw new Error("Remote dev mode is forbidden for production environments");
|
|
254492
254364
|
if (args.action === "status") {
|
|
254493
|
-
const root =
|
|
254365
|
+
const root = resolve27(String(args.project_dir || options.cwd || process.cwd()));
|
|
254494
254366
|
const config = await readDevConfig(root);
|
|
254495
254367
|
const connection = connectionArgs(options, config, args);
|
|
254496
254368
|
const execute = options.execute || ((command, commandArgs, cwd) => runProcess(command, commandArgs, cwd));
|
|
@@ -254504,7 +254376,7 @@ function registerRemoteDevTools(server2, options = {}) {
|
|
|
254504
254376
|
return { content: [{ type: "text", text: JSON.stringify(await migrateDatabase(args, options), null, 2) }] };
|
|
254505
254377
|
}
|
|
254506
254378
|
if (args.action === "watch") {
|
|
254507
|
-
const root =
|
|
254379
|
+
const root = resolve27(String(args.project_dir || options.cwd || process.cwd()));
|
|
254508
254380
|
const interval = Math.max(100, Math.min(1e4, Number(args.interval_ms || 300)));
|
|
254509
254381
|
let fingerprint = "";
|
|
254510
254382
|
let lastSync = null;
|
|
@@ -254523,9 +254395,9 @@ function registerRemoteDevTools(server2, options = {}) {
|
|
|
254523
254395
|
});
|
|
254524
254396
|
}
|
|
254525
254397
|
// package.json
|
|
254526
|
-
var
|
|
254398
|
+
var package_default = {
|
|
254527
254399
|
name: "@supacloud/cli",
|
|
254528
|
-
version: "0.
|
|
254400
|
+
version: "0.64.1",
|
|
254529
254401
|
description: "Project-scoped CLI for SupaCloud users",
|
|
254530
254402
|
type: "module",
|
|
254531
254403
|
main: "./dist/index.js",
|
|
@@ -254560,7 +254432,7 @@ var package_default8 = {
|
|
|
254560
254432
|
},
|
|
254561
254433
|
dependencies: {
|
|
254562
254434
|
"@sinclair/typebox": "^0.34.52",
|
|
254563
|
-
"@supacloud/compiler": "^0.31.
|
|
254435
|
+
"@supacloud/compiler": "^0.31.2",
|
|
254564
254436
|
"@supacloud/delivery": "0.4.0",
|
|
254565
254437
|
"@supacloud/db": "^0.2.0",
|
|
254566
254438
|
fflate: "^0.8.3",
|
|
@@ -254570,7 +254442,9 @@ var package_default8 = {
|
|
|
254570
254442
|
"@supacloud/delivery": "0.4.0"
|
|
254571
254443
|
},
|
|
254572
254444
|
devDependencies: {
|
|
254445
|
+
"@supacloud/elysia": "^0.23.1",
|
|
254573
254446
|
"@types/bun": "^1.4.2",
|
|
254447
|
+
elysia: "2.0.0-beta.19",
|
|
254574
254448
|
typescript: "^7.0.2"
|
|
254575
254449
|
}
|
|
254576
254450
|
};
|
|
@@ -255109,7 +254983,7 @@ function createCliTools(context, confirmProduction) {
|
|
|
255109
254983
|
async function main() {
|
|
255110
254984
|
const rawArgs = process.argv.slice(2);
|
|
255111
254985
|
if (rawArgs.length === 1 && rawArgs[0] === "--version") {
|
|
255112
|
-
console.log(
|
|
254986
|
+
console.log(package_default.version);
|
|
255113
254987
|
return;
|
|
255114
254988
|
}
|
|
255115
254989
|
const globalOptions = parseGlobalOptions(rawArgs);
|