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
@@ -0,0 +1,110 @@
1
+ import type { ExecutionSelection } from "@ignotum/contracts/platform";
2
+ import { createElement, Fragment, render, type ComponentChildren } from "preact";
3
+ import { useLayoutEffect, useState } from "preact/hooks";
4
+ import { mountManagedSync } from "./sync.js";
5
+ import type { ManagedBrowserClient } from "./managed-client.js";
6
+ import { RouterContext, useRouterSnapshot } from "./router.js";
7
+ // oxlint-disable-next-line anti-slop-effect/no-service-constructor-imports -- Each browser mount owns its router and releases it on disposal.
8
+ import { RouterStore, type ClientRegistration } from "./router-store.js";
9
+
10
+ import { Branch, LoadFailure } from "./route-boundaries.js";
11
+
12
+ const RouterView = ({ router }: { readonly router: RouterStore }): ComponentChildren => {
13
+ const snapshot = useRouterSnapshot(router);
14
+ useLayoutEffect(() => {
15
+ router.rendered(snapshot.commit);
16
+ }, [router, snapshot]);
17
+ return createElement(
18
+ RouterContext.Provider,
19
+ { value: router },
20
+ snapshot.branch === undefined || snapshot.location === undefined
21
+ ? createElement("div", { role: "status" }, snapshot.failure === undefined ? "Loading…" : null)
22
+ : createElement(Branch, {
23
+ branch: snapshot.branch,
24
+ location: snapshot.location,
25
+ router,
26
+ failure: snapshot.failure,
27
+ }),
28
+ snapshot.failure !== undefined && snapshot.branch === undefined
29
+ ? createElement(LoadFailure, { failure: snapshot.failure, router })
30
+ : null,
31
+ );
32
+ };
33
+
34
+ const mounts = new WeakSet<Element>();
35
+
36
+ const ManagedStatus = ({ client }: { readonly client: ManagedBrowserClient }) => {
37
+ const [snapshot, setSnapshot] = useState(client.upgrade.getSnapshot);
38
+ useLayoutEffect(
39
+ () => client.upgrade.subscribe(() => setSnapshot(client.upgrade.getSnapshot())),
40
+ [client],
41
+ );
42
+ if (snapshot.phase === "ready" && snapshot.recovery.length === 0) return null;
43
+ return createElement(
44
+ "aside",
45
+ {
46
+ "data-ignotum-update": snapshot.phase,
47
+ role: snapshot.phase === "error" ? "alert" : "status",
48
+ },
49
+ snapshot.message ?? (snapshot.phase === "connecting" ? "Connecting to the app…" : null),
50
+ snapshot.recovery.length === 0
51
+ ? null
52
+ : createElement(
53
+ "ul",
54
+ null,
55
+ snapshot.recovery.map((message) => createElement("li", { key: message }, message)),
56
+ ),
57
+ snapshot.phase === "error"
58
+ ? createElement("button", { type: "button", onClick: () => client.retry() }, "Reload app")
59
+ : null,
60
+ snapshot.recovery.length === 0
61
+ ? null
62
+ : createElement(
63
+ "button",
64
+ { type: "button", onClick: client.upgrade.dismissRecovery },
65
+ "Dismiss",
66
+ ),
67
+ );
68
+ };
69
+
70
+ /** The platform owns mounting. Generated registrations contain no Preact render/bootstrap code. */
71
+ export const mountClient = (registration: ClientRegistration, selection: ExecutionSelection) => {
72
+ const root = window.document.getElementById("app");
73
+ if (root === null) throw new Error("Ignotum mount element is missing.");
74
+ if (mounts.has(root)) throw new Error("The Ignotum client is already mounted.");
75
+ const router = new RouterStore(registration, selection, window);
76
+ const managed = mountManagedSync(selection, window, {
77
+ stopAdmission: router.stopForUpgrade,
78
+ reload: router.upgrade,
79
+ });
80
+ router.setAdmission({
81
+ validate: managed.client.validate,
82
+ recoverLoad: managed.client.recoverLoad,
83
+ });
84
+ render(
85
+ createElement(
86
+ Fragment,
87
+ null,
88
+ createElement(ManagedStatus, { client: managed.client }),
89
+ createElement(RouterView, { router }),
90
+ ),
91
+ root,
92
+ );
93
+ const ready = managed.client
94
+ .whenReady()
95
+ .then((accepted) => (accepted ? router.start() : { status: "cancelled" as const }));
96
+ mounts.add(root);
97
+ let disposed = false;
98
+ return {
99
+ ready,
100
+ upgrade: () => managed.client.upgrade.require(),
101
+ dispose: () => {
102
+ if (disposed) return;
103
+ disposed = true;
104
+ mounts.delete(root);
105
+ router.dispose();
106
+ managed.dispose();
107
+ render(null, root);
108
+ },
109
+ };
110
+ };
@@ -1,7 +1,7 @@
1
1
  /** @effect-diagnostics globalConsole:skip-file */
