@powerhousedao/connect-core 6.2.3-dev.81 → 6.2.3-dev.82
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/{index-BMlma368.d.ts → index-CCs6HTQV.d.ts} +5 -17
- package/dist/index-CCs6HTQV.d.ts.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/multi-reactor-CVwr_LdS.js +112 -0
- package/dist/multi-reactor-CVwr_LdS.js.map +1 -0
- package/dist/{runtime-D20_LlB_.js → runtime-Cb3HQhKo.js} +2 -2
- package/dist/{runtime-D20_LlB_.js.map → runtime-Cb3HQhKo.js.map} +1 -1
- package/dist/runtime.d.ts +1 -1
- package/dist/runtime.js +1 -1
- package/package.json +8 -8
- package/src/runtime/multi-reactor.ts +16 -28
- package/dist/index-BMlma368.d.ts.map +0 -1
- package/dist/multi-reactor-D_2B4jmu.js +0 -219
- package/dist/multi-reactor-D_2B4jmu.js.map +0 -1
- package/src/runtime/graphql-routable-backend.ts +0 -182
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import "./runtime-config-D3YPhYyj.js";
|
|
2
|
-
import { BrowserReactorClientModule,
|
|
2
|
+
import { BrowserReactorClientModule, PHStore, SwitchboardBackend, WorkerReactorClientModule } from "@powerhousedao/reactor-browser";
|
|
3
3
|
import { PHReactorClientMode } from "@powerhousedao/shared/clis";
|
|
4
4
|
import { DocumentDriveDocument } from "@powerhousedao/shared/document-drive";
|
|
5
5
|
import { DocumentModelModule, ISigner } from "@powerhousedao/shared/document-model";
|
|
6
6
|
import { IReactorClient, ReactorInfo } from "@powerhousedao/reactor";
|
|
7
|
-
import { CollectionRequirementsInput,
|
|
7
|
+
import { CollectionRequirementsInput, ReactorReach, RoutableBackendConfig, RouterDiagnostic, RoutingClientOptions, RoutingReactorClient } from "@powerhousedao/reactor-router";
|
|
8
8
|
import { DocumentModelLib } from "document-model";
|
|
9
9
|
//#endregion
|
|
10
10
|
//#region src/runtime/runtime-flag.d.ts
|
|
@@ -52,20 +52,8 @@ type ReactorClientMode = PHReactorClientMode;
|
|
|
52
52
|
declare const REACTOR_CLIENT_QUERY_KEY = "reactorClient";
|
|
53
53
|
declare const REACTOR_CLIENT_STORAGE_KEY = "ph:reactorClient";
|
|
54
54
|
declare function resolveReactorClientMode(): ReactorClientMode;
|
|
55
|
-
//#endregion
|
|
56
|
-
//#region src/runtime/graphql-routable-backend.d.ts
|
|
57
|
-
type GraphQLRoutableBackendOptions = Omit<GraphQLReactorClientOptions, "driveIdFor">;
|
|
58
|
-
type GraphQLRoutableBackend = {
|
|
59
|
-
readonly backend: IRoutableBackend;
|
|
60
|
-
/** The Switchboard's own facts, from its inspection subgraph. */
|
|
61
|
-
info(): Promise<ReactorInfo>;
|
|
62
|
-
/** Reopens the realtime socket on the new credentials. */
|
|
63
|
-
notifyCredentialsChanged(): void;
|
|
64
|
-
};
|
|
65
|
-
/** A Switchboard as a router backend; members GraphQL cannot serve are absent. */
|
|
66
|
-
declare function createGraphQLRoutableBackend(options: GraphQLRoutableBackendOptions): GraphQLRoutableBackend;
|
|
67
55
|
declare namespace multi_reactor_d_exports {
|
|
68
|
-
export { ConnectRoutingClient,
|
|
56
|
+
export { ConnectRoutingClient, LOCAL_BACKEND_NAME, LoadedDocumentModels, LocalReactorModule, MultiReactorParams, PLACE_ON_LOCAL, PLACE_ON_REMOTE, REMOTE_BACKEND_NAME, buildMultiReactorClient, deriveSwitchboardGraphqlUrl, localFacts, localReach };
|
|
69
57
|
}
|
|
70
58
|
declare const LOCAL_BACKEND_NAME = "connect-local";
|
|
71
59
|
declare const REMOTE_BACKEND_NAME = "switchboard-remote";
|
|
@@ -97,7 +85,7 @@ declare const PLACE_ON_REMOTE: CollectionRequirementsInput;
|
|
|
97
85
|
/** The router Connect installs, with Connect's handling of credentials and id checks. */
|
|
98
86
|
declare class ConnectRoutingClient extends RoutingReactorClient {
|
|
99
87
|
private readonly remote;
|
|
100
|
-
constructor(backends: readonly RoutableBackendConfig[], options: RoutingClientOptions, remote:
|
|
88
|
+
constructor(backends: readonly RoutableBackendConfig[], options: RoutingClientOptions, remote: SwitchboardBackend, hasLocal: boolean);
|
|
101
89
|
/** Renown's sign-in and sign-out call this on whatever client is installed. */
|
|
102
90
|
notifyCredentialsChanged(): void;
|
|
103
91
|
}
|
|
@@ -196,4 +184,4 @@ declare function loadLocalPackage(source: LocalPackageSource | undefined): Docum
|
|
|
196
184
|
//#endregion
|
|
197
185
|
export { isRuntimeFlagEnabled as A, REACTOR_WORKER_STORAGE_KEY as C, isMultiReactorEnabled as D, resolveReactorWorkerEnabled as E, RuntimeFlagInput as O, REACTOR_WORKER_QUERY_KEY as S, isReactorWorkerEnabled as T, LocalReactorModule as _, getConnectPHStore as a, ReactorClientMode as b, LocalReactorFactory as c, getAppDrives as d, planReactorClient as f, LoadedDocumentModels as g, selectAppReactorClient as h, loadLocalPackage as i, resolveRuntimeFlag as j, RuntimeFlagKeys as k, ReactorClientPlan as l, relistAppDrives as m, LocalPackageSource as n, AppReactorClientParams as o, refreshAppDrives as p, ModuleNamespace as r, CreateAppReactorClientOptions as s, LocalPackage as t, createAppReactorClient as u, REACTOR_CLIENT_QUERY_KEY as v, ReactorWorkerFlagInput as w, resolveReactorClientMode as x, REACTOR_CLIENT_STORAGE_KEY as y };
|
|
198
186
|
export {};
|
|
199
|
-
//# sourceMappingURL=index-
|
|
187
|
+
//# sourceMappingURL=index-CCs6HTQV.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-CCs6HTQV.d.ts","names":[],"sources":["../src/runtime/runtime-flag.ts","../src/runtime/multi-reactor-flag.ts","../src/runtime/reactor-worker-flag.ts","../src/runtime/reactor-client-mode.ts","../src/runtime/multi-reactor.ts","../src/runtime/app-reactor-client.ts","../src/runtime/ph-store.ts","../src/runtime/local-package.ts"],"mappings":";;;;;;;;;;KAAY;EACV;EACA;EACA;;iBAIc,mBAAmB,OAAO;KAY9B;EACV;EACA;EACA;;iBAKc,qBAAqB,MAAM;;;iBCxB3B;;;cCIH;cACA;KAED,yBAAyB;iBAErB,4BACd,OAAO;iBAKO;;;;;;;;;;;;;;;;;;;KCGJ,oBAAoB;cASnB;cACA;iBA2BG,4BAA4B;;;;cC9B/B;cACA;KAED,qBACR,6BACA;;cAGS,gBAAgB;iBAIb,WAAW,MAAM,6BAA6B;;iBAO9C,WACd,QAAQ,2BACD,QAAQ;;iBAcD,4BACd;;KAaU,gCACC,wCACO;KAER;;;EAGV,QAAQ;EACR;;EAEA,SAAS;;EAET,sBAAsB;EACtB,eAAe;;;;;cAMJ,iBAAiB;;cAwBjB,6BAA6B;mBACvB;EAEjB,YACE,mBAAmB,yBACnB,SAAS,sBACT,QAAQ,oBACR;;EAYF;;;;;;;;;iBAmBoB,wBACpB,QAAQ,qBACP,QAAQ;;;KCzIN,4BAA4B;KAErB;EACV,MAAM;;;EAGN,QAAQ;EACR;;EAEA,SAAS;EACT,sBAAsB;EACtB,mBAAmB,QAAQ;;;KAOjB;EACV,MAAM;;EAEN;EACA;;EAEA;;iBAGc,kBACd,OAAM,oBACL;;KAaS,uBACV,MAAM,sBACH,QAAQ;KAED,gCAAgC,KAC1C;EAGA,OAAO;;EAEP,eAAe;;;iBAIK,uBACpB,SAAS,gCAA6B;;;;;;;;;;;;iBA4BlB,uBACpB,QAAQ,yBACP,QAAQ;;;;;;;;;iBAoCW,aACpB,QAAQ,gBACR,OAAO,iBACN,QAAQ;;;;;;;;iBA4CW,iBACpB,QAAQ,gBACR,OAAO,iBACN;;;;;;iBASmB,mBAAmB;;;;;iBCpMzB,qBAAqB;;;;KCNzB,kBAAkB;GAC3B,OAAO;;KAGE,eAAe,wBAAwB;;KAGvC,qBAAqB,sBAAsB,QAAQ;;iBAG/C,iBACd,QAAQ,iCACP,mBAAmB,QAAQ"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { A as isRuntimeFlagEnabled, C as REACTOR_WORKER_STORAGE_KEY, D as isMultiReactorEnabled, E as resolveReactorWorkerEnabled, O as RuntimeFlagInput, S as REACTOR_WORKER_QUERY_KEY, T as isReactorWorkerEnabled, _ as LocalReactorModule, a as getConnectPHStore, b as ReactorClientMode, c as LocalReactorFactory, d as getAppDrives, f as planReactorClient, g as LoadedDocumentModels, h as selectAppReactorClient, i as loadLocalPackage, j as resolveRuntimeFlag, k as RuntimeFlagKeys, l as ReactorClientPlan, m as relistAppDrives, n as LocalPackageSource, o as AppReactorClientParams, p as refreshAppDrives, r as ModuleNamespace, s as CreateAppReactorClientOptions, t as LocalPackage, u as createAppReactorClient, v as REACTOR_CLIENT_QUERY_KEY, w as ReactorWorkerFlagInput, x as resolveReactorClientMode, y as REACTOR_CLIENT_STORAGE_KEY } from "./index-
|
|
1
|
+
import { A as isRuntimeFlagEnabled, C as REACTOR_WORKER_STORAGE_KEY, D as isMultiReactorEnabled, E as resolveReactorWorkerEnabled, O as RuntimeFlagInput, S as REACTOR_WORKER_QUERY_KEY, T as isReactorWorkerEnabled, _ as LocalReactorModule, a as getConnectPHStore, b as ReactorClientMode, c as LocalReactorFactory, d as getAppDrives, f as planReactorClient, g as LoadedDocumentModels, h as selectAppReactorClient, i as loadLocalPackage, j as resolveRuntimeFlag, k as RuntimeFlagKeys, l as ReactorClientPlan, m as relistAppDrives, n as LocalPackageSource, o as AppReactorClientParams, p as refreshAppDrives, r as ModuleNamespace, s as CreateAppReactorClientOptions, t as LocalPackage, u as createAppReactorClient, v as REACTOR_CLIENT_QUERY_KEY, w as ReactorWorkerFlagInput, x as resolveReactorClientMode, y as REACTOR_CLIENT_STORAGE_KEY } from "./index-CCs6HTQV.js";
|
|
2
2
|
import { A as useDriveRouteData, B as ConnectConfigHooks, C as holdConnectRoutes, D as DRIVE_ROUTE_ID, E as removeConnectRoutes, F as DriveRouteData, G as ConnectPluginUi, H as ConnectPluginContext, I as DriveRouteParams, J as ConnectModals, K as ConnectRouteUi, L as isDriveNotFound, M as ConnectRouterContext, N as DriveLoaderOptions, O as DriveRouteView, P as DriveNotFoundData, R as loadDrive, S as connectRoutesSettled, T as registerPackageRoutes, U as ConnectPluginDefinition, V as ConnectPlugin, W as ConnectPluginFactory, Y as ModalOutlet, _ as ConnectRoutes, a as bindConnectRouter, b as addConnectRoutes, c as applyConnectPluginUi, d as mergeConnectPluginUi, f as resetConnectPluginUi, g as ConnectRootRoute, h as APP_ROUTE_ID, i as ConnectRouterOptions, j as useDriveRouteIds, k as NODE_ROUTE_ID, l as getConnectPluginUi, m as ConnectRouteRegistration, n as ConnectRouterBundle, o as createConnectRouter, q as CORE_MODAL_VIEWS, r as ConnectRouterFor, s as ConnectPluginUiSet, t as ConnectRouter, u as loadConnectPluginUi, v as HOME_ROUTE_ID, w as registerConnectRoutes, x as connectRoutes, y as PackageRoute, z as loadNode } from "./connect-router-11uRIT3z.js";
|
|
3
3
|
import { a as DrivePending, i as DocumentViewProps, n as ContentOutlet, o as DriveViewProps, r as DRIVE_PENDING_MS, t as CONTENT_VIEW_ID } from "./route-components-1XyfosoL.js";
|
|
4
4
|
import { $ as disposeConnectAppRouter, A as stringifyConnectSearch, B as ConnectCoreApp, C as useSidebarMode, D as connectSearchMiddlewares, E as GLOBAL_SEARCH_PARAMS, F as CoreRouteOptions, G as isCoreView, H as CoreNotFound, I as coreRouteOptions, J as markNavigationClick, K as PERF_STORAGE_KEY, L as ModalDialog, M as validateDriveSearch, N as bindConnectScroll, O as definedSearch, P as connectScrollRestoration, Q as ConnectAppRouterOptions, R as ModalFrameProps, S as useNavRoutes, T as FEATURE_FLAG_PARAM_PREFIX, U as coreModals, V as CoreError, W as coreView, X as routerPerfEnabled, Y as markRouterNavigations, Z as createConnectNavigation, _ as ConnectNavItem, a as SETTINGS_ROUTE_ID, b as navRoutes, c as redirectToSettingsTab, d as settingsTabsOf, et as getConnectAppRouter, f as settingsTitle, g as ConnectChrome, h as useSettingsTabs, i as ConnectSettingsTab, j as validateConnectSearch, k as parseConnectSearch, l as setSettingsRoute, m as useForgetSettingsOpenedFrom, n as driveTitle, nt as CreateDocumentTarget, o as SettingsTabEntry, p as showsSettingsTab, q as ROUTER_MEASURES, r as notFoundTitle, rt as useCreateDocumentTarget, s as keepOpenedFrom, t as appTitle, tt as useIsColdStart, u as settingsTabs, v as NavRouteEntry, w as ConnectSearch, x as useConnectChrome, y as SidebarMode, z as useModalFrame } from "./index-Bfl1VYdj.js";
|
package/dist/index.js
CHANGED
|
@@ -8,6 +8,6 @@ import { getIsEmbedded, useIsEmbedded } from "./embedded.js";
|
|
|
8
8
|
import { getRuntimeConfig, loadRuntimeConfig, primeRuntimeConfig } from "./runtime-config.js";
|
|
9
9
|
import { n as isPluginActive, t as getActivePluginModules } from "./plugins-x1XqLPzp.js";
|
|
10
10
|
import { n as resolveRuntimeFlag, t as isRuntimeFlagEnabled } from "./runtime-flag-DvxW_SD4.js";
|
|
11
|
-
import { a as planReactorClient, c as selectAppReactorClient, d as resolveReactorClientMode, f as REACTOR_WORKER_QUERY_KEY, g as isMultiReactorEnabled, h as resolveReactorWorkerEnabled, i as getAppDrives, l as REACTOR_CLIENT_QUERY_KEY, m as isReactorWorkerEnabled, n as getConnectPHStore, o as refreshAppDrives, p as REACTOR_WORKER_STORAGE_KEY, r as createAppReactorClient, s as relistAppDrives, t as loadLocalPackage, u as REACTOR_CLIENT_STORAGE_KEY } from "./runtime-
|
|
11
|
+
import { a as planReactorClient, c as selectAppReactorClient, d as resolveReactorClientMode, f as REACTOR_WORKER_QUERY_KEY, g as isMultiReactorEnabled, h as resolveReactorWorkerEnabled, i as getAppDrives, l as REACTOR_CLIENT_QUERY_KEY, m as isReactorWorkerEnabled, n as getConnectPHStore, o as refreshAppDrives, p as REACTOR_WORKER_STORAGE_KEY, r as createAppReactorClient, s as relistAppDrives, t as loadLocalPackage, u as REACTOR_CLIENT_STORAGE_KEY } from "./runtime-Cb3HQhKo.js";
|
|
12
12
|
import { t as useBackendAuthGate } from "./backend-auth-gate-DNKg_v4Y.js";
|
|
13
13
|
export { APP_ROUTE_ID, AppearanceTab, BackendAuthGate, CONTENT_VIEW_ID, CORE_MODAL_VIEWS, ConfirmDocumentUpgradeModal, ConnectCoreApp, ContentOutlet, CoreError, CoreHeader, CoreLayout, CoreNotFound, CoreRoot, CoreRouteError, CoreSettingsPage, CreateDocumentModal, DRIVE_PENDING_MS, DRIVE_ROUTE_ID, DeleteItemModal, DirectoryListing, DocumentHistory, DocumentJson, DocumentVersionUnsupportedModal, DocumentView, DownloadDocumentWithErrorsModal, DriveAuthRequiredModal, DriveIndex, DriveLayout, DriveNotFoundPage, DrivePending, EditorHost, FEATURE_FLAG_PARAM_PREFIX, GLOBAL_SEARCH_PARAMS, HISTORY_PAGE_SIZE, HOME_ROUTE_ID, LoginModal, ModalDialog, ModalOutlet, NODE_ROUTE_ID, NodeView, NotFoundPage, PERF_STORAGE_KEY, PackagesTab, REACTOR_CLIENT_QUERY_KEY, REACTOR_CLIENT_STORAGE_KEY, REACTOR_WORKER_QUERY_KEY, REACTOR_WORKER_STORAGE_KEY, ROUTER_MEASURES, SETTINGS_ROUTE_ID, ThemeToggle, addConnectRoutes, appTitle, applyComposition, applyConnectPluginUi, bindConnectRouter, bindConnectScroll, connectRoutes, connectRoutesSettled, connectScrollRestoration, connectSearchMiddlewares, coreModals, coreRouteOptions, coreView, createAppReactorClient, createConnectNavigation, createConnectRouter, definedSearch, disposeConnectAppRouter, driveTitle, formatModified, getActivePluginModules, getAppDrives, getConnectAppRouter, getConnectPHStore, getConnectPluginUi, getIsEmbedded, getRuntimeConfig, holdConnectRoutes, isCoreView, isDriveNotFound, isMultiReactorEnabled, isPluginActive, isReactorWorkerEnabled, isRuntimeFlagEnabled, keepOpenedFrom, knownPlugins, loadConnectPluginUi, loadDrive, loadLocalPackage, loadNode, loadRuntimeConfig, markNavigationClick, markRouterNavigations, mergeConnectPluginUi, navRoutes, notFoundTitle, parseConnectSearch, planReactorClient, primeRuntimeConfig, redirectToSettingsTab, refreshAppDrives, registerConnectPlugins, registerConnectRoutes, registerPackageRoutes, relistAppDrives, removeConnectRoutes, resetConnectPluginUi, resolveReactorClientMode, resolveReactorWorkerEnabled, resolveRuntimeFlag, routerPerfEnabled, selectAppReactorClient, setSettingsRoute, settingsTabs, settingsTabsOf, settingsTitle, showsSettingsTab, stringifyConnectSearch, useBackendAuthGate, useConnectChrome, useCreateDocumentTarget, useDriveRouteData, useDriveRouteIds, useForgetSettingsOpenedFrom, useIsColdStart, useIsEmbedded, useModalFrame, useNavRoutes, useSettingsTabs, useSidebarMode, validateConnectSearch, validateDriveSearch };
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { ambientRenownSigner, ambientRenownTokenProvider, createSwitchboardBackend } from "@powerhousedao/reactor-browser";
|
|
2
|
+
import { logger } from "document-model";
|
|
3
|
+
import { createReactorInspector } from "@powerhousedao/reactor";
|
|
4
|
+
import { FanInPartialFailureError, RoutingReactorClient, fromReactorClient } from "@powerhousedao/reactor-router";
|
|
5
|
+
//#region src/runtime/multi-reactor.ts
|
|
6
|
+
const LOCAL_BACKEND_NAME = "connect-local";
|
|
7
|
+
const REMOTE_BACKEND_NAME = "switchboard-remote";
|
|
8
|
+
/** Only the tab's reactor is inspectable here, so new collections land on it. */
|
|
9
|
+
const PLACE_ON_LOCAL = Object.freeze({ inspectable: true });
|
|
10
|
+
function localReach(kind) {
|
|
11
|
+
return kind === "worker" ? {
|
|
12
|
+
hosting: "worker",
|
|
13
|
+
inspection: "rpc"
|
|
14
|
+
} : {
|
|
15
|
+
hosting: "in-process",
|
|
16
|
+
inspection: "direct"
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
/** Read at every refresh, never kept: a rebuilt reactor reports its own. */
|
|
20
|
+
function localFacts(module) {
|
|
21
|
+
if (module.kind === "worker") return () => module.inspector.info();
|
|
22
|
+
return async () => {
|
|
23
|
+
const reactorModule = module.reactorModule;
|
|
24
|
+
if (!reactorModule) throw new Error("The in-tab reactor exposes no module to inspect");
|
|
25
|
+
return createReactorInspector(reactorModule).info();
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
/** `<origin>[/<prefix>]/d/<slug>` -> `<origin>[/<prefix>]/graphql`. */
|
|
29
|
+
function deriveSwitchboardGraphqlUrl(remoteDriveUrl) {
|
|
30
|
+
let parsed;
|
|
31
|
+
try {
|
|
32
|
+
parsed = new URL(remoteDriveUrl);
|
|
33
|
+
} catch {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
const prefix = /^(.*)\/d\/[^/]+\/?$/.exec(parsed.pathname)?.[1];
|
|
37
|
+
return prefix === void 0 ? void 0 : `${parsed.origin}${prefix}/graphql`;
|
|
38
|
+
}
|
|
39
|
+
/** Remote-only placement: the Switchboard serves every collection. (It offers
|
|
40
|
+
* no inspection surface over GraphQL, so PLACE_ON_LOCAL's `inspectable`
|
|
41
|
+
* requirement must NOT apply, or no backend would be eligible.) */
|
|
42
|
+
const PLACE_ON_REMOTE = Object.freeze({});
|
|
43
|
+
/**
|
|
44
|
+
* The local answer stands when only the Switchboard could not answer -- but
|
|
45
|
+
* only when there IS a local backend. Remote-only has nothing to fall back to,
|
|
46
|
+
* so its errors surface. Installed as the router's `answerFailedIdCheck`, so
|
|
47
|
+
* the facade and `write.isDocumentIdTaken` both apply it.
|
|
48
|
+
*/
|
|
49
|
+
function localIdCheckAnswer(documentId, error) {
|
|
50
|
+
if (!failedOnlyOnRemote(error)) return;
|
|
51
|
+
logger.warn("The Switchboard could not say whether @id is taken; using the local reactor's answer: @error", documentId, error);
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
/** The router Connect installs, with Connect's handling of credentials and id checks. */
|
|
55
|
+
var ConnectRoutingClient = class extends RoutingReactorClient {
|
|
56
|
+
remote;
|
|
57
|
+
constructor(backends, options, remote, hasLocal) {
|
|
58
|
+
super(backends, {
|
|
59
|
+
...options,
|
|
60
|
+
answerFailedIdCheck: hasLocal ? localIdCheckAnswer : options.answerFailedIdCheck
|
|
61
|
+
});
|
|
62
|
+
this.remote = remote;
|
|
63
|
+
}
|
|
64
|
+
/** Renown's sign-in and sign-out call this on whatever client is installed. */
|
|
65
|
+
notifyCredentialsChanged() {
|
|
66
|
+
this.remote.notifyCredentialsChanged();
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
function failedOnlyOnRemote(error) {
|
|
70
|
+
return error instanceof FanInPartialFailureError && error.failures.every((failure) => failure.backend === "switchboard-remote");
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Build the Connect routing client. With a local `module` it is the router
|
|
74
|
+
* over the tab's reactor (primary) and the Switchboard; WITHOUT one it is the
|
|
75
|
+
* `remote` client — a remote-only router whose single backend is the
|
|
76
|
+
* Switchboard, so no local reactor (and no PGlite) is built. Either way the
|
|
77
|
+
* result is a full IReactorClient the app graph consumes unchanged.
|
|
78
|
+
*/
|
|
79
|
+
async function buildMultiReactorClient(params) {
|
|
80
|
+
const module = params.module;
|
|
81
|
+
const registry = module?.reactorModule?.documentModelRegistry;
|
|
82
|
+
const loaded = params.documentModelModules;
|
|
83
|
+
const loadedModules = typeof loaded === "function" ? loaded : () => loaded;
|
|
84
|
+
const remote = createSwitchboardBackend({
|
|
85
|
+
name: REMOTE_BACKEND_NAME,
|
|
86
|
+
url: params.remoteGraphqlUrl,
|
|
87
|
+
tokenProvider: ambientRenownTokenProvider,
|
|
88
|
+
signer: ambientRenownSigner,
|
|
89
|
+
documentModels: () => registry?.getAllModules() ?? loadedModules(),
|
|
90
|
+
inspection: "none"
|
|
91
|
+
});
|
|
92
|
+
const remoteBackend = remote.config;
|
|
93
|
+
const router = new ConnectRoutingClient(module ? [{
|
|
94
|
+
name: LOCAL_BACKEND_NAME,
|
|
95
|
+
backend: fromReactorClient(module.client),
|
|
96
|
+
facts: localFacts(module),
|
|
97
|
+
reach: localReach(module.kind),
|
|
98
|
+
refusesMisroutes: false
|
|
99
|
+
}, remoteBackend] : [remoteBackend], {
|
|
100
|
+
primaryBackend: module ? LOCAL_BACKEND_NAME : REMOTE_BACKEND_NAME,
|
|
101
|
+
defaultRequirements: module ? PLACE_ON_LOCAL : PLACE_ON_REMOTE,
|
|
102
|
+
signer: params.signer,
|
|
103
|
+
onDiagnostic: params.onDiagnostic,
|
|
104
|
+
documentModelModules: module ? void 0 : loadedModules
|
|
105
|
+
}, remote, Boolean(module));
|
|
106
|
+
await router.refreshFacts();
|
|
107
|
+
return router;
|
|
108
|
+
}
|
|
109
|
+
//#endregion
|
|
110
|
+
export { ConnectRoutingClient, LOCAL_BACKEND_NAME, PLACE_ON_LOCAL, PLACE_ON_REMOTE, REMOTE_BACKEND_NAME, buildMultiReactorClient, deriveSwitchboardGraphqlUrl, localFacts, localReach };
|
|
111
|
+
|
|
112
|
+
//# sourceMappingURL=multi-reactor-CVwr_LdS.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"multi-reactor-CVwr_LdS.js","names":[],"sources":["../src/runtime/multi-reactor.ts"],"sourcesContent":["import {\n createReactorInspector,\n type ReactorInfo,\n} from \"@powerhousedao/reactor\";\nimport {\n ambientRenownSigner,\n ambientRenownTokenProvider,\n createSwitchboardBackend,\n type BrowserReactorClientModule,\n type SwitchboardBackend,\n type WorkerReactorClientModule,\n} from \"@powerhousedao/reactor-browser\";\nimport {\n FanInPartialFailureError,\n fromReactorClient,\n RoutingReactorClient,\n type CollectionRequirementsInput,\n type ReactorReach,\n type RoutableBackendConfig,\n type RouterDiagnostic,\n type RoutingClientOptions,\n} from \"@powerhousedao/reactor-router\";\nimport type {\n DocumentModelModule,\n ISigner,\n} from \"@powerhousedao/shared/document-model\";\nimport { logger } from \"document-model\";\n\nexport const LOCAL_BACKEND_NAME = \"connect-local\";\nexport const REMOTE_BACKEND_NAME = \"switchboard-remote\";\n\nexport type LocalReactorModule =\n | BrowserReactorClientModule\n | WorkerReactorClientModule;\n\n/** Only the tab's reactor is inspectable here, so new collections land on it. */\nexport const PLACE_ON_LOCAL: CollectionRequirementsInput = Object.freeze({\n inspectable: true,\n});\n\nexport function localReach(kind: LocalReactorModule[\"kind\"]): ReactorReach {\n return kind === \"worker\"\n ? { hosting: \"worker\", inspection: \"rpc\" }\n : { hosting: \"in-process\", inspection: \"direct\" };\n}\n\n/** Read at every refresh, never kept: a rebuilt reactor reports its own. */\nexport function localFacts(\n module: LocalReactorModule,\n): () => Promise<ReactorInfo> {\n if (module.kind === \"worker\") {\n return () => module.inspector.info();\n }\n return async () => {\n const reactorModule = module.reactorModule;\n if (!reactorModule) {\n throw new Error(\"The in-tab reactor exposes no module to inspect\");\n }\n return createReactorInspector(reactorModule).info();\n };\n}\n\n/** `<origin>[/<prefix>]/d/<slug>` -> `<origin>[/<prefix>]/graphql`. */\nexport function deriveSwitchboardGraphqlUrl(\n remoteDriveUrl: string,\n): string | undefined {\n let parsed: URL;\n try {\n parsed = new URL(remoteDriveUrl);\n } catch {\n return undefined;\n }\n const prefix = /^(.*)\\/d\\/[^/]+\\/?$/.exec(parsed.pathname)?.[1];\n return prefix === undefined ? undefined : `${parsed.origin}${prefix}/graphql`;\n}\n\n/** The loaded document models, or a getter that reads the current ones. */\nexport type LoadedDocumentModels =\n | readonly DocumentModelModule[]\n | (() => readonly DocumentModelModule[]);\n\nexport type MultiReactorParams = {\n /** The local module, built and ready. Undefined builds a REMOTE-ONLY router\n * (no local backend → no local reactor, no PGlite): the `remote` client. */\n module: LocalReactorModule | undefined;\n remoteGraphqlUrl: string;\n /** Signs routed writes; unsigned (anonymous) without one. */\n signer?: ISigner;\n /** Signing models when the local module exposes no registry; the router asks the local reactor (or, remote-only, the loaded set). */\n documentModelModules: LoadedDocumentModels;\n onDiagnostic?: RouterDiagnostic;\n};\n\n/** Remote-only placement: the Switchboard serves every collection. (It offers\n * no inspection surface over GraphQL, so PLACE_ON_LOCAL's `inspectable`\n * requirement must NOT apply, or no backend would be eligible.) */\nexport const PLACE_ON_REMOTE: CollectionRequirementsInput = Object.freeze({});\n\n/**\n * The local answer stands when only the Switchboard could not answer -- but\n * only when there IS a local backend. Remote-only has nothing to fall back to,\n * so its errors surface. Installed as the router's `answerFailedIdCheck`, so\n * the facade and `write.isDocumentIdTaken` both apply it.\n */\nfunction localIdCheckAnswer(\n documentId: string,\n error: unknown,\n): boolean | undefined {\n if (!failedOnlyOnRemote(error)) {\n return undefined;\n }\n logger.warn(\n \"The Switchboard could not say whether @id is taken; using the local reactor's answer: @error\",\n documentId,\n error,\n );\n return false;\n}\n\n/** The router Connect installs, with Connect's handling of credentials and id checks. */\nexport class ConnectRoutingClient extends RoutingReactorClient {\n private readonly remote: SwitchboardBackend;\n\n constructor(\n backends: readonly RoutableBackendConfig[],\n options: RoutingClientOptions,\n remote: SwitchboardBackend,\n hasLocal: boolean,\n ) {\n super(backends, {\n ...options,\n answerFailedIdCheck: hasLocal\n ? localIdCheckAnswer\n : options.answerFailedIdCheck,\n });\n this.remote = remote;\n }\n\n /** Renown's sign-in and sign-out call this on whatever client is installed. */\n notifyCredentialsChanged(): void {\n this.remote.notifyCredentialsChanged();\n }\n}\n\nfunction failedOnlyOnRemote(error: unknown): boolean {\n return (\n error instanceof FanInPartialFailureError &&\n error.failures.every((failure) => failure.backend === REMOTE_BACKEND_NAME)\n );\n}\n\n/**\n * Build the Connect routing client. With a local `module` it is the router\n * over the tab's reactor (primary) and the Switchboard; WITHOUT one it is the\n * `remote` client — a remote-only router whose single backend is the\n * Switchboard, so no local reactor (and no PGlite) is built. Either way the\n * result is a full IReactorClient the app graph consumes unchanged.\n */\nexport async function buildMultiReactorClient(\n params: MultiReactorParams,\n): Promise<ConnectRoutingClient> {\n const module = params.module;\n const registry = module?.reactorModule?.documentModelRegistry;\n const loaded = params.documentModelModules;\n const loadedModules = typeof loaded === \"function\" ? loaded : () => loaded;\n // The logged-in Renown user's token and signer, read per request as before.\n const remote = createSwitchboardBackend({\n name: REMOTE_BACKEND_NAME,\n url: params.remoteGraphqlUrl,\n tokenProvider: ambientRenownTokenProvider,\n signer: ambientRenownSigner,\n documentModels: () => registry?.getAllModules() ?? loadedModules(),\n inspection: \"none\",\n });\n const remoteBackend = remote.config;\n const backends: RoutableBackendConfig[] = module\n ? [\n {\n name: LOCAL_BACKEND_NAME,\n backend: fromReactorClient(module.client),\n facts: localFacts(module),\n reach: localReach(module.kind),\n refusesMisroutes: false,\n },\n remoteBackend,\n ]\n : [remoteBackend];\n const router = new ConnectRoutingClient(\n backends,\n {\n // Remote-only: the Switchboard is primary and serves every collection;\n // with a local reactor, new collections land on it (inspectable).\n primaryBackend: module ? LOCAL_BACKEND_NAME : REMOTE_BACKEND_NAME,\n defaultRequirements: module ? PLACE_ON_LOCAL : PLACE_ON_REMOTE,\n signer: params.signer,\n onDiagnostic: params.onDiagnostic,\n // The Switchboard serves no models over GraphQL; remote-only uses the loaded set.\n documentModelModules: module ? undefined : loadedModules,\n },\n remote,\n Boolean(module),\n );\n await router.refreshFacts();\n return router;\n}\n"],"mappings":";;;;;AA4BA,MAAa,qBAAqB;AAClC,MAAa,sBAAsB;;AAOnC,MAAa,iBAA8C,OAAO,OAAO,EACvE,aAAa,KACf,CAAC;AAED,SAAgB,WAAW,MAAgD;CACzE,OAAO,SAAS,WACZ;EAAE,SAAS;EAAU,YAAY;CAAM,IACvC;EAAE,SAAS;EAAc,YAAY;CAAS;AACpD;;AAGA,SAAgB,WACd,QAC4B;CAC5B,IAAI,OAAO,SAAS,UAClB,aAAa,OAAO,UAAU,KAAK;CAErC,OAAO,YAAY;EACjB,MAAM,gBAAgB,OAAO;EAC7B,IAAI,CAAC,eACH,MAAM,IAAI,MAAM,iDAAiD;EAEnE,OAAO,uBAAuB,aAAa,CAAC,CAAC,KAAK;CACpD;AACF;;AAGA,SAAgB,4BACd,gBACoB;CACpB,IAAI;CACJ,IAAI;EACF,SAAS,IAAI,IAAI,cAAc;CACjC,QAAQ;EACN;CACF;CACA,MAAM,SAAS,sBAAsB,KAAK,OAAO,QAAQ,CAAC,GAAG;CAC7D,OAAO,WAAW,KAAA,IAAY,KAAA,IAAY,GAAG,OAAO,SAAS,OAAO;AACtE;;;;AAsBA,MAAa,kBAA+C,OAAO,OAAO,CAAC,CAAC;;;;;;;AAQ5E,SAAS,mBACP,YACA,OACqB;CACrB,IAAI,CAAC,mBAAmB,KAAK,GAC3B;CAEF,OAAO,KACL,gGACA,YACA,KACF;CACA,OAAO;AACT;;AAGA,IAAa,uBAAb,cAA0C,qBAAqB;CAC7D;CAEA,YACE,UACA,SACA,QACA,UACA;EACA,MAAM,UAAU;GACd,GAAG;GACH,qBAAqB,WACjB,qBACA,QAAQ;EACd,CAAC;EACD,KAAK,SAAS;CAChB;;CAGA,2BAAiC;EAC/B,KAAK,OAAO,yBAAyB;CACvC;AACF;AAEA,SAAS,mBAAmB,OAAyB;CACnD,OACE,iBAAiB,4BACjB,MAAM,SAAS,OAAO,YAAY,QAAQ,YAAA,oBAA+B;AAE7E;;;;;;;;AASA,eAAsB,wBACpB,QAC+B;CAC/B,MAAM,SAAS,OAAO;CACtB,MAAM,WAAW,QAAQ,eAAe;CACxC,MAAM,SAAS,OAAO;CACtB,MAAM,gBAAgB,OAAO,WAAW,aAAa,eAAe;CAEpE,MAAM,SAAS,yBAAyB;EACtC,MAAM;EACN,KAAK,OAAO;EACZ,eAAe;EACf,QAAQ;EACR,sBAAsB,UAAU,cAAc,KAAK,cAAc;EACjE,YAAY;CACd,CAAC;CACD,MAAM,gBAAgB,OAAO;CAa7B,MAAM,SAAS,IAAI,qBAZuB,SACtC,CACE;EACE,MAAM;EACN,SAAS,kBAAkB,OAAO,MAAM;EACxC,OAAO,WAAW,MAAM;EACxB,OAAO,WAAW,OAAO,IAAI;EAC7B,kBAAkB;CACpB,GACA,aACF,IACA,CAAC,aAAa,GAGhB;EAGE,gBAAgB,SAAS,qBAAqB;EAC9C,qBAAqB,SAAS,iBAAiB;EAC/C,QAAQ,OAAO;EACf,cAAc,OAAO;EAErB,sBAAsB,SAAS,KAAA,IAAY;CAC7C,GACA,QACA,QAAQ,MAAM,CAChB;CACA,MAAM,OAAO,aAAa;CAC1B,OAAO;AACT"}
|
|
@@ -61,7 +61,7 @@ function resolveReactorClientMode() {
|
|
|
61
61
|
}
|
|
62
62
|
//#endregion
|
|
63
63
|
//#region src/runtime/app-reactor-client.ts
|
|
64
|
-
const loadMultiReactor = () => import("./multi-reactor-
|
|
64
|
+
const loadMultiReactor = () => import("./multi-reactor-CVwr_LdS.js");
|
|
65
65
|
function planReactorClient(mode = resolveReactorClientMode()) {
|
|
66
66
|
const needsLocalReactor = mode !== "remote";
|
|
67
67
|
return {
|
|
@@ -236,4 +236,4 @@ function loadLocalPackage(source) {
|
|
|
236
236
|
//#endregion
|
|
237
237
|
export { planReactorClient as a, selectAppReactorClient as c, resolveReactorClientMode as d, REACTOR_WORKER_QUERY_KEY as f, isMultiReactorEnabled as g, resolveReactorWorkerEnabled as h, getAppDrives as i, REACTOR_CLIENT_QUERY_KEY as l, isReactorWorkerEnabled as m, getConnectPHStore as n, refreshAppDrives as o, REACTOR_WORKER_STORAGE_KEY as p, createAppReactorClient as r, relistAppDrives as s, loadLocalPackage as t, REACTOR_CLIENT_STORAGE_KEY as u };
|
|
238
238
|
|
|
239
|
-
//# sourceMappingURL=runtime-
|
|
239
|
+
//# sourceMappingURL=runtime-Cb3HQhKo.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime-D20_LlB_.js","names":[],"sources":["../src/runtime/multi-reactor-flag.ts","../src/runtime/reactor-worker-flag.ts","../src/runtime/reactor-client-mode.ts","../src/runtime/app-reactor-client.ts","../src/runtime/ph-store.ts","../src/runtime/local-package.ts"],"sourcesContent":["import { getRuntimeConfig } from \"./runtime-config.js\";\n\n// Config only: the flag is in the worker fingerprint, so a per-tab value would split tabs.\nexport function isMultiReactorEnabled(): boolean {\n return getRuntimeConfig().connect.instance?.multiReactor ?? false;\n}\n","import { getRuntimeConfig } from \"./runtime-config.js\";\nimport {\n isRuntimeFlagEnabled,\n resolveRuntimeFlag,\n type RuntimeFlagInput,\n} from \"./runtime-flag.js\";\n\nexport const REACTOR_WORKER_QUERY_KEY = \"reactorWorker\";\nexport const REACTOR_WORKER_STORAGE_KEY = \"ph:reactorWorker\";\n\nexport type ReactorWorkerFlagInput = RuntimeFlagInput;\n\nexport function resolveReactorWorkerEnabled(\n input: ReactorWorkerFlagInput,\n): boolean {\n return resolveRuntimeFlag(input);\n}\n\nexport function isReactorWorkerEnabled(): boolean {\n return isRuntimeFlagEnabled({\n queryKey: REACTOR_WORKER_QUERY_KEY,\n storageKey: REACTOR_WORKER_STORAGE_KEY,\n readConfigFlag: () =>\n getRuntimeConfig().connect.instance?.reactorWorker ?? false,\n });\n}\n","import type { PHReactorClientMode } from \"@powerhousedao/shared/clis\";\nimport { getRuntimeConfig } from \"./runtime-config.js\";\nimport { isMultiReactorEnabled } from \"./multi-reactor-flag.js\";\nimport { isReactorWorkerEnabled } from \"./reactor-worker-flag.js\";\n\n/**\n * Which of the four reactor clients Connect boots. Standardized by the\n * multi-reactor work; this resolves the single selector Connect acts on:\n *\n * in-process | worker | remote | router\n *\n * Precedence: an explicit `?reactorClient=` query override (kept in\n * localStorage so it survives a reload), then a stored override, then the\n * served `connect.instance.reactorClient` (projected from the host's reactor\n * backends), then the LEGACY booleans — so a config that only sets\n * reactorWorker/multiReactor behaves exactly as before.\n *\n * `remote` is the only mode that builds NO local reactor (no PGlite): it is a\n * pure client to a remote Switchboard. `router` keeps the local reactor and\n * adds remote backends; `worker`/`in-process` are the local reactor alone.\n */\nexport type ReactorClientMode = PHReactorClientMode;\n\nconst MODES: ReadonlySet<string> = new Set([\n \"in-process\",\n \"worker\",\n \"remote\",\n \"router\",\n]);\n\nexport const REACTOR_CLIENT_QUERY_KEY = \"reactorClient\";\nexport const REACTOR_CLIENT_STORAGE_KEY = \"ph:reactorClient\";\n\nconst asMode = (value: string | null | undefined) =>\n value && MODES.has(value) ? (value as ReactorClientMode) : undefined;\n\nfunction fromTab(): ReactorClientMode | undefined {\n if (typeof window === \"undefined\") return undefined;\n let query: ReactorClientMode | undefined;\n try {\n query = asMode(\n new URLSearchParams(window.location.search).get(REACTOR_CLIENT_QUERY_KEY),\n );\n } catch {\n return undefined;\n }\n try {\n if (query) {\n window.localStorage.setItem(REACTOR_CLIENT_STORAGE_KEY, query);\n return query;\n }\n return asMode(window.localStorage.getItem(REACTOR_CLIENT_STORAGE_KEY));\n } catch {\n // Blocked storage: the query still applies for this page load.\n return query;\n }\n}\n\nexport function resolveReactorClientMode(): ReactorClientMode {\n const override = fromTab();\n if (override) return override;\n const configured = getRuntimeConfig().connect.instance?.reactorClient;\n if (configured && MODES.has(configured)) return configured;\n // Legacy fallback — unchanged behaviour for configs without reactorClient.\n if (isMultiReactorEnabled()) return \"router\";\n if (isReactorWorkerEnabled()) return \"worker\";\n return \"in-process\";\n}\n","import type { IReactorClient } from \"@powerhousedao/reactor\";\nimport {\n getDrives,\n getFullReactorClient,\n getPHStore,\n recordBackendAuthError,\n setBackendAuth,\n setDrives,\n setFullReactorClient,\n} from \"@powerhousedao/reactor-browser\";\nimport type { DocumentDriveDocument } from \"@powerhousedao/shared/document-drive\";\nimport type { ISigner } from \"@powerhousedao/shared/document-model\";\nimport { logger } from \"document-model\";\nimport type * as MultiReactor from \"./multi-reactor.js\";\nimport type {\n LoadedDocumentModels,\n LocalReactorModule,\n} from \"./multi-reactor.js\";\nimport type { ReactorClientMode } from \"./reactor-client-mode.js\";\nimport { resolveReactorClientMode } from \"./reactor-client-mode.js\";\nimport { isReactorWorkerEnabled } from \"./reactor-worker-flag.js\";\nimport { setDriveRelister } from \"./drive-relist.js\";\n\ntype MultiReactorModule = typeof MultiReactor;\n\nexport type AppReactorClientParams = {\n mode: ReactorClientMode;\n /** Built, and ready (the worker has started up). Undefined in `remote`\n * mode, where no local reactor is built. */\n module: LocalReactorModule | undefined;\n remoteDriveUrl: string | undefined;\n /** Signs routed writes; unsigned (anonymous) without one. */\n signer?: ISigner;\n documentModelModules: LoadedDocumentModels;\n loadRouter?: () => Promise<MultiReactorModule>;\n};\n\nconst loadMultiReactor = (): Promise<MultiReactorModule> =>\n import(\"./multi-reactor.js\");\n\n/** What a mode builds in the tab; `remote` builds no local reactor (no PGlite). */\nexport type ReactorClientPlan = {\n mode: ReactorClientMode;\n /** `router`: the local reactor plus remote backends. */\n multiReactor: boolean;\n needsLocalReactor: boolean;\n /** The local reactor runs in the shared worker. */\n localAsWorker: boolean;\n};\n\nexport function planReactorClient(\n mode: ReactorClientMode = resolveReactorClientMode(),\n): ReactorClientPlan {\n const needsLocalReactor = mode !== \"remote\";\n return {\n mode,\n multiReactor: mode === \"router\",\n needsLocalReactor,\n localAsWorker:\n needsLocalReactor &&\n (mode === \"worker\" || (mode === \"router\" && isReactorWorkerEnabled())),\n };\n}\n\n/** Builds the tab's reactor, e.g. Connect's PGlite or worker reactor. */\nexport type LocalReactorFactory = (\n plan: ReactorClientPlan,\n) => Promise<LocalReactorModule>;\n\nexport type CreateAppReactorClientOptions = Omit<\n AppReactorClientParams,\n \"mode\" | \"module\"\n> & {\n plan?: ReactorClientPlan;\n /** Called only when the plan needs a local reactor. */\n localReactor?: LocalReactorFactory;\n};\n\n/** Builds the local reactor the plan needs, then selects the app's client. */\nexport async function createAppReactorClient(\n options: CreateAppReactorClientOptions,\n) {\n const { localReactor, ...params } = options;\n const plan = options.plan ?? planReactorClient();\n let module: LocalReactorModule | undefined;\n if (plan.needsLocalReactor) {\n if (!localReactor) {\n throw new Error(\n `reactorClient mode \"${plan.mode}\" needs a local reactor; pass localReactor`,\n );\n }\n module = await localReactor(plan);\n }\n const client = await selectAppReactorClient({\n ...params,\n mode: plan.mode,\n module,\n });\n return { plan, module, client };\n}\n\n/**\n * Pick the client for the resolved mode:\n * - `in-process` / `worker`: the local client, router module never loaded.\n * - `router`: the local reactor plus remote backends.\n * - `remote`: a remote-only router — a full IReactorClient that proxies to\n * the Switchboard over GraphQL with NO local reactor (no PGlite).\n */\nexport async function selectAppReactorClient(\n params: AppReactorClientParams,\n): Promise<IReactorClient> {\n if (params.mode === \"remote\") {\n setFullReactorClient(undefined);\n const remote = await buildRemoteOnly(params);\n setFullReactorClient(remote);\n return remote;\n }\n if (params.mode !== \"router\") {\n if (getPHStore()?.fullReactorClient) {\n setFullReactorClient(undefined);\n }\n return requireModule(params).client;\n }\n setFullReactorClient(undefined);\n const routed = await buildRouter(params);\n setFullReactorClient(routed);\n return routed ?? requireModule(params).client;\n}\n\nfunction requireModule(params: AppReactorClientParams): LocalReactorModule {\n if (!params.module) {\n throw new Error(\n `reactorClient mode \"${params.mode}\" needs a local reactor, but none was built`,\n );\n }\n return params.module;\n}\n\n/**\n * A Switchboard that cannot answer must not fail boot: list the tab's drives.\n *\n * A Switchboard that REFUSES the caller (401/403) must not fail boot either:\n * the refusal is recorded (`backendAuth`) so the root view shows the sign-in\n * gate, and the drive list is empty until the user is someone the backend\n * accepts. A remote-only client has no local drives to fall back on.\n */\nexport async function getAppDrives(\n client: IReactorClient,\n local: IReactorClient,\n): Promise<DocumentDriveDocument[]> {\n if (client === local) {\n try {\n const drives = await getDrives(local);\n setBackendAuth(undefined);\n return drives;\n } catch (error) {\n if (recordBackendAuthError(error, \"switchboard\")) {\n logger.warn(\n \"The Switchboard refused this caller; showing the sign-in gate: @error\",\n error,\n );\n return [];\n }\n throw error;\n }\n }\n try {\n const drives = await getDrives(client);\n setBackendAuth(undefined);\n return drives;\n } catch (error) {\n if (recordBackendAuthError(error, \"switchboard\")) {\n logger.warn(\n \"A remote backend refused this caller; listing the local reactor's drives: @error\",\n error,\n );\n } else {\n logger.warn(\n \"Could not list drives through the router; listing the local reactor's: @error\",\n error,\n );\n }\n return getDrives(local);\n }\n}\n\n/**\n * The boot refresh of the drives store. It lists through `getAppDrives`\n * whichever client is in use, so a Switchboard that refuses the caller is\n * recorded for the sign-in gate here too: the remote-only client is its own\n * `local`, and a bare `refreshReactorDataClient` would let the 401 escape\n * and fail the boot before the gate can render.\n */\nexport async function refreshAppDrives(\n client: IReactorClient,\n local: IReactorClient,\n): Promise<void> {\n setDrives(await getAppDrives(client, local));\n}\n\n/**\n * Lists the drives again as the caller the tab now is, through the clients\n * boot left in the store: after a sign-in landing or a sign-out that followed\n * a backend's refusal. Nothing to do before boot has set a client.\n */\nexport async function relistAppDrives(): Promise<void> {\n const client = getFullReactorClient();\n if (!client) return;\n const local = getPHStore()?.reactorClientModule?.client ?? client;\n await refreshAppDrives(client, local);\n}\n\n// The backend auth gate relists through drive-relist (see there)\nsetDriveRelister(relistAppDrives);\n\nasync function buildRouter(\n params: AppReactorClientParams,\n): Promise<IReactorClient | undefined> {\n if (!params.remoteDriveUrl) {\n logger.warn(\n \"multiReactor is on but no remote drive URL is configured; using the local reactor only\",\n );\n return undefined;\n }\n let multiReactor: MultiReactorModule;\n try {\n multiReactor = await (params.loadRouter ?? loadMultiReactor)();\n } catch (error) {\n logger.error(\"Could not load the multi-reactor router: @error\", error);\n return undefined;\n }\n const remoteGraphqlUrl = multiReactor.deriveSwitchboardGraphqlUrl(\n params.remoteDriveUrl,\n );\n if (!remoteGraphqlUrl) {\n logger.warn(\n \"multiReactor is on but the remote drive URL @url does not parse; using the local reactor only\",\n params.remoteDriveUrl,\n );\n return undefined;\n }\n logger.info(\"Multi-reactor routing to @url\", remoteGraphqlUrl);\n return multiReactor.buildMultiReactorClient({\n module: requireModule(params),\n remoteGraphqlUrl,\n signer: params.signer,\n documentModelModules: params.documentModelModules,\n });\n}\n\n/**\n * The `remote` mode: a remote-only router — a full IReactorClient that proxies\n * to the Switchboard over GraphQL with NO local backend, so no local reactor\n * and no PGlite are ever built. A missing/unparseable remote URL is a hard\n * config error here (unlike `router`, there is no local reactor to fall back\n * to).\n */\nasync function buildRemoteOnly(\n params: AppReactorClientParams,\n): Promise<IReactorClient> {\n if (!params.remoteDriveUrl) {\n throw new Error(\n 'reactorClient \"remote\" needs a remote drive URL — declare a remote backend / default drive the client can proxy to',\n );\n }\n const multiReactor = await (params.loadRouter ?? loadMultiReactor)();\n const remoteGraphqlUrl = multiReactor.deriveSwitchboardGraphqlUrl(\n params.remoteDriveUrl,\n );\n if (!remoteGraphqlUrl) {\n throw new Error(\n `reactorClient \"remote\": the remote drive URL \"${params.remoteDriveUrl}\" does not resolve to a Switchboard GraphQL endpoint`,\n );\n }\n logger.info(\"Remote reactor client → @url\", remoteGraphqlUrl);\n return multiReactor.buildMultiReactorClient({\n module: undefined,\n remoteGraphqlUrl,\n signer: params.signer,\n documentModelModules: params.documentModelModules,\n });\n}\n","import type { PHStore } from \"@powerhousedao/reactor-browser\";\nimport {\n bindPHStoreToWindow,\n createPHStore,\n getActivePHStore,\n} from \"@powerhousedao/reactor-browser\";\n\n/** The app's PH store: the active one, else a new one bound to `window.ph`.\n * Values set on `window.ph` before carry over. */\nexport function getConnectPHStore(): PHStore {\n const active = getActivePHStore();\n if (active) return active;\n const store = createPHStore();\n bindPHStoreToWindow(store);\n return store;\n}\n","import type { DocumentModelLib } from \"document-model\";\n\n/** A module namespace, as `import * as pkg` or Vite HMR hands it over. */\nexport type ModuleNamespace = Record<string, any> & {\n [Symbol.toStringTag]: \"Module\";\n};\n\nexport type LocalPackage = DocumentModelLib<any> | ModuleNamespace;\n\n/** The package itself, or a loader (`() => import(\"./index.js\")`) that keeps it off the boot path. */\nexport type LocalPackageSource = LocalPackage | (() => Promise<LocalPackage>);\n\n/** Starts loading the project's package; a loader runs once, here. */\nexport function loadLocalPackage(\n source: LocalPackageSource | undefined,\n): DocumentModelLib | Promise<DocumentModelLib> | undefined {\n const pkg = (typeof source === \"function\" ? source() : source) as\n | DocumentModelLib\n | Promise<DocumentModelLib>\n | undefined;\n // Consumers await it; this only stops an early rejection being reported as unhandled.\n if (pkg instanceof Promise) pkg.catch(() => undefined);\n return pkg;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"runtime-Cb3HQhKo.js","names":[],"sources":["../src/runtime/multi-reactor-flag.ts","../src/runtime/reactor-worker-flag.ts","../src/runtime/reactor-client-mode.ts","../src/runtime/app-reactor-client.ts","../src/runtime/ph-store.ts","../src/runtime/local-package.ts"],"sourcesContent":["import { getRuntimeConfig } from \"./runtime-config.js\";\n\n// Config only: the flag is in the worker fingerprint, so a per-tab value would split tabs.\nexport function isMultiReactorEnabled(): boolean {\n return getRuntimeConfig().connect.instance?.multiReactor ?? false;\n}\n","import { getRuntimeConfig } from \"./runtime-config.js\";\nimport {\n isRuntimeFlagEnabled,\n resolveRuntimeFlag,\n type RuntimeFlagInput,\n} from \"./runtime-flag.js\";\n\nexport const REACTOR_WORKER_QUERY_KEY = \"reactorWorker\";\nexport const REACTOR_WORKER_STORAGE_KEY = \"ph:reactorWorker\";\n\nexport type ReactorWorkerFlagInput = RuntimeFlagInput;\n\nexport function resolveReactorWorkerEnabled(\n input: ReactorWorkerFlagInput,\n): boolean {\n return resolveRuntimeFlag(input);\n}\n\nexport function isReactorWorkerEnabled(): boolean {\n return isRuntimeFlagEnabled({\n queryKey: REACTOR_WORKER_QUERY_KEY,\n storageKey: REACTOR_WORKER_STORAGE_KEY,\n readConfigFlag: () =>\n getRuntimeConfig().connect.instance?.reactorWorker ?? false,\n });\n}\n","import type { PHReactorClientMode } from \"@powerhousedao/shared/clis\";\nimport { getRuntimeConfig } from \"./runtime-config.js\";\nimport { isMultiReactorEnabled } from \"./multi-reactor-flag.js\";\nimport { isReactorWorkerEnabled } from \"./reactor-worker-flag.js\";\n\n/**\n * Which of the four reactor clients Connect boots. Standardized by the\n * multi-reactor work; this resolves the single selector Connect acts on:\n *\n * in-process | worker | remote | router\n *\n * Precedence: an explicit `?reactorClient=` query override (kept in\n * localStorage so it survives a reload), then a stored override, then the\n * served `connect.instance.reactorClient` (projected from the host's reactor\n * backends), then the LEGACY booleans — so a config that only sets\n * reactorWorker/multiReactor behaves exactly as before.\n *\n * `remote` is the only mode that builds NO local reactor (no PGlite): it is a\n * pure client to a remote Switchboard. `router` keeps the local reactor and\n * adds remote backends; `worker`/`in-process` are the local reactor alone.\n */\nexport type ReactorClientMode = PHReactorClientMode;\n\nconst MODES: ReadonlySet<string> = new Set([\n \"in-process\",\n \"worker\",\n \"remote\",\n \"router\",\n]);\n\nexport const REACTOR_CLIENT_QUERY_KEY = \"reactorClient\";\nexport const REACTOR_CLIENT_STORAGE_KEY = \"ph:reactorClient\";\n\nconst asMode = (value: string | null | undefined) =>\n value && MODES.has(value) ? (value as ReactorClientMode) : undefined;\n\nfunction fromTab(): ReactorClientMode | undefined {\n if (typeof window === \"undefined\") return undefined;\n let query: ReactorClientMode | undefined;\n try {\n query = asMode(\n new URLSearchParams(window.location.search).get(REACTOR_CLIENT_QUERY_KEY),\n );\n } catch {\n return undefined;\n }\n try {\n if (query) {\n window.localStorage.setItem(REACTOR_CLIENT_STORAGE_KEY, query);\n return query;\n }\n return asMode(window.localStorage.getItem(REACTOR_CLIENT_STORAGE_KEY));\n } catch {\n // Blocked storage: the query still applies for this page load.\n return query;\n }\n}\n\nexport function resolveReactorClientMode(): ReactorClientMode {\n const override = fromTab();\n if (override) return override;\n const configured = getRuntimeConfig().connect.instance?.reactorClient;\n if (configured && MODES.has(configured)) return configured;\n // Legacy fallback — unchanged behaviour for configs without reactorClient.\n if (isMultiReactorEnabled()) return \"router\";\n if (isReactorWorkerEnabled()) return \"worker\";\n return \"in-process\";\n}\n","import type { IReactorClient } from \"@powerhousedao/reactor\";\nimport {\n getDrives,\n getFullReactorClient,\n getPHStore,\n recordBackendAuthError,\n setBackendAuth,\n setDrives,\n setFullReactorClient,\n} from \"@powerhousedao/reactor-browser\";\nimport type { DocumentDriveDocument } from \"@powerhousedao/shared/document-drive\";\nimport type { ISigner } from \"@powerhousedao/shared/document-model\";\nimport { logger } from \"document-model\";\nimport type * as MultiReactor from \"./multi-reactor.js\";\nimport type {\n LoadedDocumentModels,\n LocalReactorModule,\n} from \"./multi-reactor.js\";\nimport type { ReactorClientMode } from \"./reactor-client-mode.js\";\nimport { resolveReactorClientMode } from \"./reactor-client-mode.js\";\nimport { isReactorWorkerEnabled } from \"./reactor-worker-flag.js\";\nimport { setDriveRelister } from \"./drive-relist.js\";\n\ntype MultiReactorModule = typeof MultiReactor;\n\nexport type AppReactorClientParams = {\n mode: ReactorClientMode;\n /** Built, and ready (the worker has started up). Undefined in `remote`\n * mode, where no local reactor is built. */\n module: LocalReactorModule | undefined;\n remoteDriveUrl: string | undefined;\n /** Signs routed writes; unsigned (anonymous) without one. */\n signer?: ISigner;\n documentModelModules: LoadedDocumentModels;\n loadRouter?: () => Promise<MultiReactorModule>;\n};\n\nconst loadMultiReactor = (): Promise<MultiReactorModule> =>\n import(\"./multi-reactor.js\");\n\n/** What a mode builds in the tab; `remote` builds no local reactor (no PGlite). */\nexport type ReactorClientPlan = {\n mode: ReactorClientMode;\n /** `router`: the local reactor plus remote backends. */\n multiReactor: boolean;\n needsLocalReactor: boolean;\n /** The local reactor runs in the shared worker. */\n localAsWorker: boolean;\n};\n\nexport function planReactorClient(\n mode: ReactorClientMode = resolveReactorClientMode(),\n): ReactorClientPlan {\n const needsLocalReactor = mode !== \"remote\";\n return {\n mode,\n multiReactor: mode === \"router\",\n needsLocalReactor,\n localAsWorker:\n needsLocalReactor &&\n (mode === \"worker\" || (mode === \"router\" && isReactorWorkerEnabled())),\n };\n}\n\n/** Builds the tab's reactor, e.g. Connect's PGlite or worker reactor. */\nexport type LocalReactorFactory = (\n plan: ReactorClientPlan,\n) => Promise<LocalReactorModule>;\n\nexport type CreateAppReactorClientOptions = Omit<\n AppReactorClientParams,\n \"mode\" | \"module\"\n> & {\n plan?: ReactorClientPlan;\n /** Called only when the plan needs a local reactor. */\n localReactor?: LocalReactorFactory;\n};\n\n/** Builds the local reactor the plan needs, then selects the app's client. */\nexport async function createAppReactorClient(\n options: CreateAppReactorClientOptions,\n) {\n const { localReactor, ...params } = options;\n const plan = options.plan ?? planReactorClient();\n let module: LocalReactorModule | undefined;\n if (plan.needsLocalReactor) {\n if (!localReactor) {\n throw new Error(\n `reactorClient mode \"${plan.mode}\" needs a local reactor; pass localReactor`,\n );\n }\n module = await localReactor(plan);\n }\n const client = await selectAppReactorClient({\n ...params,\n mode: plan.mode,\n module,\n });\n return { plan, module, client };\n}\n\n/**\n * Pick the client for the resolved mode:\n * - `in-process` / `worker`: the local client, router module never loaded.\n * - `router`: the local reactor plus remote backends.\n * - `remote`: a remote-only router — a full IReactorClient that proxies to\n * the Switchboard over GraphQL with NO local reactor (no PGlite).\n */\nexport async function selectAppReactorClient(\n params: AppReactorClientParams,\n): Promise<IReactorClient> {\n if (params.mode === \"remote\") {\n setFullReactorClient(undefined);\n const remote = await buildRemoteOnly(params);\n setFullReactorClient(remote);\n return remote;\n }\n if (params.mode !== \"router\") {\n if (getPHStore()?.fullReactorClient) {\n setFullReactorClient(undefined);\n }\n return requireModule(params).client;\n }\n setFullReactorClient(undefined);\n const routed = await buildRouter(params);\n setFullReactorClient(routed);\n return routed ?? requireModule(params).client;\n}\n\nfunction requireModule(params: AppReactorClientParams): LocalReactorModule {\n if (!params.module) {\n throw new Error(\n `reactorClient mode \"${params.mode}\" needs a local reactor, but none was built`,\n );\n }\n return params.module;\n}\n\n/**\n * A Switchboard that cannot answer must not fail boot: list the tab's drives.\n *\n * A Switchboard that REFUSES the caller (401/403) must not fail boot either:\n * the refusal is recorded (`backendAuth`) so the root view shows the sign-in\n * gate, and the drive list is empty until the user is someone the backend\n * accepts. A remote-only client has no local drives to fall back on.\n */\nexport async function getAppDrives(\n client: IReactorClient,\n local: IReactorClient,\n): Promise<DocumentDriveDocument[]> {\n if (client === local) {\n try {\n const drives = await getDrives(local);\n setBackendAuth(undefined);\n return drives;\n } catch (error) {\n if (recordBackendAuthError(error, \"switchboard\")) {\n logger.warn(\n \"The Switchboard refused this caller; showing the sign-in gate: @error\",\n error,\n );\n return [];\n }\n throw error;\n }\n }\n try {\n const drives = await getDrives(client);\n setBackendAuth(undefined);\n return drives;\n } catch (error) {\n if (recordBackendAuthError(error, \"switchboard\")) {\n logger.warn(\n \"A remote backend refused this caller; listing the local reactor's drives: @error\",\n error,\n );\n } else {\n logger.warn(\n \"Could not list drives through the router; listing the local reactor's: @error\",\n error,\n );\n }\n return getDrives(local);\n }\n}\n\n/**\n * The boot refresh of the drives store. It lists through `getAppDrives`\n * whichever client is in use, so a Switchboard that refuses the caller is\n * recorded for the sign-in gate here too: the remote-only client is its own\n * `local`, and a bare `refreshReactorDataClient` would let the 401 escape\n * and fail the boot before the gate can render.\n */\nexport async function refreshAppDrives(\n client: IReactorClient,\n local: IReactorClient,\n): Promise<void> {\n setDrives(await getAppDrives(client, local));\n}\n\n/**\n * Lists the drives again as the caller the tab now is, through the clients\n * boot left in the store: after a sign-in landing or a sign-out that followed\n * a backend's refusal. Nothing to do before boot has set a client.\n */\nexport async function relistAppDrives(): Promise<void> {\n const client = getFullReactorClient();\n if (!client) return;\n const local = getPHStore()?.reactorClientModule?.client ?? client;\n await refreshAppDrives(client, local);\n}\n\n// The backend auth gate relists through drive-relist (see there)\nsetDriveRelister(relistAppDrives);\n\nasync function buildRouter(\n params: AppReactorClientParams,\n): Promise<IReactorClient | undefined> {\n if (!params.remoteDriveUrl) {\n logger.warn(\n \"multiReactor is on but no remote drive URL is configured; using the local reactor only\",\n );\n return undefined;\n }\n let multiReactor: MultiReactorModule;\n try {\n multiReactor = await (params.loadRouter ?? loadMultiReactor)();\n } catch (error) {\n logger.error(\"Could not load the multi-reactor router: @error\", error);\n return undefined;\n }\n const remoteGraphqlUrl = multiReactor.deriveSwitchboardGraphqlUrl(\n params.remoteDriveUrl,\n );\n if (!remoteGraphqlUrl) {\n logger.warn(\n \"multiReactor is on but the remote drive URL @url does not parse; using the local reactor only\",\n params.remoteDriveUrl,\n );\n return undefined;\n }\n logger.info(\"Multi-reactor routing to @url\", remoteGraphqlUrl);\n return multiReactor.buildMultiReactorClient({\n module: requireModule(params),\n remoteGraphqlUrl,\n signer: params.signer,\n documentModelModules: params.documentModelModules,\n });\n}\n\n/**\n * The `remote` mode: a remote-only router — a full IReactorClient that proxies\n * to the Switchboard over GraphQL with NO local backend, so no local reactor\n * and no PGlite are ever built. A missing/unparseable remote URL is a hard\n * config error here (unlike `router`, there is no local reactor to fall back\n * to).\n */\nasync function buildRemoteOnly(\n params: AppReactorClientParams,\n): Promise<IReactorClient> {\n if (!params.remoteDriveUrl) {\n throw new Error(\n 'reactorClient \"remote\" needs a remote drive URL — declare a remote backend / default drive the client can proxy to',\n );\n }\n const multiReactor = await (params.loadRouter ?? loadMultiReactor)();\n const remoteGraphqlUrl = multiReactor.deriveSwitchboardGraphqlUrl(\n params.remoteDriveUrl,\n );\n if (!remoteGraphqlUrl) {\n throw new Error(\n `reactorClient \"remote\": the remote drive URL \"${params.remoteDriveUrl}\" does not resolve to a Switchboard GraphQL endpoint`,\n );\n }\n logger.info(\"Remote reactor client → @url\", remoteGraphqlUrl);\n return multiReactor.buildMultiReactorClient({\n module: undefined,\n remoteGraphqlUrl,\n signer: params.signer,\n documentModelModules: params.documentModelModules,\n });\n}\n","import type { PHStore } from \"@powerhousedao/reactor-browser\";\nimport {\n bindPHStoreToWindow,\n createPHStore,\n getActivePHStore,\n} from \"@powerhousedao/reactor-browser\";\n\n/** The app's PH store: the active one, else a new one bound to `window.ph`.\n * Values set on `window.ph` before carry over. */\nexport function getConnectPHStore(): PHStore {\n const active = getActivePHStore();\n if (active) return active;\n const store = createPHStore();\n bindPHStoreToWindow(store);\n return store;\n}\n","import type { DocumentModelLib } from \"document-model\";\n\n/** A module namespace, as `import * as pkg` or Vite HMR hands it over. */\nexport type ModuleNamespace = Record<string, any> & {\n [Symbol.toStringTag]: \"Module\";\n};\n\nexport type LocalPackage = DocumentModelLib<any> | ModuleNamespace;\n\n/** The package itself, or a loader (`() => import(\"./index.js\")`) that keeps it off the boot path. */\nexport type LocalPackageSource = LocalPackage | (() => Promise<LocalPackage>);\n\n/** Starts loading the project's package; a loader runs once, here. */\nexport function loadLocalPackage(\n source: LocalPackageSource | undefined,\n): DocumentModelLib | Promise<DocumentModelLib> | undefined {\n const pkg = (typeof source === \"function\" ? source() : source) as\n | DocumentModelLib\n | Promise<DocumentModelLib>\n | undefined;\n // Consumers await it; this only stops an early rejection being reported as unhandled.\n if (pkg instanceof Promise) pkg.catch(() => undefined);\n return pkg;\n}\n"],"mappings":"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"}
|
package/dist/runtime.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { A as isRuntimeFlagEnabled, C as REACTOR_WORKER_STORAGE_KEY, D as isMultiReactorEnabled, E as resolveReactorWorkerEnabled, O as RuntimeFlagInput, S as REACTOR_WORKER_QUERY_KEY, T as isReactorWorkerEnabled, _ as LocalReactorModule, a as getConnectPHStore, b as ReactorClientMode, c as LocalReactorFactory, d as getAppDrives, f as planReactorClient, g as LoadedDocumentModels, h as selectAppReactorClient, i as loadLocalPackage, j as resolveRuntimeFlag, k as RuntimeFlagKeys, l as ReactorClientPlan, m as relistAppDrives, n as LocalPackageSource, o as AppReactorClientParams, p as refreshAppDrives, r as ModuleNamespace, s as CreateAppReactorClientOptions, t as LocalPackage, u as createAppReactorClient, v as REACTOR_CLIENT_QUERY_KEY, w as ReactorWorkerFlagInput, x as resolveReactorClientMode, y as REACTOR_CLIENT_STORAGE_KEY } from "./index-
|
|
1
|
+
import { A as isRuntimeFlagEnabled, C as REACTOR_WORKER_STORAGE_KEY, D as isMultiReactorEnabled, E as resolveReactorWorkerEnabled, O as RuntimeFlagInput, S as REACTOR_WORKER_QUERY_KEY, T as isReactorWorkerEnabled, _ as LocalReactorModule, a as getConnectPHStore, b as ReactorClientMode, c as LocalReactorFactory, d as getAppDrives, f as planReactorClient, g as LoadedDocumentModels, h as selectAppReactorClient, i as loadLocalPackage, j as resolveRuntimeFlag, k as RuntimeFlagKeys, l as ReactorClientPlan, m as relistAppDrives, n as LocalPackageSource, o as AppReactorClientParams, p as refreshAppDrives, r as ModuleNamespace, s as CreateAppReactorClientOptions, t as LocalPackage, u as createAppReactorClient, v as REACTOR_CLIENT_QUERY_KEY, w as ReactorWorkerFlagInput, x as resolveReactorClientMode, y as REACTOR_CLIENT_STORAGE_KEY } from "./index-CCs6HTQV.js";
|
|
2
2
|
import { i as primeRuntimeConfig, n as getRuntimeConfig, r as loadRuntimeConfig } from "./runtime-config-D3YPhYyj.js";
|
|
3
3
|
import { n as useBackendAuthGate, t as BackendAuthGateMode } from "./backend-auth-gate-DiFpY5rt.js";
|
|
4
4
|
import { n as useIsEmbedded, t as getIsEmbedded } from "./embedded-DT1C47F0.js";
|
package/dist/runtime.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { getIsEmbedded, useIsEmbedded } from "./embedded.js";
|
|
2
2
|
import { getRuntimeConfig, loadRuntimeConfig, primeRuntimeConfig } from "./runtime-config.js";
|
|
3
3
|
import { n as resolveRuntimeFlag, t as isRuntimeFlagEnabled } from "./runtime-flag-DvxW_SD4.js";
|
|
4
|
-
import { a as planReactorClient, c as selectAppReactorClient, d as resolveReactorClientMode, f as REACTOR_WORKER_QUERY_KEY, g as isMultiReactorEnabled, h as resolveReactorWorkerEnabled, i as getAppDrives, l as REACTOR_CLIENT_QUERY_KEY, m as isReactorWorkerEnabled, n as getConnectPHStore, o as refreshAppDrives, p as REACTOR_WORKER_STORAGE_KEY, r as createAppReactorClient, s as relistAppDrives, t as loadLocalPackage, u as REACTOR_CLIENT_STORAGE_KEY } from "./runtime-
|
|
4
|
+
import { a as planReactorClient, c as selectAppReactorClient, d as resolveReactorClientMode, f as REACTOR_WORKER_QUERY_KEY, g as isMultiReactorEnabled, h as resolveReactorWorkerEnabled, i as getAppDrives, l as REACTOR_CLIENT_QUERY_KEY, m as isReactorWorkerEnabled, n as getConnectPHStore, o as refreshAppDrives, p as REACTOR_WORKER_STORAGE_KEY, r as createAppReactorClient, s as relistAppDrives, t as loadLocalPackage, u as REACTOR_CLIENT_STORAGE_KEY } from "./runtime-Cb3HQhKo.js";
|
|
5
5
|
import { t as useBackendAuthGate } from "./backend-auth-gate-DNKg_v4Y.js";
|
|
6
6
|
export { REACTOR_CLIENT_QUERY_KEY, REACTOR_CLIENT_STORAGE_KEY, REACTOR_WORKER_QUERY_KEY, REACTOR_WORKER_STORAGE_KEY, createAppReactorClient, getAppDrives, getConnectPHStore, getIsEmbedded, getRuntimeConfig, isMultiReactorEnabled, isReactorWorkerEnabled, isRuntimeFlagEnabled, loadLocalPackage, loadRuntimeConfig, planReactorClient, primeRuntimeConfig, refreshAppDrives, relistAppDrives, resolveReactorClientMode, resolveReactorWorkerEnabled, resolveRuntimeFlag, selectAppReactorClient, useBackendAuthGate, useIsEmbedded };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@powerhousedao/connect-core",
|
|
3
|
-
"version": "6.2.3-dev.
|
|
3
|
+
"version": "6.2.3-dev.82",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -73,17 +73,17 @@
|
|
|
73
73
|
"./package.json": "./package.json"
|
|
74
74
|
},
|
|
75
75
|
"dependencies": {
|
|
76
|
-
"@powerhousedao/host-core": "6.2.3-dev.
|
|
77
|
-
"@powerhousedao/reactor": "6.2.3-dev.
|
|
78
|
-
"@powerhousedao/reactor-browser": "6.2.3-dev.
|
|
79
|
-
"@powerhousedao/reactor-router": "6.2.3-dev.
|
|
80
|
-
"@powerhousedao/shared": "6.2.3-dev.
|
|
81
|
-
"document-model": "6.2.3-dev.
|
|
76
|
+
"@powerhousedao/host-core": "6.2.3-dev.82",
|
|
77
|
+
"@powerhousedao/reactor": "6.2.3-dev.82",
|
|
78
|
+
"@powerhousedao/reactor-browser": "6.2.3-dev.82",
|
|
79
|
+
"@powerhousedao/reactor-router": "6.2.3-dev.82",
|
|
80
|
+
"@powerhousedao/shared": "6.2.3-dev.82",
|
|
81
|
+
"document-model": "6.2.3-dev.82"
|
|
82
82
|
},
|
|
83
83
|
"devDependencies": {
|
|
84
84
|
"@electric-sql/pglite": "0.3.15",
|
|
85
85
|
"@playwright/test": "^1.60.0",
|
|
86
|
-
"@renown/sdk": "6.2.3-dev.
|
|
86
|
+
"@renown/sdk": "6.2.3-dev.82",
|
|
87
87
|
"@tanstack/react-router": "^1.170.41",
|
|
88
88
|
"@tanstack/router-cli": "1.167.40",
|
|
89
89
|
"@tanstack/router-core": "1.171.34",
|
|
@@ -2,9 +2,13 @@ import {
|
|
|
2
2
|
createReactorInspector,
|
|
3
3
|
type ReactorInfo,
|
|
4
4
|
} from "@powerhousedao/reactor";
|
|
5
|
-
import
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
import {
|
|
6
|
+
ambientRenownSigner,
|
|
7
|
+
ambientRenownTokenProvider,
|
|
8
|
+
createSwitchboardBackend,
|
|
9
|
+
type BrowserReactorClientModule,
|
|
10
|
+
type SwitchboardBackend,
|
|
11
|
+
type WorkerReactorClientModule,
|
|
8
12
|
} from "@powerhousedao/reactor-browser";
|
|
9
13
|
import {
|
|
10
14
|
FanInPartialFailureError,
|
|
@@ -21,16 +25,6 @@ import type {
|
|
|
21
25
|
ISigner,
|
|
22
26
|
} from "@powerhousedao/shared/document-model";
|
|
23
27
|
import { logger } from "document-model";
|
|
24
|
-
import {
|
|
25
|
-
createGraphQLRoutableBackend,
|
|
26
|
-
type GraphQLRoutableBackend,
|
|
27
|
-
} from "./graphql-routable-backend.js";
|
|
28
|
-
|
|
29
|
-
export { createGraphQLRoutableBackend } from "./graphql-routable-backend.js";
|
|
30
|
-
export type {
|
|
31
|
-
GraphQLRoutableBackend,
|
|
32
|
-
GraphQLRoutableBackendOptions,
|
|
33
|
-
} from "./graphql-routable-backend.js";
|
|
34
28
|
|
|
35
29
|
export const LOCAL_BACKEND_NAME = "connect-local";
|
|
36
30
|
export const REMOTE_BACKEND_NAME = "switchboard-remote";
|
|
@@ -39,11 +33,6 @@ export type LocalReactorModule =
|
|
|
39
33
|
| BrowserReactorClientModule
|
|
40
34
|
| WorkerReactorClientModule;
|
|
41
35
|
|
|
42
|
-
const REMOTE_REACH: ReactorReach = Object.freeze({
|
|
43
|
-
hosting: "remote",
|
|
44
|
-
inspection: "none",
|
|
45
|
-
});
|
|
46
|
-
|
|
47
36
|
/** Only the tab's reactor is inspectable here, so new collections land on it. */
|
|
48
37
|
export const PLACE_ON_LOCAL: CollectionRequirementsInput = Object.freeze({
|
|
49
38
|
inspectable: true,
|
|
@@ -130,12 +119,12 @@ function localIdCheckAnswer(
|
|
|
130
119
|
|
|
131
120
|
/** The router Connect installs, with Connect's handling of credentials and id checks. */
|
|
132
121
|
export class ConnectRoutingClient extends RoutingReactorClient {
|
|
133
|
-
private readonly remote:
|
|
122
|
+
private readonly remote: SwitchboardBackend;
|
|
134
123
|
|
|
135
124
|
constructor(
|
|
136
125
|
backends: readonly RoutableBackendConfig[],
|
|
137
126
|
options: RoutingClientOptions,
|
|
138
|
-
remote:
|
|
127
|
+
remote: SwitchboardBackend,
|
|
139
128
|
hasLocal: boolean,
|
|
140
129
|
) {
|
|
141
130
|
super(backends, {
|
|
@@ -174,17 +163,16 @@ export async function buildMultiReactorClient(
|
|
|
174
163
|
const registry = module?.reactorModule?.documentModelRegistry;
|
|
175
164
|
const loaded = params.documentModelModules;
|
|
176
165
|
const loadedModules = typeof loaded === "function" ? loaded : () => loaded;
|
|
177
|
-
|
|
166
|
+
// The logged-in Renown user's token and signer, read per request as before.
|
|
167
|
+
const remote = createSwitchboardBackend({
|
|
168
|
+
name: REMOTE_BACKEND_NAME,
|
|
178
169
|
url: params.remoteGraphqlUrl,
|
|
170
|
+
tokenProvider: ambientRenownTokenProvider,
|
|
171
|
+
signer: ambientRenownSigner,
|
|
179
172
|
documentModels: () => registry?.getAllModules() ?? loadedModules(),
|
|
173
|
+
inspection: "none",
|
|
180
174
|
});
|
|
181
|
-
const remoteBackend
|
|
182
|
-
name: REMOTE_BACKEND_NAME,
|
|
183
|
-
backend: remote.backend,
|
|
184
|
-
facts: () => remote.info(),
|
|
185
|
-
reach: REMOTE_REACH,
|
|
186
|
-
refusesMisroutes: false,
|
|
187
|
-
};
|
|
175
|
+
const remoteBackend = remote.config;
|
|
188
176
|
const backends: RoutableBackendConfig[] = module
|
|
189
177
|
? [
|
|
190
178
|
{
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index-BMlma368.d.ts","names":[],"sources":["../src/runtime/runtime-flag.ts","../src/runtime/multi-reactor-flag.ts","../src/runtime/reactor-worker-flag.ts","../src/runtime/reactor-client-mode.ts","../src/runtime/graphql-routable-backend.ts","../src/runtime/multi-reactor.ts","../src/runtime/app-reactor-client.ts","../src/runtime/ph-store.ts","../src/runtime/local-package.ts"],"mappings":";;;;;;;;;;KAAY;EACV;EACA;EACA;;iBAIc,mBAAmB,OAAO;KAY9B;EACV;EACA;EACA;;iBAKc,qBAAqB,MAAM;;;iBCxB3B;;;cCIH;cACA;KAED,yBAAyB;iBAErB,4BACd,OAAO;iBAKO;;;;;;;;;;;;;;;;;;;KCGJ,oBAAoB;cASnB;cACA;iBA2BG,4BAA4B;;;KC2BhC,gCAAgC,KAC1C;KAIU;WACD,SAAS;;EAElB,QAAQ,QAAQ;;EAEhB;;;iBAIc,6BACd,SAAS,gCACR;;;;cCnEU;cACA;KAED,qBACR,6BACA;;cAQS,gBAAgB;iBAIb,WAAW,MAAM,6BAA6B;;iBAO9C,WACd,QAAQ,2BACD,QAAQ;;iBAcD,4BACd;;KAaU,gCACC,wCACO;KAER;;;EAGV,QAAQ;EACR;;EAEA,SAAS;;EAET,sBAAsB;EACtB,eAAe;;;;;cAMJ,iBAAiB;;cAwBjB,6BAA6B;mBACvB;EAEjB,YACE,mBAAmB,yBACnB,SAAS,sBACT,QAAQ,wBACR;;EAYF;;;;;;;;;iBAmBoB,wBACpB,QAAQ,qBACP,QAAQ;;;KCpJN,4BAA4B;KAErB;EACV,MAAM;;;EAGN,QAAQ;EACR;;EAEA,SAAS;EACT,sBAAsB;EACtB,mBAAmB,QAAQ;;;KAOjB;EACV,MAAM;;EAEN;EACA;;EAEA;;iBAGc,kBACd,OAAM,oBACL;;KAaS,uBACV,MAAM,sBACH,QAAQ;KAED,gCAAgC,KAC1C;EAGA,OAAO;;EAEP,eAAe;;;iBAIK,uBACpB,SAAS,gCAA6B;;;;;;;;;;;;iBA4BlB,uBACpB,QAAQ,yBACP,QAAQ;;;;;;;;;iBAoCW,aACpB,QAAQ,gBACR,OAAO,iBACN,QAAQ;;;;;;;;iBA4CW,iBACpB,QAAQ,gBACR,OAAO,iBACN;;;;;;iBASmB,mBAAmB;;;;;iBCpMzB,qBAAqB;;;;KCNzB,kBAAkB;GAC3B,OAAO;;KAGE,eAAe,wBAAwB;;KAGvC,qBAAqB,sBAAsB,QAAQ;;iBAG/C,iBACd,QAAQ,iCACP,mBAAmB,QAAQ"}
|
|
@@ -1,219 +0,0 @@
|
|
|
1
|
-
import { DRIVE_DOCUMENT_TYPES, GraphQLReactorClient, findIsServableOverGraphQL } from "@powerhousedao/reactor-browser";
|
|
2
|
-
import { logger } from "document-model";
|
|
3
|
-
import { JOB_NOT_FOUND_ERROR_NAME, JobStatus, createReactorInspector } from "@powerhousedao/reactor";
|
|
4
|
-
import { FanInPartialFailureError, RoutingReactorClient, fromReactorClient } from "@powerhousedao/reactor-router";
|
|
5
|
-
//#region src/runtime/graphql-routable-backend.ts
|
|
6
|
-
const REMOTE_INFO_QUERY = `
|
|
7
|
-
query RemoteReactorInfo {
|
|
8
|
-
inspection {
|
|
9
|
-
info {
|
|
10
|
-
storage {
|
|
11
|
-
engine
|
|
12
|
-
persistence
|
|
13
|
-
durable
|
|
14
|
-
selfHeal
|
|
15
|
-
}
|
|
16
|
-
workflows
|
|
17
|
-
syncChannels
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
`;
|
|
22
|
-
/** Ids and slugs of documents this backend answered as drives, by drive id. */
|
|
23
|
-
var KnownDrives = class {
|
|
24
|
-
ids = /* @__PURE__ */ new Map();
|
|
25
|
-
learn(document) {
|
|
26
|
-
const { id, slug, documentType } = document.header;
|
|
27
|
-
if (DRIVE_DOCUMENT_TYPES.includes(documentType)) {
|
|
28
|
-
this.ids.set(id, id);
|
|
29
|
-
if (slug) this.ids.set(slug, id);
|
|
30
|
-
}
|
|
31
|
-
return document;
|
|
32
|
-
}
|
|
33
|
-
learnPage(page) {
|
|
34
|
-
for (const document of page.results) this.learn(document);
|
|
35
|
-
return page;
|
|
36
|
-
}
|
|
37
|
-
driveOf(identifier) {
|
|
38
|
-
return identifier === void 0 ? void 0 : this.ids.get(identifier);
|
|
39
|
-
}
|
|
40
|
-
/** Names a drive only when this backend proved it is one. */
|
|
41
|
-
driveIdFor = (call) => {
|
|
42
|
-
switch (call.method) {
|
|
43
|
-
case "create":
|
|
44
|
-
case "find": return this.driveOf(call.parentId);
|
|
45
|
-
case "execute":
|
|
46
|
-
case "deleteDocument": return this.driveOf(call.documentId);
|
|
47
|
-
case "executeBatch":
|
|
48
|
-
for (const job of call.jobs ?? []) {
|
|
49
|
-
const drive = this.driveOf(job.documentId);
|
|
50
|
-
if (drive !== void 0) return drive;
|
|
51
|
-
}
|
|
52
|
-
return;
|
|
53
|
-
}
|
|
54
|
-
};
|
|
55
|
-
};
|
|
56
|
-
/** A Switchboard as a router backend; members GraphQL cannot serve are absent. */
|
|
57
|
-
function createGraphQLRoutableBackend(options) {
|
|
58
|
-
const drives = new KnownDrives();
|
|
59
|
-
const gql = new GraphQLReactorClient({
|
|
60
|
-
...options,
|
|
61
|
-
driveIdFor: drives.driveIdFor
|
|
62
|
-
});
|
|
63
|
-
return {
|
|
64
|
-
backend: {
|
|
65
|
-
supports: {
|
|
66
|
-
find: findIsServableOverGraphQL,
|
|
67
|
-
pointInTimeViews: false
|
|
68
|
-
},
|
|
69
|
-
drives: gql.read.drives,
|
|
70
|
-
get: async (identifier, view, signal) => drives.learn(await gql.get(identifier, view, signal)),
|
|
71
|
-
getMany: async (ids, view, signal) => (await gql.getMany(ids, view, signal)).map((document) => drives.learn(document)),
|
|
72
|
-
getOperations: (identifier, view, filter, paging, signal) => gql.getOperations(identifier, view, filter, paging, signal),
|
|
73
|
-
find: async (search, view, paging, signal) => drives.learnPage(await gql.find(search, view, paging, signal)),
|
|
74
|
-
isServed: (identifier, view, signal) => gql.isServed(identifier, view, signal),
|
|
75
|
-
getOutgoingRelationships: (source, type, view, paging, signal) => gql.getOutgoingRelationships(source, type, view, paging, signal),
|
|
76
|
-
getIncomingRelationships: (target, type, view, paging, signal) => gql.getIncomingRelationships(target, type, view, paging, signal),
|
|
77
|
-
getOutgoingRelationshipEdges: (source, type, view, paging, signal) => gql.getOutgoingRelationshipEdges(source, type, view, paging, signal),
|
|
78
|
-
getIncomingRelationshipEdges: (target, type, view, paging, signal) => gql.getIncomingRelationshipEdges(target, type, view, paging, signal),
|
|
79
|
-
subscribe: (search, callback, view) => gql.subscribe(search, callback, view),
|
|
80
|
-
getCreateSignaturePolicy: () => gql.getCreateSignaturePolicy(),
|
|
81
|
-
getCreateProtocolVersions: (options, signal) => gql.getCreateProtocolVersions(options, signal),
|
|
82
|
-
create: async (document, parent, signal) => drives.learn(await gql.create(document, parent, signal)),
|
|
83
|
-
execute: async (identifier, branch, actions, signal) => drives.learn(await gql.execute(identifier, branch, actions, signal)),
|
|
84
|
-
executeBatch: (request, signal) => gql.executeBatch(request, signal),
|
|
85
|
-
deleteDocument: (identifier, propagate, signal) => gql.deleteDocument(identifier, propagate, signal),
|
|
86
|
-
setPreferredEditor: (identifier, editor, branch, signal) => gql.setPreferredEditor(identifier, editor, branch, signal),
|
|
87
|
-
getJob: async (jobId, signal) => {
|
|
88
|
-
const job = await gql.getJob(jobId, signal);
|
|
89
|
-
return job?.status === JobStatus.FAILED && job.error?.name === JOB_NOT_FOUND_ERROR_NAME ? void 0 : job;
|
|
90
|
-
},
|
|
91
|
-
waitForJob: (job, signal) => gql.waitForJob(job, signal)
|
|
92
|
-
},
|
|
93
|
-
info: async () => {
|
|
94
|
-
return {
|
|
95
|
-
...(await gql.request(REMOTE_INFO_QUERY)).inspection.info,
|
|
96
|
-
access: {
|
|
97
|
-
admin: false,
|
|
98
|
-
sql: false
|
|
99
|
-
}
|
|
100
|
-
};
|
|
101
|
-
},
|
|
102
|
-
notifyCredentialsChanged: () => gql.notifyCredentialsChanged()
|
|
103
|
-
};
|
|
104
|
-
}
|
|
105
|
-
//#endregion
|
|
106
|
-
//#region src/runtime/multi-reactor.ts
|
|
107
|
-
const LOCAL_BACKEND_NAME = "connect-local";
|
|
108
|
-
const REMOTE_BACKEND_NAME = "switchboard-remote";
|
|
109
|
-
const REMOTE_REACH = Object.freeze({
|
|
110
|
-
hosting: "remote",
|
|
111
|
-
inspection: "none"
|
|
112
|
-
});
|
|
113
|
-
/** Only the tab's reactor is inspectable here, so new collections land on it. */
|
|
114
|
-
const PLACE_ON_LOCAL = Object.freeze({ inspectable: true });
|
|
115
|
-
function localReach(kind) {
|
|
116
|
-
return kind === "worker" ? {
|
|
117
|
-
hosting: "worker",
|
|
118
|
-
inspection: "rpc"
|
|
119
|
-
} : {
|
|
120
|
-
hosting: "in-process",
|
|
121
|
-
inspection: "direct"
|
|
122
|
-
};
|
|
123
|
-
}
|
|
124
|
-
/** Read at every refresh, never kept: a rebuilt reactor reports its own. */
|
|
125
|
-
function localFacts(module) {
|
|
126
|
-
if (module.kind === "worker") return () => module.inspector.info();
|
|
127
|
-
return async () => {
|
|
128
|
-
const reactorModule = module.reactorModule;
|
|
129
|
-
if (!reactorModule) throw new Error("The in-tab reactor exposes no module to inspect");
|
|
130
|
-
return createReactorInspector(reactorModule).info();
|
|
131
|
-
};
|
|
132
|
-
}
|
|
133
|
-
/** `<origin>[/<prefix>]/d/<slug>` -> `<origin>[/<prefix>]/graphql`. */
|
|
134
|
-
function deriveSwitchboardGraphqlUrl(remoteDriveUrl) {
|
|
135
|
-
let parsed;
|
|
136
|
-
try {
|
|
137
|
-
parsed = new URL(remoteDriveUrl);
|
|
138
|
-
} catch {
|
|
139
|
-
return;
|
|
140
|
-
}
|
|
141
|
-
const prefix = /^(.*)\/d\/[^/]+\/?$/.exec(parsed.pathname)?.[1];
|
|
142
|
-
return prefix === void 0 ? void 0 : `${parsed.origin}${prefix}/graphql`;
|
|
143
|
-
}
|
|
144
|
-
/** Remote-only placement: the Switchboard serves every collection. (It offers
|
|
145
|
-
* no inspection surface over GraphQL, so PLACE_ON_LOCAL's `inspectable`
|
|
146
|
-
* requirement must NOT apply, or no backend would be eligible.) */
|
|
147
|
-
const PLACE_ON_REMOTE = Object.freeze({});
|
|
148
|
-
/**
|
|
149
|
-
* The local answer stands when only the Switchboard could not answer -- but
|
|
150
|
-
* only when there IS a local backend. Remote-only has nothing to fall back to,
|
|
151
|
-
* so its errors surface. Installed as the router's `answerFailedIdCheck`, so
|
|
152
|
-
* the facade and `write.isDocumentIdTaken` both apply it.
|
|
153
|
-
*/
|
|
154
|
-
function localIdCheckAnswer(documentId, error) {
|
|
155
|
-
if (!failedOnlyOnRemote(error)) return;
|
|
156
|
-
logger.warn("The Switchboard could not say whether @id is taken; using the local reactor's answer: @error", documentId, error);
|
|
157
|
-
return false;
|
|
158
|
-
}
|
|
159
|
-
/** The router Connect installs, with Connect's handling of credentials and id checks. */
|
|
160
|
-
var ConnectRoutingClient = class extends RoutingReactorClient {
|
|
161
|
-
remote;
|
|
162
|
-
constructor(backends, options, remote, hasLocal) {
|
|
163
|
-
super(backends, {
|
|
164
|
-
...options,
|
|
165
|
-
answerFailedIdCheck: hasLocal ? localIdCheckAnswer : options.answerFailedIdCheck
|
|
166
|
-
});
|
|
167
|
-
this.remote = remote;
|
|
168
|
-
}
|
|
169
|
-
/** Renown's sign-in and sign-out call this on whatever client is installed. */
|
|
170
|
-
notifyCredentialsChanged() {
|
|
171
|
-
this.remote.notifyCredentialsChanged();
|
|
172
|
-
}
|
|
173
|
-
};
|
|
174
|
-
function failedOnlyOnRemote(error) {
|
|
175
|
-
return error instanceof FanInPartialFailureError && error.failures.every((failure) => failure.backend === "switchboard-remote");
|
|
176
|
-
}
|
|
177
|
-
/**
|
|
178
|
-
* Build the Connect routing client. With a local `module` it is the router
|
|
179
|
-
* over the tab's reactor (primary) and the Switchboard; WITHOUT one it is the
|
|
180
|
-
* `remote` client — a remote-only router whose single backend is the
|
|
181
|
-
* Switchboard, so no local reactor (and no PGlite) is built. Either way the
|
|
182
|
-
* result is a full IReactorClient the app graph consumes unchanged.
|
|
183
|
-
*/
|
|
184
|
-
async function buildMultiReactorClient(params) {
|
|
185
|
-
const module = params.module;
|
|
186
|
-
const registry = module?.reactorModule?.documentModelRegistry;
|
|
187
|
-
const loaded = params.documentModelModules;
|
|
188
|
-
const loadedModules = typeof loaded === "function" ? loaded : () => loaded;
|
|
189
|
-
const remote = createGraphQLRoutableBackend({
|
|
190
|
-
url: params.remoteGraphqlUrl,
|
|
191
|
-
documentModels: () => registry?.getAllModules() ?? loadedModules()
|
|
192
|
-
});
|
|
193
|
-
const remoteBackend = {
|
|
194
|
-
name: REMOTE_BACKEND_NAME,
|
|
195
|
-
backend: remote.backend,
|
|
196
|
-
facts: () => remote.info(),
|
|
197
|
-
reach: REMOTE_REACH,
|
|
198
|
-
refusesMisroutes: false
|
|
199
|
-
};
|
|
200
|
-
const router = new ConnectRoutingClient(module ? [{
|
|
201
|
-
name: LOCAL_BACKEND_NAME,
|
|
202
|
-
backend: fromReactorClient(module.client),
|
|
203
|
-
facts: localFacts(module),
|
|
204
|
-
reach: localReach(module.kind),
|
|
205
|
-
refusesMisroutes: false
|
|
206
|
-
}, remoteBackend] : [remoteBackend], {
|
|
207
|
-
primaryBackend: module ? LOCAL_BACKEND_NAME : REMOTE_BACKEND_NAME,
|
|
208
|
-
defaultRequirements: module ? PLACE_ON_LOCAL : PLACE_ON_REMOTE,
|
|
209
|
-
signer: params.signer,
|
|
210
|
-
onDiagnostic: params.onDiagnostic,
|
|
211
|
-
documentModelModules: module ? void 0 : loadedModules
|
|
212
|
-
}, remote, Boolean(module));
|
|
213
|
-
await router.refreshFacts();
|
|
214
|
-
return router;
|
|
215
|
-
}
|
|
216
|
-
//#endregion
|
|
217
|
-
export { ConnectRoutingClient, LOCAL_BACKEND_NAME, PLACE_ON_LOCAL, PLACE_ON_REMOTE, REMOTE_BACKEND_NAME, buildMultiReactorClient, createGraphQLRoutableBackend, deriveSwitchboardGraphqlUrl, localFacts, localReach };
|
|
218
|
-
|
|
219
|
-
//# sourceMappingURL=multi-reactor-D_2B4jmu.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"multi-reactor-D_2B4jmu.js","names":[],"sources":["../src/runtime/graphql-routable-backend.ts","../src/runtime/multi-reactor.ts"],"sourcesContent":["import {\n JOB_NOT_FOUND_ERROR_NAME,\n JobStatus,\n type PagedResults,\n type ReactorInfo,\n type ViewFilter,\n} from \"@powerhousedao/reactor\";\nimport {\n DRIVE_DOCUMENT_TYPES,\n findIsServableOverGraphQL,\n GraphQLReactorClient,\n type DriveIdCall,\n type GraphQLReactorClientOptions,\n} from \"@powerhousedao/reactor-browser\";\nimport type { IRoutableBackend } from \"@powerhousedao/reactor-router\";\nimport type { Action, PHDocument } from \"@powerhousedao/shared/document-model\";\n\nconst REMOTE_INFO_QUERY = /* GraphQL */ `\n query RemoteReactorInfo {\n inspection {\n info {\n storage {\n engine\n persistence\n durable\n selfHeal\n }\n workflows\n syncChannels\n }\n }\n }\n`;\n\ntype RemoteReactorInfo = {\n inspection: { info: Omit<ReactorInfo, \"access\"> };\n};\n\n/** Ids and slugs of documents this backend answered as drives, by drive id. */\nclass KnownDrives {\n private readonly ids = new Map<string, string>();\n\n learn<T extends PHDocument>(document: T): T {\n const { id, slug, documentType } = document.header;\n if ((DRIVE_DOCUMENT_TYPES as readonly string[]).includes(documentType)) {\n this.ids.set(id, id);\n if (slug) {\n this.ids.set(slug, id);\n }\n }\n return document;\n }\n\n learnPage<T extends PHDocument>(page: PagedResults<T>): PagedResults<T> {\n for (const document of page.results) {\n this.learn(document);\n }\n return page;\n }\n\n driveOf(identifier: string | undefined): string | undefined {\n return identifier === undefined ? undefined : this.ids.get(identifier);\n }\n\n /** Names a drive only when this backend proved it is one. */\n driveIdFor = (call: DriveIdCall): string | undefined => {\n switch (call.method) {\n case \"create\":\n case \"find\":\n return this.driveOf(call.parentId);\n case \"execute\":\n case \"deleteDocument\":\n return this.driveOf(call.documentId);\n case \"executeBatch\":\n for (const job of call.jobs ?? []) {\n const drive = this.driveOf(job.documentId);\n if (drive !== undefined) {\n return drive;\n }\n }\n return undefined;\n }\n };\n}\n\nexport type GraphQLRoutableBackendOptions = Omit<\n GraphQLReactorClientOptions,\n \"driveIdFor\"\n>;\n\nexport type GraphQLRoutableBackend = {\n readonly backend: IRoutableBackend;\n /** The Switchboard's own facts, from its inspection subgraph. */\n info(): Promise<ReactorInfo>;\n /** Reopens the realtime socket on the new credentials. */\n notifyCredentialsChanged(): void;\n};\n\n/** A Switchboard as a router backend; members GraphQL cannot serve are absent. */\nexport function createGraphQLRoutableBackend(\n options: GraphQLRoutableBackendOptions,\n): GraphQLRoutableBackend {\n const drives = new KnownDrives();\n const gql = new GraphQLReactorClient({\n ...options,\n driveIdFor: drives.driveIdFor,\n });\n const backend: IRoutableBackend = {\n supports: { find: findIsServableOverGraphQL, pointInTimeViews: false },\n drives: gql.read.drives,\n get: async <TDocument extends PHDocument>(\n identifier: string,\n view?: ViewFilter,\n signal?: AbortSignal,\n ) => drives.learn(await gql.get<TDocument>(identifier, view, signal)),\n getMany: async <TDocument extends PHDocument>(\n ids: string[],\n view?: ViewFilter,\n signal?: AbortSignal,\n ) =>\n (await gql.getMany<TDocument>(ids, view, signal)).map((document) =>\n drives.learn(document),\n ),\n getOperations: (identifier, view, filter, paging, signal) =>\n gql.getOperations(identifier, view, filter, paging, signal),\n find: async (search, view, paging, signal) =>\n drives.learnPage(await gql.find(search, view, paging, signal)),\n isServed: (identifier, view, signal) =>\n gql.isServed(identifier, view, signal),\n getOutgoingRelationships: (source, type, view, paging, signal) =>\n gql.getOutgoingRelationships(source, type, view, paging, signal),\n getIncomingRelationships: (target, type, view, paging, signal) =>\n gql.getIncomingRelationships(target, type, view, paging, signal),\n getOutgoingRelationshipEdges: (source, type, view, paging, signal) =>\n gql.getOutgoingRelationshipEdges(source, type, view, paging, signal),\n getIncomingRelationshipEdges: (target, type, view, paging, signal) =>\n gql.getIncomingRelationshipEdges(target, type, view, paging, signal),\n subscribe: (search, callback, view) =>\n gql.subscribe(search, callback, view),\n getCreateSignaturePolicy: () => gql.getCreateSignaturePolicy(),\n getCreateProtocolVersions: (options, signal) =>\n gql.getCreateProtocolVersions(options, signal),\n create: async <TDocument extends PHDocument = PHDocument>(\n document: PHDocument,\n parent?: string,\n signal?: AbortSignal,\n ) => drives.learn(await gql.create<TDocument>(document, parent, signal)),\n execute: async <TDocument extends PHDocument>(\n identifier: string,\n branch: string,\n actions: Action[],\n signal?: AbortSignal,\n ) =>\n drives.learn(\n await gql.execute<TDocument>(identifier, branch, actions, signal),\n ),\n executeBatch: (request, signal) => gql.executeBatch(request, signal),\n deleteDocument: (identifier, propagate, signal) =>\n gql.deleteDocument(identifier, propagate, signal),\n setPreferredEditor: (identifier, editor, branch, signal) =>\n gql.setPreferredEditor(identifier, editor, branch, signal),\n getJob: async (jobId, signal) => {\n const job = await gql.getJob(jobId, signal);\n return job?.status === JobStatus.FAILED &&\n job.error?.name === JOB_NOT_FOUND_ERROR_NAME\n ? undefined\n : job;\n },\n waitForJob: (job, signal) => gql.waitForJob(job, signal),\n };\n return {\n backend,\n info: async () => {\n const result = await gql.request<RemoteReactorInfo>(REMOTE_INFO_QUERY);\n return {\n ...result.inspection.info,\n access: { admin: false, sql: false },\n };\n },\n notifyCredentialsChanged: () => gql.notifyCredentialsChanged(),\n };\n}\n","import {\n createReactorInspector,\n type ReactorInfo,\n} from \"@powerhousedao/reactor\";\nimport type {\n BrowserReactorClientModule,\n WorkerReactorClientModule,\n} from \"@powerhousedao/reactor-browser\";\nimport {\n FanInPartialFailureError,\n fromReactorClient,\n RoutingReactorClient,\n type CollectionRequirementsInput,\n type ReactorReach,\n type RoutableBackendConfig,\n type RouterDiagnostic,\n type RoutingClientOptions,\n} from \"@powerhousedao/reactor-router\";\nimport type {\n DocumentModelModule,\n ISigner,\n} from \"@powerhousedao/shared/document-model\";\nimport { logger } from \"document-model\";\nimport {\n createGraphQLRoutableBackend,\n type GraphQLRoutableBackend,\n} from \"./graphql-routable-backend.js\";\n\nexport { createGraphQLRoutableBackend } from \"./graphql-routable-backend.js\";\nexport type {\n GraphQLRoutableBackend,\n GraphQLRoutableBackendOptions,\n} from \"./graphql-routable-backend.js\";\n\nexport const LOCAL_BACKEND_NAME = \"connect-local\";\nexport const REMOTE_BACKEND_NAME = \"switchboard-remote\";\n\nexport type LocalReactorModule =\n | BrowserReactorClientModule\n | WorkerReactorClientModule;\n\nconst REMOTE_REACH: ReactorReach = Object.freeze({\n hosting: \"remote\",\n inspection: \"none\",\n});\n\n/** Only the tab's reactor is inspectable here, so new collections land on it. */\nexport const PLACE_ON_LOCAL: CollectionRequirementsInput = Object.freeze({\n inspectable: true,\n});\n\nexport function localReach(kind: LocalReactorModule[\"kind\"]): ReactorReach {\n return kind === \"worker\"\n ? { hosting: \"worker\", inspection: \"rpc\" }\n : { hosting: \"in-process\", inspection: \"direct\" };\n}\n\n/** Read at every refresh, never kept: a rebuilt reactor reports its own. */\nexport function localFacts(\n module: LocalReactorModule,\n): () => Promise<ReactorInfo> {\n if (module.kind === \"worker\") {\n return () => module.inspector.info();\n }\n return async () => {\n const reactorModule = module.reactorModule;\n if (!reactorModule) {\n throw new Error(\"The in-tab reactor exposes no module to inspect\");\n }\n return createReactorInspector(reactorModule).info();\n };\n}\n\n/** `<origin>[/<prefix>]/d/<slug>` -> `<origin>[/<prefix>]/graphql`. */\nexport function deriveSwitchboardGraphqlUrl(\n remoteDriveUrl: string,\n): string | undefined {\n let parsed: URL;\n try {\n parsed = new URL(remoteDriveUrl);\n } catch {\n return undefined;\n }\n const prefix = /^(.*)\\/d\\/[^/]+\\/?$/.exec(parsed.pathname)?.[1];\n return prefix === undefined ? undefined : `${parsed.origin}${prefix}/graphql`;\n}\n\n/** The loaded document models, or a getter that reads the current ones. */\nexport type LoadedDocumentModels =\n | readonly DocumentModelModule[]\n | (() => readonly DocumentModelModule[]);\n\nexport type MultiReactorParams = {\n /** The local module, built and ready. Undefined builds a REMOTE-ONLY router\n * (no local backend → no local reactor, no PGlite): the `remote` client. */\n module: LocalReactorModule | undefined;\n remoteGraphqlUrl: string;\n /** Signs routed writes; unsigned (anonymous) without one. */\n signer?: ISigner;\n /** Signing models when the local module exposes no registry; the router asks the local reactor (or, remote-only, the loaded set). */\n documentModelModules: LoadedDocumentModels;\n onDiagnostic?: RouterDiagnostic;\n};\n\n/** Remote-only placement: the Switchboard serves every collection. (It offers\n * no inspection surface over GraphQL, so PLACE_ON_LOCAL's `inspectable`\n * requirement must NOT apply, or no backend would be eligible.) */\nexport const PLACE_ON_REMOTE: CollectionRequirementsInput = Object.freeze({});\n\n/**\n * The local answer stands when only the Switchboard could not answer -- but\n * only when there IS a local backend. Remote-only has nothing to fall back to,\n * so its errors surface. Installed as the router's `answerFailedIdCheck`, so\n * the facade and `write.isDocumentIdTaken` both apply it.\n */\nfunction localIdCheckAnswer(\n documentId: string,\n error: unknown,\n): boolean | undefined {\n if (!failedOnlyOnRemote(error)) {\n return undefined;\n }\n logger.warn(\n \"The Switchboard could not say whether @id is taken; using the local reactor's answer: @error\",\n documentId,\n error,\n );\n return false;\n}\n\n/** The router Connect installs, with Connect's handling of credentials and id checks. */\nexport class ConnectRoutingClient extends RoutingReactorClient {\n private readonly remote: GraphQLRoutableBackend;\n\n constructor(\n backends: readonly RoutableBackendConfig[],\n options: RoutingClientOptions,\n remote: GraphQLRoutableBackend,\n hasLocal: boolean,\n ) {\n super(backends, {\n ...options,\n answerFailedIdCheck: hasLocal\n ? localIdCheckAnswer\n : options.answerFailedIdCheck,\n });\n this.remote = remote;\n }\n\n /** Renown's sign-in and sign-out call this on whatever client is installed. */\n notifyCredentialsChanged(): void {\n this.remote.notifyCredentialsChanged();\n }\n}\n\nfunction failedOnlyOnRemote(error: unknown): boolean {\n return (\n error instanceof FanInPartialFailureError &&\n error.failures.every((failure) => failure.backend === REMOTE_BACKEND_NAME)\n );\n}\n\n/**\n * Build the Connect routing client. With a local `module` it is the router\n * over the tab's reactor (primary) and the Switchboard; WITHOUT one it is the\n * `remote` client — a remote-only router whose single backend is the\n * Switchboard, so no local reactor (and no PGlite) is built. Either way the\n * result is a full IReactorClient the app graph consumes unchanged.\n */\nexport async function buildMultiReactorClient(\n params: MultiReactorParams,\n): Promise<ConnectRoutingClient> {\n const module = params.module;\n const registry = module?.reactorModule?.documentModelRegistry;\n const loaded = params.documentModelModules;\n const loadedModules = typeof loaded === \"function\" ? loaded : () => loaded;\n const remote = createGraphQLRoutableBackend({\n url: params.remoteGraphqlUrl,\n documentModels: () => registry?.getAllModules() ?? loadedModules(),\n });\n const remoteBackend: RoutableBackendConfig = {\n name: REMOTE_BACKEND_NAME,\n backend: remote.backend,\n facts: () => remote.info(),\n reach: REMOTE_REACH,\n refusesMisroutes: false,\n };\n const backends: RoutableBackendConfig[] = module\n ? [\n {\n name: LOCAL_BACKEND_NAME,\n backend: fromReactorClient(module.client),\n facts: localFacts(module),\n reach: localReach(module.kind),\n refusesMisroutes: false,\n },\n remoteBackend,\n ]\n : [remoteBackend];\n const router = new ConnectRoutingClient(\n backends,\n {\n // Remote-only: the Switchboard is primary and serves every collection;\n // with a local reactor, new collections land on it (inspectable).\n primaryBackend: module ? LOCAL_BACKEND_NAME : REMOTE_BACKEND_NAME,\n defaultRequirements: module ? PLACE_ON_LOCAL : PLACE_ON_REMOTE,\n signer: params.signer,\n onDiagnostic: params.onDiagnostic,\n // The Switchboard serves no models over GraphQL; remote-only uses the loaded set.\n documentModelModules: module ? undefined : loadedModules,\n },\n remote,\n Boolean(module),\n );\n await router.refreshFacts();\n return router;\n}\n"],"mappings":"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"}
|
|
@@ -1,182 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
JOB_NOT_FOUND_ERROR_NAME,
|
|
3
|
-
JobStatus,
|
|
4
|
-
type PagedResults,
|
|
5
|
-
type ReactorInfo,
|
|
6
|
-
type ViewFilter,
|
|
7
|
-
} from "@powerhousedao/reactor";
|
|
8
|
-
import {
|
|
9
|
-
DRIVE_DOCUMENT_TYPES,
|
|
10
|
-
findIsServableOverGraphQL,
|
|
11
|
-
GraphQLReactorClient,
|
|
12
|
-
type DriveIdCall,
|
|
13
|
-
type GraphQLReactorClientOptions,
|
|
14
|
-
} from "@powerhousedao/reactor-browser";
|
|
15
|
-
import type { IRoutableBackend } from "@powerhousedao/reactor-router";
|
|
16
|
-
import type { Action, PHDocument } from "@powerhousedao/shared/document-model";
|
|
17
|
-
|
|
18
|
-
const REMOTE_INFO_QUERY = /* GraphQL */ `
|
|
19
|
-
query RemoteReactorInfo {
|
|
20
|
-
inspection {
|
|
21
|
-
info {
|
|
22
|
-
storage {
|
|
23
|
-
engine
|
|
24
|
-
persistence
|
|
25
|
-
durable
|
|
26
|
-
selfHeal
|
|
27
|
-
}
|
|
28
|
-
workflows
|
|
29
|
-
syncChannels
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
`;
|
|
34
|
-
|
|
35
|
-
type RemoteReactorInfo = {
|
|
36
|
-
inspection: { info: Omit<ReactorInfo, "access"> };
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
/** Ids and slugs of documents this backend answered as drives, by drive id. */
|
|
40
|
-
class KnownDrives {
|
|
41
|
-
private readonly ids = new Map<string, string>();
|
|
42
|
-
|
|
43
|
-
learn<T extends PHDocument>(document: T): T {
|
|
44
|
-
const { id, slug, documentType } = document.header;
|
|
45
|
-
if ((DRIVE_DOCUMENT_TYPES as readonly string[]).includes(documentType)) {
|
|
46
|
-
this.ids.set(id, id);
|
|
47
|
-
if (slug) {
|
|
48
|
-
this.ids.set(slug, id);
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
return document;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
learnPage<T extends PHDocument>(page: PagedResults<T>): PagedResults<T> {
|
|
55
|
-
for (const document of page.results) {
|
|
56
|
-
this.learn(document);
|
|
57
|
-
}
|
|
58
|
-
return page;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
driveOf(identifier: string | undefined): string | undefined {
|
|
62
|
-
return identifier === undefined ? undefined : this.ids.get(identifier);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
/** Names a drive only when this backend proved it is one. */
|
|
66
|
-
driveIdFor = (call: DriveIdCall): string | undefined => {
|
|
67
|
-
switch (call.method) {
|
|
68
|
-
case "create":
|
|
69
|
-
case "find":
|
|
70
|
-
return this.driveOf(call.parentId);
|
|
71
|
-
case "execute":
|
|
72
|
-
case "deleteDocument":
|
|
73
|
-
return this.driveOf(call.documentId);
|
|
74
|
-
case "executeBatch":
|
|
75
|
-
for (const job of call.jobs ?? []) {
|
|
76
|
-
const drive = this.driveOf(job.documentId);
|
|
77
|
-
if (drive !== undefined) {
|
|
78
|
-
return drive;
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
return undefined;
|
|
82
|
-
}
|
|
83
|
-
};
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
export type GraphQLRoutableBackendOptions = Omit<
|
|
87
|
-
GraphQLReactorClientOptions,
|
|
88
|
-
"driveIdFor"
|
|
89
|
-
>;
|
|
90
|
-
|
|
91
|
-
export type GraphQLRoutableBackend = {
|
|
92
|
-
readonly backend: IRoutableBackend;
|
|
93
|
-
/** The Switchboard's own facts, from its inspection subgraph. */
|
|
94
|
-
info(): Promise<ReactorInfo>;
|
|
95
|
-
/** Reopens the realtime socket on the new credentials. */
|
|
96
|
-
notifyCredentialsChanged(): void;
|
|
97
|
-
};
|
|
98
|
-
|
|
99
|
-
/** A Switchboard as a router backend; members GraphQL cannot serve are absent. */
|
|
100
|
-
export function createGraphQLRoutableBackend(
|
|
101
|
-
options: GraphQLRoutableBackendOptions,
|
|
102
|
-
): GraphQLRoutableBackend {
|
|
103
|
-
const drives = new KnownDrives();
|
|
104
|
-
const gql = new GraphQLReactorClient({
|
|
105
|
-
...options,
|
|
106
|
-
driveIdFor: drives.driveIdFor,
|
|
107
|
-
});
|
|
108
|
-
const backend: IRoutableBackend = {
|
|
109
|
-
supports: { find: findIsServableOverGraphQL, pointInTimeViews: false },
|
|
110
|
-
drives: gql.read.drives,
|
|
111
|
-
get: async <TDocument extends PHDocument>(
|
|
112
|
-
identifier: string,
|
|
113
|
-
view?: ViewFilter,
|
|
114
|
-
signal?: AbortSignal,
|
|
115
|
-
) => drives.learn(await gql.get<TDocument>(identifier, view, signal)),
|
|
116
|
-
getMany: async <TDocument extends PHDocument>(
|
|
117
|
-
ids: string[],
|
|
118
|
-
view?: ViewFilter,
|
|
119
|
-
signal?: AbortSignal,
|
|
120
|
-
) =>
|
|
121
|
-
(await gql.getMany<TDocument>(ids, view, signal)).map((document) =>
|
|
122
|
-
drives.learn(document),
|
|
123
|
-
),
|
|
124
|
-
getOperations: (identifier, view, filter, paging, signal) =>
|
|
125
|
-
gql.getOperations(identifier, view, filter, paging, signal),
|
|
126
|
-
find: async (search, view, paging, signal) =>
|
|
127
|
-
drives.learnPage(await gql.find(search, view, paging, signal)),
|
|
128
|
-
isServed: (identifier, view, signal) =>
|
|
129
|
-
gql.isServed(identifier, view, signal),
|
|
130
|
-
getOutgoingRelationships: (source, type, view, paging, signal) =>
|
|
131
|
-
gql.getOutgoingRelationships(source, type, view, paging, signal),
|
|
132
|
-
getIncomingRelationships: (target, type, view, paging, signal) =>
|
|
133
|
-
gql.getIncomingRelationships(target, type, view, paging, signal),
|
|
134
|
-
getOutgoingRelationshipEdges: (source, type, view, paging, signal) =>
|
|
135
|
-
gql.getOutgoingRelationshipEdges(source, type, view, paging, signal),
|
|
136
|
-
getIncomingRelationshipEdges: (target, type, view, paging, signal) =>
|
|
137
|
-
gql.getIncomingRelationshipEdges(target, type, view, paging, signal),
|
|
138
|
-
subscribe: (search, callback, view) =>
|
|
139
|
-
gql.subscribe(search, callback, view),
|
|
140
|
-
getCreateSignaturePolicy: () => gql.getCreateSignaturePolicy(),
|
|
141
|
-
getCreateProtocolVersions: (options, signal) =>
|
|
142
|
-
gql.getCreateProtocolVersions(options, signal),
|
|
143
|
-
create: async <TDocument extends PHDocument = PHDocument>(
|
|
144
|
-
document: PHDocument,
|
|
145
|
-
parent?: string,
|
|
146
|
-
signal?: AbortSignal,
|
|
147
|
-
) => drives.learn(await gql.create<TDocument>(document, parent, signal)),
|
|
148
|
-
execute: async <TDocument extends PHDocument>(
|
|
149
|
-
identifier: string,
|
|
150
|
-
branch: string,
|
|
151
|
-
actions: Action[],
|
|
152
|
-
signal?: AbortSignal,
|
|
153
|
-
) =>
|
|
154
|
-
drives.learn(
|
|
155
|
-
await gql.execute<TDocument>(identifier, branch, actions, signal),
|
|
156
|
-
),
|
|
157
|
-
executeBatch: (request, signal) => gql.executeBatch(request, signal),
|
|
158
|
-
deleteDocument: (identifier, propagate, signal) =>
|
|
159
|
-
gql.deleteDocument(identifier, propagate, signal),
|
|
160
|
-
setPreferredEditor: (identifier, editor, branch, signal) =>
|
|
161
|
-
gql.setPreferredEditor(identifier, editor, branch, signal),
|
|
162
|
-
getJob: async (jobId, signal) => {
|
|
163
|
-
const job = await gql.getJob(jobId, signal);
|
|
164
|
-
return job?.status === JobStatus.FAILED &&
|
|
165
|
-
job.error?.name === JOB_NOT_FOUND_ERROR_NAME
|
|
166
|
-
? undefined
|
|
167
|
-
: job;
|
|
168
|
-
},
|
|
169
|
-
waitForJob: (job, signal) => gql.waitForJob(job, signal),
|
|
170
|
-
};
|
|
171
|
-
return {
|
|
172
|
-
backend,
|
|
173
|
-
info: async () => {
|
|
174
|
-
const result = await gql.request<RemoteReactorInfo>(REMOTE_INFO_QUERY);
|
|
175
|
-
return {
|
|
176
|
-
...result.inspection.info,
|
|
177
|
-
access: { admin: false, sql: false },
|
|
178
|
-
};
|
|
179
|
-
},
|
|
180
|
-
notifyCredentialsChanged: () => gql.notifyCredentialsChanged(),
|
|
181
|
-
};
|
|
182
|
-
}
|