ignotum 0.0.3 → 0.0.5
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 +26 -7
- package/dist/cli/bin.mjs +27353 -1490
- 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 +352 -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-C6KO3ZdI.d.ts → index-Dl_VQGmA.d.ts} +90 -29
- 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-wiFI7rgx.js → schema-B-jMZEbs.js} +95 -35
- 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 +13 -3
- 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 +111 -0
- package/src/cli/build/public.ts +182 -0
- package/src/cli/build/server.ts +527 -0
- package/src/cli/client-config.ts +148 -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-wiFI7rgx.js.map +0 -1
package/dist/runtime/client.js
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
|
-
import { a as
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { a as InvocationId, c as SubscriptionId, i as IdAlphabet, l as TableId, n as DeploymentId, r as GeneratedId, s as RuntimeRequestNonce, t as AppId } from "./id-D570vudg.js";
|
|
2
|
+
import { g as encodeTransportObject, h as decodeTransportValue, l as failureFromWire, s as Result$1, t as ValueDescriptor, u as pending } from "./descriptor-t6BOEGw9-BTHR-ZMv.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-DtX8qPrq.js";
|
|
4
|
+
import { Array, Cause, Context, Deferred, Duration, Effect, ErrorReporter, Fiber, HashMap, Layer, ManagedRuntime, Predicate, Schedule, Schema, String } from "effect";
|
|
4
5
|
import { useCallback, 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";
|
|
5
6
|
import * as Socket from "effect/unstable/socket/Socket";
|
|
7
|
+
import * as BrowserCrypto from "@effect/platform-browser/BrowserCrypto";
|
|
8
|
+
import { customAlphabet } from "nanoid";
|
|
6
9
|
import { Component, Fragment, cloneElement, createContext, createElement, createRef, h, isValidElement, toChildArray } from "preact";
|
|
7
10
|
//#region src/client/errors.ts
|
|
8
11
|
/** @effect-diagnostics globalConsole:skip-file */
|
|
@@ -28,19 +31,12 @@ var ServerProtocolError = class extends Schema.TaggedError()("ServerProtocolErro
|
|
|
28
31
|
message: Schema.String,
|
|
29
32
|
operation: Schema.optional(Operation)
|
|
30
33
|
}) {};
|
|
31
|
-
var MutationOutcomeUnknown = class extends Schema.TaggedError()("MutationOutcomeUnknown", {
|
|
32
|
-
cause: Schema.optional(Schema.Defect()),
|
|
33
|
-
function: FunctionAddress,
|
|
34
|
-
id: RequestId,
|
|
35
|
-
message: Schema.String
|
|
36
|
-
}) {};
|
|
37
34
|
const ClientInfrastructureError = Schema.Union([
|
|
38
35
|
ConnectionUnavailable,
|
|
39
36
|
InvalidClientMessage,
|
|
40
37
|
InvalidMutationArguments,
|
|
41
38
|
InvalidServerMessage,
|
|
42
|
-
ServerProtocolError
|
|
43
|
-
MutationOutcomeUnknown
|
|
39
|
+
ServerProtocolError
|
|
44
40
|
]);
|
|
45
41
|
const browserErrorReporter = ErrorReporter.make(({ attributes, error }) => {
|
|
46
42
|
globalThis.console.error("Ignotum infrastructure error", error, attributes);
|
|
@@ -58,15 +54,248 @@ var QuerySkipToken = class {
|
|
|
58
54
|
const skip = Object.freeze(new QuerySkipToken());
|
|
59
55
|
const Query = { skip };
|
|
60
56
|
const isQuerySkip = (value) => value === skip;
|
|
61
|
-
const syncPath = `/_ignotum/sync`;
|
|
62
57
|
//#endregion
|
|
63
|
-
//#region
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
if (
|
|
67
|
-
return `{${
|
|
58
|
+
//#region ../contracts/dist/json.js
|
|
59
|
+
const encodeScalar = (value) => Schema.decodeSync(Schema.String)(JSON.stringify(value));
|
|
60
|
+
const encodeCanonicalJson = (value) => {
|
|
61
|
+
if (value === null || Predicate.isString(value) || Predicate.isNumber(value) || Predicate.isBoolean(value)) return encodeScalar(value);
|
|
62
|
+
if (Predicate.isObject(value)) return `{${Array.map(Array.sort(String.Order)(Object.keys(value)), (key) => {
|
|
63
|
+
const field = Schema.decodeUnknownSync(Schema.Json)(value[key]);
|
|
64
|
+
return `${encodeScalar(key)}:${encodeCanonicalJson(field)}`;
|
|
65
|
+
}).join(",")}}`;
|
|
66
|
+
return `[${Schema.decodeUnknownSync(Schema.Array(Schema.Json))(value).map(encodeCanonicalJson).join(",")}]`;
|
|
67
|
+
};
|
|
68
|
+
Schema.String.pipe(Schema.brand("ignotum/hosted/QueryKey"));
|
|
69
|
+
const TableDependency = Schema.Struct({
|
|
70
|
+
type: Schema.Literal("Table"),
|
|
71
|
+
tableId: TableId
|
|
72
|
+
});
|
|
73
|
+
const DocumentDependency = Schema.Struct({
|
|
74
|
+
type: Schema.Literal("Document"),
|
|
75
|
+
tableId: TableId,
|
|
76
|
+
id: GeneratedId
|
|
77
|
+
});
|
|
78
|
+
const DependencyKey = Schema.Union([TableDependency, DocumentDependency]);
|
|
79
|
+
const DependencySet = Schema.Array(DependencyKey);
|
|
80
|
+
const InvalidationSet = Schema.Array(DependencyKey);
|
|
81
|
+
const RuntimeQueryResult = Schema.Struct({
|
|
82
|
+
type: Schema.Literal("Query"),
|
|
83
|
+
result: WireResult,
|
|
84
|
+
dependencies: DependencySet,
|
|
85
|
+
observedRevision: AppStateRevision
|
|
86
|
+
});
|
|
87
|
+
const RuntimeMutationSuccess = Schema.Struct({
|
|
88
|
+
type: Schema.Literal("Mutation"),
|
|
89
|
+
result: WireSuccess,
|
|
90
|
+
invalidations: InvalidationSet,
|
|
91
|
+
committedRevision: AppStateRevision
|
|
92
|
+
});
|
|
93
|
+
const RuntimeMutationFailure = Schema.Struct({
|
|
94
|
+
type: Schema.Literal("Mutation"),
|
|
95
|
+
result: WireFailure
|
|
96
|
+
});
|
|
97
|
+
const RuntimeMutationResult = Schema.Union([RuntimeMutationSuccess, RuntimeMutationFailure]);
|
|
98
|
+
Schema.Union([RuntimeQueryResult, RuntimeMutationResult]);
|
|
99
|
+
const InvocationBase = {
|
|
100
|
+
appId: AppId,
|
|
101
|
+
deploymentId: DeploymentId,
|
|
102
|
+
generation: DeploymentGeneration,
|
|
103
|
+
invocationKey: InvocationKey,
|
|
104
|
+
function: FunctionAddress,
|
|
105
|
+
args: Schema.Json
|
|
68
106
|
};
|
|
69
|
-
const
|
|
107
|
+
const QueryInvocation = Schema.Struct({
|
|
108
|
+
...InvocationBase,
|
|
109
|
+
type: Schema.Literal("Query")
|
|
110
|
+
});
|
|
111
|
+
const MutationInvocation = Schema.Struct({
|
|
112
|
+
...InvocationBase,
|
|
113
|
+
type: Schema.Literal("Mutation"),
|
|
114
|
+
invocationId: InvocationId
|
|
115
|
+
});
|
|
116
|
+
Schema.Union([QueryInvocation, MutationInvocation]);
|
|
117
|
+
Schema.Struct({
|
|
118
|
+
appId: AppId,
|
|
119
|
+
expectedRevision: AppStateRevision
|
|
120
|
+
});
|
|
121
|
+
Schema.Struct({ currentRevision: AppStateRevision });
|
|
122
|
+
var RuntimeDeploymentUnavailable = class extends Schema.TaggedError()("RuntimeDeploymentUnavailable", {
|
|
123
|
+
deploymentId: DeploymentId,
|
|
124
|
+
message: Schema.String
|
|
125
|
+
}) {};
|
|
126
|
+
const RuntimeInvocationRejectionCode = Schema.Literals([
|
|
127
|
+
"FunctionUnavailable",
|
|
128
|
+
"InvalidArguments",
|
|
129
|
+
"InvocationIdConflict",
|
|
130
|
+
"ResourceLimitExceeded",
|
|
131
|
+
"UnknownFunction",
|
|
132
|
+
"WrongFunctionKind"
|
|
133
|
+
]);
|
|
134
|
+
var RuntimeInvocationRejected = class extends Schema.TaggedError()("RuntimeInvocationRejected", {
|
|
135
|
+
code: RuntimeInvocationRejectionCode,
|
|
136
|
+
invocationKey: InvocationKey,
|
|
137
|
+
message: Schema.String
|
|
138
|
+
}) {};
|
|
139
|
+
var RuntimeInvocationUnavailable = class extends Schema.TaggedError()("RuntimeInvocationUnavailable", {
|
|
140
|
+
invocationKey: InvocationKey,
|
|
141
|
+
message: Schema.String
|
|
142
|
+
}) {};
|
|
143
|
+
Schema.TaggedError()("RuntimeRevisionRejected", {
|
|
144
|
+
appId: AppId,
|
|
145
|
+
message: Schema.String
|
|
146
|
+
});
|
|
147
|
+
Schema.Union([
|
|
148
|
+
RuntimeDeploymentUnavailable,
|
|
149
|
+
RuntimeInvocationRejected,
|
|
150
|
+
RuntimeInvocationUnavailable
|
|
151
|
+
]);
|
|
152
|
+
//#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
|
+
//#region ../contracts/dist/runtime/functions.js
|
|
171
|
+
const FunctionKind = Schema.Literals(["Mutation", "Query"]);
|
|
172
|
+
Schema.TaggedError()("UnknownFunction", {
|
|
173
|
+
function: FunctionAddress,
|
|
174
|
+
message: Schema.String
|
|
175
|
+
});
|
|
176
|
+
Schema.TaggedError()("WrongFunctionKind", {
|
|
177
|
+
actual: FunctionKind,
|
|
178
|
+
expected: FunctionKind,
|
|
179
|
+
function: FunctionAddress,
|
|
180
|
+
message: Schema.String
|
|
181
|
+
});
|
|
182
|
+
Schema.TaggedError()("InvalidArguments", {
|
|
183
|
+
function: FunctionAddress,
|
|
184
|
+
message: Schema.String
|
|
185
|
+
});
|
|
186
|
+
Schema.TaggedError()("FunctionUnavailable", {
|
|
187
|
+
cause: Schema.Defect(),
|
|
188
|
+
function: FunctionAddress,
|
|
189
|
+
message: Schema.String
|
|
190
|
+
});
|
|
191
|
+
//#endregion
|
|
192
|
+
//#region ../contracts/dist/deployment.js
|
|
193
|
+
const ArtifactPath = Schema.String.check(Schema.isPattern(/^(?!\/)(?![A-Za-z]:\/)(?!.*(?:^|\/)\.\.(?:\/|$))(?!.*(?:^|\/)\.(?:\/|$))(?!.*\/\/)[^\\\0]+$/)).pipe(Schema.brand("ignotum/deployment/ArtifactPath"));
|
|
194
|
+
const ClientPath = Schema.String.check(Schema.isPattern(/^\/(?!_ignotum(?:\/|$))(?:(?:[A-Za-z0-9._~-]+\/)*[A-Za-z0-9._~-]+\/?)?$/)).pipe(Schema.brand("ignotum/deployment/ClientPath"));
|
|
195
|
+
const Sha256 = Schema.String.check(Schema.isPattern(/^[0-9a-f]{64}$/)).pipe(Schema.brand("ignotum/deployment/Sha256"));
|
|
196
|
+
const ArtifactKind = Schema.Literals([
|
|
197
|
+
"ClientAsset",
|
|
198
|
+
"ClientDocument",
|
|
199
|
+
"ClientPublicFile",
|
|
200
|
+
"ClientShell",
|
|
201
|
+
"FunctionBundle",
|
|
202
|
+
"ServerManifest",
|
|
203
|
+
"SourceMap",
|
|
204
|
+
"SchemaSnapshot"
|
|
205
|
+
]);
|
|
206
|
+
const ArtifactReference = Schema.Struct({
|
|
207
|
+
path: ArtifactPath,
|
|
208
|
+
size: Schema.Natural,
|
|
209
|
+
sha256: Sha256
|
|
210
|
+
});
|
|
211
|
+
const ArtifactFile = Schema.Struct({
|
|
212
|
+
path: ArtifactPath,
|
|
213
|
+
size: Schema.Natural,
|
|
214
|
+
sha256: Sha256,
|
|
215
|
+
kind: ArtifactKind,
|
|
216
|
+
contentType: Schema.String,
|
|
217
|
+
contentEncoding: Schema.optional(Schema.String)
|
|
218
|
+
});
|
|
219
|
+
const ClientRoute = Schema.Struct({
|
|
220
|
+
pathname: ClientPath,
|
|
221
|
+
artifact: ArtifactPath
|
|
222
|
+
});
|
|
223
|
+
Schema.Struct({
|
|
224
|
+
formatVersion: Schema.Literal(1),
|
|
225
|
+
client: Schema.Struct({ routes: Schema.Array(ClientRoute) }),
|
|
226
|
+
files: Schema.Array(ArtifactFile)
|
|
227
|
+
});
|
|
228
|
+
const SchemaSnapshotField = Schema.Struct({
|
|
229
|
+
name: Schema.String,
|
|
230
|
+
value: ValueDescriptor
|
|
231
|
+
});
|
|
232
|
+
const SchemaSnapshotTable = Schema.Struct({
|
|
233
|
+
name: Schema.String,
|
|
234
|
+
fields: Schema.Array(SchemaSnapshotField)
|
|
235
|
+
});
|
|
236
|
+
Schema.Struct({
|
|
237
|
+
formatVersion: Schema.Literal(1),
|
|
238
|
+
tables: Schema.Array(SchemaSnapshotTable)
|
|
239
|
+
});
|
|
240
|
+
const ServerFunctionArtifact = Schema.Struct({
|
|
241
|
+
address: FunctionAddress,
|
|
242
|
+
kind: FunctionKind,
|
|
243
|
+
bundle: ArtifactReference,
|
|
244
|
+
sourceMap: ArtifactReference
|
|
245
|
+
});
|
|
246
|
+
Schema.Struct({
|
|
247
|
+
formatVersion: Schema.Literal(1),
|
|
248
|
+
schema: ArtifactReference,
|
|
249
|
+
functions: Schema.Array(ServerFunctionArtifact)
|
|
250
|
+
});
|
|
251
|
+
ArtifactPath.make("inventory.json");
|
|
252
|
+
ArtifactPath.make("client/_shell.html");
|
|
253
|
+
`${ArtifactPath.make("client/_ignotum/assets")}`;
|
|
254
|
+
ArtifactPath.make("server/manifest.json");
|
|
255
|
+
ArtifactPath.make("server/schema.json");
|
|
256
|
+
//#endregion
|
|
257
|
+
//#region ../contracts/dist/runtime/transport.js
|
|
258
|
+
const runtimeInvocationPath = "/v1/invoke";
|
|
259
|
+
const runtimeRevisionPath = "/v1/revision";
|
|
260
|
+
const appSyncPath = `/_ignotum/v1/sync`;
|
|
261
|
+
const RuntimeRequestPath = Schema.Literals([runtimeInvocationPath, runtimeRevisionPath]);
|
|
262
|
+
const RuntimeRequestTimestamp = Schema.FiniteFromString.pipe(Schema.check(Schema.isInt(), Schema.isGreaterThanOrEqualTo(0)), Schema.brand("ignotum/runtime/RequestTimestamp"));
|
|
263
|
+
const RuntimeRequestSignature = Sha256.pipe(Schema.brand("ignotum/runtime/RequestSignature"));
|
|
264
|
+
Schema.Struct({
|
|
265
|
+
appId: AppId,
|
|
266
|
+
deploymentId: Schema.optional(DeploymentId),
|
|
267
|
+
nonce: RuntimeRequestNonce,
|
|
268
|
+
timestamp: RuntimeRequestTimestamp,
|
|
269
|
+
signature: RuntimeRequestSignature
|
|
270
|
+
});
|
|
271
|
+
Schema.Struct({
|
|
272
|
+
method: Schema.Literal("POST"),
|
|
273
|
+
path: RuntimeRequestPath,
|
|
274
|
+
timestamp: RuntimeRequestTimestamp,
|
|
275
|
+
nonce: RuntimeRequestNonce,
|
|
276
|
+
appId: AppId,
|
|
277
|
+
deploymentId: Schema.optional(DeploymentId),
|
|
278
|
+
bodySha256: Sha256
|
|
279
|
+
});
|
|
280
|
+
const RuntimeErrorCode = Schema.Literals([
|
|
281
|
+
"InvalidRequest",
|
|
282
|
+
"InvalidSignature",
|
|
283
|
+
"RequestExpired",
|
|
284
|
+
"RequestReplay",
|
|
285
|
+
"InvocationRejected",
|
|
286
|
+
"RuntimeUnavailable"
|
|
287
|
+
]);
|
|
288
|
+
Schema.Struct({
|
|
289
|
+
code: RuntimeErrorCode,
|
|
290
|
+
message: Schema.String,
|
|
291
|
+
rejectionCode: Schema.optional(RuntimeInvocationRejectionCode)
|
|
292
|
+
});
|
|
293
|
+
//#endregion
|
|
294
|
+
//#region src/internal/http-paths.ts
|
|
295
|
+
const syncPath = appSyncPath;
|
|
296
|
+
//#endregion
|
|
297
|
+
//#region src/client/sync.ts
|
|
298
|
+
const queryKey = (functionAddress, args) => encodeCanonicalJson([functionAddress, args]);
|
|
70
299
|
const subscribeMessage = (entry) => ({
|
|
71
300
|
type: "Subscribe",
|
|
72
301
|
id: entry.subscriptionId,
|
|
@@ -91,9 +320,10 @@ const makeQueryCache = (allocateId, sendLifecycleMessage) => {
|
|
|
91
320
|
function: functionAddress,
|
|
92
321
|
generation: 0,
|
|
93
322
|
listeners: /* @__PURE__ */ new Set(),
|
|
323
|
+
revision: void 0,
|
|
94
324
|
references: 0,
|
|
95
325
|
result: pending(),
|
|
96
|
-
subscriptionId: allocateId
|
|
326
|
+
subscriptionId: yield* allocateId
|
|
97
327
|
};
|
|
98
328
|
queries.set(key, created);
|
|
99
329
|
queryKeysById.set(created.subscriptionId, key);
|
|
@@ -134,20 +364,31 @@ const makeQueryCache = (allocateId, sendLifecycleMessage) => {
|
|
|
134
364
|
entry.result = error;
|
|
135
365
|
for (const listener of entry.listeners) listener();
|
|
136
366
|
},
|
|
137
|
-
setResult: (id, result) => {
|
|
367
|
+
setResult: (id, result, revision) => {
|
|
138
368
|
const key = queryKeysById.get(id);
|
|
139
369
|
const entry = key === void 0 ? void 0 : queries.get(key);
|
|
140
370
|
if (entry === void 0) return;
|
|
371
|
+
if (entry.revision !== void 0 && revision < entry.revision) return;
|
|
372
|
+
entry.revision = revision;
|
|
141
373
|
entry.result = result;
|
|
142
374
|
for (const listener of entry.listeners) listener();
|
|
143
375
|
}
|
|
144
376
|
};
|
|
145
377
|
};
|
|
146
378
|
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)));
|
|
379
|
+
const shouldReloadForCloseCode = (code) => code === DeploymentChangedCloseCode;
|
|
380
|
+
const handshakesMatch = (first, next) => first.appId === next.appId && first.deploymentId === next.deploymentId && first.generation === next.generation;
|
|
381
|
+
const handshakeDecision = (remembered, acceptedOnConnection, next) => {
|
|
382
|
+
if (remembered !== void 0 && !handshakesMatch(remembered, next)) return "Reload";
|
|
383
|
+
return acceptedOnConnection ? "Ignore" : "Accept";
|
|
384
|
+
};
|
|
147
385
|
const syncClientInternals = {
|
|
148
386
|
makeQueryCache,
|
|
387
|
+
handshakeDecision,
|
|
149
388
|
queryIdentity: queryKey,
|
|
150
|
-
resultFromWire
|
|
389
|
+
resultFromWire,
|
|
390
|
+
handshakesMatch,
|
|
391
|
+
shouldReloadForCloseCode
|
|
151
392
|
};
|
|
152
393
|
const socketUrl = () => {
|
|
153
394
|
const url = new URL(syncPath, globalThis.location.href);
|
|
@@ -156,8 +397,10 @@ const socketUrl = () => {
|
|
|
156
397
|
};
|
|
157
398
|
var SyncClient = class SyncClient extends Context.Service()("ignotum/client/sync/SyncClient") {
|
|
158
399
|
static layer = Layer.effect(SyncClient, Effect.gen(function* () {
|
|
159
|
-
|
|
160
|
-
let
|
|
400
|
+
const ids = yield* IdGenerator;
|
|
401
|
+
let invocations = HashMap.empty();
|
|
402
|
+
let rememberedHandshake;
|
|
403
|
+
let reloadRequested = false;
|
|
161
404
|
let writer;
|
|
162
405
|
const encode = (message) => Schema.encodeEffect(ClientMessageJson)(message).pipe(Effect.mapError((cause) => InvalidClientMessage.make({
|
|
163
406
|
cause,
|
|
@@ -168,31 +411,27 @@ var SyncClient = class SyncClient extends Context.Service()("ignotum/client/sync
|
|
|
168
411
|
message: "The sync connection was lost."
|
|
169
412
|
})));
|
|
170
413
|
const send = (message) => writer === void 0 ? Effect.fail(ConnectionUnavailable.make({ message: "The sync connection is not ready." })) : sendWith(writer, message);
|
|
171
|
-
const queryCache = makeQueryCache((
|
|
414
|
+
const queryCache = makeQueryCache(ids.generate(SubscriptionId), (message) => writer === void 0 ? Effect.void : send(message).pipe(Effect.catchTags({
|
|
172
415
|
ConnectionUnavailable: reportClientError,
|
|
173
416
|
InvalidClientMessage: reportClientError
|
|
174
417
|
})));
|
|
175
|
-
const
|
|
176
|
-
const
|
|
177
|
-
if (
|
|
178
|
-
|
|
179
|
-
return reportClientError(error).pipe(Effect.andThen(Deferred.fail(
|
|
418
|
+
const rejectInvocation = (id, error) => {
|
|
419
|
+
const pendingInvocation = HashMap.getUnsafe(invocations, id);
|
|
420
|
+
if (pendingInvocation === void 0) return Effect.void;
|
|
421
|
+
invocations = HashMap.remove(invocations, id);
|
|
422
|
+
return reportClientError(error).pipe(Effect.andThen(Deferred.fail(pendingInvocation.deferred, error)), Effect.asVoid);
|
|
180
423
|
};
|
|
181
|
-
const handleMessage = Effect.fn("SyncClient.handleMessage")(function* (
|
|
182
|
-
const message = yield* Schema.decodeEffect(ServerMessageJson)(text).pipe(Effect.mapError((cause) => InvalidServerMessage.make({
|
|
183
|
-
cause,
|
|
184
|
-
message: "The server returned an invalid sync message."
|
|
185
|
-
})));
|
|
424
|
+
const handleMessage = Effect.fn("SyncClient.handleMessage")(function* (message) {
|
|
186
425
|
switch (message.type) {
|
|
187
|
-
case "
|
|
426
|
+
case "Snapshot":
|
|
188
427
|
if (queryCache.getById(message.id) === void 0) return;
|
|
189
|
-
yield* resultFromWire(message.result).pipe(Effect.tap((result) => Effect.sync(() => queryCache.setResult(message.id, result))));
|
|
428
|
+
yield* resultFromWire(message.result).pipe(Effect.tap((result) => Effect.sync(() => queryCache.setResult(message.id, result, message.revision))));
|
|
190
429
|
return;
|
|
191
|
-
case "
|
|
192
|
-
const
|
|
193
|
-
if (
|
|
194
|
-
|
|
195
|
-
yield* resultFromWire(message.result).pipe(Effect.flatMap((result) => Deferred.succeed(
|
|
430
|
+
case "Result": {
|
|
431
|
+
const pendingInvocation = HashMap.getUnsafe(invocations, message.id);
|
|
432
|
+
if (pendingInvocation === void 0) return;
|
|
433
|
+
invocations = HashMap.remove(invocations, message.id);
|
|
434
|
+
yield* resultFromWire(message.result).pipe(Effect.flatMap((result) => Deferred.succeed(pendingInvocation.deferred, result)));
|
|
196
435
|
return;
|
|
197
436
|
}
|
|
198
437
|
case "ProtocolError": {
|
|
@@ -204,8 +443,8 @@ var SyncClient = class SyncClient extends Context.Service()("ignotum/client/sync
|
|
|
204
443
|
message: message.message,
|
|
205
444
|
operation: message.operation
|
|
206
445
|
});
|
|
207
|
-
if (message.operation?.type === "
|
|
208
|
-
else if (message.operation?.type === "
|
|
446
|
+
if (message.operation?.type === "Invocation") yield* rejectInvocation(message.operation.id, error);
|
|
447
|
+
else if (message.operation?.type === "Subscription") {
|
|
209
448
|
queryCache.setError(message.operation.id, error);
|
|
210
449
|
yield* reportClientError(error);
|
|
211
450
|
} else yield* reportClientError(error);
|
|
@@ -213,27 +452,59 @@ var SyncClient = class SyncClient extends Context.Service()("ignotum/client/sync
|
|
|
213
452
|
}
|
|
214
453
|
}
|
|
215
454
|
});
|
|
216
|
-
const
|
|
455
|
+
const requestReload = () => {
|
|
456
|
+
if (reloadRequested) return;
|
|
457
|
+
reloadRequested = true;
|
|
458
|
+
writer = void 0;
|
|
459
|
+
globalThis.location.reload();
|
|
460
|
+
};
|
|
461
|
+
const disconnect = Effect.sync(() => {
|
|
217
462
|
writer = void 0;
|
|
218
|
-
const current = mutations;
|
|
219
|
-
mutations = HashMap.empty();
|
|
220
|
-
yield* Effect.forEach(HashMap.entries(current), ([id, pendingMutation]) => {
|
|
221
|
-
const error = MutationOutcomeUnknown.make({
|
|
222
|
-
function: pendingMutation.function,
|
|
223
|
-
id,
|
|
224
|
-
message: "The connection closed before the mutation outcome was known."
|
|
225
|
-
});
|
|
226
|
-
return reportClientError(error).pipe(Effect.andThen(Deferred.fail(pendingMutation.deferred, error)));
|
|
227
|
-
});
|
|
228
463
|
});
|
|
229
464
|
const connect = Effect.scoped(Effect.gen(function* () {
|
|
230
|
-
|
|
465
|
+
if (reloadRequested) return yield* Effect.never;
|
|
466
|
+
const socket = yield* Socket.makeWebSocket(socketUrl(), { closeCodeIsError: (code) => {
|
|
467
|
+
if (shouldReloadForCloseCode(code)) requestReload();
|
|
468
|
+
return false;
|
|
469
|
+
} });
|
|
231
470
|
const write = yield* socket.writer;
|
|
232
|
-
const
|
|
471
|
+
const handshakeReceived = yield* Deferred.make();
|
|
472
|
+
let handshakeAccepted = false;
|
|
473
|
+
const acceptHandshake = Effect.fn("SyncClient.acceptHandshake")(function* (handshake) {
|
|
474
|
+
const decision = handshakeDecision(rememberedHandshake, handshakeAccepted, handshake);
|
|
475
|
+
if (decision === "Reload") {
|
|
476
|
+
requestReload();
|
|
477
|
+
return;
|
|
478
|
+
}
|
|
479
|
+
if (decision === "Ignore") return;
|
|
480
|
+
rememberedHandshake = handshake;
|
|
481
|
+
handshakeAccepted = true;
|
|
233
482
|
writer = write;
|
|
234
|
-
yield*
|
|
235
|
-
|
|
236
|
-
|
|
483
|
+
yield* Deferred.succeed(handshakeReceived, void 0);
|
|
484
|
+
yield* Effect.gen(function* () {
|
|
485
|
+
yield* Effect.forEach(queryCache.entries(), (entry) => sendWith(write, subscribeMessage(entry)));
|
|
486
|
+
yield* Effect.forEach(HashMap.values(invocations), (pendingInvocation) => sendWith(write, pendingInvocation.message));
|
|
487
|
+
}).pipe(Effect.tapError(reportClientError), Effect.ignore);
|
|
488
|
+
});
|
|
489
|
+
const handleText = Effect.fn("SyncClient.handleText")(function* (text) {
|
|
490
|
+
const message = yield* Schema.decodeEffect(ServerMessageJson)(text).pipe(Effect.mapError((cause) => InvalidServerMessage.make({
|
|
491
|
+
cause,
|
|
492
|
+
message: "The server returned an invalid sync message."
|
|
493
|
+
})));
|
|
494
|
+
if (message.type === "Handshake") return yield* acceptHandshake(message);
|
|
495
|
+
if (message.type === "DeploymentChanged") {
|
|
496
|
+
requestReload();
|
|
497
|
+
return;
|
|
498
|
+
}
|
|
499
|
+
if (!handshakeAccepted) return yield* InvalidServerMessage.make({
|
|
500
|
+
cause: /* @__PURE__ */ new Error("The server sent a sync message before the handshake."),
|
|
501
|
+
message: "The server returned a sync message before the handshake."
|
|
502
|
+
});
|
|
503
|
+
return yield* handleMessage(message);
|
|
504
|
+
});
|
|
505
|
+
const run = yield* socket.runString(handleText).pipe(Effect.forkChild);
|
|
506
|
+
yield* Effect.raceFirst(Deferred.await(handshakeReceived).pipe(Effect.timeout("10 seconds")), Fiber.join(run));
|
|
507
|
+
yield* Fiber.join(run);
|
|
237
508
|
})).pipe(Effect.mapError((cause) => Schema.is(ClientInfrastructureError)(cause) ? cause : ConnectionUnavailable.make({
|
|
238
509
|
cause,
|
|
239
510
|
message: "The sync connection was lost."
|
|
@@ -244,37 +515,33 @@ var SyncClient = class SyncClient extends Context.Service()("ignotum/client/sync
|
|
|
244
515
|
return yield* queryCache.observe(functionAddress, args);
|
|
245
516
|
});
|
|
246
517
|
const mutate = Effect.fn("SyncClient.mutate")(function* (functionAddress, args) {
|
|
247
|
-
const
|
|
518
|
+
const invocationId = yield* ids.generate(InvocationId);
|
|
248
519
|
const deferred = yield* Deferred.make();
|
|
249
|
-
mutations = HashMap.set(mutations, requestId, {
|
|
250
|
-
deferred,
|
|
251
|
-
function: functionAddress
|
|
252
|
-
});
|
|
253
520
|
const message = {
|
|
254
|
-
type: "
|
|
255
|
-
id:
|
|
521
|
+
type: "Invoke",
|
|
522
|
+
id: invocationId,
|
|
523
|
+
kind: "Mutation",
|
|
256
524
|
function: functionAddress,
|
|
257
525
|
args
|
|
258
526
|
};
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
}).pipe(Effect.tapError(reportClientError), Effect.tapError(() => Effect.sync(() => mutations = HashMap.remove(mutations, requestId))));
|
|
527
|
+
invocations = HashMap.set(invocations, invocationId, {
|
|
528
|
+
deferred,
|
|
529
|
+
function: functionAddress,
|
|
530
|
+
message
|
|
531
|
+
});
|
|
532
|
+
if (writer !== void 0) yield* sendWith(writer, message).pipe(Effect.catchTags({
|
|
533
|
+
ConnectionUnavailable: reportClientError,
|
|
534
|
+
InvalidClientMessage: (error) => rejectInvocation(invocationId, error)
|
|
535
|
+
}));
|
|
269
536
|
return yield* Deferred.await(deferred);
|
|
270
537
|
});
|
|
271
538
|
return SyncClient.of({
|
|
272
539
|
mutate,
|
|
273
540
|
observe
|
|
274
541
|
});
|
|
275
|
-
})).pipe(Layer.provide(Socket.layerWebSocketConstructorGlobal));
|
|
542
|
+
})).pipe(Layer.provide(Layer.merge(Socket.layerWebSocketConstructorGlobal, BrowserCrypto.layer)));
|
|
276
543
|
};
|
|
277
|
-
const syncRuntime = ManagedRuntime.make(SyncClient.layer.pipe(Layer.provideMerge(clientErrorReporterLayer)));
|
|
544
|
+
const syncRuntime = ManagedRuntime.make(SyncClient.layer.pipe(Layer.provideMerge(clientErrorReporterLayer), Layer.provideMerge(IdGenerator.layer)));
|
|
278
545
|
const hot = import.meta.hot;
|
|
279
546
|
if (hot !== void 0) hot.dispose(() => void syncRuntime.dispose());
|
|
280
547
|
//#endregion
|
|
@@ -356,9 +623,15 @@ const useMutation = (reference) => useMemo$1(() => {
|
|
|
356
623
|
return mutate;
|
|
357
624
|
}, [reference]);
|
|
358
625
|
//#endregion
|
|
626
|
+
//#region src/client/app.ts
|
|
627
|
+
const app = (definition) => {
|
|
628
|
+
if (definition.title.trim().length === 0) throw new Error("The app title must contain a non-whitespace character.");
|
|
629
|
+
return definition;
|
|
630
|
+
};
|
|
631
|
+
//#endregion
|
|
359
632
|
//#region src/client/index.ts
|
|
360
633
|
const Result = { match: Result$1.match };
|
|
361
634
|
//#endregion
|
|
362
|
-
export { Component, Fragment, Query, Result, cloneElement, createContext, createElement, createRef, h, isValidElement, toChildArray, useCallback, useContext, useDebugValue, useEffect, useErrorBoundary, useId, useImperativeHandle, useLayoutEffect, useMemo, useMutation, useQuery, useReducer, useRef, useState };
|
|
635
|
+
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 };
|
|
363
636
|
|
|
364
637
|
//# sourceMappingURL=client.js.map
|