@jini-ai/agent-plugins 0.4.7 → 0.6.10
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/CHANGELOG.md +24 -2
- package/README.md +46 -0
- package/dist/admin-surfaces/action-dispatcher.d.ts +37 -0
- package/dist/admin-surfaces/action-dispatcher.d.ts.map +1 -0
- package/dist/admin-surfaces/action-dispatcher.js +69 -0
- package/dist/admin-surfaces/action-dispatcher.js.map +1 -0
- package/dist/admin-surfaces/action-schema.d.ts +56 -0
- package/dist/admin-surfaces/action-schema.d.ts.map +1 -0
- package/dist/admin-surfaces/action-schema.js +167 -0
- package/dist/admin-surfaces/action-schema.js.map +1 -0
- package/dist/admin-surfaces/action-tools.d.ts +40 -0
- package/dist/admin-surfaces/action-tools.d.ts.map +1 -0
- package/dist/admin-surfaces/action-tools.js +52 -0
- package/dist/admin-surfaces/action-tools.js.map +1 -0
- package/dist/admin-surfaces/callback-field-inbox.d.ts +35 -0
- package/dist/admin-surfaces/callback-field-inbox.d.ts.map +1 -0
- package/dist/admin-surfaces/callback-field-inbox.js +53 -0
- package/dist/admin-surfaces/callback-field-inbox.js.map +1 -0
- package/dist/admin-surfaces/capability-declarations.d.ts +41 -0
- package/dist/admin-surfaces/capability-declarations.d.ts.map +1 -0
- package/dist/admin-surfaces/capability-declarations.js +102 -0
- package/dist/admin-surfaces/capability-declarations.js.map +1 -0
- package/dist/admin-surfaces/contribution.d.ts +49 -0
- package/dist/admin-surfaces/contribution.d.ts.map +1 -0
- package/dist/admin-surfaces/contribution.js +30 -0
- package/dist/admin-surfaces/contribution.js.map +1 -0
- package/dist/admin-surfaces/delivery-bindings.d.ts +76 -0
- package/dist/admin-surfaces/delivery-bindings.d.ts.map +1 -0
- package/dist/admin-surfaces/delivery-bindings.js +99 -0
- package/dist/admin-surfaces/delivery-bindings.js.map +1 -0
- package/dist/admin-surfaces/descriptor.d.ts +69 -0
- package/dist/admin-surfaces/descriptor.d.ts.map +1 -0
- package/dist/admin-surfaces/descriptor.js +196 -0
- package/dist/admin-surfaces/descriptor.js.map +1 -0
- package/dist/admin-surfaces/external-links.d.ts +45 -0
- package/dist/admin-surfaces/external-links.d.ts.map +1 -0
- package/dist/admin-surfaces/external-links.js +70 -0
- package/dist/admin-surfaces/external-links.js.map +1 -0
- package/dist/admin-surfaces/host-validator.d.ts +62 -0
- package/dist/admin-surfaces/host-validator.d.ts.map +1 -0
- package/dist/admin-surfaces/host-validator.js +87 -0
- package/dist/admin-surfaces/host-validator.js.map +1 -0
- package/dist/admin-surfaces/index.d.ts +23 -0
- package/dist/admin-surfaces/index.d.ts.map +1 -0
- package/dist/admin-surfaces/index.js +21 -0
- package/dist/admin-surfaces/index.js.map +1 -0
- package/dist/admin-surfaces/protocol.d.ts +103 -0
- package/dist/admin-surfaces/protocol.d.ts.map +1 -0
- package/dist/admin-surfaces/protocol.js +25 -0
- package/dist/admin-surfaces/protocol.js.map +1 -0
- package/dist/admin-surfaces/sandbox.d.ts +78 -0
- package/dist/admin-surfaces/sandbox.d.ts.map +1 -0
- package/dist/admin-surfaces/sandbox.js +92 -0
- package/dist/admin-surfaces/sandbox.js.map +1 -0
- package/dist/admin-surfaces/settings-value.d.ts +28 -0
- package/dist/admin-surfaces/settings-value.d.ts.map +1 -0
- package/dist/admin-surfaces/settings-value.js +45 -0
- package/dist/admin-surfaces/settings-value.js.map +1 -0
- package/dist/admin-surfaces/surface-capabilities.d.ts +167 -0
- package/dist/admin-surfaces/surface-capabilities.d.ts.map +1 -0
- package/dist/admin-surfaces/surface-capabilities.js +215 -0
- package/dist/admin-surfaces/surface-capabilities.js.map +1 -0
- package/dist/admin-surfaces/surface-client.d.ts +116 -0
- package/dist/admin-surfaces/surface-client.d.ts.map +1 -0
- package/dist/admin-surfaces/surface-client.js +219 -0
- package/dist/admin-surfaces/surface-client.js.map +1 -0
- package/dist/admin-surfaces/surface-handlers.d.ts +111 -0
- package/dist/admin-surfaces/surface-handlers.d.ts.map +1 -0
- package/dist/admin-surfaces/surface-handlers.js +172 -0
- package/dist/admin-surfaces/surface-handlers.js.map +1 -0
- package/dist/admin-surfaces/theme.d.ts +59 -0
- package/dist/admin-surfaces/theme.d.ts.map +1 -0
- package/dist/admin-surfaces/theme.js +57 -0
- package/dist/admin-surfaces/theme.js.map +1 -0
- package/dist/folder-zip-node.d.ts.map +1 -0
- package/dist/folder-zip-node.js +59 -49
- package/dist/folder-zip-node.js.map +1 -0
- package/dist/folder-zip.d.ts.map +1 -0
- package/dist/folder-zip.js +9 -7
- package/dist/folder-zip.js.map +1 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js.map +1 -0
- package/dist/lifecycle/activation.d.ts.map +1 -0
- package/dist/lifecycle/activation.js.map +1 -0
- package/dist/lifecycle/automatic-use.d.ts +79 -0
- package/dist/lifecycle/automatic-use.d.ts.map +1 -0
- package/dist/lifecycle/automatic-use.js +165 -0
- package/dist/lifecycle/automatic-use.js.map +1 -0
- package/dist/lifecycle/bundled-digests.d.ts.map +1 -0
- package/dist/lifecycle/bundled-digests.js.map +1 -0
- package/dist/lifecycle/bundled-source-archive.d.ts.map +1 -0
- package/dist/lifecycle/bundled-source-archive.js.map +1 -0
- package/dist/lifecycle/capability-projection.d.ts.map +1 -0
- package/dist/lifecycle/capability-projection.js.map +1 -0
- package/dist/lifecycle/compatibility-metadata.d.ts +19 -0
- package/dist/lifecycle/compatibility-metadata.d.ts.map +1 -0
- package/dist/lifecycle/compatibility-metadata.js +45 -0
- package/dist/lifecycle/compatibility-metadata.js.map +1 -0
- package/dist/lifecycle/compatibility.d.ts +52 -0
- package/dist/lifecycle/compatibility.d.ts.map +1 -0
- package/dist/lifecycle/compatibility.js +60 -0
- package/dist/lifecycle/compatibility.js.map +1 -0
- package/dist/lifecycle/contribution-loader.d.ts.map +1 -0
- package/dist/lifecycle/contribution-loader.js.map +1 -0
- package/dist/lifecycle/fetch-archive.d.ts.map +1 -0
- package/dist/lifecycle/fetch-archive.js +26 -24
- package/dist/lifecycle/fetch-archive.js.map +1 -0
- package/dist/lifecycle/index.d.ts +14 -2
- package/dist/lifecycle/index.d.ts.map +1 -0
- package/dist/lifecycle/index.js +8 -1
- package/dist/lifecycle/index.js.map +1 -0
- package/dist/lifecycle/install-errors.d.ts.map +1 -0
- package/dist/lifecycle/install-errors.js.map +1 -0
- package/dist/lifecycle/install-from-url.d.ts.map +1 -0
- package/dist/lifecycle/install-from-url.js.map +1 -0
- package/dist/lifecycle/install.d.ts.map +1 -0
- package/dist/lifecycle/install.js +7 -0
- package/dist/lifecycle/install.js.map +1 -0
- package/dist/lifecycle/installed-package-index.d.ts.map +1 -0
- package/dist/lifecycle/installed-package-index.js +41 -29
- package/dist/lifecycle/installed-package-index.js.map +1 -0
- package/dist/lifecycle/installed-package-roots.d.ts.map +1 -0
- package/dist/lifecycle/installed-package-roots.js +28 -20
- package/dist/lifecycle/installed-package-roots.js.map +1 -0
- package/dist/lifecycle/layout.d.ts.map +1 -0
- package/dist/lifecycle/layout.js.map +1 -0
- package/dist/lifecycle/manifest.d.ts +13 -0
- package/dist/lifecycle/manifest.d.ts.map +1 -0
- package/dist/lifecycle/manifest.js +115 -101
- package/dist/lifecycle/manifest.js.map +1 -0
- package/dist/lifecycle/mcp-provisioning.d.ts.map +1 -0
- package/dist/lifecycle/mcp-provisioning.js.map +1 -0
- package/dist/lifecycle/node.d.ts.map +1 -0
- package/dist/lifecycle/node.js.map +1 -0
- package/dist/lifecycle/package-paths.d.ts.map +1 -0
- package/dist/lifecycle/package-paths.js +3 -3
- package/dist/lifecycle/package-paths.js.map +1 -0
- package/dist/lifecycle/persistent-state.d.ts.map +1 -0
- package/dist/lifecycle/persistent-state.js.map +1 -0
- package/dist/lifecycle/ports.d.ts +1 -1
- package/dist/lifecycle/ports.d.ts.map +1 -0
- package/dist/lifecycle/ports.js.map +1 -0
- package/dist/lifecycle/provider-contribution.d.ts +65 -0
- package/dist/lifecycle/provider-contribution.d.ts.map +1 -0
- package/dist/lifecycle/provider-contribution.js +93 -0
- package/dist/lifecycle/provider-contribution.js.map +1 -0
- package/dist/lifecycle/resolve-agent-plugin-refs.d.ts.map +1 -0
- package/dist/lifecycle/resolve-agent-plugin-refs.js +15 -2
- package/dist/lifecycle/resolve-agent-plugin-refs.js.map +1 -0
- package/dist/lifecycle/retire-bundled.d.ts.map +1 -0
- package/dist/lifecycle/retire-bundled.js +20 -18
- package/dist/lifecycle/retire-bundled.js.map +1 -0
- package/dist/lifecycle/search.d.ts +6 -1
- package/dist/lifecycle/search.d.ts.map +1 -0
- package/dist/lifecycle/search.js +45 -7
- package/dist/lifecycle/search.js.map +1 -0
- package/dist/lifecycle/seed-bundled.d.ts.map +1 -0
- package/dist/lifecycle/seed-bundled.js.map +1 -0
- package/dist/lifecycle/set-enabled.d.ts +2 -1
- package/dist/lifecycle/set-enabled.d.ts.map +1 -0
- package/dist/lifecycle/set-enabled.js +52 -8
- package/dist/lifecycle/set-enabled.js.map +1 -0
- package/dist/lifecycle/skill-file-reader.d.ts.map +1 -0
- package/dist/lifecycle/skill-file-reader.js +85 -71
- package/dist/lifecycle/skill-file-reader.js.map +1 -0
- package/dist/lifecycle/tools/capabilities.d.ts +199 -0
- package/dist/lifecycle/tools/capabilities.d.ts.map +1 -0
- package/dist/lifecycle/tools/capabilities.js +213 -0
- package/dist/lifecycle/tools/capabilities.js.map +1 -0
- package/dist/lifecycle/tools/definition.d.ts +32 -0
- package/dist/lifecycle/tools/definition.d.ts.map +1 -0
- package/dist/lifecycle/tools/definition.js +33 -0
- package/dist/lifecycle/tools/definition.js.map +1 -0
- package/dist/lifecycle/tools/index.d.ts +10 -0
- package/dist/lifecycle/tools/index.d.ts.map +1 -0
- package/dist/lifecycle/tools/index.js +10 -0
- package/dist/lifecycle/tools/index.js.map +1 -0
- package/dist/lifecycle/tools/manifest.d.ts +33 -0
- package/dist/lifecycle/tools/manifest.d.ts.map +1 -0
- package/dist/lifecycle/tools/manifest.js +89 -0
- package/dist/lifecycle/tools/manifest.js.map +1 -0
- package/dist/lifecycle/tools/projection.d.ts +90 -0
- package/dist/lifecycle/tools/projection.d.ts.map +1 -0
- package/dist/lifecycle/tools/projection.js +283 -0
- package/dist/lifecycle/tools/projection.js.map +1 -0
- package/dist/lifecycle/trusted-plugin-files.d.ts.map +1 -0
- package/dist/lifecycle/trusted-plugin-files.js.map +1 -0
- package/dist/lifecycle/types.d.ts +2 -0
- package/dist/lifecycle/types.d.ts.map +1 -0
- package/dist/lifecycle/types.js.map +1 -0
- package/dist/lifecycle/uninstall.d.ts +3 -1
- package/dist/lifecycle/uninstall.d.ts.map +1 -0
- package/dist/lifecycle/uninstall.js +51 -27
- package/dist/lifecycle/uninstall.js.map +1 -0
- package/dist/lifecycle/update-plan.d.ts +18 -0
- package/dist/lifecycle/update-plan.d.ts.map +1 -0
- package/dist/lifecycle/update-plan.js +22 -0
- package/dist/lifecycle/update-plan.js.map +1 -0
- package/dist/lifecycle/update-store.d.ts +71 -0
- package/dist/lifecycle/update-store.d.ts.map +1 -0
- package/dist/lifecycle/update-store.js +150 -0
- package/dist/lifecycle/update-store.js.map +1 -0
- package/dist/lifecycle/update.d.ts +55 -0
- package/dist/lifecycle/update.d.ts.map +1 -0
- package/dist/lifecycle/update.js +321 -0
- package/dist/lifecycle/update.js.map +1 -0
- package/dist/lifecycle/yauzl-archive-reader.d.ts.map +1 -0
- package/dist/lifecycle/yauzl-archive-reader.js.map +1 -0
- package/dist/manifest.d.ts.map +1 -0
- package/dist/manifest.js.map +1 -0
- package/package.json +39 -7
- package/ui-ux-design/plugin.json +7 -2
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file The host capability ports a plugin's admin-surface handlers receive, and the per-call
|
|
3
|
+
* session that wraps them. Jini defines the shapes and the checks; the host implements the ports
|
|
4
|
+
* (connections backed by its API-connection service, state by its own store, public config by its
|
|
5
|
+
* own settings) and Jini never names a provider.
|
|
6
|
+
*
|
|
7
|
+
* Why surfaces get more than tools: account actions (connect, reconnect, switch account, disconnect)
|
|
8
|
+
* and saving a chosen resource are admin actions a person takes on a settings screen, so they exist
|
|
9
|
+
* here and never on the executable-tool port. Why every check sits here and not only in the host:
|
|
10
|
+
* the surfaces file is the shipped, digest-checked allowlist, so the session refuses anything the
|
|
11
|
+
* surface did not declare (a connection, a start parameter, a callback field, a config name) before
|
|
12
|
+
* the host sees it, and a host that answers with more than the port promises (a connection ref, raw
|
|
13
|
+
* scopes, undeclared callback fields) is cut back to the declared shape. Like the tool session it
|
|
14
|
+
* revokes everything once the plugin is disabled and withholds results and errors that mention a
|
|
15
|
+
* token the plugin obtained (in this call, an earlier one, or one of its tools); it also refuses to persist
|
|
16
|
+
* such a token in plugin state.
|
|
17
|
+
*/
|
|
18
|
+
import { checkedStateKey, guardSharedCapabilities, guardStateReader, openCapabilityGate, } from '../lifecycle/tools/capabilities.js';
|
|
19
|
+
import { guardDeliveryBindings } from './delivery-bindings.js';
|
|
20
|
+
import { storedStateValue } from './settings-value.js';
|
|
21
|
+
// Moved to `./settings-value.ts` so delivery-binding config shares the exact checks; re-exported so callers keep importing them here.
|
|
22
|
+
export { ADMIN_SURFACE_STATE_LIMITS, STATE_CREDENTIAL_MESSAGE } from './settings-value.js';
|
|
23
|
+
/**
|
|
24
|
+
* The API-connection start intent each account action maps to (`ApiConnectionIntent` in
|
|
25
|
+
* `@jini-ai/integrations/api-connections`, mirrored because agent-plugins does not depend on it), so a
|
|
26
|
+
* host passes `ADMIN_SURFACE_ACTION_INTENTS[action]` straight to `start`. `reconnect` and `add-scopes`
|
|
27
|
+
* are a same-account `connect` with the scope sets the handler passes (`add-scopes` re-consents for
|
|
28
|
+
* more of them); `switch` stages another account.
|
|
29
|
+
*/
|
|
30
|
+
export const ADMIN_SURFACE_ACTION_INTENTS = Object.freeze({
|
|
31
|
+
connect: 'connect', reconnect: 'connect', switch: 'switch-account', 'add-scopes': 'connect',
|
|
32
|
+
});
|
|
33
|
+
const ACTIONS = Object.keys(ADMIN_SURFACE_ACTION_INTENTS);
|
|
34
|
+
const SCOPE_SET_ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/;
|
|
35
|
+
const ATTEMPT_ID_PATTERN = /^[A-Za-z0-9_-]{1,128}$/;
|
|
36
|
+
const MAX_SCOPE_SETS = 16;
|
|
37
|
+
const MAX_START_PARAM_LENGTH = 2048;
|
|
38
|
+
/** Names in messages come from plugin code: cut them so a message stays a message. */
|
|
39
|
+
const named = (value) => String(value).slice(0, 64);
|
|
40
|
+
const isRecord = (value) => typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
41
|
+
function declaredConnection(declared, connectionId) {
|
|
42
|
+
const found = declared.find((connection) => connection.id === connectionId);
|
|
43
|
+
if (found === undefined)
|
|
44
|
+
throw new Error(`This admin surface does not declare connection '${named(connectionId)}', so its handlers cannot use it. Declare it in the surface's connections.`);
|
|
45
|
+
return found;
|
|
46
|
+
}
|
|
47
|
+
/** A copy of the start parameters, every name declared for this connection and every value a bounded string. @complexity O(p). */
|
|
48
|
+
function checkedStartParams(connection, startParams) {
|
|
49
|
+
if (!isRecord(startParams))
|
|
50
|
+
throw new Error('Start parameters must be an object of strings.');
|
|
51
|
+
for (const [name, value] of Object.entries(startParams)) {
|
|
52
|
+
if (!connection.startParams.includes(name))
|
|
53
|
+
throw new Error(`Start parameter '${named(name)}' is not declared for connection '${connection.id}' on this admin surface.`);
|
|
54
|
+
if (typeof value !== 'string' || value.length > MAX_START_PARAM_LENGTH)
|
|
55
|
+
throw new Error(`Start parameter '${name}' must be a string of at most ${MAX_START_PARAM_LENGTH} characters.`);
|
|
56
|
+
}
|
|
57
|
+
return { ...startParams };
|
|
58
|
+
}
|
|
59
|
+
function checkedScopeSetIds(scopeSetIds) {
|
|
60
|
+
const valid = Array.isArray(scopeSetIds) && scopeSetIds.length <= MAX_SCOPE_SETS && scopeSetIds.every((id) => typeof id === 'string' && SCOPE_SET_ID_PATTERN.test(id));
|
|
61
|
+
if (!valid)
|
|
62
|
+
throw new Error(`Scope sets must be at most ${MAX_SCOPE_SETS} short ids.`);
|
|
63
|
+
return [...scopeSetIds];
|
|
64
|
+
}
|
|
65
|
+
/** The begin options the host receives: only the ones the handler passed, checked and copied. */
|
|
66
|
+
function beginOptions(connection, optional = {}) {
|
|
67
|
+
return {
|
|
68
|
+
...(optional.scopeSetIds !== undefined && { scopeSetIds: checkedScopeSetIds(optional.scopeSetIds) }),
|
|
69
|
+
...(optional.startParams !== undefined && { startParams: checkedStartParams(connection, optional.startParams) }),
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
const SAFE_CODE_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
73
|
+
const MAX_SAFE_CODE_LENGTH = 64;
|
|
74
|
+
const isSafeCode = (value) => typeof value === 'string' && value.length <= MAX_SAFE_CODE_LENGTH && SAFE_CODE_PATTERN.test(value);
|
|
75
|
+
/** Only `code` and `nextAction`, and only when both are safe codes: a host that forwarded provider
|
|
76
|
+
* text (an error description) by mistake must not put it in front of the person or the plugin. */
|
|
77
|
+
function toSignInAttempt(attempt) {
|
|
78
|
+
if (typeof attempt !== 'object' || attempt === null)
|
|
79
|
+
return null;
|
|
80
|
+
const { code, nextAction } = attempt;
|
|
81
|
+
return isSafeCode(code) && isSafeCode(nextAction) ? { code, nextAction } : null;
|
|
82
|
+
}
|
|
83
|
+
/** The status shape the port promises, whatever else the host's object carried. */
|
|
84
|
+
function toStatus(connectionId, status) {
|
|
85
|
+
return {
|
|
86
|
+
connectionId, status: status.status, accountLabel: status.accountLabel ?? null,
|
|
87
|
+
grantedScopeSetIds: [...status.grantedScopeSetIds], pendingSwitchAccountLabel: status.pendingSwitchAccountLabel ?? null,
|
|
88
|
+
lastSignInAttempt: toSignInAttempt(status.lastSignInAttempt),
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
/** Only this connection's declared callback fields, as strings; anything else the host returned is dropped. */
|
|
92
|
+
function declaredCallbackFields(connection, fields) {
|
|
93
|
+
if (fields === null)
|
|
94
|
+
return null;
|
|
95
|
+
return Object.fromEntries(connection.callbackFields.filter((name) => typeof fields[name] === 'string').map((name) => [name, fields[name]]));
|
|
96
|
+
}
|
|
97
|
+
/** Account actions run for a person; a call without one (a background route) is refused. */
|
|
98
|
+
function requireActor(actorId) {
|
|
99
|
+
if (actorId === undefined)
|
|
100
|
+
throw new Error('Account actions need a signed-in admin. Open the surface from an authenticated admin page and retry.');
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* A token is handed out (to a handler, and through bootstrap data to the frame) only for a signed-in
|
|
104
|
+
* admin: a route without one must not mint a bearer token a frame keeps until it expires. Disabling
|
|
105
|
+
* the plugin cannot recall a token already handed out; disconnecting revokes it at the provider.
|
|
106
|
+
*/
|
|
107
|
+
function requireTokenActor(actorId) {
|
|
108
|
+
if (actorId === undefined)
|
|
109
|
+
throw new Error('Connection access needs a signed-in admin. Open the surface from an authenticated admin page and retry.');
|
|
110
|
+
}
|
|
111
|
+
/** The read side: a token (noted for the scans) and token-free status. */
|
|
112
|
+
function readConnections({ gate, host, declared, actorId }) {
|
|
113
|
+
return {
|
|
114
|
+
getAccessToken: gate.guard(async ({ connectionId }) => {
|
|
115
|
+
const { id } = declaredConnection(declared, connectionId);
|
|
116
|
+
requireTokenActor(actorId);
|
|
117
|
+
return gate.noteToken({ token: await host.getAccessToken({ connectionId: id }) });
|
|
118
|
+
}),
|
|
119
|
+
status: gate.guard(async ({ connectionId }) => {
|
|
120
|
+
const { id } = declaredConnection(declared, connectionId);
|
|
121
|
+
return toStatus(id, await host.status({ connectionId: id }));
|
|
122
|
+
}),
|
|
123
|
+
takeCallbackFields: gate.guard(async ({ connectionId, attemptId }) => {
|
|
124
|
+
const connection = declaredConnection(declared, connectionId);
|
|
125
|
+
if (typeof attemptId !== 'string' || !ATTEMPT_ID_PATTERN.test(attemptId))
|
|
126
|
+
throw new Error('The sign-in attempt id is not valid; start the sign-in again.');
|
|
127
|
+
return declaredCallbackFields(connection, await host.takeCallbackFields({ connectionId: connection.id, attemptId }));
|
|
128
|
+
}),
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
/** The account actions: declared connection, declared start parameters, a signed-in admin. */
|
|
132
|
+
function actConnections({ gate, host, declared, actorId }) {
|
|
133
|
+
const forActor = (connectionId) => { requireActor(actorId); return declaredConnection(declared, connectionId); };
|
|
134
|
+
const statusAction = (run) => gate.guard(async ({ connectionId }) => {
|
|
135
|
+
const { id } = forActor(connectionId);
|
|
136
|
+
return toStatus(id, await run({ connectionId: id }));
|
|
137
|
+
});
|
|
138
|
+
return {
|
|
139
|
+
begin: gate.guard(async ({ connectionId, action }, optional) => {
|
|
140
|
+
const connection = forActor(connectionId);
|
|
141
|
+
if (!ACTIONS.includes(action))
|
|
142
|
+
throw new Error(`Account action '${named(action)}' is not one of ${ACTIONS.join(', ')}.`);
|
|
143
|
+
const started = await host.begin({ connectionId: connection.id, action }, beginOptions(connection, optional));
|
|
144
|
+
return { authorizationUrl: started.authorizationUrl, attemptId: started.attemptId, expiresAt: started.expiresAt };
|
|
145
|
+
}),
|
|
146
|
+
confirmSwitch: statusAction((input) => host.confirmSwitch(input)),
|
|
147
|
+
cancelSwitch: statusAction((input) => host.cancelSwitch(input)),
|
|
148
|
+
disconnect: gate.guard(async ({ connectionId }) => {
|
|
149
|
+
const { id } = forActor(connectionId);
|
|
150
|
+
const outcome = await host.disconnect({ connectionId: id });
|
|
151
|
+
return { ...toStatus(id, outcome), revocation: outcome.revocation };
|
|
152
|
+
}),
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
function guardState(gate, host) {
|
|
156
|
+
return Object.freeze({
|
|
157
|
+
...guardStateReader({ gate, state: host }),
|
|
158
|
+
set: gate.guard(async ({ key, value }) => host.set({ key: checkedStateKey({ key }), value: storedStateValue({ gate, value }) })),
|
|
159
|
+
delete: gate.guard(({ key }) => host.delete({ key: checkedStateKey({ key }) })),
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
function guardPublicConfig(gate, host, declared) {
|
|
163
|
+
return Object.freeze({
|
|
164
|
+
get: gate.guard(async ({ name }) => {
|
|
165
|
+
if (!declared.includes(name))
|
|
166
|
+
throw new Error(`This admin surface does not declare public config '${named(name)}'. Declare it in the surface's publicConfig.`);
|
|
167
|
+
return host.get({ name });
|
|
168
|
+
}),
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
/** Read-only discovery shares revocation and actor checks with other surface-only ports. Unknown
|
|
172
|
+
* host fields never reach a handler; collection and string caps bound the disclosure.
|
|
173
|
+
* @complexity O(min(f, 200)) time/space for f host forms, one workspace read. */
|
|
174
|
+
function guardForms(required, optional = {}) {
|
|
175
|
+
const { gate, host } = required;
|
|
176
|
+
return Object.freeze({
|
|
177
|
+
list: gate.guard(async (_input, _options = {}) => {
|
|
178
|
+
requireActor(optional.actorId);
|
|
179
|
+
const forms = await host.list({});
|
|
180
|
+
return forms.slice(0, 200).map(({ slug, title }) => {
|
|
181
|
+
if (typeof slug !== 'string' || slug.length === 0 || slug.length > 64 || typeof title !== 'string')
|
|
182
|
+
throw new Error('The forms host returned an invalid form choice.');
|
|
183
|
+
return { slug, title: title.slice(0, 1024) };
|
|
184
|
+
});
|
|
185
|
+
}),
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Opens the capability session for one admin-surface handler call.
|
|
190
|
+
* @param required.capabilities - The host's ports for this call (already scoped to plugin, workspace, principal).
|
|
191
|
+
* @param required.isLive - False once the plugin's surface handlers are revoked.
|
|
192
|
+
* @param required.declared - The surface's own capability declarations (the allowlists).
|
|
193
|
+
* @param required.issued - The plugin's token memory, shared by all its calls (tools included).
|
|
194
|
+
* @param optional.actorId - The signed-in admin; account actions are refused without one.
|
|
195
|
+
* @returns Wrapped capabilities plus the shared `release` (result) and `sanitize` (error) gates.
|
|
196
|
+
* @complexity O(1) to open; each check is bounded by the declared lists and the value caps.
|
|
197
|
+
*/
|
|
198
|
+
export function openAdminSurfaceCapabilitySession(required, optional = {}) {
|
|
199
|
+
const { capabilities: host, isLive, declared, issued } = required;
|
|
200
|
+
const gate = openCapabilityGate({ isLive, issued });
|
|
201
|
+
const input = { gate, host: host.connections, declared: declared.connections ?? [], actorId: optional.actorId };
|
|
202
|
+
const { deliveryAdapters } = declared;
|
|
203
|
+
const deliveryBindings = deliveryAdapters === undefined || host.deliveryBindings === undefined ? undefined
|
|
204
|
+
: guardDeliveryBindings({ gate, host: host.deliveryBindings, adapterIds: deliveryAdapters, connectionIds: input.declared.map((connection) => connection.id) }, { actorId: optional.actorId });
|
|
205
|
+
const capabilities = Object.freeze({
|
|
206
|
+
...guardSharedCapabilities({ gate, host }),
|
|
207
|
+
connections: Object.freeze({ ...readConnections(input), ...actConnections(input) }),
|
|
208
|
+
state: guardState(gate, host.state),
|
|
209
|
+
publicConfig: guardPublicConfig(gate, host.publicConfig, declared.publicConfig ?? []),
|
|
210
|
+
...(deliveryBindings && { deliveryBindings }),
|
|
211
|
+
...(declared.forms?.includes('list') && host.forms !== undefined && { forms: guardForms({ gate, host: host.forms }, optional) }),
|
|
212
|
+
});
|
|
213
|
+
return { capabilities, release: gate.release, sanitize: gate.sanitize };
|
|
214
|
+
}
|
|
215
|
+
//# sourceMappingURL=surface-capabilities.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"surface-capabilities.js","sourceRoot":"","sources":["../../src/admin-surfaces/surface-capabilities.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file The surface-side half of the admin-surface message protocol, for a plugin's own UI.
|
|
3
|
+
*
|
|
4
|
+
* Self-contained on purpose (no imports): a plugin's surface is plain static files, so it may import
|
|
5
|
+
* this module from the package or copy the compiled file next to its entry. The constants repeat
|
|
6
|
+
* `./protocol.ts`; the vertical-slice test proves the two still agree.
|
|
7
|
+
*
|
|
8
|
+
* Trust rules it applies: it accepts init only from its parent window (once), learns the host's
|
|
9
|
+
* origin from that init and posts only to that origin (never "*"), and accepts a response only from
|
|
10
|
+
* the parent, from that origin, for this mount, for a request it still has pending, in a valid shape.
|
|
11
|
+
*
|
|
12
|
+
* Theme: the host may send its design tokens with init and again in `theme` messages (`./theme.ts`).
|
|
13
|
+
* The client applies the `--jini-*` ones with a safe value as custom properties on the surface's root
|
|
14
|
+
* element (CSSOM `setProperty`, which a CSP without 'unsafe-inline' allows), plus `color-scheme` and
|
|
15
|
+
* `data-jini-scheme`, so the surface's own stylesheet can follow the admin's look and light/dark mode.
|
|
16
|
+
*/
|
|
17
|
+
/** The parts of `window.parent` the client uses. */
|
|
18
|
+
export interface AdminSurfaceParentPort {
|
|
19
|
+
postMessage(message: unknown, targetOrigin: string): void;
|
|
20
|
+
}
|
|
21
|
+
/** The fields of a `MessageEvent` the client reads. */
|
|
22
|
+
export interface AdminSurfaceIncomingMessage {
|
|
23
|
+
readonly origin: string;
|
|
24
|
+
readonly source: unknown;
|
|
25
|
+
readonly data: unknown;
|
|
26
|
+
}
|
|
27
|
+
/** Subscribes to `message` events; returns the unsubscribe function. */
|
|
28
|
+
export type AdminSurfaceListenPort = (handler: (event: AdminSurfaceIncomingMessage) => void) => () => void;
|
|
29
|
+
/** The element the host's tokens are applied to (in a browser, `document.documentElement`). */
|
|
30
|
+
export interface AdminSurfaceThemeRoot {
|
|
31
|
+
readonly style: {
|
|
32
|
+
setProperty(name: string, value: string): void;
|
|
33
|
+
removeProperty(name: string): void;
|
|
34
|
+
};
|
|
35
|
+
setAttribute(name: string, value: string): void;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Reports the surface's content height in CSS pixels whenever it may have changed; returns the stop
|
|
39
|
+
* function. The host sizes the frame to it, so a surface never scrolls inside the admin page.
|
|
40
|
+
*/
|
|
41
|
+
export type AdminSurfaceSizePort = (onHeight: (height: number) => void) => () => void;
|
|
42
|
+
/** The body element the default size source measures and listens on (in a browser, `document.body`). */
|
|
43
|
+
export interface AdminSurfaceSizedBody {
|
|
44
|
+
readonly scrollHeight: number;
|
|
45
|
+
getBoundingClientRect(): {
|
|
46
|
+
readonly height: number;
|
|
47
|
+
};
|
|
48
|
+
addEventListener(type: 'mouseover' | 'focusin', listener: () => void): void;
|
|
49
|
+
removeEventListener(type: 'mouseover' | 'focusin', listener: () => void): void;
|
|
50
|
+
}
|
|
51
|
+
/** An observer constructor the default size source re-measures from (Resize/MutationObserver). */
|
|
52
|
+
export type AdminSurfaceObserverConstructor = new (callback: () => void) => {
|
|
53
|
+
observe(target: AdminSurfaceSizedBody, options?: Readonly<Record<string, boolean>>): void;
|
|
54
|
+
disconnect(): void;
|
|
55
|
+
};
|
|
56
|
+
/**
|
|
57
|
+
* The browser globals the default theme root and size source read. Injectable so the defaults are
|
|
58
|
+
* testable without a DOM; `globalThis` is wired in at the client's composition edge.
|
|
59
|
+
*/
|
|
60
|
+
export interface AdminSurfaceBrowserScope {
|
|
61
|
+
readonly document?: {
|
|
62
|
+
readonly documentElement?: AdminSurfaceThemeRoot;
|
|
63
|
+
readonly body?: AdminSurfaceSizedBody | null;
|
|
64
|
+
};
|
|
65
|
+
readonly ResizeObserver?: AdminSurfaceObserverConstructor;
|
|
66
|
+
readonly MutationObserver?: AdminSurfaceObserverConstructor;
|
|
67
|
+
readonly getComputedStyle?: (element: AdminSurfaceSizedBody) => {
|
|
68
|
+
readonly marginTop: string;
|
|
69
|
+
readonly marginBottom: string;
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
/** The host's design tokens as the client accepted them. */
|
|
73
|
+
export interface AdminSurfaceClientTheme {
|
|
74
|
+
readonly scheme: 'light' | 'dark';
|
|
75
|
+
readonly tokens: Readonly<Record<string, string>>;
|
|
76
|
+
}
|
|
77
|
+
export interface AdminSurfaceClientFailure {
|
|
78
|
+
readonly code: string;
|
|
79
|
+
readonly message: string;
|
|
80
|
+
readonly retryable: boolean;
|
|
81
|
+
}
|
|
82
|
+
/** Rejection value of `call` when the host refused the action or the request timed out. */
|
|
83
|
+
export declare class AdminSurfaceCallError extends Error {
|
|
84
|
+
readonly code: string;
|
|
85
|
+
readonly retryable: boolean;
|
|
86
|
+
constructor(required: AdminSurfaceClientFailure);
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Connects a surface to its host. In a browser:
|
|
90
|
+
* `createAdminSurfaceClient({ parent: window.parent, listen: (h) => { addEventListener('message', h); return () => removeEventListener('message', h); } })`.
|
|
91
|
+
* @param optional.timeoutMs - How long `call` waits for a response before rejecting with `timeout`.
|
|
92
|
+
* @complexity O(1) per message.
|
|
93
|
+
*/
|
|
94
|
+
export declare function createAdminSurfaceClient(required: {
|
|
95
|
+
readonly parent: AdminSurfaceParentPort;
|
|
96
|
+
readonly listen: AdminSurfaceListenPort;
|
|
97
|
+
}, optional?: {
|
|
98
|
+
readonly timeoutMs?: number;
|
|
99
|
+
readonly nowMs?: () => number;
|
|
100
|
+
readonly themeRoot?: AdminSurfaceThemeRoot | null;
|
|
101
|
+
readonly size?: AdminSurfaceSizePort | null;
|
|
102
|
+
readonly browser?: AdminSurfaceBrowserScope;
|
|
103
|
+
}): {
|
|
104
|
+
ready: Promise<void>;
|
|
105
|
+
call: (input: {
|
|
106
|
+
readonly action: string;
|
|
107
|
+
readonly payload: unknown;
|
|
108
|
+
}) => Promise<unknown>;
|
|
109
|
+
openLink: (input: {
|
|
110
|
+
readonly url: string;
|
|
111
|
+
}) => Promise<void>;
|
|
112
|
+
bootstrap: () => unknown;
|
|
113
|
+
theme: () => AdminSurfaceClientTheme | undefined;
|
|
114
|
+
close: () => void;
|
|
115
|
+
};
|
|
116
|
+
//# sourceMappingURL=surface-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"surface-client.d.ts","sourceRoot":"","sources":["../../src/admin-surfaces/surface-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file The surface-side half of the admin-surface message protocol, for a plugin's own UI.
|
|
3
|
+
*
|
|
4
|
+
* Self-contained on purpose (no imports): a plugin's surface is plain static files, so it may import
|
|
5
|
+
* this module from the package or copy the compiled file next to its entry. The constants repeat
|
|
6
|
+
* `./protocol.ts`; the vertical-slice test proves the two still agree.
|
|
7
|
+
*
|
|
8
|
+
* Trust rules it applies: it accepts init only from its parent window (once), learns the host's
|
|
9
|
+
* origin from that init and posts only to that origin (never "*"), and accepts a response only from
|
|
10
|
+
* the parent, from that origin, for this mount, for a request it still has pending, in a valid shape.
|
|
11
|
+
*
|
|
12
|
+
* Theme: the host may send its design tokens with init and again in `theme` messages (`./theme.ts`).
|
|
13
|
+
* The client applies the `--jini-*` ones with a safe value as custom properties on the surface's root
|
|
14
|
+
* element (CSSOM `setProperty`, which a CSP without 'unsafe-inline' allows), plus `color-scheme` and
|
|
15
|
+
* `data-jini-scheme`, so the surface's own stylesheet can follow the admin's look and light/dark mode.
|
|
16
|
+
*/
|
|
17
|
+
const PROTOCOL = 'jini.admin-surface';
|
|
18
|
+
const VERSION = 1;
|
|
19
|
+
const DEFAULT_TIMEOUT_MS = 30_000;
|
|
20
|
+
const THEME_TOKEN = /^--jini-[a-z0-9-]{1,60}$/;
|
|
21
|
+
const UNSAFE_THEME_VALUE = /url\(|image\(|image-set\(|[;{}<>\\@]/i;
|
|
22
|
+
const MAX_THEME_TOKENS = 100;
|
|
23
|
+
/** Rejection value of `call` when the host refused the action or the request timed out. */
|
|
24
|
+
export class AdminSurfaceCallError extends Error {
|
|
25
|
+
code;
|
|
26
|
+
retryable;
|
|
27
|
+
constructor(required) {
|
|
28
|
+
super(required.message);
|
|
29
|
+
this.name = 'AdminSurfaceCallError';
|
|
30
|
+
this.code = required.code;
|
|
31
|
+
this.retryable = required.retryable;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
function isMessage(data, kind) {
|
|
35
|
+
if (typeof data !== 'object' || data === null)
|
|
36
|
+
return false;
|
|
37
|
+
const message = data;
|
|
38
|
+
return message.protocol === PROTOCOL && message.version === VERSION && message.kind === kind;
|
|
39
|
+
}
|
|
40
|
+
function isFailure(value) {
|
|
41
|
+
if (typeof value !== 'object' || value === null)
|
|
42
|
+
return false;
|
|
43
|
+
const error = value;
|
|
44
|
+
return typeof error.code === 'string' && typeof error.message === 'string' && typeof error.retryable === 'boolean';
|
|
45
|
+
}
|
|
46
|
+
/** The host's theme with every unknown name or unsafe value dropped; undefined when it is not a theme. */
|
|
47
|
+
function acceptedTheme(value) {
|
|
48
|
+
if (typeof value !== 'object' || value === null)
|
|
49
|
+
return undefined;
|
|
50
|
+
const { scheme, tokens } = value;
|
|
51
|
+
if ((scheme !== 'light' && scheme !== 'dark') || typeof tokens !== 'object' || tokens === null)
|
|
52
|
+
return undefined;
|
|
53
|
+
const safe = Object.entries(tokens).slice(0, MAX_THEME_TOKENS).filter(([name, token]) => THEME_TOKEN.test(name)
|
|
54
|
+
&& typeof token === 'string' && token.length > 0 && token.length <= 200 && !UNSAFE_THEME_VALUE.test(token));
|
|
55
|
+
return { scheme, tokens: Object.fromEntries(safe) };
|
|
56
|
+
}
|
|
57
|
+
/** The browser root when there is a document (none in a server-side test). */
|
|
58
|
+
function documentRoot(scope) {
|
|
59
|
+
return scope.document?.documentElement ?? null;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* The browser's size source: the body's height including what overflows it (an open toggletip), re-read
|
|
63
|
+
* on resize, DOM changes, hover and focus (hover/focus can show a CSS-only tooltip). Null without a DOM.
|
|
64
|
+
*/
|
|
65
|
+
function documentSize(scope) {
|
|
66
|
+
const body = scope.document?.body;
|
|
67
|
+
if (!body || !scope.ResizeObserver || !scope.MutationObserver || !scope.getComputedStyle)
|
|
68
|
+
return null;
|
|
69
|
+
const { ResizeObserver: Resize, MutationObserver: Mutation, getComputedStyle: computedStyle } = scope;
|
|
70
|
+
return (onHeight) => {
|
|
71
|
+
const measure = () => {
|
|
72
|
+
const style = computedStyle(body);
|
|
73
|
+
// scrollHeight is rounded to whole pixels; the box height keeps the fraction, which would
|
|
74
|
+
// otherwise leave a 1px inner scrollbar.
|
|
75
|
+
const content = Math.max(body.scrollHeight, body.getBoundingClientRect().height);
|
|
76
|
+
onHeight(Math.ceil(content + parseFloat(style.marginTop || '0') + parseFloat(style.marginBottom || '0')));
|
|
77
|
+
};
|
|
78
|
+
const resize = new Resize(measure);
|
|
79
|
+
const mutation = new Mutation(measure);
|
|
80
|
+
resize.observe(body);
|
|
81
|
+
mutation.observe(body, { subtree: true, childList: true, attributes: true, characterData: true });
|
|
82
|
+
body.addEventListener('mouseover', measure);
|
|
83
|
+
body.addEventListener('focusin', measure);
|
|
84
|
+
measure();
|
|
85
|
+
return () => { resize.disconnect(); mutation.disconnect(); body.removeEventListener('mouseover', measure); body.removeEventListener('focusin', measure); };
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
/** A response has `ok: true` with a result, or `ok: false` with a well-formed failure. */
|
|
89
|
+
function isWellFormedResponse(message) {
|
|
90
|
+
return message.ok === true ? Object.hasOwn(message, 'result') : message.ok === false && isFailure(message.error);
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Connects a surface to its host. In a browser:
|
|
94
|
+
* `createAdminSurfaceClient({ parent: window.parent, listen: (h) => { addEventListener('message', h); return () => removeEventListener('message', h); } })`.
|
|
95
|
+
* @param optional.timeoutMs - How long `call` waits for a response before rejecting with `timeout`.
|
|
96
|
+
* @complexity O(1) per message.
|
|
97
|
+
*/
|
|
98
|
+
export function createAdminSurfaceClient(required, optional = {}) {
|
|
99
|
+
const timeoutMs = optional.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
100
|
+
const nowMs = optional.nowMs ?? Date.now;
|
|
101
|
+
const pending = new Map();
|
|
102
|
+
let init;
|
|
103
|
+
let nextRequest = 0;
|
|
104
|
+
// The Promise executor runs synchronously, so `resolveReady` is assigned before anything can call it.
|
|
105
|
+
let resolveReady;
|
|
106
|
+
const ready = new Promise((resolve) => { resolveReady = resolve; });
|
|
107
|
+
// The DOM's own observer/element types are wider than the structural subset this client reads.
|
|
108
|
+
const browser = optional.browser ?? globalThis;
|
|
109
|
+
const themeRoot = optional.themeRoot === undefined ? documentRoot(browser) : optional.themeRoot;
|
|
110
|
+
let currentTheme;
|
|
111
|
+
const size = optional.size === undefined ? documentSize(browser) : optional.size;
|
|
112
|
+
let stopSize;
|
|
113
|
+
let lastHeight = -1;
|
|
114
|
+
/** Tells the host this surface's height (only when it changed), so the frame fits its content. */
|
|
115
|
+
function reportHeight(height) {
|
|
116
|
+
if (init === undefined || !Number.isFinite(height) || height === lastHeight)
|
|
117
|
+
return;
|
|
118
|
+
lastHeight = height;
|
|
119
|
+
required.parent.postMessage({ protocol: PROTOCOL, version: VERSION, kind: 'resize', mountId: init.mountId, height }, init.origin);
|
|
120
|
+
}
|
|
121
|
+
/** Replaces the applied tokens: a token the new theme no longer sends falls back to the surface's CSS. */
|
|
122
|
+
function applyTheme(value) {
|
|
123
|
+
const next = acceptedTheme(value);
|
|
124
|
+
if (next === undefined)
|
|
125
|
+
return;
|
|
126
|
+
if (themeRoot !== null) {
|
|
127
|
+
for (const name of Object.keys(currentTheme?.tokens ?? {}))
|
|
128
|
+
if (!(name in next.tokens))
|
|
129
|
+
themeRoot.style.removeProperty(name);
|
|
130
|
+
for (const [name, token] of Object.entries(next.tokens))
|
|
131
|
+
themeRoot.style.setProperty(name, token);
|
|
132
|
+
themeRoot.style.setProperty('color-scheme', next.scheme);
|
|
133
|
+
themeRoot.setAttribute('data-jini-scheme', next.scheme);
|
|
134
|
+
}
|
|
135
|
+
currentTheme = next;
|
|
136
|
+
}
|
|
137
|
+
function onInit(event, data) {
|
|
138
|
+
if (init !== undefined || typeof data.mountId !== 'string')
|
|
139
|
+
return;
|
|
140
|
+
init = { mountId: data.mountId, origin: event.origin, bootstrap: data.bootstrap };
|
|
141
|
+
applyTheme(data.theme);
|
|
142
|
+
stopSize = size?.(reportHeight);
|
|
143
|
+
resolveReady();
|
|
144
|
+
}
|
|
145
|
+
function onResponse(event, data) {
|
|
146
|
+
if (event.origin !== init?.origin || data.mountId !== init.mountId || typeof data.requestId !== 'string')
|
|
147
|
+
return;
|
|
148
|
+
const waiting = pending.get(data.requestId);
|
|
149
|
+
if (waiting === undefined || !isWellFormedResponse(data))
|
|
150
|
+
return;
|
|
151
|
+
pending.delete(data.requestId);
|
|
152
|
+
clearTimeout(waiting.timer);
|
|
153
|
+
if (data.ok === true)
|
|
154
|
+
waiting.resolve(data.result);
|
|
155
|
+
else
|
|
156
|
+
waiting.reject(new AdminSurfaceCallError(data.error));
|
|
157
|
+
}
|
|
158
|
+
const unsubscribe = required.listen((event) => {
|
|
159
|
+
if (event.source !== required.parent)
|
|
160
|
+
return;
|
|
161
|
+
if (isMessage(event.data, 'init'))
|
|
162
|
+
onInit(event, event.data);
|
|
163
|
+
else if (isMessage(event.data, 'theme')) {
|
|
164
|
+
if (event.origin === init?.origin && event.data.mountId === init.mountId)
|
|
165
|
+
applyTheme(event.data.theme);
|
|
166
|
+
}
|
|
167
|
+
else if (isMessage(event.data, 'action-response'))
|
|
168
|
+
onResponse(event, event.data);
|
|
169
|
+
});
|
|
170
|
+
/** Posts one request of `kind` to the host origin and waits for its `action-response`. */
|
|
171
|
+
async function send(kind, fields) {
|
|
172
|
+
if (init === undefined)
|
|
173
|
+
await ready;
|
|
174
|
+
const { mountId, origin } = init;
|
|
175
|
+
nextRequest += 1;
|
|
176
|
+
const requestId = `r${nextRequest}`;
|
|
177
|
+
return new Promise((resolve, reject) => {
|
|
178
|
+
const timer = setTimeout(() => {
|
|
179
|
+
pending.delete(requestId);
|
|
180
|
+
reject(new AdminSurfaceCallError({ code: 'timeout', message: 'The host did not answer in time. Try again.', retryable: true }));
|
|
181
|
+
}, timeoutMs);
|
|
182
|
+
pending.set(requestId, { resolve, reject, timer });
|
|
183
|
+
required.parent.postMessage({ protocol: PROTOCOL, version: VERSION, kind, mountId, requestId, ...fields }, origin);
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
/** Asks the host to run one declared action; resolves with its result. */
|
|
187
|
+
function call(input) {
|
|
188
|
+
return send('action-request', { action: input.action, payload: input.payload });
|
|
189
|
+
}
|
|
190
|
+
/** Asks the host to open `url` outside the sandbox; only https links on the surface's declared
|
|
191
|
+
* `linkOrigins` open, and the host decides how (new tab, system browser). Rejects with the host's refusal. */
|
|
192
|
+
async function openLink(input) {
|
|
193
|
+
await send('open-link', { url: input.url });
|
|
194
|
+
}
|
|
195
|
+
/** The bootstrap `data` the host sent with init, or `undefined` once it has expired (or none was sent). */
|
|
196
|
+
function bootstrap() {
|
|
197
|
+
const envelope = init?.bootstrap;
|
|
198
|
+
if (typeof envelope !== 'object' || envelope === null)
|
|
199
|
+
return undefined;
|
|
200
|
+
const { expiresAt, data } = envelope;
|
|
201
|
+
return typeof expiresAt === 'number' && nowMs() < expiresAt ? data : undefined;
|
|
202
|
+
}
|
|
203
|
+
/** The host's theme as applied, or `undefined` when the host sent none. */
|
|
204
|
+
function theme() {
|
|
205
|
+
return currentTheme;
|
|
206
|
+
}
|
|
207
|
+
/** Stops listening and rejects every pending call. */
|
|
208
|
+
function close() {
|
|
209
|
+
unsubscribe();
|
|
210
|
+
stopSize?.();
|
|
211
|
+
for (const [requestId, waiting] of pending) {
|
|
212
|
+
clearTimeout(waiting.timer);
|
|
213
|
+
waiting.reject(new AdminSurfaceCallError({ code: 'closed', message: 'The surface was closed before the host answered.', retryable: false }));
|
|
214
|
+
pending.delete(requestId);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
return { ready, call, openLink, bootstrap, theme, close };
|
|
218
|
+
}
|
|
219
|
+
//# sourceMappingURL=surface-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"surface-client.js","sourceRoot":"","sources":["../../src/admin-surfaces/surface-client.ts"],"names":[],"mappings":"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"}
|