ignotum 0.0.2 → 0.0.4
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 +23 -7
- package/dist/cli/bin.mjs +32313 -751
- package/dist/cli/bin.mjs.map +1 -1
- package/dist/runtime/{api-Cpx57mk3.d.ts → api-D2bsAz4T.d.ts} +3 -2
- package/dist/runtime/{api-BXXIZc_Q.js → api-DtX8qPrq.js} +58 -27
- package/dist/runtime/api-DtX8qPrq.js.map +1 -0
- package/dist/runtime/client.d.ts +11 -4
- package/dist/runtime/client.js +343 -79
- package/dist/runtime/client.js.map +1 -1
- package/dist/runtime/{result-B2W-z2wG.js → descriptor-t6BOEGw9-BTHR-ZMv.js} +119 -4
- package/dist/runtime/descriptor-t6BOEGw9-BTHR-ZMv.js.map +1 -0
- package/dist/runtime/id-Btwac71X-B9OeBzvq.d.ts +9 -0
- package/dist/runtime/id-D570vudg.js +26 -0
- package/dist/runtime/id-D570vudg.js.map +1 -0
- package/dist/runtime/{index-BgWROoyk.d.ts → index-Dl_VQGmA.d.ts} +114 -31
- package/dist/runtime/internal/api.d.ts +1 -1
- package/dist/runtime/internal/api.js +1 -1
- package/dist/runtime/internal/host.d.ts +44 -0
- package/dist/runtime/internal/host.js +213 -0
- package/dist/runtime/internal/host.js.map +1 -0
- 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/{result-C1ZdsM6Y.d.ts → result-BgcHn25t.d.ts} +21 -6
- package/dist/runtime/schema-B-jMZEbs.js +227 -0
- package/dist/runtime/schema-B-jMZEbs.js.map +1 -0
- package/dist/runtime/server.d.ts +2 -2
- package/dist/runtime/server.js +2 -2
- package/package.json +15 -5
- package/src/cli/agent-files.ts +6 -2
- package/src/cli/app-configuration.ts +135 -0
- package/src/cli/bin.ts +24 -1
- package/src/cli/build/artifact.ts +95 -0
- package/src/cli/build/client.ts +103 -0
- package/src/cli/build/server.ts +526 -0
- package/src/cli/client-config.ts +141 -0
- package/src/cli/client-entry.ts +152 -0
- package/src/cli/client-plugin.ts +86 -16
- package/src/cli/codegen.ts +5 -5
- package/src/cli/command.ts +41 -9
- package/src/cli/control-client.ts +343 -0
- package/src/cli/deploy.ts +217 -0
- package/src/cli/dev.ts +43 -108
- package/src/cli/module-boundaries.ts +183 -0
- package/src/cli/{new-project.ts → new-app.ts} +86 -86
- package/src/cli/package-manager.ts +9 -9
- package/src/client/app.ts +15 -0
- package/src/client/errors.ts +1 -17
- package/src/client/index.ts +2 -0
- package/src/client/sync.ts +172 -120
- package/src/dev-runtime/database.ts +253 -96
- package/src/dev-runtime/dev-database.ts +14 -14
- package/src/dev-runtime/functions.ts +57 -88
- package/src/dev-runtime/id.ts +2 -10
- package/src/dev-runtime/migrations.ts +68 -0
- package/src/dev-runtime/sync.ts +266 -83
- package/src/internal/function-definition.ts +77 -0
- package/src/internal/host.ts +1 -0
- package/src/internal/http-paths.ts +3 -1
- package/dist/runtime/api-BXXIZc_Q.js.map +0 -1
- package/dist/runtime/result-B2W-z2wG.js.map +0 -1
- package/dist/runtime/schema-CNEVLF7D.js +0 -116
- package/dist/runtime/schema-CNEVLF7D.js.map +0 -1
|
@@ -6,12 +6,11 @@ import {
|
|
|
6
6
|
type FunctionKind,
|
|
7
7
|
type FunctionResolutionError,
|
|
8
8
|
} from "@ignotum/contracts/runtime/functions";
|
|
9
|
-
import {
|
|
10
|
-
getFunctionSchema,
|
|
11
|
-
type FunctionSchemaCarrier,
|
|
12
|
-
type RuntimeSchemaDefinition,
|
|
13
|
-
} from "@ignotum/contracts/runtime/schema";
|
|
9
|
+
import { type RuntimeSchemaDefinition } from "@ignotum/contracts/runtime/schema";
|
|
14
10
|
import { ErrorValueSchema, type ErrorValue } from "@ignotum/contracts/runtime/result";
|
|
11
|
+
import { RequestId } from "@ignotum/contracts/runtime/id";
|
|
12
|
+
import { IdGenerator } from "@ignotum/shared/id";
|
|
13
|
+
import type { RuntimeInvocationResult } from "@ignotum/contracts/runtime/hosted";
|
|
15
14
|
import {
|
|
16
15
|
FunctionAddress,
|
|
17
16
|
apiFunctionParts,
|
|
@@ -22,34 +21,21 @@ import {
|
|
|
22
21
|
} from "@ignotum/contracts/runtime/sync";
|
|
23
22
|
import { FunctionRuntime } from "@ignotum/runtime/functions";
|
|
24
23
|
import { Cause, Context, Effect, Layer, Path, Predicate, Schema, Semaphore } from "effect";
|
|
25
|
-
import { nanoid } from "nanoid";
|
|
26
24
|
import type { ViteDevServer } from "vite";
|
|
27
25
|
import { normalizePath } from "vite";
|
|
28
26
|
|
|
29
27
|
import { LocalDatabase, type LocalMutationContext, type LocalQueryContext } from "./database.js";
|
|
28
|
+
import {
|
|
29
|
+
inspectRuntimeFunctionDefinition,
|
|
30
|
+
type FunctionArguments,
|
|
31
|
+
type RuntimeFunctionDefinition as InternalRuntimeFunctionDefinition,
|
|
32
|
+
} from "../internal/function-definition.js";
|
|
30
33
|
|
|
31
34
|
export { FunctionUnavailable, InvalidArguments, UnknownFunction, WrongFunctionKind };
|
|
32
|
-
export type { FunctionKind };
|
|
33
|
-
|
|
34
|
-
type RuntimeFields = Readonly<Record<string, Schema.ConstraintDecoder<unknown>>>;
|
|
35
|
-
|
|
36
|
-
declare const FunctionArgumentsTypeId: unique symbol;
|
|
37
|
-
export interface FunctionArguments {
|
|
38
|
-
readonly [FunctionArgumentsTypeId]?: never;
|
|
39
|
-
}
|
|
35
|
+
export type { FunctionArguments, FunctionKind };
|
|
40
36
|
|
|
41
37
|
export type RuntimeHandlerContext = LocalMutationContext | LocalQueryContext;
|
|
42
|
-
|
|
43
|
-
export interface RuntimeFunctionDefinition {
|
|
44
|
-
readonly _tag: FunctionKind;
|
|
45
|
-
readonly args?: RuntimeFields;
|
|
46
|
-
readonly returns?: Schema.Codec<unknown, unknown>;
|
|
47
|
-
readonly errors?: Schema.Codec<unknown, unknown>;
|
|
48
|
-
readonly handler: (
|
|
49
|
-
context: RuntimeHandlerContext,
|
|
50
|
-
args: FunctionArguments,
|
|
51
|
-
) => Generator<Effect.Effect<unknown, ErrorValue, never>, TransportValue | void, never>;
|
|
52
|
-
}
|
|
38
|
+
export type RuntimeFunctionDefinition = InternalRuntimeFunctionDefinition<RuntimeHandlerContext>;
|
|
53
39
|
|
|
54
40
|
export interface ResolvedFunction {
|
|
55
41
|
readonly definition: RuntimeFunctionDefinition;
|
|
@@ -57,52 +43,6 @@ export interface ResolvedFunction {
|
|
|
57
43
|
readonly schema: RuntimeSchemaDefinition;
|
|
58
44
|
}
|
|
59
45
|
|
|
60
|
-
interface RuntimeFunctionCandidate extends FunctionSchemaCarrier {
|
|
61
|
-
readonly _tag?: unknown;
|
|
62
|
-
readonly args?: unknown;
|
|
63
|
-
readonly returns?: unknown;
|
|
64
|
-
readonly errors?: unknown;
|
|
65
|
-
readonly handler?: unknown;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
const inspectRuntimeFunctionDefinition = (
|
|
69
|
-
value: RuntimeFunctionCandidate,
|
|
70
|
-
):
|
|
71
|
-
| { readonly definition: RuntimeFunctionDefinition; readonly schema: RuntimeSchemaDefinition }
|
|
72
|
-
| undefined => {
|
|
73
|
-
const schema = getFunctionSchema(value);
|
|
74
|
-
if (
|
|
75
|
-
schema === undefined ||
|
|
76
|
-
!Predicate.hasProperty(value, "_tag") ||
|
|
77
|
-
(value._tag !== "Mutation" && value._tag !== "Query") ||
|
|
78
|
-
(Predicate.hasProperty(value, "args") &&
|
|
79
|
-
value.args !== undefined &&
|
|
80
|
-
!Predicate.isObject(value.args)) ||
|
|
81
|
-
(Predicate.hasProperty(value, "returns") &&
|
|
82
|
-
value.returns !== undefined &&
|
|
83
|
-
!Schema.isSchema(value.returns)) ||
|
|
84
|
-
(Predicate.hasProperty(value, "errors") &&
|
|
85
|
-
value.errors !== undefined &&
|
|
86
|
-
!Schema.isSchema(value.errors)) ||
|
|
87
|
-
!Predicate.hasProperty(value, "handler") ||
|
|
88
|
-
!Predicate.isFunction(value.handler)
|
|
89
|
-
) {
|
|
90
|
-
return undefined;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
if (
|
|
94
|
-
Predicate.hasProperty(value, "args") &&
|
|
95
|
-
Predicate.isObject(value.args) &&
|
|
96
|
-
!Object.values(value.args).every(Schema.isSchema)
|
|
97
|
-
) {
|
|
98
|
-
return undefined;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
// SAFETY: every RuntimeFunctionDefinition property and argument Schema was
|
|
102
|
-
// checked above. Predicate.hasProperty does not retain the literal tag type.
|
|
103
|
-
return { definition: value as RuntimeFunctionDefinition, schema };
|
|
104
|
-
};
|
|
105
|
-
|
|
106
46
|
export class FunctionRegistry extends Context.Service<
|
|
107
47
|
FunctionRegistry,
|
|
108
48
|
{
|
|
@@ -113,7 +53,7 @@ export class FunctionRegistry extends Context.Service<
|
|
|
113
53
|
) => Effect.Effect<ResolvedFunction, FunctionResolutionError>;
|
|
114
54
|
}
|
|
115
55
|
>()("ignotum/dev-runtime/functions/FunctionRegistry") {
|
|
116
|
-
static layer(server: ViteDevServer,
|
|
56
|
+
static layer(server: ViteDevServer, appDirectory: string) {
|
|
117
57
|
return Layer.effect(
|
|
118
58
|
FunctionRegistry,
|
|
119
59
|
Effect.gen(function* () {
|
|
@@ -121,9 +61,7 @@ export class FunctionRegistry extends Context.Service<
|
|
|
121
61
|
return FunctionRegistry.of({
|
|
122
62
|
resolve: Effect.fn("FunctionRegistry.resolve")(function* (functionAddress, kind, args) {
|
|
123
63
|
const { functionName, moduleName } = apiFunctionParts(functionAddress);
|
|
124
|
-
const modulePath = normalizePath(
|
|
125
|
-
path.join(projectDirectory, "server", `${moduleName}.ts`),
|
|
126
|
-
);
|
|
64
|
+
const modulePath = normalizePath(path.join(appDirectory, "server", `${moduleName}.ts`));
|
|
127
65
|
const loadedModule = yield* Effect.tryPromise({
|
|
128
66
|
try: () => server.ssrLoadModule(modulePath),
|
|
129
67
|
catch: (cause) =>
|
|
@@ -136,7 +74,7 @@ export class FunctionRegistry extends Context.Service<
|
|
|
136
74
|
const candidate = loadedModule[functionName];
|
|
137
75
|
|
|
138
76
|
const inspected = Predicate.isObject(candidate)
|
|
139
|
-
? inspectRuntimeFunctionDefinition(candidate)
|
|
77
|
+
? inspectRuntimeFunctionDefinition<RuntimeHandlerContext>(candidate)
|
|
140
78
|
: undefined;
|
|
141
79
|
if (inspected === undefined) {
|
|
142
80
|
return yield* UnknownFunction.make({
|
|
@@ -186,13 +124,14 @@ export class FunctionExecutor extends Context.Service<
|
|
|
186
124
|
functionAddress: FunctionAddress,
|
|
187
125
|
kind: FunctionKind,
|
|
188
126
|
resolved: ResolvedFunction,
|
|
189
|
-
) => Effect.Effect<
|
|
127
|
+
) => Effect.Effect<RuntimeInvocationResult>;
|
|
190
128
|
}
|
|
191
129
|
>()("ignotum/dev-runtime/functions/FunctionExecutor") {
|
|
192
130
|
static readonly layer = Layer.effect(
|
|
193
131
|
FunctionExecutor,
|
|
194
132
|
Effect.gen(function* () {
|
|
195
133
|
const database = yield* LocalDatabase;
|
|
134
|
+
const ids = yield* IdGenerator;
|
|
196
135
|
const mutationSemaphore = yield* Semaphore.make(1);
|
|
197
136
|
|
|
198
137
|
const encodeSuccess = (
|
|
@@ -235,10 +174,19 @@ export class FunctionExecutor extends Context.Service<
|
|
|
235
174
|
|
|
236
175
|
const execution =
|
|
237
176
|
kind === "Query"
|
|
238
|
-
? database.
|
|
177
|
+
? database.trackedQueryTransaction(resolved.schema, invoke).pipe(
|
|
178
|
+
Effect.map(
|
|
179
|
+
({ dependencies, observedRevision, value }): RuntimeInvocationResult => ({
|
|
180
|
+
type: "Query",
|
|
181
|
+
result: value,
|
|
182
|
+
dependencies,
|
|
183
|
+
observedRevision,
|
|
184
|
+
}),
|
|
185
|
+
),
|
|
186
|
+
)
|
|
239
187
|
: mutationSemaphore.withPermits(1)(
|
|
240
188
|
database
|
|
241
|
-
.
|
|
189
|
+
.trackedMutationTransaction(resolved.schema, (context) =>
|
|
242
190
|
invoke(context).pipe(
|
|
243
191
|
Effect.flatMap((result) =>
|
|
244
192
|
result.type === "Failure"
|
|
@@ -248,9 +196,20 @@ export class FunctionExecutor extends Context.Service<
|
|
|
248
196
|
),
|
|
249
197
|
)
|
|
250
198
|
.pipe(
|
|
199
|
+
Effect.map(
|
|
200
|
+
({ committedRevision, invalidations, value }): RuntimeInvocationResult => ({
|
|
201
|
+
type: "Mutation",
|
|
202
|
+
result: value,
|
|
203
|
+
invalidations,
|
|
204
|
+
committedRevision,
|
|
205
|
+
}),
|
|
206
|
+
),
|
|
251
207
|
Effect.catchTags({
|
|
252
208
|
MutationApplicationFailure: ({ error }) =>
|
|
253
|
-
Effect.succeed({
|
|
209
|
+
Effect.succeed<RuntimeInvocationResult>({
|
|
210
|
+
type: "Mutation",
|
|
211
|
+
result: { type: "Failure", error },
|
|
212
|
+
}),
|
|
254
213
|
}),
|
|
255
214
|
),
|
|
256
215
|
);
|
|
@@ -259,16 +218,26 @@ export class FunctionExecutor extends Context.Service<
|
|
|
259
218
|
Effect.orDie,
|
|
260
219
|
Effect.catchCauseIf(
|
|
261
220
|
(cause) => !Cause.hasInterruptsOnly(cause),
|
|
262
|
-
(cause) =>
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
Effect.
|
|
266
|
-
|
|
221
|
+
(cause) =>
|
|
222
|
+
Effect.gen(function* () {
|
|
223
|
+
const requestId = yield* ids.generate(RequestId);
|
|
224
|
+
yield* Effect.logError(`${functionAddress} failed during execution.`).pipe(
|
|
225
|
+
Effect.annotateLogs({ cause, function: functionAddress, requestId }),
|
|
226
|
+
);
|
|
227
|
+
const result = {
|
|
267
228
|
type: "Failure" as const,
|
|
268
229
|
error: { _tag: "InternalServerError", requestId },
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
|
|
230
|
+
};
|
|
231
|
+
if (kind === "Mutation") {
|
|
232
|
+
return { type: "Mutation" as const, result };
|
|
233
|
+
}
|
|
234
|
+
return {
|
|
235
|
+
type: "Query" as const,
|
|
236
|
+
result,
|
|
237
|
+
dependencies: [],
|
|
238
|
+
observedRevision: yield* database.revision,
|
|
239
|
+
};
|
|
240
|
+
}),
|
|
272
241
|
),
|
|
273
242
|
);
|
|
274
243
|
}),
|
package/src/dev-runtime/id.ts
CHANGED
|
@@ -1,11 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { IdGenerator } from "@ignotum/runtime/id";
|
|
3
|
-
import { Effect, Layer } from "effect";
|
|
4
|
-
import { customAlphabet } from "nanoid";
|
|
1
|
+
import { IdGenerator } from "@ignotum/shared/id";
|
|
5
2
|
|
|
6
|
-
export const idGeneratorLayer =
|
|
7
|
-
const nanoid = customAlphabet(IdAlphabet, IdLength);
|
|
8
|
-
return IdGenerator.of({
|
|
9
|
-
generate: Effect.sync(() => GeneratedId.make(nanoid())),
|
|
10
|
-
});
|
|
11
|
-
});
|
|
3
|
+
export const idGeneratorLayer = IdGenerator.layer;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { Context, Effect, Layer } from "effect";
|
|
2
|
+
import * as Migrator from "effect/unstable/sql/Migrator";
|
|
3
|
+
import * as SqlClient from "effect/unstable/sql/SqlClient";
|
|
4
|
+
|
|
5
|
+
const initialDevelopmentSchema = Effect.gen(function* () {
|
|
6
|
+
const sql = yield* SqlClient.SqlClient;
|
|
7
|
+
yield* sql`
|
|
8
|
+
CREATE TABLE tables (
|
|
9
|
+
id TEXT PRIMARY KEY NOT NULL
|
|
10
|
+
CHECK (
|
|
11
|
+
length(id) = 30
|
|
12
|
+
AND substr(id, 1, 6) = 'table_'
|
|
13
|
+
AND substr(id, 7) NOT GLOB '*[^0-9a-z]*'
|
|
14
|
+
),
|
|
15
|
+
name TEXT NOT NULL UNIQUE
|
|
16
|
+
) STRICT
|
|
17
|
+
`;
|
|
18
|
+
yield* sql`
|
|
19
|
+
CREATE TABLE documents (
|
|
20
|
+
id TEXT NOT NULL
|
|
21
|
+
CHECK (length(id) = 24 AND id NOT GLOB '*[^0-9a-z]*'),
|
|
22
|
+
tableId TEXT NOT NULL REFERENCES tables(id) ON DELETE RESTRICT,
|
|
23
|
+
createdAt INTEGER NOT NULL,
|
|
24
|
+
updatedAt INTEGER NOT NULL,
|
|
25
|
+
fields TEXT NOT NULL CHECK (json_valid(fields)),
|
|
26
|
+
PRIMARY KEY (tableId, id)
|
|
27
|
+
) STRICT
|
|
28
|
+
`;
|
|
29
|
+
yield* sql`
|
|
30
|
+
CREATE INDEX documents_table_id_idx
|
|
31
|
+
ON documents (tableId, createdAt, id)
|
|
32
|
+
`;
|
|
33
|
+
yield* sql`
|
|
34
|
+
CREATE TABLE app_state (
|
|
35
|
+
singleton INTEGER PRIMARY KEY NOT NULL CHECK (singleton = 1),
|
|
36
|
+
revision INTEGER NOT NULL CHECK (revision >= 0)
|
|
37
|
+
) STRICT
|
|
38
|
+
`;
|
|
39
|
+
yield* sql`INSERT INTO app_state (singleton, revision) VALUES (1, 0)`;
|
|
40
|
+
yield* sql`
|
|
41
|
+
CREATE TABLE invocation_replays (
|
|
42
|
+
id TEXT PRIMARY KEY NOT NULL,
|
|
43
|
+
input TEXT NOT NULL,
|
|
44
|
+
result TEXT NOT NULL CHECK (json_valid(result))
|
|
45
|
+
) STRICT
|
|
46
|
+
`;
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
export const developmentMigrationLoader = Migrator.fromRecord({
|
|
50
|
+
"0001_initial_development_schema": initialDevelopmentSchema,
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
interface DevelopmentDatabaseService {
|
|
54
|
+
readonly migrated: true;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export class DevelopmentDatabase extends Context.Service<
|
|
58
|
+
DevelopmentDatabase,
|
|
59
|
+
DevelopmentDatabaseService
|
|
60
|
+
>()("ignotum/dev-runtime/migrations/DevelopmentDatabase") {
|
|
61
|
+
static readonly layer = Layer.effect(
|
|
62
|
+
DevelopmentDatabase,
|
|
63
|
+
Migrator.make({})({ loader: developmentMigrationLoader, table: "migrations" }).pipe(
|
|
64
|
+
Effect.orDie,
|
|
65
|
+
Effect.as(DevelopmentDatabase.of({ migrated: true })),
|
|
66
|
+
),
|
|
67
|
+
);
|
|
68
|
+
}
|