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
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,239 @@ 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 Sha256 = Schema.String.check(Schema.isPattern(/^[0-9a-f]{64}$/)).pipe(Schema.brand("ignotum/deployment/Sha256"));
|
|
195
|
+
const ArtifactKind = Schema.Literals([
|
|
196
|
+
"ClientAsset",
|
|
197
|
+
"ClientShell",
|
|
198
|
+
"FunctionBundle",
|
|
199
|
+
"ServerManifest",
|
|
200
|
+
"SourceMap",
|
|
201
|
+
"SchemaSnapshot"
|
|
202
|
+
]);
|
|
203
|
+
const ArtifactReference = Schema.Struct({
|
|
204
|
+
path: ArtifactPath,
|
|
205
|
+
size: Schema.Natural,
|
|
206
|
+
sha256: Sha256
|
|
207
|
+
});
|
|
208
|
+
const ArtifactFile = Schema.Struct({
|
|
209
|
+
path: ArtifactPath,
|
|
210
|
+
size: Schema.Natural,
|
|
211
|
+
sha256: Sha256,
|
|
212
|
+
kind: ArtifactKind,
|
|
213
|
+
contentType: Schema.String,
|
|
214
|
+
contentEncoding: Schema.optional(Schema.String)
|
|
215
|
+
});
|
|
216
|
+
Schema.Struct({
|
|
217
|
+
formatVersion: Schema.Literal(1),
|
|
218
|
+
files: Schema.Array(ArtifactFile)
|
|
219
|
+
});
|
|
220
|
+
const SchemaSnapshotField = Schema.Struct({
|
|
221
|
+
name: Schema.String,
|
|
222
|
+
value: ValueDescriptor
|
|
223
|
+
});
|
|
224
|
+
const SchemaSnapshotTable = Schema.Struct({
|
|
225
|
+
name: Schema.String,
|
|
226
|
+
fields: Schema.Array(SchemaSnapshotField)
|
|
227
|
+
});
|
|
228
|
+
Schema.Struct({
|
|
229
|
+
formatVersion: Schema.Literal(1),
|
|
230
|
+
tables: Schema.Array(SchemaSnapshotTable)
|
|
231
|
+
});
|
|
232
|
+
const ServerFunctionArtifact = Schema.Struct({
|
|
233
|
+
address: FunctionAddress,
|
|
234
|
+
kind: FunctionKind,
|
|
235
|
+
bundle: ArtifactReference,
|
|
236
|
+
sourceMap: ArtifactReference
|
|
237
|
+
});
|
|
238
|
+
Schema.Struct({
|
|
239
|
+
formatVersion: Schema.Literal(1),
|
|
240
|
+
schema: ArtifactReference,
|
|
241
|
+
functions: Schema.Array(ServerFunctionArtifact)
|
|
242
|
+
});
|
|
243
|
+
ArtifactPath.make("inventory.json");
|
|
244
|
+
ArtifactPath.make("client/_shell.html");
|
|
245
|
+
ArtifactPath.make("server/manifest.json");
|
|
246
|
+
ArtifactPath.make("server/schema.json");
|
|
247
|
+
//#endregion
|
|
248
|
+
//#region ../contracts/dist/runtime/transport.js
|
|
249
|
+
const runtimeInvocationPath = "/v1/invoke";
|
|
250
|
+
const runtimeRevisionPath = "/v1/revision";
|
|
251
|
+
const appSyncPath = "/_ignotum/v1/sync";
|
|
252
|
+
const RuntimeRequestPath = Schema.Literals([runtimeInvocationPath, runtimeRevisionPath]);
|
|
253
|
+
const RuntimeRequestTimestamp = Schema.FiniteFromString.pipe(Schema.check(Schema.isInt(), Schema.isGreaterThanOrEqualTo(0)), Schema.brand("ignotum/runtime/RequestTimestamp"));
|
|
254
|
+
const RuntimeRequestSignature = Sha256.pipe(Schema.brand("ignotum/runtime/RequestSignature"));
|
|
255
|
+
Schema.Struct({
|
|
256
|
+
appId: AppId,
|
|
257
|
+
deploymentId: Schema.optional(DeploymentId),
|
|
258
|
+
nonce: RuntimeRequestNonce,
|
|
259
|
+
timestamp: RuntimeRequestTimestamp,
|
|
260
|
+
signature: RuntimeRequestSignature
|
|
261
|
+
});
|
|
262
|
+
Schema.Struct({
|
|
263
|
+
method: Schema.Literal("POST"),
|
|
264
|
+
path: RuntimeRequestPath,
|
|
265
|
+
timestamp: RuntimeRequestTimestamp,
|
|
266
|
+
nonce: RuntimeRequestNonce,
|
|
267
|
+
appId: AppId,
|
|
268
|
+
deploymentId: Schema.optional(DeploymentId),
|
|
269
|
+
bodySha256: Sha256
|
|
270
|
+
});
|
|
271
|
+
const RuntimeErrorCode = Schema.Literals([
|
|
272
|
+
"InvalidRequest",
|
|
273
|
+
"InvalidSignature",
|
|
274
|
+
"RequestExpired",
|
|
275
|
+
"RequestReplay",
|
|
276
|
+
"InvocationRejected",
|
|
277
|
+
"RuntimeUnavailable"
|
|
278
|
+
]);
|
|
279
|
+
Schema.Struct({
|
|
280
|
+
code: RuntimeErrorCode,
|
|
281
|
+
message: Schema.String,
|
|
282
|
+
rejectionCode: Schema.optional(RuntimeInvocationRejectionCode)
|
|
283
|
+
});
|
|
284
|
+
//#endregion
|
|
285
|
+
//#region src/internal/http-paths.ts
|
|
286
|
+
const syncPath = appSyncPath;
|
|
287
|
+
//#endregion
|
|
288
|
+
//#region src/client/sync.ts
|
|
289
|
+
const queryKey = (functionAddress, args) => encodeCanonicalJson([functionAddress, args]);
|
|
70
290
|
const subscribeMessage = (entry) => ({
|
|
71
291
|
type: "Subscribe",
|
|
72
292
|
id: entry.subscriptionId,
|
|
@@ -91,9 +311,10 @@ const makeQueryCache = (allocateId, sendLifecycleMessage) => {
|
|
|
91
311
|
function: functionAddress,
|
|
92
312
|
generation: 0,
|
|
93
313
|
listeners: /* @__PURE__ */ new Set(),
|
|
314
|
+
revision: void 0,
|
|
94
315
|
references: 0,
|
|
95
316
|
result: pending(),
|
|
96
|
-
subscriptionId: allocateId
|
|
317
|
+
subscriptionId: yield* allocateId
|
|
97
318
|
};
|
|
98
319
|
queries.set(key, created);
|
|
99
320
|
queryKeysById.set(created.subscriptionId, key);
|
|
@@ -134,20 +355,31 @@ const makeQueryCache = (allocateId, sendLifecycleMessage) => {
|
|
|
134
355
|
entry.result = error;
|
|
135
356
|
for (const listener of entry.listeners) listener();
|
|
136
357
|
},
|
|
137
|
-
setResult: (id, result) => {
|
|
358
|
+
setResult: (id, result, revision) => {
|
|
138
359
|
const key = queryKeysById.get(id);
|
|
139
360
|
const entry = key === void 0 ? void 0 : queries.get(key);
|
|
140
361
|
if (entry === void 0) return;
|
|
362
|
+
if (entry.revision !== void 0 && revision < entry.revision) return;
|
|
363
|
+
entry.revision = revision;
|
|
141
364
|
entry.result = result;
|
|
142
365
|
for (const listener of entry.listeners) listener();
|
|
143
366
|
}
|
|
144
367
|
};
|
|
145
368
|
};
|
|
146
369
|
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)));
|
|
370
|
+
const shouldReloadForCloseCode = (code) => code === DeploymentChangedCloseCode;
|
|
371
|
+
const handshakesMatch = (first, next) => first.appId === next.appId && first.deploymentId === next.deploymentId && first.generation === next.generation;
|
|
372
|
+
const handshakeDecision = (remembered, acceptedOnConnection, next) => {
|
|
373
|
+
if (remembered !== void 0 && !handshakesMatch(remembered, next)) return "Reload";
|
|
374
|
+
return acceptedOnConnection ? "Ignore" : "Accept";
|
|
375
|
+
};
|
|
147
376
|
const syncClientInternals = {
|
|
148
377
|
makeQueryCache,
|
|
378
|
+
handshakeDecision,
|
|
149
379
|
queryIdentity: queryKey,
|
|
150
|
-
resultFromWire
|
|
380
|
+
resultFromWire,
|
|
381
|
+
handshakesMatch,
|
|
382
|
+
shouldReloadForCloseCode
|
|
151
383
|
};
|
|
152
384
|
const socketUrl = () => {
|
|
153
385
|
const url = new URL(syncPath, globalThis.location.href);
|
|
@@ -156,8 +388,10 @@ const socketUrl = () => {
|
|
|
156
388
|
};
|
|
157
389
|
var SyncClient = class SyncClient extends Context.Service()("ignotum/client/sync/SyncClient") {
|
|
158
390
|
static layer = Layer.effect(SyncClient, Effect.gen(function* () {
|
|
159
|
-
|
|
160
|
-
let
|
|
391
|
+
const ids = yield* IdGenerator;
|
|
392
|
+
let invocations = HashMap.empty();
|
|
393
|
+
let rememberedHandshake;
|
|
394
|
+
let reloadRequested = false;
|
|
161
395
|
let writer;
|
|
162
396
|
const encode = (message) => Schema.encodeEffect(ClientMessageJson)(message).pipe(Effect.mapError((cause) => InvalidClientMessage.make({
|
|
163
397
|
cause,
|
|
@@ -168,31 +402,27 @@ var SyncClient = class SyncClient extends Context.Service()("ignotum/client/sync
|
|
|
168
402
|
message: "The sync connection was lost."
|
|
169
403
|
})));
|
|
170
404
|
const send = (message) => writer === void 0 ? Effect.fail(ConnectionUnavailable.make({ message: "The sync connection is not ready." })) : sendWith(writer, message);
|
|
171
|
-
const queryCache = makeQueryCache((
|
|
405
|
+
const queryCache = makeQueryCache(ids.generate(SubscriptionId), (message) => writer === void 0 ? Effect.void : send(message).pipe(Effect.catchTags({
|
|
172
406
|
ConnectionUnavailable: reportClientError,
|
|
173
407
|
InvalidClientMessage: reportClientError
|
|
174
408
|
})));
|
|
175
|
-
const
|
|
176
|
-
const
|
|
177
|
-
if (
|
|
178
|
-
|
|
179
|
-
return reportClientError(error).pipe(Effect.andThen(Deferred.fail(
|
|
409
|
+
const rejectInvocation = (id, error) => {
|
|
410
|
+
const pendingInvocation = HashMap.getUnsafe(invocations, id);
|
|
411
|
+
if (pendingInvocation === void 0) return Effect.void;
|
|
412
|
+
invocations = HashMap.remove(invocations, id);
|
|
413
|
+
return reportClientError(error).pipe(Effect.andThen(Deferred.fail(pendingInvocation.deferred, error)), Effect.asVoid);
|
|
180
414
|
};
|
|
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
|
-
})));
|
|
415
|
+
const handleMessage = Effect.fn("SyncClient.handleMessage")(function* (message) {
|
|
186
416
|
switch (message.type) {
|
|
187
|
-
case "
|
|
417
|
+
case "Snapshot":
|
|
188
418
|
if (queryCache.getById(message.id) === void 0) return;
|
|
189
|
-
yield* resultFromWire(message.result).pipe(Effect.tap((result) => Effect.sync(() => queryCache.setResult(message.id, result))));
|
|
419
|
+
yield* resultFromWire(message.result).pipe(Effect.tap((result) => Effect.sync(() => queryCache.setResult(message.id, result, message.revision))));
|
|
190
420
|
return;
|
|
191
|
-
case "
|
|
192
|
-
const
|
|
193
|
-
if (
|
|
194
|
-
|
|
195
|
-
yield* resultFromWire(message.result).pipe(Effect.flatMap((result) => Deferred.succeed(
|
|
421
|
+
case "Result": {
|
|
422
|
+
const pendingInvocation = HashMap.getUnsafe(invocations, message.id);
|
|
423
|
+
if (pendingInvocation === void 0) return;
|
|
424
|
+
invocations = HashMap.remove(invocations, message.id);
|
|
425
|
+
yield* resultFromWire(message.result).pipe(Effect.flatMap((result) => Deferred.succeed(pendingInvocation.deferred, result)));
|
|
196
426
|
return;
|
|
197
427
|
}
|
|
198
428
|
case "ProtocolError": {
|
|
@@ -204,8 +434,8 @@ var SyncClient = class SyncClient extends Context.Service()("ignotum/client/sync
|
|
|
204
434
|
message: message.message,
|
|
205
435
|
operation: message.operation
|
|
206
436
|
});
|
|
207
|
-
if (message.operation?.type === "
|
|
208
|
-
else if (message.operation?.type === "
|
|
437
|
+
if (message.operation?.type === "Invocation") yield* rejectInvocation(message.operation.id, error);
|
|
438
|
+
else if (message.operation?.type === "Subscription") {
|
|
209
439
|
queryCache.setError(message.operation.id, error);
|
|
210
440
|
yield* reportClientError(error);
|
|
211
441
|
} else yield* reportClientError(error);
|
|
@@ -213,27 +443,59 @@ var SyncClient = class SyncClient extends Context.Service()("ignotum/client/sync
|
|
|
213
443
|
}
|
|
214
444
|
}
|
|
215
445
|
});
|
|
216
|
-
const
|
|
446
|
+
const requestReload = () => {
|
|
447
|
+
if (reloadRequested) return;
|
|
448
|
+
reloadRequested = true;
|
|
449
|
+
writer = void 0;
|
|
450
|
+
globalThis.location.reload();
|
|
451
|
+
};
|
|
452
|
+
const disconnect = Effect.sync(() => {
|
|
217
453
|
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
454
|
});
|
|
229
455
|
const connect = Effect.scoped(Effect.gen(function* () {
|
|
230
|
-
|
|
456
|
+
if (reloadRequested) return yield* Effect.never;
|
|
457
|
+
const socket = yield* Socket.makeWebSocket(socketUrl(), { closeCodeIsError: (code) => {
|
|
458
|
+
if (shouldReloadForCloseCode(code)) requestReload();
|
|
459
|
+
return false;
|
|
460
|
+
} });
|
|
231
461
|
const write = yield* socket.writer;
|
|
232
|
-
const
|
|
462
|
+
const handshakeReceived = yield* Deferred.make();
|
|
463
|
+
let handshakeAccepted = false;
|
|
464
|
+
const acceptHandshake = Effect.fn("SyncClient.acceptHandshake")(function* (handshake) {
|
|
465
|
+
const decision = handshakeDecision(rememberedHandshake, handshakeAccepted, handshake);
|
|
466
|
+
if (decision === "Reload") {
|
|
467
|
+
requestReload();
|
|
468
|
+
return;
|
|
469
|
+
}
|
|
470
|
+
if (decision === "Ignore") return;
|
|
471
|
+
rememberedHandshake = handshake;
|
|
472
|
+
handshakeAccepted = true;
|
|
233
473
|
writer = write;
|
|
234
|
-
yield*
|
|
235
|
-
|
|
236
|
-
|
|
474
|
+
yield* Deferred.succeed(handshakeReceived, void 0);
|
|
475
|
+
yield* Effect.gen(function* () {
|
|
476
|
+
yield* Effect.forEach(queryCache.entries(), (entry) => sendWith(write, subscribeMessage(entry)));
|
|
477
|
+
yield* Effect.forEach(HashMap.values(invocations), (pendingInvocation) => sendWith(write, pendingInvocation.message));
|
|
478
|
+
}).pipe(Effect.tapError(reportClientError), Effect.ignore);
|
|
479
|
+
});
|
|
480
|
+
const handleText = Effect.fn("SyncClient.handleText")(function* (text) {
|
|
481
|
+
const message = yield* Schema.decodeEffect(ServerMessageJson)(text).pipe(Effect.mapError((cause) => InvalidServerMessage.make({
|
|
482
|
+
cause,
|
|
483
|
+
message: "The server returned an invalid sync message."
|
|
484
|
+
})));
|
|
485
|
+
if (message.type === "Handshake") return yield* acceptHandshake(message);
|
|
486
|
+
if (message.type === "DeploymentChanged") {
|
|
487
|
+
requestReload();
|
|
488
|
+
return;
|
|
489
|
+
}
|
|
490
|
+
if (!handshakeAccepted) return yield* InvalidServerMessage.make({
|
|
491
|
+
cause: /* @__PURE__ */ new Error("The server sent a sync message before the handshake."),
|
|
492
|
+
message: "The server returned a sync message before the handshake."
|
|
493
|
+
});
|
|
494
|
+
return yield* handleMessage(message);
|
|
495
|
+
});
|
|
496
|
+
const run = yield* socket.runString(handleText).pipe(Effect.forkChild);
|
|
497
|
+
yield* Effect.raceFirst(Deferred.await(handshakeReceived).pipe(Effect.timeout("10 seconds")), Fiber.join(run));
|
|
498
|
+
yield* Fiber.join(run);
|
|
237
499
|
})).pipe(Effect.mapError((cause) => Schema.is(ClientInfrastructureError)(cause) ? cause : ConnectionUnavailable.make({
|
|
238
500
|
cause,
|
|
239
501
|
message: "The sync connection was lost."
|
|
@@ -244,37 +506,33 @@ var SyncClient = class SyncClient extends Context.Service()("ignotum/client/sync
|
|
|
244
506
|
return yield* queryCache.observe(functionAddress, args);
|
|
245
507
|
});
|
|
246
508
|
const mutate = Effect.fn("SyncClient.mutate")(function* (functionAddress, args) {
|
|
247
|
-
const
|
|
509
|
+
const invocationId = yield* ids.generate(InvocationId);
|
|
248
510
|
const deferred = yield* Deferred.make();
|
|
249
|
-
mutations = HashMap.set(mutations, requestId, {
|
|
250
|
-
deferred,
|
|
251
|
-
function: functionAddress
|
|
252
|
-
});
|
|
253
511
|
const message = {
|
|
254
|
-
type: "
|
|
255
|
-
id:
|
|
512
|
+
type: "Invoke",
|
|
513
|
+
id: invocationId,
|
|
514
|
+
kind: "Mutation",
|
|
256
515
|
function: functionAddress,
|
|
257
516
|
args
|
|
258
517
|
};
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
}).pipe(Effect.tapError(reportClientError), Effect.tapError(() => Effect.sync(() => mutations = HashMap.remove(mutations, requestId))));
|
|
518
|
+
invocations = HashMap.set(invocations, invocationId, {
|
|
519
|
+
deferred,
|
|
520
|
+
function: functionAddress,
|
|
521
|
+
message
|
|
522
|
+
});
|
|
523
|
+
if (writer !== void 0) yield* sendWith(writer, message).pipe(Effect.catchTags({
|
|
524
|
+
ConnectionUnavailable: reportClientError,
|
|
525
|
+
InvalidClientMessage: (error) => rejectInvocation(invocationId, error)
|
|
526
|
+
}));
|
|
269
527
|
return yield* Deferred.await(deferred);
|
|
270
528
|
});
|
|
271
529
|
return SyncClient.of({
|
|
272
530
|
mutate,
|
|
273
531
|
observe
|
|
274
532
|
});
|
|
275
|
-
})).pipe(Layer.provide(Socket.layerWebSocketConstructorGlobal));
|
|
533
|
+
})).pipe(Layer.provide(Layer.merge(Socket.layerWebSocketConstructorGlobal, BrowserCrypto.layer)));
|
|
276
534
|
};
|
|
277
|
-
const syncRuntime = ManagedRuntime.make(SyncClient.layer.pipe(Layer.provideMerge(clientErrorReporterLayer)));
|
|
535
|
+
const syncRuntime = ManagedRuntime.make(SyncClient.layer.pipe(Layer.provideMerge(clientErrorReporterLayer), Layer.provideMerge(IdGenerator.layer)));
|
|
278
536
|
const hot = import.meta.hot;
|
|
279
537
|
if (hot !== void 0) hot.dispose(() => void syncRuntime.dispose());
|
|
280
538
|
//#endregion
|
|
@@ -356,9 +614,15 @@ const useMutation = (reference) => useMemo$1(() => {
|
|
|
356
614
|
return mutate;
|
|
357
615
|
}, [reference]);
|
|
358
616
|
//#endregion
|
|
617
|
+
//#region src/client/app.ts
|
|
618
|
+
const app = (definition) => {
|
|
619
|
+
if (definition.title.trim().length === 0) throw new Error("The app title must contain a non-whitespace character.");
|
|
620
|
+
return definition;
|
|
621
|
+
};
|
|
622
|
+
//#endregion
|
|
359
623
|
//#region src/client/index.ts
|
|
360
624
|
const Result = { match: Result$1.match };
|
|
361
625
|
//#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 };
|
|
626
|
+
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
627
|
|
|
364
628
|
//# sourceMappingURL=client.js.map
|