ignotum 0.0.12 → 0.0.14
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/dist/cli/bin.mjs +1183 -447
- package/dist/cli/bin.mjs.map +1 -1
- package/dist/runtime/{api-DzcR7spt.js → api-CAgKDij7.js} +38 -2
- package/dist/runtime/api-CAgKDij7.js.map +1 -0
- package/dist/runtime/{api-5XSrIeqW.d.ts → api-Cv3hMbzo.d.ts} +4 -4
- package/dist/runtime/client.d.ts +39 -9
- package/dist/runtime/client.js +362 -63
- package/dist/runtime/client.js.map +1 -1
- package/dist/runtime/descriptor-DCCz5AHd-_nhlnu8U.js +298 -0
- package/dist/runtime/descriptor-DCCz5AHd-_nhlnu8U.js.map +1 -0
- package/dist/runtime/id-Bt9XWRGL.js +423 -0
- package/dist/runtime/id-Bt9XWRGL.js.map +1 -0
- package/dist/runtime/{id-Cs82tq9Q-CK-maMgN.d.ts → id-BzFHf3Wo-DGPCjgrf.d.ts} +2 -2
- package/dist/runtime/id-E7JKqQ9r.d.ts +1 -0
- package/dist/runtime/index-DWU-7TIh.d.ts +185 -0
- package/dist/runtime/internal/api.d.ts +1 -1
- package/dist/runtime/internal/api.js +1 -1
- package/dist/runtime/internal/host.d.ts +28 -7
- package/dist/runtime/internal/host.js +37 -8
- package/dist/runtime/internal/host.js.map +1 -1
- package/dist/runtime/internal/server.d.ts +1 -1
- package/dist/runtime/internal/server.js +1 -1
- package/dist/runtime/internal/types.d.ts +2 -1
- package/dist/runtime/internal/types.js +1 -1
- package/dist/runtime/{pagination-D-R9NR61-CpIoHFoI.d.ts → pagination-CpYCaRYD-C2Rpp4Cw.d.ts} +42 -7
- package/dist/runtime/pagination-E7JKqQ9r.d.ts +1 -0
- package/dist/runtime/result-DKAA4gpS.d.ts +1 -0
- package/dist/runtime/{schema-B9XxyRO8.js → schema-DqogEydG.js} +41 -12
- package/dist/runtime/schema-DqogEydG.js.map +1 -0
- package/dist/runtime/server.d.ts +7 -4
- package/dist/runtime/server.js +2 -2
- package/dist/runtime/server.js.map +1 -1
- package/dist/runtime/{sync-avN7NkcU.d.ts → sync-Bs8J3fIr.d.ts} +2 -2
- package/dist/runtime/types-C1iDP2Yf-BnkfBOQf.d.ts +224 -0
- package/package.json +2 -2
- package/src/cli/agent-files.ts +10 -0
- package/src/cli/build/server.ts +35 -6
- package/src/cli/command.ts +25 -2
- package/src/cli/deploy.ts +34 -11
- package/src/client/hooks.ts +68 -0
- package/src/client/id.ts +259 -0
- package/src/client/index.ts +5 -2
- package/src/client/sync.ts +144 -11
- package/src/dev-runtime/database.ts +77 -2
- package/src/dev-runtime/functions.ts +111 -88
- package/src/dev-runtime/id.ts +190 -0
- package/src/dev-runtime/migrations.ts +9 -0
- package/src/dev-runtime/query-cache.ts +105 -0
- package/src/dev-runtime/sync.ts +149 -17
- package/src/internal/host.ts +1 -1
- package/src/server/index.ts +2 -0
- package/dist/runtime/api-DzcR7spt.js.map +0 -1
- package/dist/runtime/descriptor-XzDX2JDw-j3O6YHgW.js +0 -330
- package/dist/runtime/descriptor-XzDX2JDw-j3O6YHgW.js.map +0 -1
- package/dist/runtime/file-C1abuMgd.js +0 -173
- package/dist/runtime/file-C1abuMgd.js.map +0 -1
- package/dist/runtime/index-CrWg4Z0y.d.ts +0 -398
- package/dist/runtime/pagination-CX5IPbEi.d.ts +0 -1
- package/dist/runtime/result-DIjKM-p4.d.ts +0 -1
- package/dist/runtime/schema-B9XxyRO8.js.map +0 -1
package/dist/runtime/client.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { Array as Array$1, Cause, Context, Deferred, Duration, Effect, ErrorReporter, Fiber, HashMap, Layer, ManagedRuntime, Predicate, Schedule, Schema, String } from "effect";
|
|
1
|
+
import { A as RuntimeFileMetadata, B as makeFileValue, D as encodeTransportObject, E as decodeTransportValue, F as fileIdOf, G as IdAlphabet, H as AppId, I as fileLimits, J as SessionEpoch, K as InvocationId, L as fileMimeTypes, N as fileFormats, P as fileGrantUrlOf, R as grantFileValue, U as DeploymentId, W as GeneratedId, X as TableId, Y as SubscriptionId, _ as Result$2, a as SessionResponse, b as inspectResult, d as sessionPath, f as sessionRequestsPath, i as SessionRequest, j as RuntimeFileOccurrence, k as FileId, l as developmentSelectionKey, m as upgrade, n as SessionOutcome, o as SessionState, p as initial, q as RuntimeRequestNonce, r as SessionRedirect, t as DevelopmentSelection, x as pending, y as failureFromWire, z as isFileValue } from "./id-Bt9XWRGL.js";
|
|
2
|
+
import { a as ErrorCode, c as ServerMessageJson, d as WireSuccess, f as AppStateRevision, i as DeploymentCloseCode, l as WireFailure, m as InvocationKey, n as functionPathOf, o as FunctionAddress, p as DeploymentGeneration, r as ClientMessageJson, s as Operation, u as WireResult } from "./api-CAgKDij7.js";
|
|
3
|
+
import { d as PaginationPageSize, t as ValueDescriptor } from "./descriptor-DCCz5AHd-_nhlnu8U.js";
|
|
4
|
+
import { Array as Array$1, Cause, Context, Deferred, Duration, Effect, ErrorReporter, Fiber, HashMap, Layer, ManagedRuntime, Option, Predicate, Schedule, Schema, Semaphore, String } from "effect";
|
|
5
5
|
import { customAlphabet } from "nanoid";
|
|
6
|
-
import {
|
|
6
|
+
import { FetchHttpClient, HttpClient, HttpClientRequest, HttpClientResponse } from "effect/unstable/http";
|
|
7
|
+
import { useCallback, useCallback as useCallback$1, useContext, useDebugValue, useDebugValue as useDebugValue$1, useEffect, useEffect as useEffect$1, useErrorBoundary, useId as useElementId, useImperativeHandle, useLayoutEffect, useMemo, useMemo as useMemo$1, useReducer, useRef, useState, useState as useState$1 } from "preact/hooks";
|
|
7
8
|
import * as Socket from "effect/unstable/socket/Socket";
|
|
8
9
|
import * as BrowserCrypto from "@effect/platform-browser/BrowserCrypto";
|
|
9
10
|
import { Component, Fragment, cloneElement, createContext, createElement, createRef, h, isValidElement, toChildArray } from "preact";
|
|
@@ -119,6 +120,177 @@ const encodeJson = (value) => {
|
|
|
119
120
|
};
|
|
120
121
|
const encodeCanonicalJson = (value) => encodeJson(Schema.decodeSync(Schema.Json)(value));
|
|
121
122
|
//#endregion
|
|
123
|
+
//#region src/client/id.ts
|
|
124
|
+
var IdRequestError = class extends Schema.TaggedError()("IdRequestError", { message: Schema.String }) {};
|
|
125
|
+
const outcomeKey = "ignotum.id.outcome";
|
|
126
|
+
const selectionJson = Schema.fromJsonString(DevelopmentSelection);
|
|
127
|
+
var BrowserSession = class BrowserSession extends Context.Service()("ignotum/client/id/BrowserSession") {
|
|
128
|
+
static layer = Layer.effect(BrowserSession, Effect.gen(function* () {
|
|
129
|
+
const client = (yield* HttpClient.HttpClient).pipe(HttpClient.filterStatusOk);
|
|
130
|
+
const ids = yield* IdGenerator;
|
|
131
|
+
const bootstrapLock = yield* Semaphore.make(1);
|
|
132
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
133
|
+
let state = { status: "pending" };
|
|
134
|
+
let current;
|
|
135
|
+
let generation = 0;
|
|
136
|
+
let deadline = Infinity;
|
|
137
|
+
let development = false;
|
|
138
|
+
let selection;
|
|
139
|
+
let expiry;
|
|
140
|
+
const notify = () => {
|
|
141
|
+
for (const listener of listeners) listener();
|
|
142
|
+
};
|
|
143
|
+
const suspend = (error) => {
|
|
144
|
+
generation += 1;
|
|
145
|
+
deadline = Infinity;
|
|
146
|
+
if (expiry !== void 0) clearTimeout(expiry);
|
|
147
|
+
current = void 0;
|
|
148
|
+
state = error === void 0 ? {
|
|
149
|
+
status: "pending",
|
|
150
|
+
outcome: state.outcome
|
|
151
|
+
} : {
|
|
152
|
+
status: "error",
|
|
153
|
+
error,
|
|
154
|
+
outcome: state.outcome
|
|
155
|
+
};
|
|
156
|
+
notify();
|
|
157
|
+
};
|
|
158
|
+
const accept = (session, serverTime) => {
|
|
159
|
+
generation += 1;
|
|
160
|
+
if (expiry !== void 0) clearTimeout(expiry);
|
|
161
|
+
current = session;
|
|
162
|
+
state = session.user === null ? {
|
|
163
|
+
status: "signedOut",
|
|
164
|
+
outcome: state.outcome
|
|
165
|
+
} : {
|
|
166
|
+
status: "signedIn",
|
|
167
|
+
user: session.user,
|
|
168
|
+
outcome: state.outcome
|
|
169
|
+
};
|
|
170
|
+
const delay = Math.max(0, session.validUntil - serverTime);
|
|
171
|
+
deadline = performance.now() + delay;
|
|
172
|
+
if (delay < 2147483647) expiry = setTimeout(() => suspend(), delay);
|
|
173
|
+
notify();
|
|
174
|
+
};
|
|
175
|
+
const checkExpiry = () => {
|
|
176
|
+
if (current !== void 0 && performance.now() >= deadline) suspend();
|
|
177
|
+
};
|
|
178
|
+
globalThis.addEventListener?.("focus", checkExpiry);
|
|
179
|
+
globalThis.document?.addEventListener("visibilitychange", checkExpiry);
|
|
180
|
+
yield* Effect.addFinalizer(() => Effect.sync(() => {
|
|
181
|
+
if (expiry !== void 0) clearTimeout(expiry);
|
|
182
|
+
listeners.clear();
|
|
183
|
+
globalThis.removeEventListener?.("focus", checkExpiry);
|
|
184
|
+
globalThis.document?.removeEventListener("visibilitychange", checkExpiry);
|
|
185
|
+
}));
|
|
186
|
+
const readOutcome = () => {
|
|
187
|
+
const raw = globalThis.sessionStorage.getItem(outcomeKey);
|
|
188
|
+
if (raw !== null) {
|
|
189
|
+
const decoded = Schema.decodeUnknownOption(SessionOutcome)(raw);
|
|
190
|
+
if (Option.isSome(decoded)) state = {
|
|
191
|
+
...state,
|
|
192
|
+
outcome: decoded.value
|
|
193
|
+
};
|
|
194
|
+
globalThis.sessionStorage.removeItem(outcomeKey);
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
const parameters = () => {
|
|
198
|
+
if (!development || selection === void 0) return "";
|
|
199
|
+
const params = new URLSearchParams({ epoch: selection.epoch });
|
|
200
|
+
if (selection.username !== null) params.set("username", selection.username);
|
|
201
|
+
return `?${params}`;
|
|
202
|
+
};
|
|
203
|
+
const readSession = Effect.fn("BrowserSession.read")(function* () {
|
|
204
|
+
return yield* client.get(`${sessionPath}${parameters()}`, { headers: { "x-ignotum-request": "1" } }).pipe(Effect.flatMap(HttpClientResponse.schemaBodyJson(SessionResponse)));
|
|
205
|
+
});
|
|
206
|
+
let bootstrapGeneration = 0;
|
|
207
|
+
const bootstrap = bootstrapLock.withPermits(1)(Effect.gen(function* () {
|
|
208
|
+
const admittedGeneration = generation;
|
|
209
|
+
bootstrapGeneration = admittedGeneration;
|
|
210
|
+
const startedAt = performance.now();
|
|
211
|
+
let session = yield* readSession();
|
|
212
|
+
development = session.development === true;
|
|
213
|
+
if (development && selection === void 0) {
|
|
214
|
+
const saved = globalThis.sessionStorage.getItem(developmentSelectionKey);
|
|
215
|
+
const decoded = saved === null ? Option.none() : Schema.decodeOption(selectionJson)(saved);
|
|
216
|
+
selection = Option.getOrElse(decoded, () => ({
|
|
217
|
+
formatVersion: 1,
|
|
218
|
+
username: null,
|
|
219
|
+
epoch: ""
|
|
220
|
+
}));
|
|
221
|
+
if (selection.epoch === "") selection = {
|
|
222
|
+
...selection,
|
|
223
|
+
epoch: yield* ids.generate(SessionEpoch)
|
|
224
|
+
};
|
|
225
|
+
globalThis.sessionStorage.setItem(developmentSelectionKey, Schema.encodeSync(selectionJson)(selection));
|
|
226
|
+
session = yield* readSession();
|
|
227
|
+
}
|
|
228
|
+
if (generation !== admittedGeneration) {
|
|
229
|
+
if (current !== void 0) return current;
|
|
230
|
+
return yield* IdRequestError.make({ message: "Your ID session changed while loading." });
|
|
231
|
+
}
|
|
232
|
+
readOutcome();
|
|
233
|
+
if (session.outcome !== void 0) state = {
|
|
234
|
+
...state,
|
|
235
|
+
outcome: session.outcome
|
|
236
|
+
};
|
|
237
|
+
accept(session, session.serverTime + performance.now() - startedAt);
|
|
238
|
+
return session;
|
|
239
|
+
})).pipe(Effect.mapError(() => IdRequestError.make({ message: "Could not load your ID session." })), Effect.tapError((error) => Effect.sync(() => {
|
|
240
|
+
if (generation === bootstrapGeneration) suspend(error.message);
|
|
241
|
+
})));
|
|
242
|
+
const start = Effect.fn("BrowserSession.start")(function* (intent, profile, returnTo) {
|
|
243
|
+
const session = current ?? (yield* bootstrap);
|
|
244
|
+
if (intent === "requestProfile" && session.user === null) return yield* IdRequestError.make({ message: "Sign in before requesting profile information." });
|
|
245
|
+
const request = yield* Schema.decodeUnknownEffect(SessionRequest)({
|
|
246
|
+
intent,
|
|
247
|
+
profile,
|
|
248
|
+
sessionEpoch: session.sessionEpoch,
|
|
249
|
+
returnTo: returnTo ?? `${globalThis.location.pathname}${globalThis.location.search}${globalThis.location.hash}`
|
|
250
|
+
}).pipe(Effect.mapError(() => IdRequestError.make({ message: "The ID request is invalid." })));
|
|
251
|
+
const redirect = yield* HttpClientRequest.post(sessionRequestsPath).pipe(HttpClientRequest.setHeader("x-ignotum-request", "1"), HttpClientRequest.bodyJsonUnsafe(request), client.execute, Effect.flatMap(HttpClientResponse.schemaBodyJson(SessionRedirect)), Effect.mapError(() => IdRequestError.make({ message: "Could not start the ID request." })));
|
|
252
|
+
if (current?.sessionEpoch !== session.sessionEpoch) return yield* IdRequestError.make({ message: "Your ID session changed. Try again." });
|
|
253
|
+
globalThis.location.assign(redirect.redirectUrl);
|
|
254
|
+
});
|
|
255
|
+
const signOut = Effect.gen(function* () {
|
|
256
|
+
const session = current ?? (yield* bootstrap);
|
|
257
|
+
yield* HttpClientRequest.delete(sessionPath).pipe(HttpClientRequest.setHeader("x-ignotum-request", "1"), HttpClientRequest.bodyJsonUnsafe({ sessionEpoch: session.sessionEpoch }), client.execute, Effect.mapError(() => IdRequestError.make({ message: "Could not sign out." })));
|
|
258
|
+
suspend();
|
|
259
|
+
if (development) {
|
|
260
|
+
selection = {
|
|
261
|
+
formatVersion: 1,
|
|
262
|
+
username: null,
|
|
263
|
+
epoch: yield* ids.generate(SessionEpoch)
|
|
264
|
+
};
|
|
265
|
+
globalThis.sessionStorage.setItem(developmentSelectionKey, Schema.encodeSync(selectionJson)(selection));
|
|
266
|
+
}
|
|
267
|
+
globalThis.location.reload();
|
|
268
|
+
});
|
|
269
|
+
return BrowserSession.of({
|
|
270
|
+
snapshot: () => {
|
|
271
|
+
checkExpiry();
|
|
272
|
+
return state;
|
|
273
|
+
},
|
|
274
|
+
current: () => {
|
|
275
|
+
checkExpiry();
|
|
276
|
+
return current;
|
|
277
|
+
},
|
|
278
|
+
subscribe: (listener) => {
|
|
279
|
+
listeners.add(listener);
|
|
280
|
+
return () => {
|
|
281
|
+
listeners.delete(listener);
|
|
282
|
+
};
|
|
283
|
+
},
|
|
284
|
+
accept,
|
|
285
|
+
suspend,
|
|
286
|
+
bootstrap,
|
|
287
|
+
start,
|
|
288
|
+
signOut,
|
|
289
|
+
socketParameters: parameters
|
|
290
|
+
});
|
|
291
|
+
})).pipe(Layer.provide(FetchHttpClient.layer));
|
|
292
|
+
};
|
|
293
|
+
//#endregion
|
|
122
294
|
//#region src/client/errors.ts
|
|
123
295
|
/** @effect-diagnostics globalConsole:skip-file */
|
|
124
296
|
var ConnectionUnavailable = class extends Schema.TaggedError()("ConnectionUnavailable", {
|
|
@@ -198,7 +370,9 @@ const IndexPointInvalidation = Schema.Struct({
|
|
|
198
370
|
index: IndexIdentity,
|
|
199
371
|
key: EncodedIndexKey
|
|
200
372
|
});
|
|
373
|
+
const IdDependency = Schema.Struct({ type: Schema.Literal("Id") });
|
|
201
374
|
const ReadDependency = Schema.Union([
|
|
375
|
+
IdDependency,
|
|
202
376
|
TableDependency,
|
|
203
377
|
DocumentDependency,
|
|
204
378
|
IndexRangeDependency
|
|
@@ -263,7 +437,8 @@ const InvocationBase = {
|
|
|
263
437
|
generation: DeploymentGeneration,
|
|
264
438
|
invocationKey: InvocationKey,
|
|
265
439
|
function: FunctionAddress,
|
|
266
|
-
args: Schema.Json
|
|
440
|
+
args: Schema.Json,
|
|
441
|
+
identity: Schema.optional(SessionState)
|
|
267
442
|
};
|
|
268
443
|
const QueryInvocation = Schema.Struct({
|
|
269
444
|
...InvocationBase,
|
|
@@ -286,6 +461,7 @@ var RuntimeDeploymentUnavailable = class extends Schema.TaggedError()("RuntimeDe
|
|
|
286
461
|
message: Schema.String
|
|
287
462
|
}) {};
|
|
288
463
|
const RuntimeInvocationRejectionCode = Schema.Literals([
|
|
464
|
+
"SessionExpired",
|
|
289
465
|
"FunctionUnavailable",
|
|
290
466
|
"InvalidArguments",
|
|
291
467
|
"InvocationIdConflict",
|
|
@@ -473,11 +649,25 @@ const ServerBuildManifestV3 = Schema.Struct({
|
|
|
473
649
|
environment: Schema.optional(ServerEnvironmentArtifact),
|
|
474
650
|
functions: Schema.Array(ServerFunctionArtifact)
|
|
475
651
|
});
|
|
476
|
-
upgrade(ServerBuildManifestThroughV2, ServerBuildManifestV3, (manifest) => ({
|
|
652
|
+
const ServerBuildManifestThroughV3 = upgrade(ServerBuildManifestThroughV2, ServerBuildManifestV3, (manifest) => ({
|
|
477
653
|
formatVersion: 3,
|
|
478
654
|
schema: manifest.schema,
|
|
479
655
|
functions: manifest.functions
|
|
480
656
|
}));
|
|
657
|
+
const ServerBuildManifestV4 = Schema.Struct({
|
|
658
|
+
formatVersion: Schema.Literal(4),
|
|
659
|
+
schema: ArtifactReference,
|
|
660
|
+
environment: Schema.optional(ServerEnvironmentArtifact),
|
|
661
|
+
functions: Schema.Array(ServerFunctionArtifact),
|
|
662
|
+
schemaEvolution: Schema.optional(Schema.Struct({
|
|
663
|
+
bundle: ArtifactReference,
|
|
664
|
+
sourceMap: ArtifactReference
|
|
665
|
+
}))
|
|
666
|
+
});
|
|
667
|
+
upgrade(ServerBuildManifestThroughV3, ServerBuildManifestV4, (manifest) => ({
|
|
668
|
+
...manifest,
|
|
669
|
+
formatVersion: 4
|
|
670
|
+
}));
|
|
481
671
|
ArtifactPath.make("inventory.json");
|
|
482
672
|
ArtifactPath.make("client/manifest.json");
|
|
483
673
|
ArtifactPath.make("client/shell.html");
|
|
@@ -489,6 +679,7 @@ ArtifactPath.make("server/environment.json");
|
|
|
489
679
|
//#endregion
|
|
490
680
|
//#region ../contracts/dist/runtime/transport.js
|
|
491
681
|
const runtimeInvocationPath = "/v1/invoke";
|
|
682
|
+
const runtimeConsolePath = "/v1/console/read";
|
|
492
683
|
const runtimeRevisionPath = "/v1/revision";
|
|
493
684
|
const runtimeIndexPreparePath = "/v1/indexes/prepare";
|
|
494
685
|
const runtimeIndexCommitPath = "/v1/indexes/commit";
|
|
@@ -496,6 +687,7 @@ const runtimeFileEffectsPath = "/v1/files/effects";
|
|
|
496
687
|
const runtimeFileEffectsAcknowledgePath = "/v1/files/effects/acknowledge";
|
|
497
688
|
const appSyncPath = `/_ignotum/v1/sync`;
|
|
498
689
|
const RuntimeRequestPath = Schema.Literals([
|
|
690
|
+
runtimeConsolePath,
|
|
499
691
|
runtimeInvocationPath,
|
|
500
692
|
runtimeRevisionPath,
|
|
501
693
|
runtimeIndexPreparePath,
|
|
@@ -523,9 +715,13 @@ Schema.Struct({
|
|
|
523
715
|
});
|
|
524
716
|
Schema.Struct({
|
|
525
717
|
appId: AppId,
|
|
526
|
-
deploymentId: DeploymentId
|
|
718
|
+
deploymentId: DeploymentId,
|
|
719
|
+
generation: Schema.optional(Schema.Natural)
|
|
527
720
|
});
|
|
528
|
-
Schema.Struct({ completed: Schema.Literal(true) })
|
|
721
|
+
Schema.Union([Schema.Struct({ completed: Schema.Literal(true) }), Schema.Struct({
|
|
722
|
+
completed: Schema.Literal(false),
|
|
723
|
+
message: Schema.String
|
|
724
|
+
})]);
|
|
529
725
|
const RuntimeErrorCode = Schema.Literals([
|
|
530
726
|
"InvalidRequest",
|
|
531
727
|
"InvalidSignature",
|
|
@@ -554,55 +750,67 @@ const subscribeMessage = (entry) => ({
|
|
|
554
750
|
const makeQueryCache = (allocateId, sendLifecycleMessage) => {
|
|
555
751
|
const queries = /* @__PURE__ */ new Map();
|
|
556
752
|
const queriesById = /* @__PURE__ */ new Map();
|
|
753
|
+
const observe = Effect.fn("SyncClient.QueryCache.observe")(function* (functionAddress, args) {
|
|
754
|
+
const key = queryKey(functionAddress, args);
|
|
755
|
+
let entry = queries.get(key);
|
|
756
|
+
if (entry === void 0) {
|
|
757
|
+
const created = {
|
|
758
|
+
args,
|
|
759
|
+
function: functionAddress,
|
|
760
|
+
generation: 0,
|
|
761
|
+
listeners: /* @__PURE__ */ new Set(),
|
|
762
|
+
revision: void 0,
|
|
763
|
+
references: 0,
|
|
764
|
+
result: pending(),
|
|
765
|
+
subscriptionId: yield* allocateId
|
|
766
|
+
};
|
|
767
|
+
queries.set(key, created);
|
|
768
|
+
queriesById.set(created.subscriptionId, created);
|
|
769
|
+
yield* sendLifecycleMessage(subscribeMessage(created));
|
|
770
|
+
entry = created;
|
|
771
|
+
}
|
|
772
|
+
const observed = entry;
|
|
773
|
+
observed.references += 1;
|
|
774
|
+
observed.generation += 1;
|
|
775
|
+
let released = false;
|
|
776
|
+
return {
|
|
777
|
+
getSnapshot: () => observed.result,
|
|
778
|
+
subscribe: (listener) => {
|
|
779
|
+
observed.listeners.add(listener);
|
|
780
|
+
return () => observed.listeners.delete(listener);
|
|
781
|
+
},
|
|
782
|
+
release: Effect.gen(function* () {
|
|
783
|
+
if (released) return;
|
|
784
|
+
released = true;
|
|
785
|
+
observed.references -= 1;
|
|
786
|
+
if (observed.references !== 0) return;
|
|
787
|
+
const generation = ++observed.generation;
|
|
788
|
+
yield* Effect.sleep("25 millis");
|
|
789
|
+
if (observed.references !== 0 || observed.generation !== generation || queries.get(key) !== observed) return;
|
|
790
|
+
queries.delete(key);
|
|
791
|
+
queriesById.delete(observed.subscriptionId);
|
|
792
|
+
yield* sendLifecycleMessage({
|
|
793
|
+
type: "Unsubscribe",
|
|
794
|
+
id: observed.subscriptionId
|
|
795
|
+
});
|
|
796
|
+
})
|
|
797
|
+
};
|
|
798
|
+
});
|
|
799
|
+
const clear = (entry) => {
|
|
800
|
+
entry.result = pending();
|
|
801
|
+
entry.revision = void 0;
|
|
802
|
+
for (const listener of entry.listeners) listener();
|
|
803
|
+
};
|
|
557
804
|
return {
|
|
805
|
+
invalidate: (ids) => {
|
|
806
|
+
for (const entry of queries.values()) if (ids === void 0 || ids.includes(entry.subscriptionId)) clear(entry);
|
|
807
|
+
},
|
|
808
|
+
invalidatePrivate: () => {
|
|
809
|
+
for (const entry of queries.values()) if (entry.dependsOnId !== false) clear(entry);
|
|
810
|
+
},
|
|
558
811
|
entries: () => queries.values(),
|
|
559
812
|
getById: (id) => queriesById.get(id),
|
|
560
|
-
observe
|
|
561
|
-
const key = queryKey(functionAddress, args);
|
|
562
|
-
let entry = queries.get(key);
|
|
563
|
-
if (entry === void 0) {
|
|
564
|
-
const created = {
|
|
565
|
-
args,
|
|
566
|
-
function: functionAddress,
|
|
567
|
-
generation: 0,
|
|
568
|
-
listeners: /* @__PURE__ */ new Set(),
|
|
569
|
-
revision: void 0,
|
|
570
|
-
references: 0,
|
|
571
|
-
result: pending(),
|
|
572
|
-
subscriptionId: yield* allocateId
|
|
573
|
-
};
|
|
574
|
-
queries.set(key, created);
|
|
575
|
-
queriesById.set(created.subscriptionId, created);
|
|
576
|
-
yield* sendLifecycleMessage(subscribeMessage(created));
|
|
577
|
-
entry = created;
|
|
578
|
-
}
|
|
579
|
-
const observed = entry;
|
|
580
|
-
observed.references += 1;
|
|
581
|
-
observed.generation += 1;
|
|
582
|
-
let released = false;
|
|
583
|
-
return {
|
|
584
|
-
getSnapshot: () => observed.result,
|
|
585
|
-
subscribe: (listener) => {
|
|
586
|
-
observed.listeners.add(listener);
|
|
587
|
-
return () => observed.listeners.delete(listener);
|
|
588
|
-
},
|
|
589
|
-
release: Effect.gen(function* () {
|
|
590
|
-
if (released) return;
|
|
591
|
-
released = true;
|
|
592
|
-
observed.references -= 1;
|
|
593
|
-
if (observed.references !== 0) return;
|
|
594
|
-
const generation = ++observed.generation;
|
|
595
|
-
yield* Effect.sleep("25 millis");
|
|
596
|
-
if (observed.references !== 0 || observed.generation !== generation || queries.get(key) !== observed) return;
|
|
597
|
-
queries.delete(key);
|
|
598
|
-
queriesById.delete(observed.subscriptionId);
|
|
599
|
-
yield* sendLifecycleMessage({
|
|
600
|
-
type: "Unsubscribe",
|
|
601
|
-
id: observed.subscriptionId
|
|
602
|
-
});
|
|
603
|
-
})
|
|
604
|
-
};
|
|
605
|
-
}),
|
|
813
|
+
observe,
|
|
606
814
|
setResult: (id, result, revision) => {
|
|
607
815
|
const entry = queriesById.get(id);
|
|
608
816
|
if (entry === void 0) return;
|
|
@@ -644,10 +852,12 @@ const socketUrl = () => {
|
|
|
644
852
|
var SyncClient = class SyncClient extends Context.Service()("ignotum/client/sync/SyncClient") {
|
|
645
853
|
static layer = Layer.effect(SyncClient, Effect.gen(function* () {
|
|
646
854
|
const ids = yield* IdGenerator;
|
|
855
|
+
const session = yield* BrowserSession;
|
|
647
856
|
let invocations = HashMap.empty();
|
|
648
857
|
let rememberedHandshake;
|
|
649
858
|
let reloadRequested = false;
|
|
650
859
|
let writer;
|
|
860
|
+
let sessionSuspended;
|
|
651
861
|
const encode = (message) => Schema.encodeEffect(ClientMessageJson)(message).pipe(Effect.mapError((cause) => InvalidClientMessage.make({
|
|
652
862
|
cause,
|
|
653
863
|
message: "Could not encode an Ignotum sync message."
|
|
@@ -661,17 +871,47 @@ var SyncClient = class SyncClient extends Context.Service()("ignotum/client/sync
|
|
|
661
871
|
ConnectionUnavailable: reportClientError,
|
|
662
872
|
InvalidClientMessage: reportClientError
|
|
663
873
|
})));
|
|
874
|
+
const unsubscribeSession = session.subscribe(() => {
|
|
875
|
+
if (session.current() === void 0) {
|
|
876
|
+
queryCache.invalidatePrivate();
|
|
877
|
+
writer = void 0;
|
|
878
|
+
if (sessionSuspended !== void 0) Deferred.doneUnsafe(sessionSuspended, Effect.void);
|
|
879
|
+
}
|
|
880
|
+
});
|
|
881
|
+
yield* Effect.addFinalizer(() => Effect.sync(unsubscribeSession));
|
|
664
882
|
const rejectInvocation = (id, error) => {
|
|
665
|
-
const pendingInvocation = HashMap.
|
|
883
|
+
const pendingInvocation = Option.getOrUndefined(HashMap.get(invocations, id));
|
|
666
884
|
if (pendingInvocation === void 0) return Effect.void;
|
|
667
885
|
invocations = HashMap.remove(invocations, id);
|
|
668
886
|
return reportClientError(error).pipe(Effect.andThen(Deferred.fail(pendingInvocation.prepared, error)), Effect.andThen(Deferred.fail(pendingInvocation.deferred, error)), Effect.asVoid);
|
|
669
887
|
};
|
|
670
888
|
const handleMessage = Effect.fn("SyncClient.handleMessage")(function* (message) {
|
|
671
889
|
switch (message.type) {
|
|
890
|
+
case "Session":
|
|
891
|
+
if (message.event === "Updated") {
|
|
892
|
+
const previous = session.current();
|
|
893
|
+
if (previous !== void 0 && previous.sessionEpoch !== message.session.sessionEpoch) return;
|
|
894
|
+
if (previous?.viewRevision !== message.session.viewRevision) queryCache.invalidatePrivate();
|
|
895
|
+
session.accept(message.session, message.serverTime);
|
|
896
|
+
} else {
|
|
897
|
+
if (rememberedHandshake?.session?.sessionEpoch !== message.sessionEpoch) return;
|
|
898
|
+
session.suspend(message.event === "Unavailable" ? "Your ID session is temporarily unavailable." : void 0);
|
|
899
|
+
if (message.event !== "Unavailable") yield* Effect.forEach(HashMap.keys(invocations), (id) => rejectInvocation(id, ServerError.make({
|
|
900
|
+
code: "SessionChanged",
|
|
901
|
+
message: "The session changed. This operation may already have completed."
|
|
902
|
+
})));
|
|
903
|
+
}
|
|
904
|
+
return;
|
|
905
|
+
case "Invalidate":
|
|
906
|
+
if (message.sessionEpoch === session.current()?.sessionEpoch) queryCache.invalidate(message.ids);
|
|
907
|
+
return;
|
|
672
908
|
case "Snapshot": {
|
|
909
|
+
const current = session.current();
|
|
910
|
+
if (current === void 0 || message.identity?.sessionEpoch !== current.sessionEpoch) return;
|
|
911
|
+
if (message.identity.dependsOnId && message.identity.viewRevision !== current.viewRevision) return;
|
|
673
912
|
const entry = queryCache.getById(message.id);
|
|
674
913
|
if (entry === void 0) return;
|
|
914
|
+
entry.dependsOnId = message.identity.dependsOnId;
|
|
675
915
|
if (entry.revision !== void 0 && message.revision < entry.revision) return;
|
|
676
916
|
yield* resultFromWire(message.result, message.files ?? []).pipe(Effect.tap((result) => Effect.sync(() => queryCache.setResult(message.id, result, message.revision))), Effect.catchTags({ InvalidServerMessage: (error) => {
|
|
677
917
|
queryCache.setResult(message.id, error, message.revision);
|
|
@@ -680,12 +920,14 @@ var SyncClient = class SyncClient extends Context.Service()("ignotum/client/sync
|
|
|
680
920
|
return;
|
|
681
921
|
}
|
|
682
922
|
case "Preparation": {
|
|
683
|
-
|
|
923
|
+
if (message.sessionEpoch !== session.current()?.sessionEpoch) return;
|
|
924
|
+
const pendingInvocation = Option.getOrUndefined(HashMap.get(invocations, message.id));
|
|
684
925
|
if (pendingInvocation !== void 0) yield* Deferred.succeed(pendingInvocation.prepared, message.uploads);
|
|
685
926
|
return;
|
|
686
927
|
}
|
|
687
928
|
case "Result": {
|
|
688
|
-
|
|
929
|
+
if (message.sessionEpoch !== session.current()?.sessionEpoch) return;
|
|
930
|
+
const pendingInvocation = Option.getOrUndefined(HashMap.get(invocations, message.id));
|
|
689
931
|
if (pendingInvocation === void 0) return;
|
|
690
932
|
yield* resultFromWire(message.result).pipe(Effect.flatMap((result) => {
|
|
691
933
|
invocations = HashMap.remove(invocations, message.id);
|
|
@@ -694,6 +936,7 @@ var SyncClient = class SyncClient extends Context.Service()("ignotum/client/sync
|
|
|
694
936
|
return;
|
|
695
937
|
}
|
|
696
938
|
case "Error": {
|
|
939
|
+
if (message.sessionEpoch !== session.current()?.sessionEpoch) return;
|
|
697
940
|
const error = message.operation === void 0 ? ServerError.make({
|
|
698
941
|
code: message.code,
|
|
699
942
|
message: message.message
|
|
@@ -722,7 +965,8 @@ var SyncClient = class SyncClient extends Context.Service()("ignotum/client/sync
|
|
|
722
965
|
});
|
|
723
966
|
const connect = Effect.scoped(Effect.gen(function* () {
|
|
724
967
|
if (reloadRequested) return yield* Effect.never;
|
|
725
|
-
|
|
968
|
+
yield* session.bootstrap.pipe(Effect.mapError((error) => ConnectionUnavailable.make({ message: error.message })));
|
|
969
|
+
const socket = yield* Socket.makeWebSocket(`${socketUrl()}${session.socketParameters()}`, { closeCodeIsError: (code) => {
|
|
726
970
|
if (shouldReloadForCloseCode(code)) requestReload();
|
|
727
971
|
return false;
|
|
728
972
|
} });
|
|
@@ -736,6 +980,22 @@ var SyncClient = class SyncClient extends Context.Service()("ignotum/client/sync
|
|
|
736
980
|
return;
|
|
737
981
|
}
|
|
738
982
|
if (decision === "Ignore") return;
|
|
983
|
+
if (handshake.session === void 0 || handshake.serverTime === void 0) {
|
|
984
|
+
requestReload();
|
|
985
|
+
return;
|
|
986
|
+
}
|
|
987
|
+
if (rememberedHandshake?.session !== void 0 && rememberedHandshake.session.sessionEpoch !== handshake.session.sessionEpoch) {
|
|
988
|
+
queryCache.invalidatePrivate();
|
|
989
|
+
yield* Effect.forEach(HashMap.keys(invocations), (id) => rejectInvocation(id, ServerError.make({
|
|
990
|
+
code: "SessionChanged",
|
|
991
|
+
message: "The session changed. This operation may already have completed."
|
|
992
|
+
})));
|
|
993
|
+
} else if (rememberedHandshake?.session?.viewRevision !== handshake.session.viewRevision) queryCache.invalidatePrivate();
|
|
994
|
+
yield* Effect.forEach(HashMap.entries(invocations), ([id, pending]) => pending.sessionEpoch === handshake.session.sessionEpoch ? Effect.void : rejectInvocation(id, ServerError.make({
|
|
995
|
+
code: "SessionChanged",
|
|
996
|
+
message: "The session changed. This operation may already have completed."
|
|
997
|
+
})));
|
|
998
|
+
session.accept(handshake.session, handshake.serverTime);
|
|
739
999
|
rememberedHandshake = handshake;
|
|
740
1000
|
handshakeAccepted = true;
|
|
741
1001
|
writer = write;
|
|
@@ -761,9 +1021,14 @@ var SyncClient = class SyncClient extends Context.Service()("ignotum/client/sync
|
|
|
761
1021
|
});
|
|
762
1022
|
return yield* handleMessage(message);
|
|
763
1023
|
});
|
|
1024
|
+
const suspended = yield* Deferred.make();
|
|
1025
|
+
sessionSuspended = suspended;
|
|
1026
|
+
yield* Effect.addFinalizer(() => Effect.sync(() => {
|
|
1027
|
+
if (sessionSuspended === suspended) sessionSuspended = void 0;
|
|
1028
|
+
}));
|
|
764
1029
|
const run = yield* socket.runString(handleText).pipe(Effect.forkChild);
|
|
765
1030
|
yield* Effect.raceFirst(Deferred.await(handshakeReceived).pipe(Effect.timeout("10 seconds")), Fiber.join(run));
|
|
766
|
-
yield* Fiber.join(run);
|
|
1031
|
+
yield* Effect.raceFirst(Fiber.join(run), Deferred.await(suspended));
|
|
767
1032
|
})).pipe(Effect.mapError((cause) => Schema.is(ClientInfrastructureError)(cause) ? cause : ConnectionUnavailable.make({
|
|
768
1033
|
cause,
|
|
769
1034
|
message: "The sync connection was lost."
|
|
@@ -774,6 +1039,7 @@ var SyncClient = class SyncClient extends Context.Service()("ignotum/client/sync
|
|
|
774
1039
|
return yield* queryCache.observe(functionAddress, args);
|
|
775
1040
|
});
|
|
776
1041
|
const mutate = Effect.fn("SyncClient.mutate")(function* (functionAddress, args) {
|
|
1042
|
+
const admittedSession = session.current() ?? rememberedHandshake?.session ?? (yield* session.bootstrap.pipe(Effect.mapError((error) => ConnectionUnavailable.make({ message: error.message }))));
|
|
777
1043
|
const invocationId = yield* ids.generate(InvocationId);
|
|
778
1044
|
const preparedArguments = yield* prepareMutationArguments(args).pipe(Effect.provideService(IdGenerator, ids), Effect.mapError((cause) => InvalidMutationArguments.make({
|
|
779
1045
|
cause,
|
|
@@ -806,6 +1072,7 @@ var SyncClient = class SyncClient extends Context.Service()("ignotum/client/sync
|
|
|
806
1072
|
files: preparedArguments.fileIds
|
|
807
1073
|
};
|
|
808
1074
|
invocations = HashMap.set(invocations, invocationId, {
|
|
1075
|
+
sessionEpoch: admittedSession.sessionEpoch,
|
|
809
1076
|
deferred,
|
|
810
1077
|
function: functionAddress,
|
|
811
1078
|
message,
|
|
@@ -867,7 +1134,7 @@ var SyncClient = class SyncClient extends Context.Service()("ignotum/client/sync
|
|
|
867
1134
|
concurrency: 3,
|
|
868
1135
|
discard: true
|
|
869
1136
|
});
|
|
870
|
-
const pendingInvocation = HashMap.
|
|
1137
|
+
const pendingInvocation = Option.getOrUndefined(HashMap.get(invocations, invocationId));
|
|
871
1138
|
if (pendingInvocation === void 0) return yield* Deferred.await(deferred);
|
|
872
1139
|
invocations = HashMap.set(invocations, invocationId, {
|
|
873
1140
|
...pendingInvocation,
|
|
@@ -889,7 +1156,7 @@ var SyncClient = class SyncClient extends Context.Service()("ignotum/client/sync
|
|
|
889
1156
|
});
|
|
890
1157
|
})).pipe(Layer.provide(Layer.merge(Socket.layerWebSocketConstructorGlobal, BrowserCrypto.layer)));
|
|
891
1158
|
};
|
|
892
|
-
const syncRuntime = ManagedRuntime.make(SyncClient.layer.pipe(Layer.provideMerge(clientErrorReporterLayer), Layer.provideMerge(IdGenerator.layer)));
|
|
1159
|
+
const syncRuntime = ManagedRuntime.make(SyncClient.layer.pipe(Layer.provideMerge(BrowserSession.layer), Layer.provideMerge(clientErrorReporterLayer), Layer.provideMerge(IdGenerator.layer)));
|
|
893
1160
|
const hot = import.meta.hot;
|
|
894
1161
|
if (hot !== void 0) hot.dispose(() => void syncRuntime.dispose());
|
|
895
1162
|
//#endregion
|
|
@@ -1135,6 +1402,38 @@ const useMutation = (reference) => useMemo$1(() => {
|
|
|
1135
1402
|
};
|
|
1136
1403
|
return mutate;
|
|
1137
1404
|
}, [reference]);
|
|
1405
|
+
function useId() {
|
|
1406
|
+
const [state, setState] = useState$1({ status: "pending" });
|
|
1407
|
+
useEffect$1(() => {
|
|
1408
|
+
let active = true;
|
|
1409
|
+
let unsubscribe;
|
|
1410
|
+
syncRuntime.runPromise(BrowserSession).then((session) => {
|
|
1411
|
+
if (!active) return;
|
|
1412
|
+
const update = () => setState(session.snapshot());
|
|
1413
|
+
unsubscribe = session.subscribe(update);
|
|
1414
|
+
update();
|
|
1415
|
+
});
|
|
1416
|
+
return () => {
|
|
1417
|
+
active = false;
|
|
1418
|
+
unsubscribe?.();
|
|
1419
|
+
};
|
|
1420
|
+
}, []);
|
|
1421
|
+
const actions = useMemo$1(() => ({
|
|
1422
|
+
signIn: (options) => syncRuntime.runPromise(Effect.gen(function* () {
|
|
1423
|
+
return yield* (yield* BrowserSession).start("signIn", options?.profile ?? [], options?.returnTo);
|
|
1424
|
+
})),
|
|
1425
|
+
requestProfile: (fields, options) => syncRuntime.runPromise(Effect.gen(function* () {
|
|
1426
|
+
return yield* (yield* BrowserSession).start("requestProfile", fields, options?.returnTo);
|
|
1427
|
+
})),
|
|
1428
|
+
signOut: () => syncRuntime.runPromise(Effect.gen(function* () {
|
|
1429
|
+
return yield* (yield* BrowserSession).signOut;
|
|
1430
|
+
}))
|
|
1431
|
+
}), []);
|
|
1432
|
+
return {
|
|
1433
|
+
...state,
|
|
1434
|
+
...actions
|
|
1435
|
+
};
|
|
1436
|
+
}
|
|
1138
1437
|
//#endregion
|
|
1139
1438
|
//#region src/client/app.ts
|
|
1140
1439
|
const app = (definition) => {
|
|
@@ -1145,6 +1444,6 @@ const app = (definition) => {
|
|
|
1145
1444
|
//#region src/client/index.ts
|
|
1146
1445
|
const Result = { match: Result$2.match };
|
|
1147
1446
|
//#endregion
|
|
1148
|
-
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 };
|
|
1447
|
+
export { Component, Files, Fragment, Query, Result, app, cloneElement, createContext, createElement, createRef, h, isValidElement, toChildArray, useCallback, useContext, useDebugValue, useEffect, useElementId, useErrorBoundary, useId, useImperativeHandle, useLayoutEffect, useMemo, useMutation, usePaginatedQuery, useQuery, useReducer, useRef, useState };
|
|
1149
1448
|
|
|
1150
1449
|
//# sourceMappingURL=client.js.map
|