ignotum 0.0.13 → 0.0.15

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.
Files changed (131) hide show
  1. package/README.md +6 -6
  2. package/dist/cli/bin.mjs +6111 -4448
  3. package/dist/cli/bin.mjs.map +1 -1
  4. package/dist/cli/emscripten-module-D5GzfUNv.mjs +533 -0
  5. package/dist/cli/emscripten-module-D5GzfUNv.mjs.map +1 -0
  6. package/dist/cli/ffi-7IElU4Co.mjs +148 -0
  7. package/dist/cli/ffi-7IElU4Co.mjs.map +1 -0
  8. package/dist/cli/managed-release-WHYLZwaS.mjs +10902 -0
  9. package/dist/cli/managed-release-WHYLZwaS.mjs.map +1 -0
  10. package/dist/cli/managed-release.d.mts +1 -0
  11. package/dist/cli/managed-release.mjs +14 -0
  12. package/dist/cli/managed-release.mjs.map +1 -0
  13. package/dist/cli/module-ES6BEMUI-D36I4NVn.mjs +1289 -0
  14. package/dist/cli/module-ES6BEMUI-D36I4NVn.mjs.map +1 -0
  15. package/dist/runtime/{api-Cv3hMbzo.d.ts → api-B4fwp5a2.d.ts} +4 -4
  16. package/dist/runtime/bootstrap-BISQSn_O.js +916 -0
  17. package/dist/runtime/bootstrap-BISQSn_O.js.map +1 -0
  18. package/dist/runtime/bootstrap-BTFScKAc.d.ts +545 -0
  19. package/dist/runtime/client.d.ts +50 -15
  20. package/dist/runtime/client.js +7 -1138
  21. package/dist/runtime/client.js.map +1 -1
  22. package/dist/runtime/descriptor-CTY4mtwS-cS43EbwS.js +269 -0
  23. package/dist/runtime/descriptor-CTY4mtwS-cS43EbwS.js.map +1 -0
  24. package/dist/runtime/{id-Bt9XWRGL.js → id--1m0NuUL.js} +4 -4
  25. package/dist/runtime/id--1m0NuUL.js.map +1 -0
  26. package/dist/runtime/{id-BzFHf3Wo-DGPCjgrf.d.ts → id-7an3nxTu-DZJSM5xh.d.ts} +2 -2
  27. package/dist/runtime/id-CBOt2kDo.d.ts +1 -0
  28. package/dist/runtime/identity-QjtJRxBD.d.ts +2 -0
  29. package/dist/runtime/image-Djtjy4Z8.js +19 -0
  30. package/dist/runtime/image-Djtjy4Z8.js.map +1 -0
  31. package/dist/runtime/index-D4seNHlX.d.ts +184 -0
  32. package/dist/runtime/internal/api.d.ts +1 -1
  33. package/dist/runtime/internal/api.js +30 -1
  34. package/dist/runtime/internal/api.js.map +1 -0
  35. package/dist/runtime/internal/bootstrap.d.ts +2 -0
  36. package/dist/runtime/internal/bootstrap.js +2 -0
  37. package/dist/runtime/internal/client.d.ts +2 -0
  38. package/dist/runtime/internal/client.js +75 -0
  39. package/dist/runtime/internal/client.js.map +1 -0
  40. package/dist/runtime/internal/host.d.ts +25 -8
  41. package/dist/runtime/internal/host.js +27 -6
  42. package/dist/runtime/internal/host.js.map +1 -1
  43. package/dist/runtime/internal/routes.d.ts +2 -0
  44. package/dist/runtime/internal/routes.js +2 -0
  45. package/dist/runtime/internal/server.d.ts +1 -1
  46. package/dist/runtime/internal/server.js +1 -1
  47. package/dist/runtime/internal/types.d.ts +2 -1
  48. package/dist/runtime/internal/types.js +1 -1
  49. package/dist/runtime/pagination-CBOt2kDo.d.ts +1 -0
  50. package/dist/runtime/pagination-D3qd6s9N.js +33 -0
  51. package/dist/runtime/pagination-D3qd6s9N.js.map +1 -0
  52. package/dist/runtime/result-BkziOG1L.d.ts +1 -0
  53. package/dist/runtime/router-BSBI1oN1.js +2377 -0
  54. package/dist/runtime/router-BSBI1oN1.js.map +1 -0
  55. package/dist/runtime/routes-Ce8TVP-T.js +690 -0
  56. package/dist/runtime/routes-Ce8TVP-T.js.map +1 -0
  57. package/dist/runtime/{schema-1Zs03-iS.js → schema-D1wOqiNH.js} +40 -12
  58. package/dist/runtime/schema-D1wOqiNH.js.map +1 -0
  59. package/dist/runtime/server.d.ts +5 -5
  60. package/dist/runtime/server.js +2 -2
  61. package/dist/runtime/{sync-Bs8J3fIr.d.ts → sync-D-GK2sv9.d.ts} +3 -2
  62. package/dist/runtime/{api-CAgKDij7.js → sync-DzUwA8W9.js} +22 -41
  63. package/dist/runtime/sync-DzUwA8W9.js.map +1 -0
  64. package/dist/runtime/types-DeCCyqLU-BIm7rU-0.d.ts +341 -0
  65. package/package.json +29 -4
  66. package/src/cli/agent-files.ts +14 -8
  67. package/src/cli/build/managed-client.ts +411 -0
  68. package/src/cli/build/managed-server.ts +294 -0
  69. package/src/cli/build/managed.ts +67 -0
  70. package/src/cli/build/output.ts +47 -0
  71. package/src/cli/build/server.ts +51 -220
  72. package/src/cli/client-config.ts +1 -140
  73. package/src/cli/client-styles.ts +1 -0
  74. package/src/cli/codegen.ts +9 -4
  75. package/src/cli/command.ts +28 -5
  76. package/src/cli/control-client.ts +84 -101
  77. package/src/cli/deploy.ts +133 -177
  78. package/src/cli/dev.ts +506 -107
  79. package/src/cli/image-assets.ts +499 -0
  80. package/src/cli/managed-client-boundaries.ts +103 -0
  81. package/src/cli/managed-dev-platform.ts +118 -0
  82. package/src/cli/managed-exports.ts +219 -0
  83. package/src/cli/managed-release-bin.ts +13 -0
  84. package/src/cli/managed-release.ts +260 -0
  85. package/src/cli/module-boundaries.ts +11 -1
  86. package/src/cli/new-app.ts +111 -87
  87. package/src/cli/route-codegen.ts +311 -0
  88. package/src/cli/route-static.ts +710 -0
  89. package/src/client/bootstrap.ts +110 -0
  90. package/src/client/errors.ts +13 -7
  91. package/src/client/files.ts +64 -0
  92. package/src/client/id.ts +9 -5
  93. package/src/client/image.ts +28 -0
  94. package/src/client/index.ts +25 -2
  95. package/src/client/managed-client.ts +729 -0
  96. package/src/client/managed-upgrade.ts +283 -0
  97. package/src/client/recovery-journal.ts +195 -0
  98. package/src/client/route-boundaries.ts +184 -0
  99. package/src/client/router-history.ts +152 -0
  100. package/src/client/router-store.ts +644 -0
  101. package/src/client/router.ts +324 -0
  102. package/src/client/routes.ts +28 -0
  103. package/src/client/sync.ts +66 -592
  104. package/src/dev-runtime/database.ts +77 -2
  105. package/src/dev-runtime/functions.ts +3 -3
  106. package/src/dev-runtime/id.ts +19 -4
  107. package/src/dev-runtime/managed-functions.ts +255 -0
  108. package/src/dev-runtime/managed-sync.ts +263 -0
  109. package/src/dev-runtime/managed-websocket.ts +71 -0
  110. package/src/dev-runtime/migrations.ts +20 -0
  111. package/src/dev-runtime/sync.ts +236 -236
  112. package/src/image-assets.d.ts +36 -0
  113. package/src/internal/client.ts +186 -0
  114. package/src/internal/host.ts +1 -1
  115. package/src/internal/http-paths.ts +0 -3
  116. package/src/internal/routes.ts +45 -0
  117. package/dist/runtime/api-CAgKDij7.js.map +0 -1
  118. package/dist/runtime/descriptor-Cyo9FP9n-C0SRVXNW.js +0 -154
  119. package/dist/runtime/descriptor-Cyo9FP9n-C0SRVXNW.js.map +0 -1
  120. package/dist/runtime/id-Bt9XWRGL.js.map +0 -1
  121. package/dist/runtime/id-Dz0apuB3.d.ts +0 -1
  122. package/dist/runtime/index-D54flWtH.d.ts +0 -402
  123. package/dist/runtime/pagination-DnKg3dkI-r5ZUxBBx.d.ts +0 -112
  124. package/dist/runtime/pagination-Dz0apuB3.d.ts +0 -1
  125. package/dist/runtime/result-DKAA4gpS.d.ts +0 -1
  126. package/dist/runtime/schema-1Zs03-iS.js.map +0 -1
  127. package/src/cli/build/client.ts +0 -119
  128. package/src/cli/build/public.ts +0 -186
  129. package/src/cli/client-entry.ts +0 -152
  130. package/src/cli/client-plugin.ts +0 -136
  131. package/src/client/app.ts +0 -15
