ignotum 0.0.11 → 0.0.13
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 +8 -3
- package/dist/cli/bin.mjs +1372 -492
- package/dist/cli/bin.mjs.map +1 -1
- package/dist/runtime/{api-DzcR7spt.js → api-CAgKDij7.js} +38 -2
- package/dist/runtime/api-CAgKDij7.js.map +1 -0
- package/dist/runtime/{api-DR_8vfKg.d.ts → api-Cv3hMbzo.d.ts} +4 -3
- package/dist/runtime/client.d.ts +39 -8
- package/dist/runtime/client.js +505 -131
- package/dist/runtime/client.js.map +1 -1
- package/dist/runtime/descriptor-Cyo9FP9n-C0SRVXNW.js +154 -0
- package/dist/runtime/descriptor-Cyo9FP9n-C0SRVXNW.js.map +1 -0
- package/dist/runtime/id-Bt9XWRGL.js +423 -0
- package/dist/runtime/id-Bt9XWRGL.js.map +1 -0
- package/dist/runtime/{id-Cs82tq9Q-hmYFyqTa.d.ts → id-BzFHf3Wo-DGPCjgrf.d.ts} +13 -13
- package/dist/runtime/id-Dz0apuB3.d.ts +1 -0
- package/dist/runtime/{index-2q9FwJud.d.ts → index-D54flWtH.d.ts} +136 -76
- package/dist/runtime/internal/api.d.ts +1 -1
- package/dist/runtime/internal/api.js +1 -1
- package/dist/runtime/internal/host.d.ts +21 -17
- package/dist/runtime/internal/host.js +22 -8
- package/dist/runtime/internal/host.js.map +1 -1
- package/dist/runtime/internal/server.d.ts +1 -1
- package/dist/runtime/internal/server.js +1 -1
- package/dist/runtime/internal/types.d.ts +1 -1
- package/dist/runtime/internal/types.js +1 -1
- package/dist/runtime/{pagination-Bt3l7QaC-BYEGmLBE.d.ts → pagination-DnKg3dkI-r5ZUxBBx.d.ts} +34 -6
- package/dist/runtime/pagination-Dz0apuB3.d.ts +1 -0
- package/dist/runtime/result-DKAA4gpS.d.ts +1 -0
- package/dist/runtime/{schema-ERFjT8-m.js → schema-1Zs03-iS.js} +135 -17
- package/dist/runtime/schema-1Zs03-iS.js.map +1 -0
- package/dist/runtime/server.d.ts +9 -3
- package/dist/runtime/server.js +5 -3
- package/dist/runtime/server.js.map +1 -1
- package/dist/runtime/{sync-a2EdGSdY.d.ts → sync-Bs8J3fIr.d.ts} +2 -2
- package/package.json +4 -4
- package/src/cli/agent-files.ts +8 -0
- package/src/cli/auth-client.ts +1 -1
- package/src/cli/bin.ts +13 -3
- package/src/cli/build/server.ts +102 -13
- package/src/cli/codegen.ts +7 -4
- package/src/cli/control-client.ts +30 -8
- package/src/cli/deploy.ts +7 -2
- package/src/cli/environment.ts +133 -0
- package/src/client/files.ts +43 -27
- package/src/client/hooks.ts +94 -17
- package/src/client/id.ts +259 -0
- package/src/client/index.ts +5 -2
- package/src/client/page-observers.ts +77 -0
- package/src/client/sync.ts +214 -69
- package/src/dev-runtime/functions.ts +232 -86
- package/src/dev-runtime/id.ts +174 -2
- package/src/dev-runtime/query-cache.ts +105 -0
- package/src/dev-runtime/sync.ts +187 -26
- package/src/server/index.ts +13 -1
- package/dist/runtime/api-DzcR7spt.js.map +0 -1
- package/dist/runtime/descriptor-C5VA9qRl-DuQsowaQ.js +0 -311
- package/dist/runtime/descriptor-C5VA9qRl-DuQsowaQ.js.map +0 -1
- package/dist/runtime/file-C1abuMgd.js +0 -173
- package/dist/runtime/file-C1abuMgd.js.map +0 -1
- package/dist/runtime/pagination-CFJ3xlAt.d.ts +0 -1
- package/dist/runtime/schema-ERFjT8-m.js.map +0 -1
package/dist/runtime/server.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { _ as Result$1 } from "./id-Bt9XWRGL.js";
|
|
2
|
+
import { a as defineSchema$1, i as defineEnv$1, l as Secret$1 } from "./schema-1Zs03-iS.js";
|
|
3
3
|
//#region src/server/index.ts
|
|
4
4
|
const Result = Result$1;
|
|
5
|
+
const defineEnv = defineEnv$1;
|
|
5
6
|
const defineSchema = defineSchema$1;
|
|
7
|
+
const Secret = Secret$1;
|
|
6
8
|
//#endregion
|
|
7
|
-
export { Result, defineSchema };
|
|
9
|
+
export { Result, Secret, defineEnv, defineSchema };
|
|
8
10
|
|
|
9
11
|
//# sourceMappingURL=server.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","names":["contractResult","defineContractSchema"],"sources":["../../src/server/index.ts"],"sourcesContent":["import { Result as contractResult } from \"@ignotum/contracts/runtime/result\";\nimport type { ErrorValue, Result as ContractResult } from \"@ignotum/contracts/runtime/result\";\nimport { defineSchema as defineContractSchema } from \"@ignotum/contracts/schema\";\n\nexport const Result: typeof contractResult = contractResult;\nexport type Result<Success, Failure extends ErrorValue> = ContractResult<Success, Failure>;\nexport const defineSchema: typeof defineContractSchema = defineContractSchema;\nexport type {\n DefinedSchema,\n FileFormat,\n FileMetadata,\n FileMimeType,\n FileValue,\n SchemaAuthoring,\n} from \"@ignotum/contracts/schema\";\n"],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"server.js","names":["contractResult","defineContractEnv","defineContractSchema","contractSecret"],"sources":["../../src/server/index.ts"],"sourcesContent":["import { Result as contractResult } from \"@ignotum/contracts/runtime/result\";\nimport type { ErrorValue, Result as ContractResult } from \"@ignotum/contracts/runtime/result\";\nimport {\n defineEnv as defineContractEnv,\n defineSchema as defineContractSchema,\n Secret as contractSecret,\n} from \"@ignotum/contracts/schema\";\nimport type { Secret as ContractSecret } from \"@ignotum/contracts/schema\";\n\nexport const Result: typeof contractResult = contractResult;\nexport type Result<Success, Failure extends ErrorValue> = ContractResult<Success, Failure>;\nexport const defineEnv: typeof defineContractEnv = defineContractEnv;\nexport const defineSchema: typeof defineContractSchema = defineContractSchema;\nexport const Secret: typeof contractSecret = contractSecret;\nexport type Secret<Value> = ContractSecret<Value>;\nexport type {\n DefinedEnv,\n DefinedSchema,\n EnvironmentAuthoring,\n FileFormat,\n FileMetadata,\n FileMimeType,\n FileValue,\n SchemaAuthoring,\n} from \"@ignotum/contracts/schema\";\n\nexport type { User, UserId } from \"@ignotum/contracts/id\";\n"],"mappings":";;;AASA,MAAa,SAAgCA;AAE7C,MAAa,YAAsCC;AACnD,MAAa,eAA4CC;AACzD,MAAa,SAAgCC"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import "./id-
|
|
1
|
+
import "./id-BzFHf3Wo-DGPCjgrf.js";
|
|
2
2
|
import { Schema } from "effect";
|
|
3
3
|
//#region ../contracts/dist/runtime/sync.d.ts
|
|
4
4
|
declare const FunctionAddress: Schema.TemplateLiteral<readonly ["api.", Schema.String, ".", Schema.String]>;
|
|
5
5
|
type FunctionAddress = typeof FunctionAddress.Type;
|
|
6
6
|
//#endregion
|
|
7
7
|
export { FunctionAddress as t };
|
|
8
|
-
//# sourceMappingURL=sync-
|
|
8
|
+
//# sourceMappingURL=sync-Bs8J3fIr.d.ts.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ignotum",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.13",
|
|
4
4
|
"description": "Ignotum is an opinionated TypeScript application cloud.",
|
|
5
5
|
"author": "Johannes Schießl",
|
|
6
6
|
"repository": {
|
|
@@ -80,10 +80,10 @@
|
|
|
80
80
|
"@effect/platform-node": "4.0.0-rc.111",
|
|
81
81
|
"@effect/sql-sqlite-node": "4.0.0-rc.111",
|
|
82
82
|
"redis": "6.2.1",
|
|
83
|
-
"@ignotum/runtime": "1.0.0",
|
|
84
83
|
"@ignotum/contracts": "1.0.0",
|
|
85
|
-
"@ignotum/
|
|
86
|
-
"@ignotum/
|
|
84
|
+
"@ignotum/deployment": "1.0.0",
|
|
85
|
+
"@ignotum/runtime": "1.0.0",
|
|
86
|
+
"@ignotum/shared": "1.0.0"
|
|
87
87
|
},
|
|
88
88
|
"engines": {
|
|
89
89
|
"node": ">=22.18.0"
|
package/src/cli/agent-files.ts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import authentication from "../../../../docs/user/authentication.md?raw";
|
|
2
|
+
import profileSharing from "../../../../docs/user/profile-sharing.md?raw";
|
|
3
|
+
import localAuthentication from "../../../../docs/user/local-authentication.md?raw";
|
|
1
4
|
import agents from "../../../../docs/agent/AGENTS.md?raw";
|
|
2
5
|
import skill from "../../../../docs/agent/skills/ignotum/SKILL.md?raw";
|
|
3
6
|
import api from "../../../../docs/user/api.md?raw";
|
|
@@ -8,6 +11,7 @@ import deployApp from "../../../../docs/user/deploy-app.md?raw";
|
|
|
8
11
|
import deploymentModel from "../../../../docs/user/deployment-model.md?raw";
|
|
9
12
|
import deployments from "../../../../docs/user/deployments.md?raw";
|
|
10
13
|
import errors from "../../../../docs/user/errors.md?raw";
|
|
14
|
+
import environmentVariables from "../../../../docs/user/environment-variables.md?raw";
|
|
11
15
|
import files from "../../../../docs/user/files.md?raw";
|
|
12
16
|
import functions from "../../../../docs/user/functions.md?raw";
|
|
13
17
|
import generatedCode from "../../../../docs/user/generated-code.md?raw";
|
|
@@ -37,6 +41,9 @@ export interface AppFile {
|
|
|
37
41
|
}
|
|
38
42
|
|
|
39
43
|
const references = [
|
|
44
|
+
["authentication.md", authentication],
|
|
45
|
+
["profile-sharing.md", profileSharing],
|
|
46
|
+
["local-authentication.md", localAuthentication],
|
|
40
47
|
["api.md", api],
|
|
41
48
|
["app-entry.md", appEntry],
|
|
42
49
|
["cli.md", cli],
|
|
@@ -45,6 +52,7 @@ const references = [
|
|
|
45
52
|
["deployment-model.md", deploymentModel],
|
|
46
53
|
["deployments.md", deployments],
|
|
47
54
|
["errors.md", errors],
|
|
55
|
+
["environment-variables.md", environmentVariables],
|
|
48
56
|
["files.md", files],
|
|
49
57
|
["functions.md", functions],
|
|
50
58
|
["generated-code.md", generatedCode],
|
package/src/cli/auth-client.ts
CHANGED
|
@@ -30,7 +30,7 @@ const AuthUrl = Schema.URL.check(
|
|
|
30
30
|
Schema.makeFilter(
|
|
31
31
|
(url) =>
|
|
32
32
|
url.protocol === "https:" ||
|
|
33
|
-
(url.protocol === "http:" && ["127.0.0.1", "::1", "localhost"].includes(url.hostname)),
|
|
33
|
+
(url.protocol === "http:" && ["127.0.0.1", "[::1]", "localhost"].includes(url.hostname)),
|
|
34
34
|
{ message: "The auth URL must use HTTPS unless it targets localhost." },
|
|
35
35
|
),
|
|
36
36
|
);
|
package/src/cli/bin.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
+
// @effect-diagnostics-next-line nodeBuiltinImport:off The isolated worker returns sensitive metadata over a dedicated inherited pipe.
|
|
4
|
+
import { writeSync } from "node:fs";
|
|
3
5
|
import process from "node:process";
|
|
4
6
|
|
|
5
7
|
import { NodeRuntime, NodeServices } from "@effect/platform-node";
|
|
@@ -9,15 +11,23 @@ import { main } from "./command.js";
|
|
|
9
11
|
import { runServerDiscoveryWorker } from "./build/server.js";
|
|
10
12
|
|
|
11
13
|
const discoveryWorker = process.argv[2] === "__ignotum_discover_server";
|
|
14
|
+
const writeDiscovery = (encoded: string): void => {
|
|
15
|
+
const bytes = new TextEncoder().encode(encoded);
|
|
16
|
+
let offset = 0;
|
|
17
|
+
while (offset < bytes.byteLength) {
|
|
18
|
+
offset += writeSync(3, bytes, offset, bytes.byteLength - offset);
|
|
19
|
+
}
|
|
20
|
+
};
|
|
12
21
|
|
|
13
22
|
if (discoveryWorker) {
|
|
14
23
|
const appDirectory = process.argv[3];
|
|
15
24
|
const moduleNames = process.argv[4];
|
|
16
|
-
const outputPath = process.argv[5];
|
|
17
25
|
globalThis.fetch = () => Promise.reject(new Error("Network access is disabled during builds."));
|
|
18
|
-
(appDirectory === undefined || moduleNames === undefined
|
|
26
|
+
(appDirectory === undefined || moduleNames === undefined
|
|
19
27
|
? Effect.die("Invalid isolated discovery arguments.")
|
|
20
|
-
: runServerDiscoveryWorker(appDirectory, moduleNames
|
|
28
|
+
: runServerDiscoveryWorker(appDirectory, moduleNames).pipe(
|
|
29
|
+
Effect.tap((encoded) => Effect.sync(() => writeDiscovery(encoded))),
|
|
30
|
+
)
|
|
21
31
|
).pipe(
|
|
22
32
|
// @effect-diagnostics-next-line strictEffectProvide:off The isolated worker is a process entry point.
|
|
23
33
|
Effect.provide(NodeServices.layer),
|
package/src/cli/build/server.ts
CHANGED
|
@@ -3,7 +3,18 @@ import process from "node:process";
|
|
|
3
3
|
import { fileURLToPath } from "node:url";
|
|
4
4
|
|
|
5
5
|
import * as Config from "effect/Config";
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
Array,
|
|
8
|
+
Crypto,
|
|
9
|
+
Effect,
|
|
10
|
+
Encoding,
|
|
11
|
+
FileSystem,
|
|
12
|
+
Path,
|
|
13
|
+
Predicate,
|
|
14
|
+
Schema,
|
|
15
|
+
Stream,
|
|
16
|
+
String,
|
|
17
|
+
} from "effect";
|
|
7
18
|
import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process";
|
|
8
19
|
import { createServer, defaultServerConditions, normalizePath } from "vite";
|
|
9
20
|
import type { Plugin, ViteDevServer } from "vite";
|
|
@@ -11,7 +22,10 @@ import type { Plugin, ViteDevServer } from "vite";
|
|
|
11
22
|
import {
|
|
12
23
|
ServerBuildManifest,
|
|
13
24
|
SchemaSnapshot,
|
|
25
|
+
SchemaSnapshotField,
|
|
26
|
+
EnvironmentArtifact,
|
|
14
27
|
schemaSnapshotPath,
|
|
28
|
+
serverEnvironmentPath,
|
|
15
29
|
type ServerFunctionArtifact,
|
|
16
30
|
} from "@ignotum/contracts/deployment";
|
|
17
31
|
import { FunctionAddress } from "@ignotum/contracts/runtime/sync";
|
|
@@ -19,7 +33,9 @@ import type { FunctionKind } from "@ignotum/contracts/runtime/functions";
|
|
|
19
33
|
import {
|
|
20
34
|
descriptorContainsFile,
|
|
21
35
|
descriptorFields,
|
|
36
|
+
emptyEnv,
|
|
22
37
|
getValueDescriptor,
|
|
38
|
+
isDefinedEnv,
|
|
23
39
|
isDefinedSchema,
|
|
24
40
|
ValueDescriptor,
|
|
25
41
|
type DefinedSchema,
|
|
@@ -34,6 +50,7 @@ import {
|
|
|
34
50
|
} from "@ignotum/deployment";
|
|
35
51
|
|
|
36
52
|
import { inspectRuntimeFunctionDefinition } from "../../internal/function-definition.js";
|
|
53
|
+
import { loadEnvironment } from "../environment.js";
|
|
37
54
|
import { moduleBoundariesPlugin, BuildBoundaryViolation } from "../module-boundaries.js";
|
|
38
55
|
import {
|
|
39
56
|
causeMessage,
|
|
@@ -69,6 +86,11 @@ interface DiscoveredServerFunction {
|
|
|
69
86
|
}
|
|
70
87
|
|
|
71
88
|
const ServerDiscoveryManifest = Schema.Struct({
|
|
89
|
+
environment: Schema.Struct({
|
|
90
|
+
fields: Schema.Array(SchemaSnapshotField),
|
|
91
|
+
hasDefinition: Schema.Boolean,
|
|
92
|
+
values: Schema.Record(Schema.String, Schema.String),
|
|
93
|
+
}),
|
|
72
94
|
functions: Schema.Array(DiscoveredServerFunction),
|
|
73
95
|
schema: SchemaSnapshot,
|
|
74
96
|
});
|
|
@@ -77,6 +99,10 @@ const ServerDiscoveryManifestJson = Schema.fromJsonString(ServerDiscoveryManifes
|
|
|
77
99
|
const ServerModuleNamesJson = Schema.fromJsonString(Schema.Array(Schema.String));
|
|
78
100
|
|
|
79
101
|
export interface ServerBuildResult {
|
|
102
|
+
readonly environment: {
|
|
103
|
+
readonly bytes: Uint8Array;
|
|
104
|
+
readonly path: typeof serverEnvironmentPath;
|
|
105
|
+
};
|
|
80
106
|
readonly functions: number;
|
|
81
107
|
readonly manifestPath: string;
|
|
82
108
|
}
|
|
@@ -268,6 +294,7 @@ const discoverServerFunctionsInProcess = Effect.fn("Deploy.discoverServerFunctio
|
|
|
268
294
|
return yield* Effect.scoped(
|
|
269
295
|
Effect.gen(function* () {
|
|
270
296
|
const server = yield* acquireModuleRunner(appDirectory, conditions);
|
|
297
|
+
const fileSystem = yield* FileSystem.FileSystem;
|
|
271
298
|
const path = yield* Path.Path;
|
|
272
299
|
const schemaPath = path.join(appDirectory, "server", "schema.ts");
|
|
273
300
|
const loadedSchemaModule = yield* Effect.tryPromise({
|
|
@@ -295,14 +322,59 @@ const discoverServerFunctionsInProcess = Effect.fn("Deploy.discoverServerFunctio
|
|
|
295
322
|
message: "The default export from server/schema.ts is not an Ignotum schema.",
|
|
296
323
|
});
|
|
297
324
|
}
|
|
325
|
+
const environmentPath = path.join(appDirectory, "server", "env.ts");
|
|
326
|
+
const hasEnvironmentDefinition = yield* fileSystem.exists(environmentPath);
|
|
327
|
+
const environment = hasEnvironmentDefinition
|
|
328
|
+
? yield* Effect.gen(function* () {
|
|
329
|
+
const loadedEnvironmentModule = yield* Effect.tryPromise({
|
|
330
|
+
try: () => server.ssrLoadModule(normalizePath(environmentPath)),
|
|
331
|
+
catch: (cause) =>
|
|
332
|
+
ServerFunctionDiscoveryFailed.make({
|
|
333
|
+
cause,
|
|
334
|
+
message: "Could not load the application environment declaration.",
|
|
335
|
+
path: environmentPath,
|
|
336
|
+
}),
|
|
337
|
+
});
|
|
338
|
+
if (
|
|
339
|
+
!Predicate.isObject(loadedEnvironmentModule.default) ||
|
|
340
|
+
!isDefinedEnv(loadedEnvironmentModule.default)
|
|
341
|
+
) {
|
|
342
|
+
return yield* InvalidBuildOutput.make({
|
|
343
|
+
message: "The default export from server/env.ts is not an Ignotum environment.",
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
const loaded = yield* loadEnvironment(
|
|
347
|
+
appDirectory,
|
|
348
|
+
loadedEnvironmentModule.default,
|
|
349
|
+
true,
|
|
350
|
+
);
|
|
351
|
+
return {
|
|
352
|
+
fields: loadedEnvironmentModule.default.descriptors,
|
|
353
|
+
hasDefinition: true,
|
|
354
|
+
values: loaded.raw,
|
|
355
|
+
} as const;
|
|
356
|
+
})
|
|
357
|
+
: yield* loadEnvironment(appDirectory, emptyEnv, false).pipe(
|
|
358
|
+
Effect.map((loaded) => ({
|
|
359
|
+
fields: [],
|
|
360
|
+
hasDefinition: false,
|
|
361
|
+
values: loaded.raw,
|
|
362
|
+
})),
|
|
363
|
+
);
|
|
298
364
|
const modules = yield* Effect.forEach(moduleNames, (moduleName) =>
|
|
299
365
|
discoverModuleFunctions(server, appDirectory, moduleName),
|
|
300
366
|
);
|
|
301
367
|
return {
|
|
302
368
|
functions: Array.flatten(modules),
|
|
369
|
+
environment,
|
|
303
370
|
schema: schemaCandidate,
|
|
304
371
|
} satisfies {
|
|
305
372
|
readonly functions: ReadonlyArray<DiscoveredServerFunction>;
|
|
373
|
+
readonly environment: {
|
|
374
|
+
readonly fields: ReadonlyArray<SchemaSnapshotField>;
|
|
375
|
+
readonly hasDefinition: boolean;
|
|
376
|
+
readonly values: Readonly<Record<string, string>>;
|
|
377
|
+
};
|
|
306
378
|
readonly schema: DefinedSchema<Tables>;
|
|
307
379
|
};
|
|
308
380
|
}),
|
|
@@ -312,9 +384,7 @@ const discoverServerFunctionsInProcess = Effect.fn("Deploy.discoverServerFunctio
|
|
|
312
384
|
export const runServerDiscoveryWorker = Effect.fn("Deploy.runServerDiscoveryWorker")(function* (
|
|
313
385
|
appDirectory: string,
|
|
314
386
|
moduleNamesJson: string,
|
|
315
|
-
outputPath: string,
|
|
316
387
|
) {
|
|
317
|
-
const fileSystem = yield* FileSystem.FileSystem;
|
|
318
388
|
const moduleNames = yield* Schema.decodeEffect(ServerModuleNamesJson)(moduleNamesJson).pipe(
|
|
319
389
|
Effect.orDie,
|
|
320
390
|
);
|
|
@@ -327,11 +397,11 @@ export const runServerDiscoveryWorker = Effect.fn("Deploy.runServerDiscoveryWork
|
|
|
327
397
|
message: "The application schema does not have canonical Ignotum descriptors.",
|
|
328
398
|
}),
|
|
329
399
|
});
|
|
330
|
-
|
|
400
|
+
return yield* Schema.encodeEffect(ServerDiscoveryManifestJson)({
|
|
401
|
+
environment: discovered.environment,
|
|
331
402
|
functions: discovered.functions,
|
|
332
403
|
schema,
|
|
333
404
|
});
|
|
334
|
-
yield* fileSystem.writeFileString(outputPath, encoded);
|
|
335
405
|
});
|
|
336
406
|
|
|
337
407
|
const discoveryWorkerEntry = Effect.fn("Deploy.discoveryWorkerEntry")(function* () {
|
|
@@ -365,7 +435,6 @@ const discoverServerFunctions = Effect.fn("Deploy.discoverServerFunctionsIsolate
|
|
|
365
435
|
(temporary) =>
|
|
366
436
|
fileSystem.remove(temporary, { force: true, recursive: true }).pipe(Effect.orDie),
|
|
367
437
|
);
|
|
368
|
-
const outputPath = path.join(directory, "discovery.json");
|
|
369
438
|
const encodedModuleNames = yield* Schema.encodeEffect(ServerModuleNamesJson)(moduleNames);
|
|
370
439
|
const packageRoot = path.resolve(path.dirname(workerEntry), "../..");
|
|
371
440
|
const workspaceProbes: Array<string> = [];
|
|
@@ -387,23 +456,25 @@ const discoverServerFunctions = Effect.fn("Deploy.discoverServerFunctionsIsolate
|
|
|
387
456
|
const readPermissions = [
|
|
388
457
|
appDirectory,
|
|
389
458
|
nodeModulesDirectory(),
|
|
459
|
+
path.dirname(nodeModulesDirectory()),
|
|
390
460
|
packageRoot,
|
|
391
461
|
path.join(packageRoot, "node_modules"),
|
|
462
|
+
path.resolve(packageRoot, "../..", "node_modules"),
|
|
392
463
|
...workspaceProbes,
|
|
393
464
|
].map((allowedPath) => `--allow-fs-read=${allowedPath}`);
|
|
394
|
-
const
|
|
465
|
+
const handle = yield* spawner.spawn(
|
|
395
466
|
ChildProcess.make(
|
|
396
467
|
process.execPath,
|
|
397
468
|
[
|
|
398
469
|
"--permission",
|
|
399
470
|
"--allow-addons",
|
|
471
|
+
"--conditions=@ignotum/source",
|
|
400
472
|
...readPermissions,
|
|
401
473
|
`--allow-fs-write=${directory}`,
|
|
402
474
|
workerEntry,
|
|
403
475
|
"__ignotum_discover_server",
|
|
404
476
|
appDirectory,
|
|
405
477
|
encodedModuleNames,
|
|
406
|
-
outputPath,
|
|
407
478
|
],
|
|
408
479
|
{
|
|
409
480
|
cwd: appDirectory,
|
|
@@ -414,9 +485,14 @@ const discoverServerFunctions = Effect.fn("Deploy.discoverServerFunctionsIsolate
|
|
|
414
485
|
},
|
|
415
486
|
stderr: "inherit",
|
|
416
487
|
stdout: "ignore",
|
|
488
|
+
additionalFds: { fd3: { type: "output" } },
|
|
417
489
|
},
|
|
418
490
|
),
|
|
419
491
|
);
|
|
492
|
+
const [encoded, exitCode] = yield* Effect.all(
|
|
493
|
+
[Stream.mkString(Stream.decodeText(handle.getOutputFd(3))), handle.exitCode],
|
|
494
|
+
{ concurrency: "unbounded" },
|
|
495
|
+
);
|
|
420
496
|
if (exitCode !== ChildProcessSpawner.ExitCode(0)) {
|
|
421
497
|
return yield* ServerFunctionDiscoveryFailed.make({
|
|
422
498
|
cause: new Error(`Discovery worker exited with code ${exitCode}.`),
|
|
@@ -424,13 +500,12 @@ const discoverServerFunctions = Effect.fn("Deploy.discoverServerFunctionsIsolate
|
|
|
424
500
|
path: appDirectory,
|
|
425
501
|
});
|
|
426
502
|
}
|
|
427
|
-
const encoded = yield* fileSystem.readFileString(outputPath);
|
|
428
503
|
return yield* Schema.decodeEffect(ServerDiscoveryManifestJson)(encoded).pipe(
|
|
429
504
|
Effect.mapError((cause) =>
|
|
430
505
|
ServerFunctionDiscoveryFailed.make({
|
|
431
506
|
cause,
|
|
432
507
|
message: "The isolated build process returned invalid application metadata.",
|
|
433
|
-
path:
|
|
508
|
+
path: appDirectory,
|
|
434
509
|
}),
|
|
435
510
|
),
|
|
436
511
|
);
|
|
@@ -445,8 +520,8 @@ const serverFunctionEntryPlugin = (definition: DiscoveredServerFunction): Plugin
|
|
|
445
520
|
import { invoke } from "ignotum/internal/host"
|
|
446
521
|
import { ${definition.exportName} as definition } from ${encodeJavaScriptString(normalizePath(definition.modulePath))}
|
|
447
522
|
|
|
448
|
-
export default async function handler(encodedRequest) {
|
|
449
|
-
return invoke(definition, JSON.parse(encodedRequest), call)
|
|
523
|
+
export default async function handler(encodedRequest, encodedEnvironment) {
|
|
524
|
+
return invoke(definition, JSON.parse(encodedRequest), call, JSON.parse(encodedEnvironment))
|
|
450
525
|
}
|
|
451
526
|
`;
|
|
452
527
|
|
|
@@ -573,6 +648,15 @@ export const buildServer = Effect.fn("Deploy.buildServer")(function* (
|
|
|
573
648
|
const path = yield* Path.Path;
|
|
574
649
|
const conditions = yield* serverConditions();
|
|
575
650
|
const discovered = yield* discoverServerFunctions(appDirectory, functionModules);
|
|
651
|
+
const crypto = yield* Crypto.Crypto;
|
|
652
|
+
const environmentArtifact = {
|
|
653
|
+
formatVersion: 1,
|
|
654
|
+
nonce: Encoding.encodeBase64Url(yield* crypto.randomBytes(32)),
|
|
655
|
+
values: discovered.environment.values,
|
|
656
|
+
} satisfies EnvironmentArtifact;
|
|
657
|
+
const environmentBytes = utf8Bytes(
|
|
658
|
+
`${encodeCanonical(EnvironmentArtifact, environmentArtifact)}\n`,
|
|
659
|
+
);
|
|
576
660
|
|
|
577
661
|
yield* fileSystem.makeDirectory(outputDirectory, { recursive: true });
|
|
578
662
|
const encodedSnapshot = encodeSchemaSnapshot(discovered.schema);
|
|
@@ -584,7 +668,11 @@ export const buildServer = Effect.fn("Deploy.buildServer")(function* (
|
|
|
584
668
|
{ concurrency: 4 },
|
|
585
669
|
);
|
|
586
670
|
const manifest = {
|
|
587
|
-
formatVersion:
|
|
671
|
+
formatVersion: 3,
|
|
672
|
+
environment: {
|
|
673
|
+
artifact: yield* artifactReference(serverEnvironmentPath, environmentBytes),
|
|
674
|
+
fields: discovered.environment.fields,
|
|
675
|
+
},
|
|
588
676
|
schema: yield* artifactReference(schemaSnapshotPath, snapshotBytes),
|
|
589
677
|
functions,
|
|
590
678
|
} satisfies ServerBuildManifest;
|
|
@@ -598,6 +686,7 @@ export const buildServer = Effect.fn("Deploy.buildServer")(function* (
|
|
|
598
686
|
);
|
|
599
687
|
|
|
600
688
|
return {
|
|
689
|
+
environment: { bytes: environmentBytes, path: serverEnvironmentPath },
|
|
601
690
|
functions: functions.length,
|
|
602
691
|
manifestPath,
|
|
603
692
|
} satisfies ServerBuildResult;
|
package/src/cli/codegen.ts
CHANGED
|
@@ -41,6 +41,7 @@ const isFunctionModuleFile = (fileName: string): boolean =>
|
|
|
41
41
|
!fileName.endsWith(".test.ts") &&
|
|
42
42
|
!fileName.endsWith(".spec.ts") &&
|
|
43
43
|
fileName !== "index.ts" &&
|
|
44
|
+
fileName !== "env.ts" &&
|
|
44
45
|
fileName !== "schema.ts" &&
|
|
45
46
|
!fileName.startsWith("_");
|
|
46
47
|
|
|
@@ -57,13 +58,13 @@ const moduleNameFromFile = (filePath: string, fileName: string) => {
|
|
|
57
58
|
);
|
|
58
59
|
};
|
|
59
60
|
|
|
60
|
-
const renderServerBindings = (): string => `${generatedHeader}
|
|
61
|
+
const renderServerBindings = (hasEnvironment: boolean): string => `${generatedHeader}
|
|
61
62
|
|
|
62
63
|
import { bindSchema } from "ignotum/internal/server";
|
|
63
64
|
|
|
64
|
-
import schema from "../server/schema.js";
|
|
65
|
+
${hasEnvironment ? 'import environment from "../server/env.js";\n' : ""}import schema from "../server/schema.js";
|
|
65
66
|
|
|
66
|
-
export const { mutation, query, values } = bindSchema(schema);
|
|
67
|
+
export const { mutation, query, values } = bindSchema(schema${hasEnvironment ? ", environment" : ""});
|
|
67
68
|
`;
|
|
68
69
|
|
|
69
70
|
const renderTypes = (): string => `${generatedHeader}
|
|
@@ -157,6 +158,7 @@ export const generate = Effect.fn("Codegen.generate")(function* (appDirectory: s
|
|
|
157
158
|
const path = yield* Path.Path;
|
|
158
159
|
const serverDirectory = path.join(appDirectory, "server");
|
|
159
160
|
const schemaPath = path.join(serverDirectory, "schema.ts");
|
|
161
|
+
const environmentPath = path.join(serverDirectory, "env.ts");
|
|
160
162
|
const schemaExists = yield* fileSystem.exists(schemaPath);
|
|
161
163
|
|
|
162
164
|
if (!schemaExists) {
|
|
@@ -167,13 +169,14 @@ export const generate = Effect.fn("Codegen.generate")(function* (appDirectory: s
|
|
|
167
169
|
}
|
|
168
170
|
|
|
169
171
|
const entries = yield* fileSystem.readDirectory(serverDirectory);
|
|
172
|
+
const hasEnvironment = yield* fileSystem.exists(environmentPath);
|
|
170
173
|
const functionFiles = Array.sort(String.Order)(Array.filter(entries, isFunctionModuleFile));
|
|
171
174
|
const functionModules = yield* Effect.forEach(functionFiles, (fileName) =>
|
|
172
175
|
moduleNameFromFile(path.join(serverDirectory, fileName), fileName),
|
|
173
176
|
);
|
|
174
177
|
const outputs: ReadonlyArray<GeneratedOutput> = [
|
|
175
178
|
{
|
|
176
|
-
content: renderServerBindings(),
|
|
179
|
+
content: renderServerBindings(hasEnvironment),
|
|
177
180
|
path: path.join(appDirectory, "_generated", "server.ts"),
|
|
178
181
|
},
|
|
179
182
|
{
|
|
@@ -102,11 +102,12 @@ export class ControlClientUnavailable extends Schema.TaggedError<ControlClientUn
|
|
|
102
102
|
) {}
|
|
103
103
|
|
|
104
104
|
export interface DeploymentUploadFile {
|
|
105
|
+
readonly bytes?: Uint8Array;
|
|
105
106
|
readonly contentType: string;
|
|
106
107
|
readonly path: string;
|
|
107
108
|
readonly sha256: string;
|
|
108
109
|
readonly size: number;
|
|
109
|
-
readonly sourcePath
|
|
110
|
+
readonly sourcePath?: string;
|
|
110
111
|
}
|
|
111
112
|
|
|
112
113
|
interface ControlClientService {
|
|
@@ -168,6 +169,7 @@ export const deploymentUploadFiles = Effect.fn("ControlClient.deploymentUploadFi
|
|
|
168
169
|
inventorySha256: string,
|
|
169
170
|
inventorySize: number,
|
|
170
171
|
buildDirectory: string,
|
|
172
|
+
memoryFiles: ReadonlyMap<string, Uint8Array> = new Map(),
|
|
171
173
|
) {
|
|
172
174
|
const path = yield* Path.Path;
|
|
173
175
|
return [
|
|
@@ -178,7 +180,18 @@ export const deploymentUploadFiles = Effect.fn("ControlClient.deploymentUploadFi
|
|
|
178
180
|
size: inventorySize,
|
|
179
181
|
sourcePath: path.join(buildDirectory, deploymentInventoryPath),
|
|
180
182
|
},
|
|
181
|
-
...inventory.files.map((file) =>
|
|
183
|
+
...inventory.files.map((file) => {
|
|
184
|
+
const bytes = memoryFiles.get(file.path);
|
|
185
|
+
return bytes === undefined
|
|
186
|
+
? uploadFile(file, path.join(buildDirectory, file.path))
|
|
187
|
+
: {
|
|
188
|
+
bytes,
|
|
189
|
+
contentType: file.contentType,
|
|
190
|
+
path: file.path,
|
|
191
|
+
sha256: file.sha256,
|
|
192
|
+
size: file.size,
|
|
193
|
+
};
|
|
194
|
+
}),
|
|
182
195
|
];
|
|
183
196
|
});
|
|
184
197
|
|
|
@@ -304,17 +317,26 @@ export const controlClientLayer = Layer.effect(
|
|
|
304
317
|
deploymentId: DeploymentId,
|
|
305
318
|
file: DeploymentUploadFile,
|
|
306
319
|
) {
|
|
307
|
-
const
|
|
320
|
+
const baseRequest = HttpClientRequest.put(
|
|
308
321
|
endpoint(config.apiUrl, controlDeploymentFilePath(appId, deploymentId, file.path)),
|
|
309
322
|
).pipe(
|
|
310
323
|
HttpClientRequest.setHeader(controlUploadHeaderNames.contentLength, String(file.size)),
|
|
311
324
|
HttpClientRequest.setHeader(controlUploadHeaderNames.sha256, file.sha256),
|
|
312
|
-
HttpClientRequest.bodyFile(file.sourcePath, { contentType: file.contentType }),
|
|
313
|
-
Effect.provideService(FileSystem.FileSystem, fileSystem),
|
|
314
|
-
Effect.mapError((cause) =>
|
|
315
|
-
unavailable(`Deployment file '${file.path}' could not be opened.`, cause),
|
|
316
|
-
),
|
|
317
325
|
);
|
|
326
|
+
const request = yield* file.bytes === undefined
|
|
327
|
+
? file.sourcePath === undefined
|
|
328
|
+
? Effect.fail(unavailable(`Deployment file '${file.path}' has no upload source.`, {}))
|
|
329
|
+
: HttpClientRequest.bodyFile(baseRequest, file.sourcePath, {
|
|
330
|
+
contentType: file.contentType,
|
|
331
|
+
}).pipe(
|
|
332
|
+
Effect.provideService(FileSystem.FileSystem, fileSystem),
|
|
333
|
+
Effect.mapError((cause) =>
|
|
334
|
+
unavailable(`Deployment file '${file.path}' could not be opened.`, cause),
|
|
335
|
+
),
|
|
336
|
+
)
|
|
337
|
+
: Effect.succeed(
|
|
338
|
+
HttpClientRequest.bodyUint8Array(baseRequest, file.bytes, file.contentType),
|
|
339
|
+
);
|
|
318
340
|
const response = yield* executeIdempotent(request, DeploymentFileUploadResponse);
|
|
319
341
|
return response.status;
|
|
320
342
|
});
|
package/src/cli/deploy.ts
CHANGED
|
@@ -22,6 +22,7 @@ export interface DeploymentBuildResult {
|
|
|
22
22
|
readonly inventory: DeploymentInventory;
|
|
23
23
|
readonly inventoryBytes: Uint8Array;
|
|
24
24
|
readonly outputDirectory: string;
|
|
25
|
+
readonly memoryFiles?: ReadonlyMap<string, Uint8Array>;
|
|
25
26
|
readonly serverFunctions: number;
|
|
26
27
|
}
|
|
27
28
|
|
|
@@ -119,13 +120,15 @@ export const buildDeploymentArtifact = Effect.fn("Deploy.buildArtifact")(functio
|
|
|
119
120
|
const serverOutput = path.join(stagingDirectory, "server");
|
|
120
121
|
const client = yield* buildClient(appDirectory, clientOutput);
|
|
121
122
|
const server = yield* buildServer(appDirectory, serverOutput, codegen.functionModules);
|
|
122
|
-
const
|
|
123
|
+
const diskPayloadFiles = yield* readArtifactDirectory(stagingDirectory);
|
|
124
|
+
const payloadFiles = [...diskPayloadFiles, server.environment];
|
|
123
125
|
const inventory = yield* makeDeploymentInventory(payloadFiles);
|
|
124
126
|
yield* fileSystem.writeFile(
|
|
125
127
|
path.join(stagingDirectory, deploymentInventoryPath),
|
|
126
128
|
inventory.bytes,
|
|
127
129
|
);
|
|
128
|
-
const
|
|
130
|
+
const diskArtifactFiles = yield* readArtifactDirectory(stagingDirectory);
|
|
131
|
+
const artifactFiles = [...diskArtifactFiles, server.environment];
|
|
129
132
|
yield* validateDeploymentArtifact(artifactFiles);
|
|
130
133
|
yield* Effect.logInfo("Built deployment artifact").pipe(
|
|
131
134
|
Effect.annotateLogs({
|
|
@@ -140,6 +143,7 @@ export const buildDeploymentArtifact = Effect.fn("Deploy.buildArtifact")(functio
|
|
|
140
143
|
clientAssets: client.assets,
|
|
141
144
|
inventory: inventory.inventory,
|
|
142
145
|
inventoryBytes: inventory.bytes,
|
|
146
|
+
memoryFiles: new Map([[server.environment.path, server.environment.bytes]]),
|
|
143
147
|
outputDirectory: buildDirectory,
|
|
144
148
|
serverFunctions: server.functions,
|
|
145
149
|
} satisfies DeploymentBuildResult;
|
|
@@ -158,6 +162,7 @@ export const uploadDeployment = Effect.fn("Deploy.upload")(function* (
|
|
|
158
162
|
inventorySha256,
|
|
159
163
|
build.inventoryBytes.byteLength,
|
|
160
164
|
build.outputDirectory,
|
|
165
|
+
build.memoryFiles,
|
|
161
166
|
);
|
|
162
167
|
const deployment = yield* control.beginDeployment(configuration.appId, build.inventory);
|
|
163
168
|
|