ignotum 0.0.6 → 0.0.8
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 +85 -101
- package/dist/cli/bin.mjs +1487 -168
- package/dist/cli/bin.mjs.map +1 -1
- package/dist/runtime/{api-DtX8qPrq.js → api-BTeMI5tx.js} +27 -3
- package/dist/runtime/api-BTeMI5tx.js.map +1 -0
- package/dist/runtime/{api-D2bsAz4T.d.ts → api-D9lV-5av.d.ts} +7 -10
- package/dist/runtime/client.d.ts +27 -3
- package/dist/runtime/client.js +468 -68
- package/dist/runtime/client.js.map +1 -1
- package/dist/runtime/{descriptor-t6BOEGw9-BTHR-ZMv.js → descriptor-C5VA9qRl-C338iC6l.js} +63 -5
- package/dist/runtime/descriptor-C5VA9qRl-C338iC6l.js.map +1 -0
- package/dist/runtime/file-BXf63ulU.js +166 -0
- package/dist/runtime/file-BXf63ulU.js.map +1 -0
- package/dist/runtime/{result-BgcHn25t.d.ts → id-Btwac71X-DGj0DQuu.d.ts} +56 -4
- package/dist/runtime/{index-Dl_VQGmA.d.ts → index-CF04_Dps.d.ts} +96 -86
- package/dist/runtime/internal/api.d.ts +2 -2
- package/dist/runtime/internal/api.js +1 -1
- package/dist/runtime/internal/host.d.ts +25 -8
- package/dist/runtime/internal/host.js +209 -15
- 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-BNFhAjns.d.ts +1 -0
- package/dist/runtime/pagination-DrOowBve-Bnipd34u.d.ts +84 -0
- package/dist/runtime/{schema-B-jMZEbs.js → schema-DJfwfq87.js} +108 -30
- package/dist/runtime/schema-DJfwfq87.js.map +1 -0
- package/dist/runtime/server.d.ts +3 -3
- package/dist/runtime/server.js +2 -2
- package/dist/runtime/server.js.map +1 -1
- package/dist/runtime/sync-mIXn9eKv.d.ts +8 -0
- package/package.json +2 -2
- package/src/cli/agent-files.ts +56 -13
- package/src/cli/app-configuration.ts +4 -1
- package/src/cli/build/server.ts +83 -6
- package/src/cli/new-app.ts +15 -0
- package/src/client/files.ts +168 -0
- package/src/client/hooks.ts +166 -17
- package/src/client/index.ts +9 -1
- package/src/client/sync.ts +137 -21
- package/src/dev-runtime/database.ts +621 -78
- package/src/dev-runtime/files.ts +338 -0
- package/src/dev-runtime/functions.ts +14 -6
- package/src/dev-runtime/migrations.ts +44 -0
- package/src/dev-runtime/sync.ts +123 -5
- package/src/internal/api.ts +16 -1
- package/src/server/index.ts +8 -1
- package/dist/runtime/api-DtX8qPrq.js.map +0 -1
- package/dist/runtime/descriptor-t6BOEGw9-BTHR-ZMv.js.map +0 -1
- package/dist/runtime/id-Btwac71X-B9OeBzvq.d.ts +0 -9
- package/dist/runtime/id-D570vudg.js +0 -26
- package/dist/runtime/id-D570vudg.js.map +0 -1
- package/dist/runtime/schema-B-jMZEbs.js.map +0 -1
package/dist/runtime/client.js
CHANGED
|
@@ -1,12 +1,127 @@
|
|
|
1
|
-
import { a as
|
|
2
|
-
import {
|
|
3
|
-
import { a as FunctionAddress, c as ServerMessageJson, d as WireSuccess, f as AppStateRevision, i as DeploymentChangedCloseCode, l as WireFailure, m as InvocationKey, n as functionPathOf, o as Operation, p as DeploymentGeneration, r as ClientMessageJson, s as ProtocolErrorCode, u as WireResult } from "./api-
|
|
4
|
-
import { Array, Cause, Context, Deferred, Duration, Effect, ErrorReporter, Fiber, HashMap, Layer, ManagedRuntime, Predicate, Schedule, Schema, String } from "effect";
|
|
5
|
-
import {
|
|
1
|
+
import { C as RuntimeRequestNonce, T as TableId, _ as AppId, a as RuntimeFileMetadata, b as IdAlphabet, c as fileFormats, d as fileLimits, f as fileMimeTypes, h as makeFileValue, l as fileGrantUrlOf, m as isFileValue, o as RuntimeFileOccurrence, p as grantFileValue, r as FileId, u as fileIdOf, v as DeploymentId, w as SubscriptionId, x as InvocationId, y as GeneratedId } from "./file-BXf63ulU.js";
|
|
2
|
+
import { b as decodeTransportValue, c as upgrade, d as Result$1, h as pending, m as inspectResult, o as PaginationPageSize, p as failureFromWire, s as initial, t as ValueDescriptor, x as encodeTransportObject } from "./descriptor-C5VA9qRl-C338iC6l.js";
|
|
3
|
+
import { a as FunctionAddress, c as ServerMessageJson, d as WireSuccess, f as AppStateRevision, i as DeploymentChangedCloseCode, l as WireFailure, m as InvocationKey, n as functionPathOf, o as Operation, p as DeploymentGeneration, r as ClientMessageJson, s as ProtocolErrorCode, u as WireResult } from "./api-BTeMI5tx.js";
|
|
4
|
+
import { Array as Array$1, Cause, Context, Deferred, Duration, Effect, ErrorReporter, Fiber, HashMap, Layer, ManagedRuntime, Predicate, Schedule, Schema, String } from "effect";
|
|
5
|
+
import { customAlphabet } from "nanoid";
|
|
6
|
+
import { useCallback, useCallback as useCallback$1, useContext, useDebugValue, useDebugValue as useDebugValue$1, useEffect, useEffect as useEffect$1, useErrorBoundary, useId, useImperativeHandle, useLayoutEffect, useMemo, useMemo as useMemo$1, useReducer, useRef, useState, useState as useState$1 } from "preact/hooks";
|
|
6
7
|
import * as Socket from "effect/unstable/socket/Socket";
|
|
7
8
|
import * as BrowserCrypto from "@effect/platform-browser/BrowserCrypto";
|
|
8
|
-
import { customAlphabet } from "nanoid";
|
|
9
9
|
import { Component, Fragment, cloneElement, createContext, createElement, createRef, h, isValidElement, toChildArray } from "preact";
|
|
10
|
+
//#region ../shared/dist/id.js
|
|
11
|
+
const decodeGenerated = (definition, payload) => Schema.decodeSync(definition)(definition.idPrefix === void 0 ? payload : `${definition.idPrefix}_${payload}`);
|
|
12
|
+
var IdGenerator = class IdGenerator extends Context.Service()("@ignotum/shared/id/IdGenerator") {
|
|
13
|
+
static layer = Layer.sync(IdGenerator, () => {
|
|
14
|
+
const generatePayload = customAlphabet(IdAlphabet, 24);
|
|
15
|
+
return IdGenerator.of({ generate: (definition) => Effect.sync(() => decodeGenerated(definition, generatePayload())) });
|
|
16
|
+
});
|
|
17
|
+
static deterministic = (startAt = 1) => Layer.sync(IdGenerator, () => {
|
|
18
|
+
const counters = /* @__PURE__ */ new Map();
|
|
19
|
+
return IdGenerator.of({ generate: (definition) => Effect.sync(() => {
|
|
20
|
+
const counter = (counters.get(definition.idPrefix) ?? startAt - 1) + 1;
|
|
21
|
+
counters.set(definition.idPrefix, counter);
|
|
22
|
+
return decodeGenerated(definition, counter.toString(36).padStart(24, "0"));
|
|
23
|
+
}) });
|
|
24
|
+
});
|
|
25
|
+
};
|
|
26
|
+
//#endregion
|
|
27
|
+
//#region src/client/files.ts
|
|
28
|
+
const Files = { url: (file) => {
|
|
29
|
+
const url = fileGrantUrlOf(file);
|
|
30
|
+
if (url === void 0) throw new Error("This FileValue has no active query grant.");
|
|
31
|
+
return url;
|
|
32
|
+
} };
|
|
33
|
+
const formatByMime = {};
|
|
34
|
+
for (const format of fileFormats) formatByMime[fileMimeTypes[format]] = format;
|
|
35
|
+
const collectNativeFiles = (value, path, occurrences) => {
|
|
36
|
+
if (value instanceof File) {
|
|
37
|
+
occurrences.push({
|
|
38
|
+
path,
|
|
39
|
+
value
|
|
40
|
+
});
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
if (isFileValue(value) || Predicate.isDate(value)) return;
|
|
44
|
+
if (globalThis.Array.isArray(value)) {
|
|
45
|
+
for (const [index, child] of value.entries()) collectNativeFiles(child, [...path, index], occurrences);
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
if (!Predicate.isObject(value)) return;
|
|
49
|
+
for (const [key, child] of Object.entries(value)) collectNativeFiles(child, [...path, key], occurrences);
|
|
50
|
+
};
|
|
51
|
+
const replaceNativeFiles = (value, replacements) => {
|
|
52
|
+
if (value instanceof File) return replacements.get(value);
|
|
53
|
+
if (isFileValue(value) || Predicate.isDate(value)) return value;
|
|
54
|
+
if (globalThis.Array.isArray(value)) return value.map((child) => replaceNativeFiles(child, replacements));
|
|
55
|
+
if (!Predicate.isObject(value)) return value;
|
|
56
|
+
return Object.fromEntries(Object.entries(value).map(([key, child]) => [key, replaceNativeFiles(child, replacements)]));
|
|
57
|
+
};
|
|
58
|
+
const prepareMutationArguments = Effect.fn("SyncClient.prepareMutationArguments")(function* (input) {
|
|
59
|
+
const ids = yield* IdGenerator;
|
|
60
|
+
const native = [];
|
|
61
|
+
collectNativeFiles(input, [], native);
|
|
62
|
+
const unique = new Set(native.map(({ value }) => value));
|
|
63
|
+
if (unique.size > fileLimits.filesPerMutation) throw new Error(`A mutation may upload at most ${fileLimits.filesPerMutation} files.`);
|
|
64
|
+
if ([...unique].reduce((total, file) => total + file.size, 0) > fileLimits.mutationBytes) throw new Error(`Mutation uploads may total at most ${fileLimits.mutationBytes} bytes.`);
|
|
65
|
+
const replacements = /* @__PURE__ */ new Map();
|
|
66
|
+
const nativeFiles = /* @__PURE__ */ new Map();
|
|
67
|
+
for (const file of unique) {
|
|
68
|
+
const format = formatByMime[file.type.toLowerCase()];
|
|
69
|
+
if (format === void 0) throw new Error(`File '${file.name}' has unsupported media type '${file.type || "unknown"}'.`);
|
|
70
|
+
if (file.size === 0 || file.size > fileLimits.fileBytes) throw new Error(`File '${file.name}' must be between 1 and ${fileLimits.fileBytes} bytes.`);
|
|
71
|
+
if (new TextEncoder().encode(file.name).byteLength > fileLimits.filenameBytes) throw new Error(`File '${file.name}' has a filename that is too long.`);
|
|
72
|
+
const id = yield* ids.generate(FileId);
|
|
73
|
+
replacements.set(file, makeFileValue(id, {
|
|
74
|
+
format,
|
|
75
|
+
name: file.name,
|
|
76
|
+
size: file.size
|
|
77
|
+
}));
|
|
78
|
+
nativeFiles.set(id, file);
|
|
79
|
+
}
|
|
80
|
+
return {
|
|
81
|
+
value: replaceNativeFiles(input, replacements),
|
|
82
|
+
nativeFiles,
|
|
83
|
+
occurrences: native.map(({ path, value: file }) => {
|
|
84
|
+
const replacement = replacements.get(file);
|
|
85
|
+
if (replacement === void 0) throw new Error("A native file replacement is missing.");
|
|
86
|
+
return {
|
|
87
|
+
path,
|
|
88
|
+
file: {
|
|
89
|
+
id: fileIdOf(replacement),
|
|
90
|
+
format: replacement.format,
|
|
91
|
+
name: replacement.name,
|
|
92
|
+
size: replacement.size
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
})
|
|
96
|
+
};
|
|
97
|
+
});
|
|
98
|
+
const pathKey = (path) => JSON.stringify(path);
|
|
99
|
+
const applyFileGrants = (value, grants) => {
|
|
100
|
+
const byPath = new Map(grants.map((grant) => [pathKey(grant.path), grant]));
|
|
101
|
+
const visit = (current, path) => {
|
|
102
|
+
const grant = byPath.get(pathKey(path));
|
|
103
|
+
if (grant !== void 0) {
|
|
104
|
+
if (!isFileValue(current) || fileIdOf(current) !== grant.file.id) throw new Error("A query file grant does not match its result value.");
|
|
105
|
+
return grantFileValue(current, grant.url);
|
|
106
|
+
}
|
|
107
|
+
if (globalThis.Array.isArray(current)) return current.map((child, index) => visit(child, [...path, index]));
|
|
108
|
+
if (!Predicate.isObject(current) || Predicate.isDate(current) || isFileValue(current)) return current;
|
|
109
|
+
return Object.fromEntries(Object.entries(current).map(([key, child]) => [key, visit(child, [...path, key])]));
|
|
110
|
+
};
|
|
111
|
+
return visit(value, []);
|
|
112
|
+
};
|
|
113
|
+
//#endregion
|
|
114
|
+
//#region ../contracts/dist/json.js
|
|
115
|
+
const encodeScalar = (value) => Schema.decodeSync(Schema.String)(JSON.stringify(value));
|
|
116
|
+
const encodeCanonicalJson = (value) => {
|
|
117
|
+
if (value === null || Predicate.isString(value) || Predicate.isNumber(value) || Predicate.isBoolean(value)) return encodeScalar(value);
|
|
118
|
+
if (Predicate.isObject(value)) return `{${Array$1.map(Array$1.sort(String.Order)(Object.keys(value)), (key) => {
|
|
119
|
+
const field = Schema.decodeUnknownSync(Schema.Json)(value[key]);
|
|
120
|
+
return `${encodeScalar(key)}:${encodeCanonicalJson(field)}`;
|
|
121
|
+
}).join(",")}}`;
|
|
122
|
+
return `[${Schema.decodeUnknownSync(Schema.Array(Schema.Json))(value).map(encodeCanonicalJson).join(",")}]`;
|
|
123
|
+
};
|
|
124
|
+
//#endregion
|
|
10
125
|
//#region src/client/errors.ts
|
|
11
126
|
/** @effect-diagnostics globalConsole:skip-file */
|
|
12
127
|
var ConnectionUnavailable = class extends Schema.TaggedError()("ConnectionUnavailable", {
|
|
@@ -55,16 +170,14 @@ const skip = Object.freeze(new QuerySkipToken());
|
|
|
55
170
|
const Query = { skip };
|
|
56
171
|
const isQuerySkip = (value) => value === skip;
|
|
57
172
|
//#endregion
|
|
58
|
-
//#region ../contracts/dist/
|
|
59
|
-
const
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
return `[${Schema.decodeUnknownSync(Schema.Array(Schema.Json))(value).map(encodeCanonicalJson).join(",")}]`;
|
|
67
|
-
};
|
|
173
|
+
//#region ../contracts/dist/runtime/index.js
|
|
174
|
+
const IndexIdentity = Schema.String.pipe(Schema.brand("ignotum/runtime/IndexIdentity"));
|
|
175
|
+
const EncodedIndexKey = Schema.String.check(Schema.isPattern(/^(?:[0-9a-f]{2})*$/)).pipe(Schema.brand("ignotum/runtime/EncodedIndexKey"));
|
|
176
|
+
Schema.Union([
|
|
177
|
+
Schema.Boolean,
|
|
178
|
+
Schema.Finite,
|
|
179
|
+
Schema.String
|
|
180
|
+
]);
|
|
68
181
|
Schema.String.pipe(Schema.brand("ignotum/hosted/QueryKey"));
|
|
69
182
|
const TableDependency = Schema.Struct({
|
|
70
183
|
type: Schema.Literal("Table"),
|
|
@@ -75,20 +188,71 @@ const DocumentDependency = Schema.Struct({
|
|
|
75
188
|
tableId: TableId,
|
|
76
189
|
id: GeneratedId
|
|
77
190
|
});
|
|
78
|
-
const
|
|
79
|
-
|
|
80
|
-
|
|
191
|
+
const IndexRangeDependency = Schema.Struct({
|
|
192
|
+
type: Schema.Literal("IndexRange"),
|
|
193
|
+
tableId: TableId,
|
|
194
|
+
index: IndexIdentity,
|
|
195
|
+
lower: Schema.optional(EncodedIndexKey),
|
|
196
|
+
upper: Schema.optional(EncodedIndexKey)
|
|
197
|
+
});
|
|
198
|
+
const IndexPointInvalidation = Schema.Struct({
|
|
199
|
+
type: Schema.Literal("IndexPoint"),
|
|
200
|
+
tableId: TableId,
|
|
201
|
+
index: IndexIdentity,
|
|
202
|
+
key: EncodedIndexKey
|
|
203
|
+
});
|
|
204
|
+
const ReadDependency = Schema.Union([
|
|
205
|
+
TableDependency,
|
|
206
|
+
DocumentDependency,
|
|
207
|
+
IndexRangeDependency
|
|
208
|
+
]);
|
|
209
|
+
const WriteInvalidation = Schema.Union([
|
|
210
|
+
TableDependency,
|
|
211
|
+
DocumentDependency,
|
|
212
|
+
IndexPointInvalidation
|
|
213
|
+
]);
|
|
214
|
+
Schema.Union([ReadDependency, IndexPointInvalidation]);
|
|
215
|
+
const DependencySet = Schema.Array(ReadDependency);
|
|
216
|
+
const InvalidationSet = Schema.Array(WriteInvalidation);
|
|
81
217
|
const RuntimeQueryResult = Schema.Struct({
|
|
82
218
|
type: Schema.Literal("Query"),
|
|
83
219
|
result: WireResult,
|
|
84
220
|
dependencies: DependencySet,
|
|
85
|
-
observedRevision: AppStateRevision
|
|
221
|
+
observedRevision: AppStateRevision,
|
|
222
|
+
files: Schema.optional(Schema.Array(RuntimeFileOccurrence))
|
|
223
|
+
});
|
|
224
|
+
const FileReferenceAdded = Schema.Struct({
|
|
225
|
+
type: Schema.Literal("AddReference"),
|
|
226
|
+
file: RuntimeFileMetadata,
|
|
227
|
+
tableId: TableId,
|
|
228
|
+
documentId: GeneratedId
|
|
229
|
+
});
|
|
230
|
+
const FileReferenceRemoved = Schema.Struct({
|
|
231
|
+
type: Schema.Literal("RemoveReference"),
|
|
232
|
+
fileId: FileId,
|
|
233
|
+
tableId: TableId,
|
|
234
|
+
documentId: GeneratedId
|
|
235
|
+
});
|
|
236
|
+
const FileReferenceEffect = Schema.Union([FileReferenceAdded, FileReferenceRemoved]);
|
|
237
|
+
const FileEffectBatch = Schema.Struct({
|
|
238
|
+
id: InvocationId,
|
|
239
|
+
committedRevision: AppStateRevision,
|
|
240
|
+
effects: Schema.Array(FileReferenceEffect)
|
|
86
241
|
});
|
|
242
|
+
Schema.Struct({ appId: AppId });
|
|
243
|
+
Schema.Struct({ batches: Schema.Array(FileEffectBatch) });
|
|
244
|
+
Schema.Struct({
|
|
245
|
+
appId: AppId,
|
|
246
|
+
invocationId: InvocationId,
|
|
247
|
+
acknowledgedAt: Schema.Int
|
|
248
|
+
});
|
|
249
|
+
Schema.Struct({ completed: Schema.Literal(true) });
|
|
87
250
|
const RuntimeMutationSuccess = Schema.Struct({
|
|
88
251
|
type: Schema.Literal("Mutation"),
|
|
89
252
|
result: WireSuccess,
|
|
90
253
|
invalidations: InvalidationSet,
|
|
91
|
-
committedRevision: AppStateRevision
|
|
254
|
+
committedRevision: AppStateRevision,
|
|
255
|
+
fileEffects: Schema.optional(FileEffectBatch)
|
|
92
256
|
});
|
|
93
257
|
const RuntimeMutationFailure = Schema.Struct({
|
|
94
258
|
type: Schema.Literal("Mutation"),
|
|
@@ -111,7 +275,8 @@ const QueryInvocation = Schema.Struct({
|
|
|
111
275
|
const MutationInvocation = Schema.Struct({
|
|
112
276
|
...InvocationBase,
|
|
113
277
|
type: Schema.Literal("Mutation"),
|
|
114
|
-
invocationId: InvocationId
|
|
278
|
+
invocationId: InvocationId,
|
|
279
|
+
files: Schema.optional(Schema.Array(RuntimeFileOccurrence))
|
|
115
280
|
});
|
|
116
281
|
Schema.Union([QueryInvocation, MutationInvocation]);
|
|
117
282
|
Schema.Struct({
|
|
@@ -150,23 +315,6 @@ Schema.Union([
|
|
|
150
315
|
RuntimeInvocationUnavailable
|
|
151
316
|
]);
|
|
152
317
|
//#endregion
|
|
153
|
-
//#region ../shared/dist/id.js
|
|
154
|
-
const decodeGenerated = (definition, payload) => Schema.decodeSync(definition)(definition.idPrefix === void 0 ? payload : `${definition.idPrefix}_${payload}`);
|
|
155
|
-
var IdGenerator = class IdGenerator extends Context.Service()("@ignotum/shared/id/IdGenerator") {
|
|
156
|
-
static layer = Layer.sync(IdGenerator, () => {
|
|
157
|
-
const generatePayload = customAlphabet(IdAlphabet, 24);
|
|
158
|
-
return IdGenerator.of({ generate: (definition) => Effect.sync(() => decodeGenerated(definition, generatePayload())) });
|
|
159
|
-
});
|
|
160
|
-
static deterministic = (startAt = 1) => Layer.sync(IdGenerator, () => {
|
|
161
|
-
const counters = /* @__PURE__ */ new Map();
|
|
162
|
-
return IdGenerator.of({ generate: (definition) => Effect.sync(() => {
|
|
163
|
-
const counter = (counters.get(definition.idPrefix) ?? startAt - 1) + 1;
|
|
164
|
-
counters.set(definition.idPrefix, counter);
|
|
165
|
-
return decodeGenerated(definition, counter.toString(36).padStart(24, "0"));
|
|
166
|
-
}) });
|
|
167
|
-
});
|
|
168
|
-
};
|
|
169
|
-
//#endregion
|
|
170
318
|
//#region ../contracts/dist/runtime/functions.js
|
|
171
319
|
const FunctionKind = Schema.Literals(["Mutation", "Query"]);
|
|
172
320
|
Schema.TaggedError()("UnknownFunction", {
|
|
@@ -221,47 +369,89 @@ const ClientRoute = Schema.Struct({
|
|
|
221
369
|
pathname: ClientPath,
|
|
222
370
|
artifact: ArtifactReference
|
|
223
371
|
});
|
|
224
|
-
Schema.Struct({
|
|
372
|
+
const DeploymentInventoryV1 = Schema.Struct({
|
|
225
373
|
formatVersion: Schema.Literal(1),
|
|
226
374
|
files: Schema.Array(ArtifactFile)
|
|
227
375
|
});
|
|
228
|
-
|
|
376
|
+
initial(DeploymentInventoryV1);
|
|
377
|
+
const ClientManifestV1 = Schema.Struct({
|
|
229
378
|
formatVersion: Schema.Literal(1),
|
|
230
379
|
shell: ArtifactReference,
|
|
231
380
|
routes: Schema.Array(ClientRoute)
|
|
232
381
|
});
|
|
382
|
+
initial(ClientManifestV1);
|
|
233
383
|
const ClientRoutingRoute = Schema.Struct({
|
|
234
384
|
pathname: ClientPath,
|
|
235
385
|
artifact: ArtifactPath
|
|
236
386
|
});
|
|
237
|
-
Schema.Struct({
|
|
387
|
+
const ClientRoutingV1 = Schema.Struct({
|
|
238
388
|
formatVersion: Schema.Literal(1),
|
|
239
389
|
shell: ArtifactPath,
|
|
240
390
|
routes: Schema.Array(ClientRoutingRoute)
|
|
241
391
|
});
|
|
392
|
+
initial(ClientRoutingV1);
|
|
242
393
|
const SchemaSnapshotField = Schema.Struct({
|
|
243
394
|
name: Schema.String,
|
|
244
395
|
value: ValueDescriptor
|
|
245
396
|
});
|
|
246
|
-
const
|
|
397
|
+
const SchemaSnapshotIndex = Schema.Struct({
|
|
398
|
+
name: Schema.String,
|
|
399
|
+
fields: Schema.Array(Schema.String)
|
|
400
|
+
});
|
|
401
|
+
const SchemaSnapshotTableV1 = Schema.Struct({
|
|
247
402
|
name: Schema.String,
|
|
248
403
|
fields: Schema.Array(SchemaSnapshotField)
|
|
249
404
|
});
|
|
250
|
-
Schema.Struct({
|
|
405
|
+
const SchemaSnapshotV1 = Schema.Struct({
|
|
251
406
|
formatVersion: Schema.Literal(1),
|
|
407
|
+
tables: Schema.Array(SchemaSnapshotTableV1)
|
|
408
|
+
});
|
|
409
|
+
const SchemaSnapshotTable = Schema.Struct({
|
|
410
|
+
name: Schema.String,
|
|
411
|
+
fields: Schema.Array(SchemaSnapshotField),
|
|
412
|
+
indexes: Schema.Array(SchemaSnapshotIndex)
|
|
413
|
+
});
|
|
414
|
+
const SchemaSnapshotV2 = Schema.Struct({
|
|
415
|
+
formatVersion: Schema.Literal(2),
|
|
252
416
|
tables: Schema.Array(SchemaSnapshotTable)
|
|
253
417
|
});
|
|
418
|
+
upgrade(initial(SchemaSnapshotV1), SchemaSnapshotV2, (snapshot) => ({
|
|
419
|
+
formatVersion: 2,
|
|
420
|
+
tables: snapshot.tables.map((table) => ({
|
|
421
|
+
...table,
|
|
422
|
+
indexes: []
|
|
423
|
+
}))
|
|
424
|
+
}));
|
|
425
|
+
const ServerFunctionArtifactV1 = Schema.Struct({
|
|
426
|
+
address: FunctionAddress,
|
|
427
|
+
kind: FunctionKind,
|
|
428
|
+
bundle: ArtifactReference,
|
|
429
|
+
sourceMap: ArtifactReference
|
|
430
|
+
});
|
|
254
431
|
const ServerFunctionArtifact = Schema.Struct({
|
|
255
432
|
address: FunctionAddress,
|
|
256
433
|
kind: FunctionKind,
|
|
434
|
+
args: Schema.optional(ValueDescriptor),
|
|
435
|
+
returns: Schema.optional(ValueDescriptor),
|
|
436
|
+
errors: Schema.optional(ValueDescriptor),
|
|
257
437
|
bundle: ArtifactReference,
|
|
258
438
|
sourceMap: ArtifactReference
|
|
259
439
|
});
|
|
260
|
-
Schema.Struct({
|
|
440
|
+
const ServerBuildManifestV1 = Schema.Struct({
|
|
261
441
|
formatVersion: Schema.Literal(1),
|
|
262
442
|
schema: ArtifactReference,
|
|
443
|
+
functions: Schema.Array(ServerFunctionArtifactV1)
|
|
444
|
+
});
|
|
445
|
+
const ServerBuildManifestV2 = Schema.Struct({
|
|
446
|
+
formatVersion: Schema.Literal(2),
|
|
447
|
+
schema: ArtifactReference,
|
|
263
448
|
functions: Schema.Array(ServerFunctionArtifact)
|
|
264
449
|
});
|
|
450
|
+
upgrade(initial(ServerBuildManifestV1), ServerBuildManifestV2, (manifest) => ({
|
|
451
|
+
formatVersion: 2,
|
|
452
|
+
schema: manifest.schema,
|
|
453
|
+
functions: manifest.functions
|
|
454
|
+
}));
|
|
265
455
|
ArtifactPath.make("inventory.json");
|
|
266
456
|
ArtifactPath.make("client/manifest.json");
|
|
267
457
|
ArtifactPath.make("client/shell.html");
|
|
@@ -273,8 +463,19 @@ ArtifactPath.make("server/schema.json");
|
|
|
273
463
|
//#region ../contracts/dist/runtime/transport.js
|
|
274
464
|
const runtimeInvocationPath = "/v1/invoke";
|
|
275
465
|
const runtimeRevisionPath = "/v1/revision";
|
|
466
|
+
const runtimeIndexPreparePath = "/v1/indexes/prepare";
|
|
467
|
+
const runtimeIndexCommitPath = "/v1/indexes/commit";
|
|
468
|
+
const runtimeFileEffectsPath = "/v1/files/effects";
|
|
469
|
+
const runtimeFileEffectsAcknowledgePath = "/v1/files/effects/acknowledge";
|
|
276
470
|
const appSyncPath = `/_ignotum/v1/sync`;
|
|
277
|
-
const RuntimeRequestPath = Schema.Literals([
|
|
471
|
+
const RuntimeRequestPath = Schema.Literals([
|
|
472
|
+
runtimeInvocationPath,
|
|
473
|
+
runtimeRevisionPath,
|
|
474
|
+
runtimeIndexPreparePath,
|
|
475
|
+
runtimeIndexCommitPath,
|
|
476
|
+
runtimeFileEffectsPath,
|
|
477
|
+
runtimeFileEffectsAcknowledgePath
|
|
478
|
+
]);
|
|
278
479
|
const RuntimeRequestTimestamp = Schema.FiniteFromString.pipe(Schema.check(Schema.isInt(), Schema.isGreaterThanOrEqualTo(0)), Schema.brand("ignotum/runtime/RequestTimestamp"));
|
|
279
480
|
const RuntimeRequestSignature = Sha256.pipe(Schema.brand("ignotum/runtime/RequestSignature"));
|
|
280
481
|
Schema.Struct({
|
|
@@ -293,6 +494,11 @@ Schema.Struct({
|
|
|
293
494
|
deploymentId: Schema.optional(DeploymentId),
|
|
294
495
|
bodySha256: Sha256
|
|
295
496
|
});
|
|
497
|
+
Schema.Struct({
|
|
498
|
+
appId: AppId,
|
|
499
|
+
deploymentId: DeploymentId
|
|
500
|
+
});
|
|
501
|
+
Schema.Struct({ completed: Schema.Literal(true) });
|
|
296
502
|
const RuntimeErrorCode = Schema.Literals([
|
|
297
503
|
"InvalidRequest",
|
|
298
504
|
"InvalidSignature",
|
|
@@ -391,7 +597,7 @@ const makeQueryCache = (allocateId, sendLifecycleMessage) => {
|
|
|
391
597
|
}
|
|
392
598
|
};
|
|
393
599
|
};
|
|
394
|
-
const resultFromWire = Effect.fn("SyncClient.resultFromWire")((wire) => Effect.succeed(wire.type === "Success" ? Result$1.succeed(wire.value === void 0 ? void 0 : decodeTransportValue(wire.value, wire.dates ?? [])) : failureFromWire(wire.error, wire.dates)));
|
|
600
|
+
const resultFromWire = Effect.fn("SyncClient.resultFromWire")((wire, files = []) => Effect.succeed(wire.type === "Success" ? Result$1.succeed(wire.value === void 0 ? void 0 : applyFileGrants(decodeTransportValue(wire.value, wire.dates ?? []), files)) : failureFromWire(wire.error, wire.dates)));
|
|
395
601
|
const shouldReloadForCloseCode = (code) => code === DeploymentChangedCloseCode;
|
|
396
602
|
const handshakesMatch = (first, next) => first.appId === next.appId && first.deploymentId === next.deploymentId && first.generation === next.generation;
|
|
397
603
|
const handshakeDecision = (remembered, acceptedOnConnection, next) => {
|
|
@@ -435,14 +641,19 @@ var SyncClient = class SyncClient extends Context.Service()("ignotum/client/sync
|
|
|
435
641
|
const pendingInvocation = HashMap.getUnsafe(invocations, id);
|
|
436
642
|
if (pendingInvocation === void 0) return Effect.void;
|
|
437
643
|
invocations = HashMap.remove(invocations, id);
|
|
438
|
-
return reportClientError(error).pipe(Effect.andThen(Deferred.fail(pendingInvocation.deferred, error)), Effect.asVoid);
|
|
644
|
+
return reportClientError(error).pipe(Effect.andThen(Deferred.fail(pendingInvocation.prepared, error)), Effect.andThen(Deferred.fail(pendingInvocation.deferred, error)), Effect.asVoid);
|
|
439
645
|
};
|
|
440
646
|
const handleMessage = Effect.fn("SyncClient.handleMessage")(function* (message) {
|
|
441
647
|
switch (message.type) {
|
|
442
648
|
case "Snapshot":
|
|
443
649
|
if (queryCache.getById(message.id) === void 0) return;
|
|
444
|
-
yield* resultFromWire(message.result).pipe(Effect.tap((result) => Effect.sync(() => queryCache.setResult(message.id, result, message.revision))));
|
|
650
|
+
yield* resultFromWire(message.result, message.files ?? []).pipe(Effect.tap((result) => Effect.sync(() => queryCache.setResult(message.id, result, message.revision))));
|
|
445
651
|
return;
|
|
652
|
+
case "MutationPrepared": {
|
|
653
|
+
const pendingInvocation = HashMap.getUnsafe(invocations, message.id);
|
|
654
|
+
if (pendingInvocation !== void 0) yield* Deferred.succeed(pendingInvocation.prepared, message.uploads);
|
|
655
|
+
return;
|
|
656
|
+
}
|
|
446
657
|
case "Result": {
|
|
447
658
|
const pendingInvocation = HashMap.getUnsafe(invocations, message.id);
|
|
448
659
|
if (pendingInvocation === void 0) return;
|
|
@@ -532,24 +743,94 @@ var SyncClient = class SyncClient extends Context.Service()("ignotum/client/sync
|
|
|
532
743
|
});
|
|
533
744
|
const mutate = Effect.fn("SyncClient.mutate")(function* (functionAddress, args) {
|
|
534
745
|
const invocationId = yield* ids.generate(InvocationId);
|
|
746
|
+
const preparedArguments = yield* prepareMutationArguments(args).pipe(Effect.provideService(IdGenerator, ids), Effect.mapError((cause) => InvalidMutationArguments.make({
|
|
747
|
+
cause,
|
|
748
|
+
function: functionAddress,
|
|
749
|
+
message: `Mutation arguments for ${functionAddress} contain an unsupported file or value.`
|
|
750
|
+
})), Effect.tapError(reportClientError));
|
|
751
|
+
const jsonArgs = yield* Effect.try({
|
|
752
|
+
try: () => encodeTransportObject(preparedArguments.value),
|
|
753
|
+
catch: (cause) => InvalidMutationArguments.make({
|
|
754
|
+
cause,
|
|
755
|
+
function: functionAddress,
|
|
756
|
+
message: `Mutation arguments for ${functionAddress} contain an unsupported value.`
|
|
757
|
+
})
|
|
758
|
+
}).pipe(Effect.tapError(reportClientError));
|
|
535
759
|
const deferred = yield* Deferred.make();
|
|
536
|
-
const
|
|
760
|
+
const prepared = yield* Deferred.make();
|
|
761
|
+
const invokeMessage = {
|
|
537
762
|
type: "Invoke",
|
|
538
763
|
id: invocationId,
|
|
539
764
|
kind: "Mutation",
|
|
540
765
|
function: functionAddress,
|
|
541
|
-
args
|
|
766
|
+
args: jsonArgs
|
|
767
|
+
};
|
|
768
|
+
const message = preparedArguments.occurrences.length === 0 ? invokeMessage : {
|
|
769
|
+
type: "PrepareMutation",
|
|
770
|
+
id: invocationId,
|
|
771
|
+
kind: "Mutation",
|
|
772
|
+
function: functionAddress,
|
|
773
|
+
args: jsonArgs,
|
|
774
|
+
files: preparedArguments.occurrences
|
|
542
775
|
};
|
|
543
776
|
invocations = HashMap.set(invocations, invocationId, {
|
|
544
777
|
deferred,
|
|
545
778
|
function: functionAddress,
|
|
546
|
-
message
|
|
779
|
+
message,
|
|
780
|
+
prepared
|
|
547
781
|
});
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
782
|
+
return yield* Effect.gen(function* () {
|
|
783
|
+
if (writer !== void 0) yield* sendWith(writer, message).pipe(Effect.catchTags({
|
|
784
|
+
ConnectionUnavailable: reportClientError,
|
|
785
|
+
InvalidClientMessage: (error) => rejectInvocation(invocationId, error)
|
|
786
|
+
}));
|
|
787
|
+
if (message.type === "PrepareMutation") {
|
|
788
|
+
const uploads = yield* Deferred.await(prepared);
|
|
789
|
+
const uploaded = /* @__PURE__ */ new Set();
|
|
790
|
+
for (const upload of uploads) {
|
|
791
|
+
if (upload.url === void 0 || uploaded.has(upload.file.id)) continue;
|
|
792
|
+
const uploadUrl = upload.url;
|
|
793
|
+
uploaded.add(upload.file.id);
|
|
794
|
+
const file = preparedArguments.nativeFiles.get(upload.file.id);
|
|
795
|
+
if (file === void 0) return yield* InvalidServerMessage.make({
|
|
796
|
+
cause: /* @__PURE__ */ new Error(`Missing native file '${upload.file.id}'.`),
|
|
797
|
+
message: "The server prepared an unknown application file."
|
|
798
|
+
});
|
|
799
|
+
const response = yield* Effect.tryPromise({
|
|
800
|
+
try: () => fetch(uploadUrl, {
|
|
801
|
+
method: "PUT",
|
|
802
|
+
body: file,
|
|
803
|
+
headers: { "content-type": file.type }
|
|
804
|
+
}),
|
|
805
|
+
catch: (cause) => ConnectionUnavailable.make({
|
|
806
|
+
cause,
|
|
807
|
+
message: `File '${file.name}' could not be uploaded.`
|
|
808
|
+
})
|
|
809
|
+
});
|
|
810
|
+
if (!response.ok) {
|
|
811
|
+
const detail = yield* Effect.promise(() => response.text());
|
|
812
|
+
return yield* InvalidMutationArguments.make({
|
|
813
|
+
cause: new Error(detail),
|
|
814
|
+
function: functionAddress,
|
|
815
|
+
message: `File '${file.name}' was rejected by application storage.`
|
|
816
|
+
});
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
const pendingInvocation = HashMap.getUnsafe(invocations, invocationId);
|
|
820
|
+
if (pendingInvocation === void 0) return yield* Deferred.await(deferred);
|
|
821
|
+
invocations = HashMap.set(invocations, invocationId, {
|
|
822
|
+
...pendingInvocation,
|
|
823
|
+
message: invokeMessage
|
|
824
|
+
});
|
|
825
|
+
if (writer !== void 0) yield* sendWith(writer, invokeMessage).pipe(Effect.catchTags({
|
|
826
|
+
ConnectionUnavailable: reportClientError,
|
|
827
|
+
InvalidClientMessage: (error) => rejectInvocation(invocationId, error)
|
|
828
|
+
}));
|
|
829
|
+
}
|
|
830
|
+
return yield* Deferred.await(deferred);
|
|
831
|
+
}).pipe(Effect.tapError(() => Effect.sync(() => {
|
|
832
|
+
invocations = HashMap.remove(invocations, invocationId);
|
|
833
|
+
})));
|
|
553
834
|
});
|
|
554
835
|
return SyncClient.of({
|
|
555
836
|
mutate,
|
|
@@ -619,21 +900,140 @@ function useQuery(reference, args) {
|
|
|
619
900
|
if (Schema.is(ClientInfrastructureError)(result)) throw result;
|
|
620
901
|
return result;
|
|
621
902
|
}
|
|
903
|
+
function usePaginatedQuery(reference, args, options = {}) {
|
|
904
|
+
const functionPath = functionPathOf(reference);
|
|
905
|
+
const skipped = isQuerySkip(args);
|
|
906
|
+
const input = args === void 0 || skipped ? {} : args;
|
|
907
|
+
const jsonArgs = encodeTransportObject(input);
|
|
908
|
+
const pageSize = Schema.decodeSync(PaginationPageSize)(options.pageSize ?? 20);
|
|
909
|
+
const identity = skipped ? `skip:${functionPath}` : syncClientInternals.queryIdentity(functionPath, jsonArgs);
|
|
910
|
+
const [requestedPages, setRequestedPages] = useState$1(1);
|
|
911
|
+
const [refresh, setRefresh] = useState$1(0);
|
|
912
|
+
const [state, setState] = useState$1(() => ({
|
|
913
|
+
identity,
|
|
914
|
+
result: pending()
|
|
915
|
+
}));
|
|
916
|
+
const loadMore = useCallback$1(() => setRequestedPages((count) => count + 1), []);
|
|
917
|
+
useDebugValue$1({
|
|
918
|
+
args: input,
|
|
919
|
+
function: functionPath,
|
|
920
|
+
result: state.result
|
|
921
|
+
});
|
|
922
|
+
useEffect$1(() => {
|
|
923
|
+
setRequestedPages(1);
|
|
924
|
+
setState({
|
|
925
|
+
identity,
|
|
926
|
+
result: pending()
|
|
927
|
+
});
|
|
928
|
+
}, [identity, pageSize]);
|
|
929
|
+
useEffect$1(() => {
|
|
930
|
+
if (skipped) return;
|
|
931
|
+
let active = true;
|
|
932
|
+
const releases = [];
|
|
933
|
+
syncRuntime.runPromise(Effect.gen(function* () {
|
|
934
|
+
const client = yield* SyncClient;
|
|
935
|
+
const items = [];
|
|
936
|
+
let cursor = null;
|
|
937
|
+
for (let pageNumber = 0; pageNumber < requestedPages; pageNumber += 1) {
|
|
938
|
+
const pageArgs = encodeTransportObject({
|
|
939
|
+
...input,
|
|
940
|
+
pagination: {
|
|
941
|
+
cursor,
|
|
942
|
+
pageSize
|
|
943
|
+
}
|
|
944
|
+
});
|
|
945
|
+
const observer = yield* client.observe(functionPath, pageArgs);
|
|
946
|
+
if (!active) {
|
|
947
|
+
yield* observer.release;
|
|
948
|
+
return;
|
|
949
|
+
}
|
|
950
|
+
const releaseSubscription = observer.subscribe(() => {
|
|
951
|
+
if (active) setRefresh((version) => version + 1);
|
|
952
|
+
});
|
|
953
|
+
releases.push(() => {
|
|
954
|
+
releaseSubscription();
|
|
955
|
+
syncRuntime.runFork(observer.release);
|
|
956
|
+
});
|
|
957
|
+
const snapshot = observer.getSnapshot();
|
|
958
|
+
if (Schema.is(ClientInfrastructureError)(snapshot)) {
|
|
959
|
+
setState({
|
|
960
|
+
identity,
|
|
961
|
+
result: snapshot
|
|
962
|
+
});
|
|
963
|
+
return;
|
|
964
|
+
}
|
|
965
|
+
const inspected = inspectResult(snapshot);
|
|
966
|
+
if (inspected === void 0) {
|
|
967
|
+
setState({
|
|
968
|
+
identity,
|
|
969
|
+
result: items.length === 0 ? pending() : Result$1.succeed({
|
|
970
|
+
items,
|
|
971
|
+
loadMore,
|
|
972
|
+
status: "LoadingMore"
|
|
973
|
+
})
|
|
974
|
+
});
|
|
975
|
+
return;
|
|
976
|
+
}
|
|
977
|
+
if (inspected.type === "Failure") {
|
|
978
|
+
setState({
|
|
979
|
+
identity,
|
|
980
|
+
result: snapshot
|
|
981
|
+
});
|
|
982
|
+
return;
|
|
983
|
+
}
|
|
984
|
+
const page = inspected.value;
|
|
985
|
+
items.push(...page.items);
|
|
986
|
+
cursor = page.nextCursor;
|
|
987
|
+
if (cursor === null) {
|
|
988
|
+
setState({
|
|
989
|
+
identity,
|
|
990
|
+
result: Result$1.succeed({
|
|
991
|
+
items,
|
|
992
|
+
loadMore,
|
|
993
|
+
status: "Exhausted"
|
|
994
|
+
})
|
|
995
|
+
});
|
|
996
|
+
return;
|
|
997
|
+
}
|
|
998
|
+
}
|
|
999
|
+
setState({
|
|
1000
|
+
identity,
|
|
1001
|
+
result: Result$1.succeed({
|
|
1002
|
+
items,
|
|
1003
|
+
loadMore,
|
|
1004
|
+
status: "CanLoadMore"
|
|
1005
|
+
})
|
|
1006
|
+
});
|
|
1007
|
+
})).catch((error) => {
|
|
1008
|
+
if (active && Schema.is(ClientInfrastructureError)(error)) setState({
|
|
1009
|
+
identity,
|
|
1010
|
+
result: error
|
|
1011
|
+
});
|
|
1012
|
+
});
|
|
1013
|
+
return () => {
|
|
1014
|
+
active = false;
|
|
1015
|
+
for (const release of releases) release();
|
|
1016
|
+
};
|
|
1017
|
+
}, [
|
|
1018
|
+
functionPath,
|
|
1019
|
+
identity,
|
|
1020
|
+
loadMore,
|
|
1021
|
+
pageSize,
|
|
1022
|
+
refresh,
|
|
1023
|
+
requestedPages,
|
|
1024
|
+
skipped
|
|
1025
|
+
]);
|
|
1026
|
+
if (skipped || state.identity !== identity) return pending();
|
|
1027
|
+
const result = state.result;
|
|
1028
|
+
if (Schema.is(ClientInfrastructureError)(result)) throw result;
|
|
1029
|
+
return result;
|
|
1030
|
+
}
|
|
622
1031
|
const useMutation = (reference) => useMemo$1(() => {
|
|
623
1032
|
const mutate = (args) => {
|
|
624
1033
|
const functionPath = functionPathOf(reference);
|
|
625
1034
|
const input = args === void 0 ? {} : args;
|
|
626
1035
|
return syncRuntime.runPromise(Effect.gen(function* () {
|
|
627
|
-
|
|
628
|
-
const jsonArgs = yield* Effect.try({
|
|
629
|
-
try: () => encodeTransportObject(input),
|
|
630
|
-
catch: (cause) => InvalidMutationArguments.make({
|
|
631
|
-
cause,
|
|
632
|
-
function: functionPath,
|
|
633
|
-
message: `Mutation arguments for ${functionPath} contain an unsupported value.`
|
|
634
|
-
})
|
|
635
|
-
}).pipe(Effect.tapError(reportClientError));
|
|
636
|
-
return yield* client.mutate(functionPath, jsonArgs);
|
|
1036
|
+
return yield* (yield* SyncClient).mutate(functionPath, input);
|
|
637
1037
|
}));
|
|
638
1038
|
};
|
|
639
1039
|
return mutate;
|
|
@@ -648,6 +1048,6 @@ const app = (definition) => {
|
|
|
648
1048
|
//#region src/client/index.ts
|
|
649
1049
|
const Result = { match: Result$1.match };
|
|
650
1050
|
//#endregion
|
|
651
|
-
export { Component, Fragment, Query, Result, app, cloneElement, createContext, createElement, createRef, h, isValidElement, toChildArray, useCallback, useContext, useDebugValue, useEffect, useErrorBoundary, useId, useImperativeHandle, useLayoutEffect, useMemo, useMutation, useQuery, useReducer, useRef, useState };
|
|
1051
|
+
export { Component, Files, Fragment, Query, Result, app, cloneElement, createContext, createElement, createRef, h, isValidElement, toChildArray, useCallback, useContext, useDebugValue, useEffect, useErrorBoundary, useId, useImperativeHandle, useLayoutEffect, useMemo, useMutation, usePaginatedQuery, useQuery, useReducer, useRef, useState };
|
|
652
1052
|
|
|
653
1053
|
//# sourceMappingURL=client.js.map
|