@@ -1,335 +1,11 @@
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 { s as PaginationPageSize, t as ValueDescriptor } from "./descriptor-Cyo9FP9n-C0SRVXNW.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
- import { customAlphabet } from "nanoid";
6
- import { FetchHttpClient, HttpClient, HttpClientRequest, HttpClientResponse } from "effect/unstable/http";
1
+ import { D as encodeTransportObject, _ as Result$2, b as inspectResult, x as pending } from "./id--1m0NuUL.js";
2
+ import { C as Files, S as BrowserSession, a as url, b as syncClientInternals, c as useMatch, d as useRoute, l as useNavigate, n as NavLink, o as useBlocker, r as Redirect, s as useLocation, t as Link, u as useNavigation, v as SyncClient, w as ClientInfrastructureError, x as syncRuntime } from "./router-BSBI1oN1.js";
3
+ import { functionPathOf } from "./internal/api.js";
4
+ import { n as PaginationPageSize } from "./pagination-D3qd6s9N.js";
5
+ import { t as Image } from "./image-Djtjy4Z8.js";
6
+ import { Effect, Schema } from "effect";
7
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";
8
- import * as Socket from "effect/unstable/socket/Socket";
9
- import * as BrowserCrypto from "@effect/platform-browser/BrowserCrypto";
10
8
  import { Component, Fragment, cloneElement, createContext, createElement, createRef, h, isValidElement, toChildArray } from "preact";
11
- //#region ../shared/dist/id.js
12
- const decodeGenerated = (definition, payload) => Schema.decodeSync(definition)(definition.idPrefix === void 0 ? payload : `${definition.idPrefix}_${payload}`);
13
- var IdGenerator = class IdGenerator extends Context.Service()("@ignotum/shared/id/IdGenerator") {
14
- static layer = Layer.sync(IdGenerator, () => {
15
- const generatePayload = customAlphabet(IdAlphabet, 24);
16
- return IdGenerator.of({ generate: (definition) => Effect.sync(() => decodeGenerated(definition, generatePayload())) });
17
- });
18
- static deterministic = (startAt = 1) => Layer.sync(IdGenerator, () => {
19
- const counters = /* @__PURE__ */ new Map();
20
- return IdGenerator.of({ generate: (definition) => Effect.sync(() => {
21
- const counter = (counters.get(definition.idPrefix) ?? startAt - 1) + 1;
22
- counters.set(definition.idPrefix, counter);
23
- return decodeGenerated(definition, counter.toString(36).padStart(24, "0"));
24
- }) });
25
- });
26
- };
27
- //#endregion
28
- //#region src/client/files.ts
29
- const Files = { url: (file) => {
30
- const url = fileGrantUrlOf(file);
31
- if (url === void 0) throw new Error("This FileValue has no active query grant.");
32
- return url;
33
- } };
34
- const formatByMime = {};
35
- for (const format of fileFormats) formatByMime[fileMimeTypes[format]] = format;
36
- const MutationObject = Schema.ObjectKeyword.check(Schema.makeFilter((value) => Object.prototype.toString.call(value) === "[object Object]", { message: "Mutation objects must contain ordinary fields; built-in collections are unsupported." }));
37
- const collectNativeFiles = (value, files) => {
38
- if (value instanceof File) {
39
- files.add(value);
40
- return;
41
- }
42
- if (isFileValue(value) || Predicate.isDate(value)) return;
43
- if (globalThis.Array.isArray(value)) {
44
- for (const child of value) collectNativeFiles(child, files);
45
- return;
46
- }
47
- if (!Predicate.isObject(value)) return;
48
- for (const child of Object.values(Schema.decodeSync(MutationObject)(value))) collectNativeFiles(child, files);
49
- };
50
- const replaceNativeFiles = (value, replacements) => {
51
- if (value instanceof File) return replacements.get(value);
52
- if (isFileValue(value) || Predicate.isDate(value)) return value;
53
- if (globalThis.Array.isArray(value)) return value.map((child) => replaceNativeFiles(child, replacements));
54
- if (!Predicate.isObject(value)) return value;
55
- return Object.fromEntries(Object.entries(value).map(([key, child]) => [key, replaceNativeFiles(child, replacements)]));
56
- };
57
- const prepareMutationArguments = Effect.fn("SyncClient.prepareMutationArguments")(function* (input) {
58
- const ids = yield* IdGenerator;
59
- const unique = yield* Effect.try(() => {
60
- const files = /* @__PURE__ */ new Set();
61
- collectNativeFiles(input, files);
62
- if (files.size > fileLimits.filesPerMutation) throw new Error(`A mutation may upload at most ${fileLimits.filesPerMutation} files.`);
63
- if ([...files].reduce((total, file) => total + file.size, 0) > fileLimits.mutationBytes) throw new Error(`Mutation uploads may total at most ${fileLimits.mutationBytes} bytes.`);
64
- return files;
65
- });
66
- const replacements = /* @__PURE__ */ new Map();
67
- const nativeFiles = /* @__PURE__ */ new Map();
68
- for (const file of unique) {
69
- const format = yield* Effect.try(() => {
70
- const format = formatByMime[file.type.toLowerCase()];
71
- if (format === void 0) throw new Error(`File '${file.name}' has unsupported media type '${file.type || "unknown"}'.`);
72
- if (file.size === 0 || file.size > fileLimits.fileBytes) throw new Error(`File '${file.name}' must be between 1 and ${fileLimits.fileBytes} bytes.`);
73
- if (new TextEncoder().encode(file.name).byteLength > fileLimits.filenameBytes) throw new Error(`File '${file.name}' has a filename that is too long.`);
74
- return format;
75
- });
76
- const id = yield* ids.generate(FileId);
77
- replacements.set(file, makeFileValue(id, {
78
- format,
79
- name: file.name,
80
- size: file.size
81
- }));
82
- nativeFiles.set(id, file);
83
- }
84
- return {
85
- value: unique.size === 0 ? input : yield* Effect.try(() => replaceNativeFiles(input, replacements)),
86
- nativeFiles,
87
- fileIds: Array.from(nativeFiles.keys())
88
- };
89
- });
90
- const applyFileGrants = (value, grants) => {
91
- if (grants.length === 0) return value;
92
- const byId = /* @__PURE__ */ new Map();
93
- for (const grant of grants) {
94
- if (byId.has(grant.id)) throw new Error("A query file grant ID is duplicated.");
95
- byId.set(grant.id, grant.url);
96
- }
97
- const matched = /* @__PURE__ */ new Set();
98
- const visit = (current) => {
99
- if (isFileValue(current)) {
100
- const id = fileIdOf(current);
101
- const url = byId.get(id);
102
- if (url === void 0) return current;
103
- matched.add(id);
104
- return grantFileValue(current, url);
105
- }
106
- if (globalThis.Array.isArray(current)) return current.map(visit);
107
- if (!Predicate.isObject(current) || Predicate.isDate(current)) return current;
108
- return Object.fromEntries(Object.entries(current).map(([key, child]) => [key, visit(child)]));
109
- };
110
- const granted = visit(value);
111
- if (matched.size !== byId.size) throw new Error("A query file grant has no result value.");
112
- return granted;
113
- };
114
- //#endregion
115
- //#region ../contracts/dist/json.js
116
- const encodeJson = (value) => {
117
- if (Array$1.isArray(value)) return `[${value.map(encodeJson).join(",")}]`;
118
- if (value === null || Predicate.isString(value) || Predicate.isNumber(value) || Predicate.isBoolean(value)) return JSON.stringify(value);
119
- return `{${Array$1.sortWith(Object.entries(value), ([key]) => key, String.Order).map(([key, field]) => `${JSON.stringify(key)}:${encodeJson(field)}`).join(",")}}`;
120
- };
121
- const encodeCanonicalJson = (value) => encodeJson(Schema.decodeSync(Schema.Json)(value));
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
294
- //#region src/client/errors.ts
295
- /** @effect-diagnostics globalConsole:skip-file */
296
- var ConnectionUnavailable = class extends Schema.TaggedError()("ConnectionUnavailable", {
297
- cause: Schema.optional(Schema.Defect()),
298
- message: Schema.String
299
- }) {};
300
- var InvalidClientMessage = class extends Schema.TaggedError()("InvalidClientMessage", {
301
- cause: Schema.Defect(),
302
- message: Schema.String
303
- }) {};
304
- var InvalidMutationArguments = class extends Schema.TaggedError()("InvalidMutationArguments", {
305
- cause: Schema.Defect(),
306
- function: FunctionAddress,
307
- message: Schema.String
308
- }) {};
309
- var InvalidServerMessage = class extends Schema.TaggedError()("InvalidServerMessage", {
310
- cause: Schema.Defect(),
311
- message: Schema.String
312
- }) {};
313
- var ServerError = class extends Schema.TaggedError()("ServerError", {
314
- code: ErrorCode,
315
- message: Schema.String,
316
- operation: Schema.optional(Operation)
317
- }) {};
318
- const ClientInfrastructureError = Schema.Union([
319
- ConnectionUnavailable,
320
- InvalidClientMessage,
321
- InvalidMutationArguments,
322
- InvalidServerMessage,
323
- ServerError
324
- ]);
325
- const browserErrorReporter = ErrorReporter.make(({ attributes, error }) => {
326
- globalThis.console.error("Ignotum infrastructure error", error, attributes);
327
- });
328
- const clientErrorReporterLayer = ErrorReporter.layer([browserErrorReporter]);
329
- const reportClientError = Effect.fn("ClientErrorReporter.report")(function* (error) {
330
- yield* ErrorReporter.report(Cause.fail(error));
331
- });
332
- //#endregion
333
9
  //#region src/client/query.ts