2
2
  import { Cause, Effect, ErrorReporter, Schema } from "effect";
3
3
 
4
- import { ErrorCode, FunctionAddress, Operation } from "@ignotum/contracts/runtime/sync";
4
+ import { FunctionAddress } from "@ignotum/contracts/runtime/sync";
5
5
 
6
6
  export class ConnectionUnavailable extends Schema.TaggedError<ConnectionUnavailable>()(
7
7
  "ConnectionUnavailable",
@@ -11,10 +11,9 @@ export class ConnectionUnavailable extends Schema.TaggedError<ConnectionUnavaila
11
11
  },
12
12
  ) {}
13
13
 
14
- export class InvalidClientMessage extends Schema.TaggedError<InvalidClientMessage>()(
15
- "InvalidClientMessage",
14
+ export class PlatformUpgrading extends Schema.TaggedError<PlatformUpgrading>()(
15
+ "PlatformUpgrading",
16
16
  {
17
- cause: Schema.Defect(),
18
17
  message: Schema.String,
19
18
  },
20
19
  ) {}
@@ -37,14 +36,21 @@ export class InvalidServerMessage extends Schema.TaggedError<InvalidServerMessag
37
36
  ) {}
38
37
 
39
38
  export class ServerError extends Schema.TaggedError<ServerError>()("ServerError", {
40
- code: ErrorCode,
39
+ code: Schema.Literals([
40
+ "PlatformUpgrading",
41
+ "SessionExpired",
42
+ "InvalidMessage",
43
+ "Unavailable",
44
+ "InvalidArguments",
45
+ "InvocationIdConflict",
46
+ "ResourceLimitExceeded",
47
+ ]),
41
48
  message: Schema.String,
42
- operation: Schema.optional(Operation),
43
49
  }) {}
44
50
 