334
10
  const QuerySkipTypeId = Symbol.for("ignotum/client/QuerySkip");
335
11
  var QuerySkipToken = class {
@@ -339,807 +15,6 @@ const skip = Object.freeze(new QuerySkipToken());
339
15
  const Query = { skip };
340
16
  const isQuerySkip = (value) => value === skip;
341
17
  //#endregion
342
- //#region ../contracts/dist/runtime/index.js
343
- const IndexIdentity = Schema.String.pipe(Schema.brand("ignotum/runtime/IndexIdentity"));
344
- const EncodedIndexKey = Schema.String.check(Schema.isPattern(/^(?:[0-9a-f]{2})*$/)).pipe(Schema.brand("ignotum/runtime/EncodedIndexKey"));
345
- Schema.Union([
346
- Schema.Boolean,
347
- Schema.Finite,
348
- Schema.String
349
- ]);
350
- Schema.String.pipe(Schema.brand("ignotum/hosted/QueryKey"));
351
- const TableDependency = Schema.Struct({
352
- type: Schema.Literal("Table"),
353
- tableId: TableId
354
- });
355
- const DocumentDependency = Schema.Struct({
356
- type: Schema.Literal("Document"),
357
- tableId: TableId,
358
- id: GeneratedId
359
- });
360
- const IndexRangeDependency = Schema.Struct({
361
- type: Schema.Literal("IndexRange"),
362
- tableId: TableId,
363
- index: IndexIdentity,
364
- lower: Schema.optional(EncodedIndexKey),
365
- upper: Schema.optional(EncodedIndexKey)
366
- });
367
- const IndexPointInvalidation = Schema.Struct({
368
- type: Schema.Literal("IndexPoint"),
369
- tableId: TableId,
370
- index: IndexIdentity,
371
- key: EncodedIndexKey
372
- });
373
- const IdDependency = Schema.Struct({ type: Schema.Literal("Id") });
374
- const ReadDependency = Schema.Union([
375
- IdDependency,
376
- TableDependency,
377
- DocumentDependency,
378
- IndexRangeDependency
379
- ]);
380
- const WriteInvalidation = Schema.Union([
381
- TableDependency,
382
- DocumentDependency,
383
- IndexPointInvalidation
384
- ]);
385
- Schema.Union([ReadDependency, IndexPointInvalidation]);
386
- const DependencySet = Schema.Array(ReadDependency);
387
- const InvalidationSet = Schema.Array(WriteInvalidation);
388
- const RuntimeQueryResult = Schema.Struct({
389
- type: Schema.Literal("Query"),
390
- result: WireResult,
391
- dependencies: DependencySet,
392
- observedRevision: AppStateRevision,
393
- files: Schema.optional(Schema.Array(RuntimeFileOccurrence))
394
- });
395
- const FileReferenceAdded = Schema.Struct({
396
- type: Schema.Literal("AddReference"),
397
- file: RuntimeFileMetadata,
398
- tableId: TableId,
399
- documentId: GeneratedId
400
- });
401
- const FileReferenceRemoved = Schema.Struct({
402
- type: Schema.Literal("RemoveReference"),
403
- fileId: FileId,
404
- tableId: TableId,
405
- documentId: GeneratedId
406
- });
407
- const FileReferenceEffect = Schema.Union([FileReferenceAdded, FileReferenceRemoved]);
408
- const FileEffectBatch = Schema.Struct({
409
- id: InvocationId,
410
- committedRevision: AppStateRevision,
411
- effects: Schema.Array(FileReferenceEffect)
412
- });
413
- Schema.Struct({ appId: AppId });
414
- Schema.Struct({ batches: Schema.Array(FileEffectBatch) });
415
- Schema.Struct({
416
- appId: AppId,
417
- invocationId: InvocationId,
418
- acknowledgedAt: Schema.Int
419
- });
420
- Schema.Struct({ completed: Schema.Literal(true) });
421
- const RuntimeMutationSuccess = Schema.Struct({
422
- type: Schema.Literal("Mutation"),
423
- result: WireSuccess,
424
- invalidations: InvalidationSet,
425
- committedRevision: AppStateRevision,
426
- fileEffects: Schema.optional(FileEffectBatch)
427
- });
428
- const RuntimeMutationFailure = Schema.Struct({
429
- type: Schema.Literal("Mutation"),
430
- result: WireFailure
431
- });
432
- const RuntimeMutationResult = Schema.Union([RuntimeMutationSuccess, RuntimeMutationFailure]);
433
- Schema.Union([RuntimeQueryResult, RuntimeMutationResult]);
434
- const InvocationBase = {
435
- appId: AppId,
436
- deploymentId: DeploymentId,
437
- generation: DeploymentGeneration,
438
- invocationKey: InvocationKey,
439
- function: FunctionAddress,
440
- args: Schema.Json,
441
- identity: Schema.optional(SessionState)
442
- };
443
- const QueryInvocation = Schema.Struct({
444
- ...InvocationBase,
445
- type: Schema.Literal("Query")
446
- });
447
- const MutationInvocation = Schema.Struct({
448
- ...InvocationBase,
449
- type: Schema.Literal("Mutation"),
450
- invocationId: InvocationId,
451
- files: Schema.optional(Schema.Array(RuntimeFileOccurrence))
452
- });
453
- Schema.Union([QueryInvocation, MutationInvocation]);
454
- Schema.Struct({
455
- appId: AppId,
456
- expectedRevision: AppStateRevision
457
- });
458
- Schema.Struct({ currentRevision: AppStateRevision });
459
- var RuntimeDeploymentUnavailable = class extends Schema.TaggedError()("RuntimeDeploymentUnavailable", {
460
- deploymentId: DeploymentId,
461
- message: Schema.String
462
- }) {};
463
- const RuntimeInvocationRejectionCode = Schema.Literals([
464
- "SessionExpired",
465
- "FunctionUnavailable",
466
- "InvalidArguments",
467
- "InvocationIdConflict",
468
- "ResourceLimitExceeded",
469
- "UnknownFunction",
470
- "WrongFunctionKind"
471
- ]);
472
- var RuntimeInvocationRejected = class extends Schema.TaggedError()("RuntimeInvocationRejected", {
473
- code: RuntimeInvocationRejectionCode,
474
- invocationKey: InvocationKey,
475
- message: Schema.String
476
- }) {};
477
- var RuntimeInvocationUnavailable = class extends Schema.TaggedError()("RuntimeInvocationUnavailable", {
478
- invocationKey: InvocationKey,
479
- message: Schema.String
480
- }) {};
481
- Schema.TaggedError()("RuntimeRevisionRejected", {
482
- appId: AppId,
483
- message: Schema.String
484
- });
485
- Schema.Union([
486
- RuntimeDeploymentUnavailable,
487
- RuntimeInvocationRejected,
488
- RuntimeInvocationUnavailable
489
- ]);
490
- //#endregion
491
- //#region ../contracts/dist/runtime/functions.js
492
- const FunctionKind = Schema.Literals(["Mutation", "Query"]);
493
- Schema.TaggedError()("UnknownFunction", {
494
- function: FunctionAddress,
495
- message: Schema.String
496
- });
497
- Schema.TaggedError()("WrongFunctionKind", {
498
- actual: FunctionKind,
499
- expected: FunctionKind,
500
- function: FunctionAddress,
501
- message: Schema.String
502
- });
503
- Schema.TaggedError()("InvalidArguments", {
504
- function: FunctionAddress,
505
- message: Schema.String
506
- });
507
- Schema.TaggedError()("FunctionUnavailable", {
508
- cause: Schema.Defect(),
509
- function: FunctionAddress,
510
- message: Schema.String
511
- });
512
- //#endregion
513
- //#region ../contracts/dist/deployment.js
514
- const ArtifactPath = Schema.String.check(Schema.isPattern(/^(?!\/)(?![A-Za-z]:\/)(?!.*(?:^|\/)\.\.(?:\/|$))(?!.*(?:^|\/)\.(?:\/|$))(?!.*\/\/)[^\\\0]+$/)).pipe(Schema.brand("ignotum/deployment/ArtifactPath"));
515
- const ClientPath = Schema.String.check(Schema.isPattern(/^\/(?!_ignotum(?:\/|$))(?:(?:[A-Za-z0-9._~-]+\/)*[A-Za-z0-9._~-]+\/?)?$/)).pipe(Schema.brand("ignotum/deployment/ClientPath"));
516
- const Sha256 = Schema.String.check(Schema.isPattern(/^[0-9a-f]{64}$/)).pipe(Schema.brand("ignotum/deployment/Sha256"));
517
- const ArtifactKind = Schema.Literals([
518
- "ClientAsset",
519
- "ClientDocument",
520
- "ClientManifest",
521
- "ClientPublicFile",
522
- "ClientShell",
523
- "FunctionBundle",
524
- "ServerManifest",
525
- "ServerEnvironment",
526
- "SourceMap",
527
- "SchemaSnapshot"
528
- ]);
529
- const ArtifactReference = Schema.Struct({
530
- path: ArtifactPath,
531
- size: Schema.Natural,
532
- sha256: Sha256
533
- });
534
- const ArtifactFile = Schema.Struct({
535
- path: ArtifactPath,
536
- size: Schema.Natural,
537
- sha256: Sha256,
538
- kind: ArtifactKind,
539
- contentType: Schema.String,
540
- contentEncoding: Schema.optional(Schema.String)
541
- });
542
- const ClientRoute = Schema.Struct({
543
- pathname: ClientPath,
544
- artifact: ArtifactReference
545
- });
546
- const DeploymentInventoryV1 = Schema.Struct({
547
- formatVersion: Schema.Literal(1),
548
- files: Schema.Array(ArtifactFile)
549
- });
550
- const DeploymentInventoryV2 = Schema.Struct({
551
- formatVersion: Schema.Literal(2),
552
- files: Schema.Array(ArtifactFile)
553
- });
554
- upgrade(initial(DeploymentInventoryV1), DeploymentInventoryV2, (inventory) => ({
555
- formatVersion: 2,
556
- files: inventory.files
557
- }));
558
- const ClientManifestV1 = Schema.Struct({
559
- formatVersion: Schema.Literal(1),
560
- shell: ArtifactReference,
561
- routes: Schema.Array(ClientRoute)
562
- });
563
- initial(ClientManifestV1);
564
- const ClientRoutingRoute = Schema.Struct({
565
- pathname: ClientPath,
566
- artifact: ArtifactPath
567
- });
568
- const ClientRoutingV1 = Schema.Struct({
569
- formatVersion: Schema.Literal(1),
570
- shell: ArtifactPath,
571
- routes: Schema.Array(ClientRoutingRoute)
572
- });
573
- initial(ClientRoutingV1);
574
- const SchemaSnapshotField = Schema.Struct({
575
- name: Schema.String,
576
- value: ValueDescriptor
577
- });
578
- const EnvironmentArtifactV1 = Schema.Struct({
579
- formatVersion: Schema.Literal(1),
580
- nonce: Schema.String.check(Schema.isPattern(/^[A-Za-z0-9_-]{43}$/)),
581
- values: Schema.Record(Schema.String, Schema.String)
582
- });
583
- initial(EnvironmentArtifactV1);
584
- const ServerEnvironmentArtifact = Schema.Struct({
585
- artifact: ArtifactReference,
586
- fields: Schema.Array(SchemaSnapshotField)
587
- });
588
- const SchemaSnapshotIndex = Schema.Struct({
589
- name: Schema.String,
590
- fields: Schema.Array(Schema.String)
591
- });
592
- const SchemaSnapshotTableV1 = Schema.Struct({
593
- name: Schema.String,
594
- fields: Schema.Array(SchemaSnapshotField)
595
- });
596
- const SchemaSnapshotV1 = Schema.Struct({
597
- formatVersion: Schema.Literal(1),
598
- tables: Schema.Array(SchemaSnapshotTableV1)
599
- });
600
- const SchemaSnapshotTable = Schema.Struct({
601
- name: Schema.String,
602
- fields: Schema.Array(SchemaSnapshotField),
603
- indexes: Schema.Array(SchemaSnapshotIndex)
604
- });
605
- const SchemaSnapshotV2 = Schema.Struct({
606
- formatVersion: Schema.Literal(2),
607
- tables: Schema.Array(SchemaSnapshotTable)
608
- });
609
- upgrade(initial(SchemaSnapshotV1), SchemaSnapshotV2, (snapshot) => ({
610
- formatVersion: 2,
611
- tables: snapshot.tables.map((table) => ({
612
- ...table,
613
- indexes: []
614
- }))
615
- }));
616
- const ServerFunctionArtifactV1 = Schema.Struct({
617
- address: FunctionAddress,
618
- kind: FunctionKind,
619
- bundle: ArtifactReference,
620
- sourceMap: ArtifactReference
621
- });
622
- const ServerFunctionArtifact = Schema.Struct({
623
- address: FunctionAddress,
624
- kind: FunctionKind,
625
- args: Schema.optional(ValueDescriptor),
626
- returns: Schema.optional(ValueDescriptor),
627
- errors: Schema.optional(ValueDescriptor),
628
- bundle: ArtifactReference,
629
- sourceMap: ArtifactReference
630
- });
631
- const ServerBuildManifestV1 = Schema.Struct({
632
- formatVersion: Schema.Literal(1),
633
- schema: ArtifactReference,
634
- functions: Schema.Array(ServerFunctionArtifactV1)
635
- });
636
- const ServerBuildManifestV2 = Schema.Struct({
637
- formatVersion: Schema.Literal(2),
638
- schema: ArtifactReference,
639
- functions: Schema.Array(ServerFunctionArtifact)
640
- });
641
- const ServerBuildManifestThroughV2 = upgrade(initial(ServerBuildManifestV1), ServerBuildManifestV2, (manifest) => ({
642
- formatVersion: 2,
643
- schema: manifest.schema,
644
- functions: manifest.functions
645
- }));
646
- const ServerBuildManifestV3 = Schema.Struct({
647
- formatVersion: Schema.Literal(3),
648
- schema: ArtifactReference,
649
- environment: Schema.optional(ServerEnvironmentArtifact),
650
- functions: Schema.Array(ServerFunctionArtifact)
651
- });
652
- upgrade(ServerBuildManifestThroughV2, ServerBuildManifestV3, (manifest) => ({
653
- formatVersion: 3,
654
- schema: manifest.schema,
655
- functions: manifest.functions
656
- }));
657
- ArtifactPath.make("inventory.json");
658
- ArtifactPath.make("client/manifest.json");
659
- ArtifactPath.make("client/shell.html");
660
- `${ArtifactPath.make("client/assets")}`;
661
- `${ArtifactPath.make("client/routes")}`;
662
- ArtifactPath.make("server/manifest.json");
663
- ArtifactPath.make("server/schema.json");
664
- ArtifactPath.make("server/environment.json");
665
- //#endregion
666
- //#region ../contracts/dist/runtime/transport.js
667
- const runtimeInvocationPath = "/v1/invoke";
668
- const runtimeRevisionPath = "/v1/revision";
669
- const runtimeIndexPreparePath = "/v1/indexes/prepare";
670
- const runtimeIndexCommitPath = "/v1/indexes/commit";
671
- const runtimeFileEffectsPath = "/v1/files/effects";
672
- const runtimeFileEffectsAcknowledgePath = "/v1/files/effects/acknowledge";
673
- const appSyncPath = `/_ignotum/v1/sync`;
674
- const RuntimeRequestPath = Schema.Literals([
675
- runtimeInvocationPath,
676
- runtimeRevisionPath,
677
- runtimeIndexPreparePath,
678
- runtimeIndexCommitPath,
679
- runtimeFileEffectsPath,
680
- runtimeFileEffectsAcknowledgePath
681
- ]);
682
- const RuntimeRequestTimestamp = Schema.FiniteFromString.pipe(Schema.check(Schema.isInt(), Schema.isGreaterThanOrEqualTo(0)), Schema.brand("ignotum/runtime/RequestTimestamp"));
683
- const RuntimeRequestSignature = Sha256.pipe(Schema.brand("ignotum/runtime/RequestSignature"));
684
- Schema.Struct({
685
- appId: AppId,
686
- deploymentId: Schema.optional(DeploymentId),
687
- nonce: RuntimeRequestNonce,
688
- timestamp: RuntimeRequestTimestamp,
689
- signature: RuntimeRequestSignature
690
- });
691
- Schema.Struct({
692
- method: Schema.Literal("POST"),
693
- path: RuntimeRequestPath,
694
- timestamp: RuntimeRequestTimestamp,
695
- nonce: RuntimeRequestNonce,
696
- appId: AppId,
697
- deploymentId: Schema.optional(DeploymentId),
698
- bodySha256: Sha256
699
- });
700
- Schema.Struct({
701
- appId: AppId,
702
- deploymentId: DeploymentId
703
- });
704
- Schema.Struct({ completed: Schema.Literal(true) });
705
- const RuntimeErrorCode = Schema.Literals([
706
- "InvalidRequest",
707
- "InvalidSignature",
708
- "RequestExpired",
709
- "RequestReplay",
710
- "InvocationRejected",
711
- "RuntimeUnavailable"
712
- ]);
713
- Schema.Struct({
714
- code: RuntimeErrorCode,
715
- message: Schema.String,
716
- rejectionCode: Schema.optional(RuntimeInvocationRejectionCode)
717
- });
718
- //#endregion
719
- //#region src/internal/http-paths.ts
720
- const syncPath = appSyncPath;
721
- //#endregion
722
- //#region src/client/sync.ts
723
- const queryKey = (functionAddress, args) => encodeCanonicalJson([functionAddress, args]);
724
- const subscribeMessage = (entry) => ({
725
- type: "Subscribe",
726
- id: entry.subscriptionId,
727
- function: entry.function,
728
- args: entry.args
729
- });
730
- const makeQueryCache = (allocateId, sendLifecycleMessage) => {
731
- const queries = /* @__PURE__ */ new Map();
732
- const queriesById = /* @__PURE__ */ new Map();
733
- const observe = Effect.fn("SyncClient.QueryCache.observe")(function* (functionAddress, args) {
734
- const key = queryKey(functionAddress, args);
735
- let entry = queries.get(key);
736
- if (entry === void 0) {
737
- const created = {
738
- args,
739
- function: functionAddress,
740
- generation: 0,
741
- listeners: /* @__PURE__ */ new Set(),
742
- revision: void 0,
743
- references: 0,
744
- result: pending(),
745
- subscriptionId: yield* allocateId
746
- };
747
- queries.set(key, created);
748
- queriesById.set(created.subscriptionId, created);
749
- yield* sendLifecycleMessage(subscribeMessage(created));
750
- entry = created;
751
- }
752
- const observed = entry;
753
- observed.references += 1;
754
- observed.generation += 1;
755
- let released = false;
756
- return {
757
- getSnapshot: () => observed.result,
758
- subscribe: (listener) => {
759
- observed.listeners.add(listener);
760
- return () => observed.listeners.delete(listener);
761
- },
762
- release: Effect.gen(function* () {
763
- if (released) return;
764
- released = true;
765
- observed.references -= 1;
766
- if (observed.references !== 0) return;
767
- const generation = ++observed.generation;
768
- yield* Effect.sleep("25 millis");
769
- if (observed.references !== 0 || observed.generation !== generation || queries.get(key) !== observed) return;
770
- queries.delete(key);
771
- queriesById.delete(observed.subscriptionId);
772
- yield* sendLifecycleMessage({
773
- type: "Unsubscribe",
774
- id: observed.subscriptionId
775
- });
776
- })
777
- };
778
- });
779
- const clear = (entry) => {
780
- entry.result = pending();
781
- entry.revision = void 0;
782
- for (const listener of entry.listeners) listener();
783
- };
784
- return {
785
- invalidate: (ids) => {
786
- for (const entry of queries.values()) if (ids === void 0 || ids.includes(entry.subscriptionId)) clear(entry);
787
- },
788
- invalidatePrivate: () => {
789
- for (const entry of queries.values()) if (entry.dependsOnId !== false) clear(entry);
790
- },
791
- entries: () => queries.values(),
792
- getById: (id) => queriesById.get(id),
793
- observe,
794
- setResult: (id, result, revision) => {
795
- const entry = queriesById.get(id);
796
- if (entry === void 0) return;
797
- if (revision !== void 0) {
798
- if (entry.revision !== void 0 && revision < entry.revision) return;
799
- entry.revision = revision;
800
- }
801
- entry.result = result;
802
- for (const listener of entry.listeners) listener();
803
- }
804
- };
805
- };
806
- const resultFromWire = Effect.fn("SyncClient.resultFromWire")((wire, files = []) => Effect.try({
807
- try: () => wire.type === "Success" ? Result$2.succeed(wire.value === void 0 ? void 0 : applyFileGrants(decodeTransportValue(wire.value, wire.dates ?? []), files)) : failureFromWire(wire.error, wire.dates),
808
- catch: (cause) => InvalidServerMessage.make({
809
- cause,
810
- message: "The server returned an invalid function result."
811
- })
812
- }));
813
- const shouldReloadForCloseCode = (code) => code === DeploymentCloseCode;
814
- const handshakesMatch = (first, next) => first.appId === next.appId && first.deploymentId === next.deploymentId && first.generation === next.generation;
815
- const handshakeDecision = (remembered, acceptedOnConnection, next) => {
816
- if (remembered !== void 0 && !handshakesMatch(remembered, next)) return "Reload";
817
- return acceptedOnConnection ? "Ignore" : "Accept";
818
- };
819
- const syncClientInternals = {
820
- makeQueryCache,
821
- handshakeDecision,
822
- queryIdentity: queryKey,
823
- resultFromWire,
824
- handshakesMatch,
825
- shouldReloadForCloseCode
826
- };
827
- const socketUrl = () => {
828
- const url = new URL(syncPath, globalThis.location.href);
829
- url.protocol = url.protocol === "https:" ? "wss:" : "ws:";
830
- return url.href;
831
- };
832
- var SyncClient = class SyncClient extends Context.Service()("ignotum/client/sync/SyncClient") {
833
- static layer = Layer.effect(SyncClient, Effect.gen(function* () {
834
- const ids = yield* IdGenerator;
835
- const session = yield* BrowserSession;
836
- let invocations = HashMap.empty();
837
- let rememberedHandshake;
838
- let reloadRequested = false;
839
- let writer;
840
- let sessionSuspended;
841
- const encode = (message) => Schema.encodeEffect(ClientMessageJson)(message).pipe(Effect.mapError((cause) => InvalidClientMessage.make({
842
- cause,
843
- message: "Could not encode an Ignotum sync message."
844
- })));
845
- const sendWith = (write, message) => encode(message).pipe(Effect.flatMap(write), Effect.mapError((cause) => Schema.is(InvalidClientMessage)(cause) ? cause : ConnectionUnavailable.make({
846
- cause,
847
- message: "The sync connection was lost."
848
- })));
849
- const send = (message) => writer === void 0 ? Effect.fail(ConnectionUnavailable.make({ message: "The sync connection is not ready." })) : sendWith(writer, message);
850
- const queryCache = makeQueryCache(ids.generate(SubscriptionId), (message) => writer === void 0 ? Effect.void : send(message).pipe(Effect.catchTags({
851
- ConnectionUnavailable: reportClientError,
852
- InvalidClientMessage: reportClientError
853
- })));
854
- const unsubscribeSession = session.subscribe(() => {
855
- if (session.current() === void 0) {
856
- queryCache.invalidatePrivate();
857
- writer = void 0;
858
- if (sessionSuspended !== void 0) Deferred.doneUnsafe(sessionSuspended, Effect.void);
859
- }
860
- });
861
- yield* Effect.addFinalizer(() => Effect.sync(unsubscribeSession));
862
- const rejectInvocation = (id, error) => {
863
- const pendingInvocation = Option.getOrUndefined(HashMap.get(invocations, id));
864
- if (pendingInvocation === void 0) return Effect.void;
865
- invocations = HashMap.remove(invocations, id);
866
- return reportClientError(error).pipe(Effect.andThen(Deferred.fail(pendingInvocation.prepared, error)), Effect.andThen(Deferred.fail(pendingInvocation.deferred, error)), Effect.asVoid);
867
- };
868
- const handleMessage = Effect.fn("SyncClient.handleMessage")(function* (message) {
869
- switch (message.type) {
870
- case "Session":
871
- if (message.event === "Updated") {
872
- const previous = session.current();
873
- if (previous !== void 0 && previous.sessionEpoch !== message.session.sessionEpoch) return;
874
- if (previous?.viewRevision !== message.session.viewRevision) queryCache.invalidatePrivate();
875
- session.accept(message.session, message.serverTime);
876
- } else {
877
- if (rememberedHandshake?.session?.sessionEpoch !== message.sessionEpoch) return;
878
- session.suspend(message.event === "Unavailable" ? "Your ID session is temporarily unavailable." : void 0);
879
- if (message.event !== "Unavailable") yield* Effect.forEach(HashMap.keys(invocations), (id) => rejectInvocation(id, ServerError.make({
880
- code: "SessionChanged",
881
- message: "The session changed. This operation may already have completed."
882
- })));
883
- }
884
- return;
885
- case "Invalidate":
886
- if (message.sessionEpoch === session.current()?.sessionEpoch) queryCache.invalidate(message.ids);
887
- return;
888
- case "Snapshot": {
889
- const current = session.current();
890
- if (current === void 0 || message.identity?.sessionEpoch !== current.sessionEpoch) return;
891
- if (message.identity.dependsOnId && message.identity.viewRevision !== current.viewRevision) return;
892
- const entry = queryCache.getById(message.id);
893
- if (entry === void 0) return;
894
- entry.dependsOnId = message.identity.dependsOnId;
895
- if (entry.revision !== void 0 && message.revision < entry.revision) return;
896
- yield* resultFromWire(message.result, message.files ?? []).pipe(Effect.tap((result) => Effect.sync(() => queryCache.setResult(message.id, result, message.revision))), Effect.catchTags({ InvalidServerMessage: (error) => {
897
- queryCache.setResult(message.id, error, message.revision);
898
- return reportClientError(error);
899
- } }));
900
- return;
901
- }
902
- case "Preparation": {
903
- if (message.sessionEpoch !== session.current()?.sessionEpoch) return;
904
- const pendingInvocation = Option.getOrUndefined(HashMap.get(invocations, message.id));
905
- if (pendingInvocation !== void 0) yield* Deferred.succeed(pendingInvocation.prepared, message.uploads);
906
- return;
907
- }
908
- case "Result": {
909
- if (message.sessionEpoch !== session.current()?.sessionEpoch) return;
910
- const pendingInvocation = Option.getOrUndefined(HashMap.get(invocations, message.id));
911
- if (pendingInvocation === void 0) return;
912
- yield* resultFromWire(message.result).pipe(Effect.flatMap((result) => {
913
- invocations = HashMap.remove(invocations, message.id);
914
- return Deferred.succeed(pendingInvocation.deferred, result);
915
- }), Effect.catchTags({ InvalidServerMessage: (error) => rejectInvocation(message.id, error) }));
916
- return;
917
- }
918
- case "Error": {
919
- if (message.sessionEpoch !== session.current()?.sessionEpoch) return;
920
- const error = message.operation === void 0 ? ServerError.make({
921
- code: message.code,
922
- message: message.message
923
- }) : ServerError.make({
924
- code: message.code,
925
- message: message.message,
926
- operation: message.operation
927
- });
928
- if (message.operation?.type === "Invocation") yield* rejectInvocation(message.operation.id, error);
929
- else if (message.operation?.type === "Subscription") {
930
- queryCache.setResult(message.operation.id, error);
931
- yield* reportClientError(error);
932
- } else yield* reportClientError(error);
933
- return;
934
- }
935
- }
936
- });
937
- const requestReload = () => {
938
- if (reloadRequested) return;
939
- reloadRequested = true;
940
- writer = void 0;
941
- globalThis.location.reload();
942
- };
943
- const disconnect = Effect.sync(() => {
944
- writer = void 0;
945
- });
946
- const connect = Effect.scoped(Effect.gen(function* () {
947
- if (reloadRequested) return yield* Effect.never;
948
- yield* session.bootstrap.pipe(Effect.mapError((error) => ConnectionUnavailable.make({ message: error.message })));
949
- const socket = yield* Socket.makeWebSocket(`${socketUrl()}${session.socketParameters()}`, { closeCodeIsError: (code) => {
950
- if (shouldReloadForCloseCode(code)) requestReload();
951
- return false;
952
- } });
953
- const write = yield* socket.writer;
954
- const handshakeReceived = yield* Deferred.make();
955
- let handshakeAccepted = false;
956
- const acceptHandshake = Effect.fn("SyncClient.acceptHandshake")(function* (handshake) {
957
- const decision = handshakeDecision(rememberedHandshake, handshakeAccepted, handshake);
958
- if (decision === "Reload") {
959
- requestReload();
960
- return;
961
- }
962
- if (decision === "Ignore") return;
963
- if (handshake.session === void 0 || handshake.serverTime === void 0) {
964
- requestReload();
965
- return;
966
- }
967
- if (rememberedHandshake?.session !== void 0 && rememberedHandshake.session.sessionEpoch !== handshake.session.sessionEpoch) {
968
- queryCache.invalidatePrivate();
969
- yield* Effect.forEach(HashMap.keys(invocations), (id) => rejectInvocation(id, ServerError.make({
970
- code: "SessionChanged",
971
- message: "The session changed. This operation may already have completed."
972
- })));
973
- } else if (rememberedHandshake?.session?.viewRevision !== handshake.session.viewRevision) queryCache.invalidatePrivate();
974
- yield* Effect.forEach(HashMap.entries(invocations), ([id, pending]) => pending.sessionEpoch === handshake.session.sessionEpoch ? Effect.void : rejectInvocation(id, ServerError.make({
975
- code: "SessionChanged",
976
- message: "The session changed. This operation may already have completed."
977
- })));
978
- session.accept(handshake.session, handshake.serverTime);
979
- rememberedHandshake = handshake;
980
- handshakeAccepted = true;
981
- writer = write;
982
- yield* Deferred.succeed(handshakeReceived, void 0);
983
- yield* Effect.gen(function* () {
984
- yield* Effect.forEach(queryCache.entries(), (entry) => sendWith(write, subscribeMessage(entry)));
985
- yield* Effect.forEach(HashMap.values(invocations), (pendingInvocation) => sendWith(write, pendingInvocation.message));
986
- }).pipe(Effect.tapError(reportClientError), Effect.ignore);
987
- });
988
- const handleText = Effect.fn("SyncClient.handleText")(function* (text) {
989
- const message = yield* Schema.decodeEffect(ServerMessageJson)(text).pipe(Effect.mapError((cause) => InvalidServerMessage.make({
990
- cause,
991
- message: "The server returned an invalid sync message."
992
- })));
993
- if (message.type === "Handshake") return yield* acceptHandshake(message);
994
- if (message.type === "Deployment") {
995
- requestReload();
996
- return;
997
- }
998
- if (!handshakeAccepted) return yield* InvalidServerMessage.make({
999
- cause: /* @__PURE__ */ new Error("The server sent a sync message before the handshake."),
1000
- message: "The server returned a sync message before the handshake."
1001
- });
1002
- return yield* handleMessage(message);
1003
- });
1004
- const suspended = yield* Deferred.make();
1005
- sessionSuspended = suspended;
1006
- yield* Effect.addFinalizer(() => Effect.sync(() => {
1007
- if (sessionSuspended === suspended) sessionSuspended = void 0;
1008
- }));
1009
- const run = yield* socket.runString(handleText).pipe(Effect.forkChild);
1010
- yield* Effect.raceFirst(Deferred.await(handshakeReceived).pipe(Effect.timeout("10 seconds")), Fiber.join(run));
1011
- yield* Effect.raceFirst(Fiber.join(run), Deferred.await(suspended));
1012
- })).pipe(Effect.mapError((cause) => Schema.is(ClientInfrastructureError)(cause) ? cause : ConnectionUnavailable.make({
1013
- cause,
1014
- message: "The sync connection was lost."
1015
- })), Effect.ensuring(disconnect));
1016
- const reconnectSchedule = Schedule.exponential("250 millis").pipe(Schedule.modifyDelay(({ duration }) => Effect.succeed(Duration.min(duration, Duration.seconds(5)))), Schedule.jittered);
1017
- yield* connect.pipe(Effect.andThen(Effect.fail(ConnectionUnavailable.make({ message: "The sync connection closed; reconnecting." }))), Effect.tapError(reportClientError), Effect.retry(reconnectSchedule), Effect.forkScoped);
1018
- const observe = Effect.fn("SyncClient.observe")(function* (functionAddress, args) {
1019
- return yield* queryCache.observe(functionAddress, args);
1020
- });
1021
- const mutate = Effect.fn("SyncClient.mutate")(function* (functionAddress, args) {
1022
- const admittedSession = session.current() ?? rememberedHandshake?.session ?? (yield* session.bootstrap.pipe(Effect.mapError((error) => ConnectionUnavailable.make({ message: error.message }))));
1023
- const invocationId = yield* ids.generate(InvocationId);
1024
- const preparedArguments = yield* prepareMutationArguments(args).pipe(Effect.provideService(IdGenerator, ids), Effect.mapError((cause) => InvalidMutationArguments.make({
1025
- cause,
1026
- function: functionAddress,
1027
- message: `Mutation arguments for ${functionAddress} contain an unsupported file or value.`
1028
- })), Effect.tapError(reportClientError));
1029
- const jsonArgs = yield* Effect.try({
1030
- try: () => encodeTransportObject(preparedArguments.value),
1031
- catch: (cause) => InvalidMutationArguments.make({
1032
- cause,
1033
- function: functionAddress,
1034
- message: `Mutation arguments for ${functionAddress} contain an unsupported value.`
1035
- })
1036
- }).pipe(Effect.tapError(reportClientError));
1037
- const deferred = yield* Deferred.make();
1038
- const prepared = yield* Deferred.make();
1039
- const invokeMessage = {
1040
- type: "Invoke",
1041
- id: invocationId,
1042
- kind: "Mutation",
1043
- function: functionAddress,
1044
- args: jsonArgs
1045
- };
1046
- const message = preparedArguments.fileIds.length === 0 ? invokeMessage : {
1047
- type: "Prepare",
1048
- id: invocationId,
1049
- kind: "Mutation",
1050
- function: functionAddress,
1051
- args: jsonArgs,
1052
- files: preparedArguments.fileIds
1053
- };
1054
- invocations = HashMap.set(invocations, invocationId, {
1055
- sessionEpoch: admittedSession.sessionEpoch,
1056
- deferred,
1057
- function: functionAddress,
1058
- message,
1059
- prepared
1060
- });
1061
- return yield* Effect.gen(function* () {
1062
- if (writer !== void 0) yield* sendWith(writer, message).pipe(Effect.catchTags({
1063
- ConnectionUnavailable: reportClientError,
1064
- InvalidClientMessage: (error) => rejectInvocation(invocationId, error)
1065
- }));
1066
- if (message.type === "Prepare") {
1067
- const uploads = yield* Deferred.await(prepared);
1068
- const expected = new Set(message.files);
1069
- const received = /* @__PURE__ */ new Set();
1070
- const transfers = [];
1071
- for (const upload of uploads) {
1072
- if (!expected.has(upload.id) || received.has(upload.id)) return yield* InvalidServerMessage.make({
1073
- cause: /* @__PURE__ */ new Error(`Unexpected prepared file '${upload.id}'.`),
1074
- message: "The server returned invalid application file preparation data."
1075
- });
1076
- received.add(upload.id);
1077
- const file = preparedArguments.nativeFiles.get(upload.id);
1078
- if (file === void 0) return yield* InvalidServerMessage.make({
1079
- cause: /* @__PURE__ */ new Error(`Missing native file '${upload.id}'.`),
1080
- message: "The server prepared an unknown application file."
1081
- });
1082
- if (upload.url === void 0) continue;
1083
- transfers.push({
1084
- file,
1085
- url: upload.url
1086
- });
1087
- }
1088
- if (received.size !== expected.size) return yield* InvalidServerMessage.make({
1089
- cause: /* @__PURE__ */ new Error("The server omitted a prepared file."),
1090
- message: "The server returned incomplete application file preparation data."
1091
- });
1092
- yield* Effect.forEach(transfers, Effect.fn("SyncClient.uploadFile")(function* ({ file, url }) {
1093
- const response = yield* Effect.tryPromise({
1094
- try: (signal) => fetch(url, {
1095
- method: "PUT",
1096
- body: file,
1097
- headers: { "content-type": file.type },
1098
- signal
1099
- }),
1100
- catch: (cause) => ConnectionUnavailable.make({
1101
- cause,
1102
- message: `File '${file.name}' could not be uploaded.`
1103
- })
1104
- });
1105
- if (!response.ok) {
1106
- const detail = yield* Effect.promise(() => response.text());
1107
- return yield* InvalidMutationArguments.make({
1108
- cause: new Error(detail),
1109
- function: functionAddress,
1110
- message: `File '${file.name}' was rejected by application storage.`
1111
- });
1112
- }
1113
- }), {
1114
- concurrency: 3,
1115
- discard: true
1116
- });
1117
- const pendingInvocation = Option.getOrUndefined(HashMap.get(invocations, invocationId));
1118
- if (pendingInvocation === void 0) return yield* Deferred.await(deferred);
1119
- invocations = HashMap.set(invocations, invocationId, {
1120
- ...pendingInvocation,
1121
- message: invokeMessage
1122
- });
1123
- if (writer !== void 0) yield* sendWith(writer, invokeMessage).pipe(Effect.catchTags({
1124
- ConnectionUnavailable: reportClientError,
1125
- InvalidClientMessage: (error) => rejectInvocation(invocationId, error)
1126
- }));
1127
- }
1128
- return yield* Deferred.await(deferred);
1129
- }).pipe(Effect.tapError(() => Effect.sync(() => {
1130
- invocations = HashMap.remove(invocations, invocationId);
1131
- })));
1132
- });
1133
- return SyncClient.of({
1134
- mutate,
1135
- observe
1136
- });
1137
- })).pipe(Layer.provide(Layer.merge(Socket.layerWebSocketConstructorGlobal, BrowserCrypto.layer)));
1138
- };
1139
- const syncRuntime = ManagedRuntime.make(SyncClient.layer.pipe(Layer.provideMerge(BrowserSession.layer), Layer.provideMerge(clientErrorReporterLayer), Layer.provideMerge(IdGenerator.layer)));
1140
- const hot = import.meta.hot;
1141
- if (hot !== void 0) hot.dispose(() => void syncRuntime.dispose());
1142
- //#endregion
1143
18
  //#region src/client/page-observers.ts
1144
19
  const makePageObservers = (onChange, releaseObserver) => {
1145
20
  const pages = /* @__PURE__ */ new Map();
@@ -1415,15 +290,9 @@ function useId() {
1415
290
  };
1416
291
  }
1417
292
  //#endregion
1418
- //#region src/client/app.ts
1419
- const app = (definition) => {
1420
- if (definition.title.trim().length === 0) throw new Error("The app title must contain a non-whitespace character.");
1421
- return definition;
1422
- };
1423
- //#endregion
1424
293
  //#region src/client/index.ts
1425
294
  const Result = { match: Result$2.match };
1426
295
  //#endregion
1427
- 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 };
296
+ export { Component, Files, Fragment, Image, Link, NavLink, Query, Redirect, Result, cloneElement, createContext, createElement, createRef, h, isValidElement, toChildArray, url, useBlocker, useCallback, useContext, useDebugValue, useEffect, useElementId, useErrorBoundary, useId, useImperativeHandle, useLayoutEffect, useLocation, useMatch, useMemo, useMutation, useNavigate, useNavigation, usePaginatedQuery, useQuery, useReducer, useRef, useRoute, useState };
1428
297
 
1429
298
  //# sourceMappingURL=client.js.map