45
51
  export const ClientInfrastructureError = Schema.Union([
52
+ PlatformUpgrading,
46
53
  ConnectionUnavailable,
47
- InvalidClientMessage,
48
54
  InvalidMutationArguments,
49
55
  InvalidServerMessage,
50
56
  ServerError,
@@ -11,6 +11,8 @@ import {
11
11
  type FileFormat,
12
12
  type FileValue,
13
13
  } from "@ignotum/contracts/schema/file";
14
+ import type { FunctionAddress } from "@ignotum/contracts/runtime/sync";
15
+ import { InvalidServerMessage, ConnectionUnavailable, InvalidMutationArguments } from "./errors.js";
14
16
  import { IdGenerator } from "@ignotum/shared/id";
15
17
  import { Effect, Predicate, Schema } from "effect";
16
18
 
@@ -167,3 +169,65 @@ export const applyFileGrants = (
167
169
  if (matched.size !== byId.size) throw new Error("A query file grant has no result value.");
168
170
  return granted;
169
171
  };
172
+
173
+ export const uploadPreparedFiles = Effect.fn("uploadPreparedFiles")(function* (
174
+ nativeFiles: ReadonlyMap<FileId, File>,
175
+ uploads: ReadonlyArray<{ readonly id: FileId; readonly url?: string }>,
176
+ functionAddress: FunctionAddress,
177
+ ) {
178
+ const expected = new Set(nativeFiles.keys());
179
+ const received = new Set<string>();
180
+ const transfers: Array<{ readonly file: File; readonly url: string }> = [];
181
+ for (const upload of uploads) {
182
+ if (!expected.has(upload.id) || received.has(upload.id)) {
183
+ return yield* InvalidServerMessage.make({
184
+ cause: new Error(`Unexpected prepared file '${upload.id}'.`),
185
+ message: "The server returned invalid application file preparation data.",
186
+ });
187
+ }
188
+ received.add(upload.id);
189
+ const file = nativeFiles.get(upload.id);
190
+ if (file === undefined) {
191
+ return yield* InvalidServerMessage.make({
192
+ cause: new Error(`Missing native file '${upload.id}'.`),
193
+ message: "The server prepared an unknown application file.",
194
+ });
195
+ }
196
+ if (upload.url === undefined) continue;
197
+ transfers.push({ file, url: upload.url });
198
+ }
199
+ if (received.size !== expected.size) {
200
+ return yield* InvalidServerMessage.make({
201
+ cause: new Error("The server omitted a prepared file."),
202
+ message: "The server returned incomplete application file preparation data.",
203
+ });
204
+ }
205
+ yield* Effect.forEach(
206
+ transfers,
207
+ Effect.fn("SyncClient.uploadFile")(function* ({ file, url }) {
208
+ const response = yield* Effect.tryPromise({
209
+ try: (signal) =>
210
+ fetch(url, {
211
+ method: "PUT",
212
+ body: file,
213
+ headers: { "content-type": file.type },
214
+ signal,
215
+ }),
216
+ catch: (cause) =>
217
+ ConnectionUnavailable.make({
218
+ cause,
219
+ message: `File '${file.name}' could not be uploaded.`,
220
+ }),
221
+ });
222
+ if (!response.ok) {
223
+ const detail = yield* Effect.promise(() => response.text());
224
+ return yield* InvalidMutationArguments.make({
225
+ cause: new Error(detail),
226
+ function: functionAddress,
227
+ message: `File '${file.name}' was rejected by application storage.`,
228
+ });
229
+ }
230
+ }),
231
+ { concurrency: 3, discard: true },
232
+ );
233
+ });
package/src/client/id.ts CHANGED
@@ -108,11 +108,15 @@ export class BrowserSession extends Context.Service<
108
108
  );
109
109
 
110
110
  const readOutcome = () => {
111
- const raw = globalThis.sessionStorage.getItem(outcomeKey);
112
- if (raw !== null) {
113
- const decoded = Schema.decodeUnknownOption(SessionOutcome)(raw);
114
- if (Option.isSome(decoded)) state = { ...state, outcome: decoded.value };
115
- globalThis.sessionStorage.removeItem(outcomeKey);
111
+ try {
112
+ const raw = globalThis.sessionStorage.getItem(outcomeKey);
113
+ if (raw !== null) {
114
+ const decoded = Schema.decodeUnknownOption(SessionOutcome)(raw);
115
+ if (Option.isSome(decoded)) state = { ...state, outcome: decoded.value };
116
+ globalThis.sessionStorage.removeItem(outcomeKey);
117
+ }
118
+ } catch {
119
+ // The authenticated session response remains valid when optional redirect storage is denied.
116
120
  }
117
121
  };
118
122
  const parameters = () => {
@@ -0,0 +1,28 @@
1
+ import { createElement, type JSX } from "preact";
2
+
3
+ declare const ImageSourceTypeId: unique symbol;
4
+
5
+ /** A compiler-provided reference to an imported image. */
6
+ export interface ImageSource {
7
+ readonly type: "ImageSource";
8
+ readonly url: string;
9
+ readonly [ImageSourceTypeId]: true;
10
+ }
11
+
12
+ export type ImageProps = Omit<
13
+ JSX.ImgHTMLAttributes<HTMLImageElement>,
14
+ "alt" | "src" | "srcSet" | "srcset"
15
+ > & {
16
+ readonly src: ImageSource;
17
+ readonly alt: string;
18
+ };
19
+
20
+ /** Renders an imported image. */
21
+ export const Image = ({ src, alt, ...attributes }: ImageProps): JSX.Element =>
22
+ createElement("img", { ...attributes, src: src.url, alt });
23
+
24
+ /** @internal Creates an image reference from a compiler-resolved URL. */
25
+ export const createImageSource = (url: string): ImageSource => {
26
+ // SAFETY: This factory constructs the complete runtime representation; the brand exists only in types.
27
+ return { type: "ImageSource", url } as ImageSource;
28
+ };
@@ -20,8 +20,8 @@ export { useId, useMutation, usePaginatedQuery, useQuery } from "./hooks.js";
20
20
  export type { PaginatedQueryOptions, PaginatedQueryValue, PaginationStatus } from "./hooks.js";
21
21
  export { Query } from "./query.js";
22
22
  export type { QuerySkip } from "./query.js";
23
- export { app } from "./app.js";
24
- export type { AppDefinition } from "./app.js";
23
+ export { Image } from "./image.js";
24
+ export type { ImageProps, ImageSource } from "./image.js";
25
25
 
26
26
  export {
27
27
  Component,
@@ -101,3 +101,26 @@ export type { Dispatch, Reducer, StateUpdater } from "preact/hooks";
101
101
 
102
102
  export type { User, UserId, ProfileField } from "@ignotum/contracts/id";
103
103
  export type { IdResult, IdOptions } from "./hooks.js";
104
+
105
+ export type {
106
+ RouteInputs,
107
+ RouteProps,
108
+ RouteMatch,
109
+ RouteLocation,
110
+ NavigationResult,
111
+ } from "./routes.js";
112
+
113
+ export {
114
+ Link,
115
+ NavLink,
116
+ Redirect,
117
+ url,
118
+ useNavigate,
119
+ useRoute,
120
+ useMatch,
121
+ useLocation,
122
+ useNavigation,
123
+ useBlocker,
124
+ } from "./router.js";
125
+
126
+ export type { BlockerState } from "./router-store.js";