@sema-agent/client-core 0.104.1 → 0.106.0
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 +310 -0
- package/README.md +36 -14
- package/dist/adapt/arms.js +23 -6
- package/dist/adapter/activeRunSelfHeal.d.ts +14 -2
- package/dist/adapter/activeRunSelfHeal.js +90 -12
- package/dist/adapter/downstream/eventToSdkMessage.d.ts +0 -5
- package/dist/adapter/downstream/eventToSdkMessage.js +24 -23
- package/dist/adapter/downstream/terminalToSdkResult.js +2 -3
- package/dist/adapter/downstream/wiringManifestView.d.ts +7 -3
- package/dist/adapter/downstream/wiringManifestView.js +25 -1
- package/dist/adapter/runStream.js +8 -5
- package/dist/approvalReachWire.d.ts +1 -0
- package/dist/approvalReachWire.js +4 -1
- package/dist/approvalSeat.d.ts +21 -0
- package/dist/approvalSeat.js +73 -0
- package/dist/assistantInbox.d.ts +2 -0
- package/dist/assistantInbox.js +3 -0
- package/dist/checkpointRowVerdict.d.ts +23 -0
- package/dist/checkpointRowVerdict.js +89 -0
- package/dist/cloudConfigWireCaps.js +3 -0
- package/dist/compensations.js +6 -6
- package/dist/coreValuePorts.d.ts +14 -1
- package/dist/coreValuePorts.js +14 -0
- package/dist/decideFailureNote.js +3 -1
- package/dist/decideReceipt.d.ts +9 -0
- package/dist/decideReceipt.js +29 -1
- package/dist/declared/supportFloorDeclared.js +2 -2
- package/dist/deviceRebind.d.ts +7 -0
- package/dist/deviceRebind.js +39 -5
- package/dist/displayUntrusted.d.ts +4 -2
- package/dist/displayUntrusted.js +45 -22
- package/dist/engineAddress.d.ts +3 -0
- package/dist/engineAddress.js +25 -0
- package/dist/engineDirectory.js +9 -17
- package/dist/engineErrorCodes.d.ts +8 -0
- package/dist/engineErrorCodes.js +8 -0
- package/dist/engineGenerationPort.d.ts +11 -2
- package/dist/engineGenerationPort.js +63 -9
- package/dist/engineHealthFacts.d.ts +5 -0
- package/dist/engineHealthFacts.js +11 -0
- package/dist/engineNoticeCodes.d.ts +26 -3
- package/dist/engineNoticeCodes.js +52 -7
- package/dist/engineRowRef.js +1 -1
- package/dist/errorSupplementRoles.js +2 -0
- package/dist/eventLeg.d.ts +3 -3
- package/dist/eventLeg.js +25 -4
- package/dist/fleet/fleetProjection.js +26 -5
- package/dist/generated/engineFactTables.d.ts +3 -1
- package/dist/generated/engineFactTables.js +4 -1
- package/dist/generated/engineNoticeTables.js +19 -4
- package/dist/generated/sdkFactTables.d.ts +5 -0
- package/dist/generated/sdkFactTables.js +24 -0
- package/dist/generated/settingsSchemaFns.d.ts +11 -0
- package/dist/generated/settingsSchemaFns.js +2 -1
- package/dist/generated/settingsSchemaSafetyMergeSpec.js +1 -1
- package/dist/generated/settingsSchemaSettingsSources.d.ts +1 -1
- package/dist/generated/settingsSchemaSettingsSources.js +22 -2
- package/dist/headlessReconnectWire.js +31 -4
- package/dist/hitl/approvalLiveFace.d.ts +17 -0
- package/dist/hitl/approvalLiveFace.js +35 -0
- package/dist/hitl/approvalQueueRow.d.ts +21 -0
- package/dist/hitl/approvalQueueRow.js +69 -0
- package/dist/hitl/approvalsFeed.d.ts +5 -4
- package/dist/hitl/approvalsFeed.js +38 -6
- package/dist/hitl/askGateWire.js +26 -2
- package/dist/hitl/askParkRowRouting.d.ts +4 -3
- package/dist/hitl/askParkRowRouting.js +15 -3
- package/dist/hitl/automaticAnswerVerdict.js +13 -10
- package/dist/hitl/crashConverged.d.ts +5 -1
- package/dist/hitl/decisionConflict.js +2 -1
- package/dist/hitl/decisionRefusal.js +1 -1
- package/dist/hitl/decisionSend.d.ts +1 -0
- package/dist/hitl/decisionSend.js +14 -2
- package/dist/hitl/frameRouter.d.ts +4 -0
- package/dist/hitl/frameRouter.js +18 -5
- package/dist/hitl/gateIdentity.d.ts +1 -0
- package/dist/hitl/gateIdentity.js +3 -0
- package/dist/hitl/hitlBridge.d.ts +1 -1
- package/dist/hitl/hitlBridge.js +26 -5
- package/dist/hitl/livePendingAsk.d.ts +5 -0
- package/dist/hitl/livePendingAsk.js +6 -1
- package/dist/hitl/planReviewCard.d.ts +23 -0
- package/dist/hitl/planReviewCard.js +250 -0
- package/dist/hitl/planReviewWire.d.ts +39 -14
- package/dist/hitl/planReviewWire.js +450 -163
- package/dist/hitl/sessionAllowRoute.d.ts +2 -0
- package/dist/hitl/sessionAllowRoute.js +7 -0
- package/dist/hitl/sessionPolicyWire.d.ts +1 -7
- package/dist/hitl/sessionPolicyWire.js +3 -43
- package/dist/hitl/subagentSource.d.ts +1 -0
- package/dist/hitl/subagentSource.js +13 -0
- package/dist/hitl/toolApprovalWire.d.ts +3 -2
- package/dist/hitl/toolApprovalWire.js +79 -37
- package/dist/hostSettingsSource.d.ts +5 -2
- package/dist/hostSettingsSource.js +19 -10
- package/dist/hostTurnSettings.d.ts +5 -6
- package/dist/hostTurnSettings.js +106 -26
- package/dist/i18n/messages.en.d.ts +85 -12
- package/dist/i18n/messages.en.js +85 -12
- package/dist/i18n/messages.zh.js +88 -12
- package/dist/index.d.ts +35 -4
- package/dist/index.js +19 -2
- package/dist/liveInitToolFace.js +0 -1
- package/dist/liveModelCatalog.d.ts +15 -0
- package/dist/liveModelCatalog.js +40 -0
- package/dist/mcpTransportKindsCapability.d.ts +18 -0
- package/dist/mcpTransportKindsCapability.js +75 -0
- package/dist/mcpWireCaps.d.ts +4 -1
- package/dist/mcpWireCaps.js +25 -14
- package/dist/modelCapabilityProbe.js +66 -33
- package/dist/notifications.d.ts +9 -0
- package/dist/notifications.js +11 -2
- package/dist/ownKey.d.ts +4 -1
- package/dist/ownKey.js +8 -2
- package/dist/permissionModeWriteCapability.d.ts +13 -0
- package/dist/permissionModeWriteCapability.js +35 -0
- package/dist/permissionsAllowGrantCapability.d.ts +3 -0
- package/dist/permissionsAllowGrantCapability.js +26 -3
- package/dist/permissionsDeclaration.d.ts +25 -3
- package/dist/permissionsDeclaration.js +69 -41
- package/dist/planReviewCardFacts.d.ts +116 -0
- package/dist/planReviewCardFacts.js +469 -0
- package/dist/projectSeed.d.ts +39 -0
- package/dist/projectSeed.js +80 -0
- package/dist/promptDelivery.js +1 -1
- package/dist/reattachWindow.d.ts +8 -1
- package/dist/reattachWindow.js +44 -12
- package/dist/replayBody.d.ts +7 -6
- package/dist/replayBody.js +62 -7
- package/dist/request/taskRequest.js +3 -4
- package/dist/ruleCompileVerdict.d.ts +0 -2
- package/dist/ruleCompileVerdict.js +0 -31
- package/dist/ruleRefusalSentence.js +0 -3
- package/dist/runFollow.d.ts +30 -0
- package/dist/runFollow.js +117 -0
- package/dist/runLedgerSnapshot.d.ts +20 -0
- package/dist/runLedgerSnapshot.js +272 -0
- package/dist/runPermissionModeSwitch.d.ts +57 -0
- package/dist/runPermissionModeSwitch.js +135 -0
- package/dist/runReattachPolicy.d.ts +16 -5
- package/dist/runReattachPolicy.js +72 -24
- package/dist/runTerminal.js +30 -8
- package/dist/sandboxWire.d.ts +0 -3
- package/dist/sandboxWire.js +0 -9
- package/dist/seam.d.ts +17 -7
- package/dist/seam.js +13 -1
- package/dist/seatContract.d.ts +57 -7
- package/dist/seatContract.js +133 -3
- package/dist/serverSupportRange.d.ts +18 -0
- package/dist/serverSupportRange.js +25 -0
- package/dist/sessionEngine.d.ts +156 -0
- package/dist/sessionEngine.js +464 -0
- package/dist/sessionMap.d.ts +11 -1
- package/dist/sessionMap.js +35 -9
- package/dist/sessionMemoryErase.d.ts +1 -1
- package/dist/sessionMemoryErase.js +5 -0
- package/dist/sessionMemoryStatus.d.ts +27 -1
- package/dist/sessionMemoryStatus.js +117 -0
- package/dist/sessionMemorySync.d.ts +31 -0
- package/dist/sessionMemorySync.js +95 -0
- package/dist/sessionRowTag.d.ts +4 -0
- package/dist/sessionRowTag.js +18 -0
- package/dist/settingsLayerAdmission.d.ts +1 -0
- package/dist/settingsLayerAdmission.js +4 -1
- package/dist/sseIdleTriage.d.ts +3 -1
- package/dist/sseIdleTriage.js +19 -4
- package/dist/subagent/engineSubagentTail.js +2 -0
- package/dist/subagentContentStore.d.ts +3 -0
- package/dist/subagentContentStore.js +10 -1
- package/dist/toolResult.js +1 -1
- package/dist/turnFailurePresentation.d.ts +5 -2
- package/dist/turnFailurePresentation.js +12 -4
- package/dist/wireRefusalCopy.js +2 -6
- package/docs/INTEGRATION-CLIENTS.md +1507 -18
- package/package.json +5 -5
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { engineSupportFloorEffective, engineVersionTier } from './supportFloor.js';
|
|
2
|
+
import { msg, renderMessage } from './i18n/translate.js';
|
|
3
|
+
export const SERVER_SUPPORT_RANGE_REASONS = Object.freeze(['below_floor', 'version_absent', 'version_unreadable']);
|
|
4
|
+
export function serverSupportRangeVerdict(version) {
|
|
5
|
+
const floor = engineSupportFloorEffective();
|
|
6
|
+
const tier = engineVersionTier(version);
|
|
7
|
+
if (tier === 'engine')
|
|
8
|
+
return Object.freeze({ kind: 'in_range', floor });
|
|
9
|
+
if (tier === 'legacy')
|
|
10
|
+
return Object.freeze({ kind: 'out_of_range', reason: 'below_floor', version: version, floor });
|
|
11
|
+
return Object.freeze({ kind: 'unknown', reason: version === undefined ? 'version_absent' : 'version_unreadable', floor });
|
|
12
|
+
}
|
|
13
|
+
export function serverSupportRangeSentence(verdict, lang) {
|
|
14
|
+
try {
|
|
15
|
+
if (typeof verdict !== 'object' || verdict === null || verdict.kind !== 'out_of_range')
|
|
16
|
+
return undefined;
|
|
17
|
+
const again = serverSupportRangeVerdict(verdict.version);
|
|
18
|
+
if (again.kind !== 'out_of_range')
|
|
19
|
+
return undefined;
|
|
20
|
+
return renderMessage(msg('config.engineTarget.serverBelowSupportFloor', { version: again.version, floor: again.floor }), lang);
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
return undefined;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import type { EngineRowReading } from './engineDirectory.js';
|
|
2
|
+
import type { EngineTargetCloudAuth } from './seatContract.js';
|
|
3
|
+
import { type SessionMapRecord, type SessionMapStorePort } from './sessionMap.js';
|
|
4
|
+
import { type MessageRef } from './i18n/translate.js';
|
|
5
|
+
export type SessionEngineKind = 'local' | 'cloud';
|
|
6
|
+
export type SessionEngineIdentityKind = 'self' | 'declared' | 'address';
|
|
7
|
+
export type SessionEngineBindingInput = {
|
|
8
|
+
readonly role: 'self';
|
|
9
|
+
} | SessionEngineRowInput | {
|
|
10
|
+
readonly role: 'external';
|
|
11
|
+
readonly address: string;
|
|
12
|
+
};
|
|
13
|
+
export interface SessionEngineRowInput {
|
|
14
|
+
readonly role: 'external';
|
|
15
|
+
readonly row: EngineRowReading;
|
|
16
|
+
readonly center: string;
|
|
17
|
+
}
|
|
18
|
+
export type SessionEngineBindingFailure = 'row-incomplete' | 'center-invalid' | 'address-invalid' | 'input-invalid';
|
|
19
|
+
export type SessionEngineSelfPresentation = Readonly<Record<string, never>>;
|
|
20
|
+
export interface SessionEngineDeclaredPresentation {
|
|
21
|
+
readonly center: string;
|
|
22
|
+
readonly scope: string;
|
|
23
|
+
readonly name: string;
|
|
24
|
+
}
|
|
25
|
+
export interface SessionEngineAddressPresentation {
|
|
26
|
+
readonly address: string;
|
|
27
|
+
}
|
|
28
|
+
export type SessionEngineBindingOk = SessionEngineSelfBinding | SessionEngineDeclaredBinding | SessionEngineAddressBinding;
|
|
29
|
+
export interface SessionEngineSelfBinding {
|
|
30
|
+
readonly ok: true;
|
|
31
|
+
readonly identityKind: 'self';
|
|
32
|
+
readonly key: string;
|
|
33
|
+
readonly presentation: SessionEngineSelfPresentation;
|
|
34
|
+
}
|
|
35
|
+
export interface SessionEngineDeclaredBinding {
|
|
36
|
+
readonly ok: true;
|
|
37
|
+
readonly identityKind: 'declared';
|
|
38
|
+
readonly key: string;
|
|
39
|
+
readonly presentation: SessionEngineDeclaredPresentation;
|
|
40
|
+
readonly connect: {
|
|
41
|
+
readonly viaCenter: string;
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
export interface SessionEngineAddressBinding {
|
|
45
|
+
readonly ok: true;
|
|
46
|
+
readonly identityKind: 'address';
|
|
47
|
+
readonly key: string;
|
|
48
|
+
readonly presentation: SessionEngineAddressPresentation;
|
|
49
|
+
readonly connect: {
|
|
50
|
+
readonly url: string;
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
export type SessionEngineBinding = SessionEngineBindingOk | {
|
|
54
|
+
readonly ok: false;
|
|
55
|
+
readonly reason: SessionEngineBindingFailure;
|
|
56
|
+
};
|
|
57
|
+
export interface SessionEngineAssignment {
|
|
58
|
+
readonly kind: SessionEngineKind;
|
|
59
|
+
readonly identity: SessionEngineBindingOk;
|
|
60
|
+
}
|
|
61
|
+
export type SessionEngineView = SessionEngineSelfView | SessionEngineDeclaredView | SessionEngineAddressView;
|
|
62
|
+
export interface SessionEngineSelfView {
|
|
63
|
+
readonly kind: SessionEngineKind;
|
|
64
|
+
readonly identityKind: 'self';
|
|
65
|
+
readonly identity: {
|
|
66
|
+
readonly key: string;
|
|
67
|
+
readonly presentation: SessionEngineSelfPresentation;
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
export interface SessionEngineDeclaredView {
|
|
71
|
+
readonly kind: SessionEngineKind;
|
|
72
|
+
readonly identityKind: 'declared';
|
|
73
|
+
readonly identity: {
|
|
74
|
+
readonly key: string;
|
|
75
|
+
readonly presentation: SessionEngineDeclaredPresentation;
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
export interface SessionEngineAddressView {
|
|
79
|
+
readonly kind: SessionEngineKind;
|
|
80
|
+
readonly identityKind: 'address';
|
|
81
|
+
readonly identity: {
|
|
82
|
+
readonly key: string;
|
|
83
|
+
readonly presentation: SessionEngineAddressPresentation;
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
export type SessionEngineReading = SessionEngineBoundReading | {
|
|
87
|
+
readonly kind: 'legacy';
|
|
88
|
+
} | {
|
|
89
|
+
readonly kind: 'unresolved';
|
|
90
|
+
} | {
|
|
91
|
+
readonly kind: 'none';
|
|
92
|
+
};
|
|
93
|
+
export interface SessionEngineBoundReading {
|
|
94
|
+
readonly kind: 'bound';
|
|
95
|
+
readonly binding: SessionEngineAssignment;
|
|
96
|
+
readonly engine: SessionEngineView;
|
|
97
|
+
readonly uuid: string;
|
|
98
|
+
}
|
|
99
|
+
export interface SessionEngineSessionRef {
|
|
100
|
+
readonly shellSessionId: string;
|
|
101
|
+
readonly uuid: string;
|
|
102
|
+
}
|
|
103
|
+
export type SessionEngineCommitRequest = {
|
|
104
|
+
readonly arm: 'create';
|
|
105
|
+
readonly binding: SessionEngineAssignment;
|
|
106
|
+
} | {
|
|
107
|
+
readonly arm: 'resume';
|
|
108
|
+
readonly binding: SessionEngineAssignment;
|
|
109
|
+
} | SessionEngineRecoverRequest;
|
|
110
|
+
export interface SessionEngineRecoverRequest {
|
|
111
|
+
readonly arm: 'recover';
|
|
112
|
+
readonly binding: SessionEngineAssignment;
|
|
113
|
+
readonly chosenByUser?: true;
|
|
114
|
+
}
|
|
115
|
+
export type SessionEngineUnresolvedReason = 'request-invalid' | 'record-mismatch' | 'record-legacy' | 'record-unbound' | 'record-unreadable' | 'recover-unproven';
|
|
116
|
+
export type SessionEngineCommitResult = SessionEngineCommitted | {
|
|
117
|
+
readonly kind: 'conflict';
|
|
118
|
+
readonly bound: SessionEngineView;
|
|
119
|
+
} | {
|
|
120
|
+
readonly kind: 'unresolved';
|
|
121
|
+
readonly reason: SessionEngineUnresolvedReason;
|
|
122
|
+
} | {
|
|
123
|
+
readonly kind: 'store-failed';
|
|
124
|
+
};
|
|
125
|
+
export interface SessionEngineCommitted {
|
|
126
|
+
readonly kind: 'committed';
|
|
127
|
+
readonly engine: SessionEngineView;
|
|
128
|
+
readonly notice?: MessageRef;
|
|
129
|
+
}
|
|
130
|
+
export interface SessionEngineWiring {
|
|
131
|
+
readonly id: string;
|
|
132
|
+
readonly selfSpawned: boolean;
|
|
133
|
+
readonly wiredAddresses: readonly string[];
|
|
134
|
+
readonly auth: EngineTargetCloudAuth | undefined;
|
|
135
|
+
readonly explicitAddresses?: readonly string[];
|
|
136
|
+
}
|
|
137
|
+
export type SessionDispatchRefusal = 'not-wired' | 'scope-mismatch' | 'scope-unproven' | 'unresolved';
|
|
138
|
+
export type SessionDispatchDecision = {
|
|
139
|
+
readonly kind: 'self';
|
|
140
|
+
readonly wiringSnapshotId: string;
|
|
141
|
+
} | SessionDispatchUrlTarget | SessionDispatchRefused;
|
|
142
|
+
export interface SessionDispatchUrlTarget {
|
|
143
|
+
readonly kind: 'address' | 'center';
|
|
144
|
+
readonly url: string;
|
|
145
|
+
readonly wiringSnapshotId: string;
|
|
146
|
+
}
|
|
147
|
+
export interface SessionDispatchRefused {
|
|
148
|
+
readonly kind: 'refused';
|
|
149
|
+
readonly refusal: SessionDispatchRefusal;
|
|
150
|
+
readonly message: MessageRef;
|
|
151
|
+
}
|
|
152
|
+
export declare function sessionEngineBindingFor(input: SessionEngineBindingInput): SessionEngineBinding;
|
|
153
|
+
export declare function isSessionEngineView(v: {} | null | undefined): boolean;
|
|
154
|
+
export declare function readSessionEngine(record: SessionMapRecord | undefined): SessionEngineReading;
|
|
155
|
+
export declare function commitSessionEngine(store: SessionMapStorePort, session: SessionEngineSessionRef, request: SessionEngineCommitRequest): SessionEngineCommitResult;
|
|
156
|
+
export declare function sessionDispatchTarget(reading: SessionEngineReading, ctx: SessionEngineWiring): SessionDispatchDecision;
|
|
@@ -0,0 +1,464 @@
|
|
|
1
|
+
import { engineNamespaceKeyFor } from './sessionMap.js';
|
|
2
|
+
import { carriesNoCredentialSlots, isCenterRelativePath, tupleOriginUrlOf } from './engineAddress.js';
|
|
3
|
+
import { ownSendableField, readOwnDataNonEmptyString, readOwnDataValue } from './ownKey.js';
|
|
4
|
+
import { slotReadOf } from './wireFailureShape.js';
|
|
5
|
+
import { msg } from './i18n/translate.js';
|
|
6
|
+
const V1 = 'v1';
|
|
7
|
+
const SELF_KEY = JSON.stringify([V1, 'self']);
|
|
8
|
+
const EMPTY = Object.freeze({});
|
|
9
|
+
function isObj(v) {
|
|
10
|
+
return typeof v === 'object' && v !== null && !Array.isArray(v);
|
|
11
|
+
}
|
|
12
|
+
function isCanonicalAddress(s) {
|
|
13
|
+
return s !== '' && tupleOriginUrlOf(s) !== undefined && engineNamespaceKeyFor(s) === s;
|
|
14
|
+
}
|
|
15
|
+
function decodeKey(key) {
|
|
16
|
+
let parsed;
|
|
17
|
+
try {
|
|
18
|
+
parsed = JSON.parse(key);
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
return undefined;
|
|
22
|
+
}
|
|
23
|
+
if (!Array.isArray(parsed) || !parsed.every((x) => typeof x === 'string'))
|
|
24
|
+
return undefined;
|
|
25
|
+
const t = parsed;
|
|
26
|
+
if (JSON.stringify(t) !== key || t[0] !== V1)
|
|
27
|
+
return undefined;
|
|
28
|
+
if (t[1] === 'self' && t.length === 2)
|
|
29
|
+
return { identityKind: 'self' };
|
|
30
|
+
if (t[1] === 'declared' && t.length === 5) {
|
|
31
|
+
const [, , center, scope, name] = t;
|
|
32
|
+
return isCanonicalAddress(center) && scope !== '' && name !== '' ? { identityKind: 'declared', center, scope, name } : undefined;
|
|
33
|
+
}
|
|
34
|
+
if (t[1] === 'address' && t.length === 3) {
|
|
35
|
+
const address = t[2];
|
|
36
|
+
return isCanonicalAddress(address) ? { identityKind: 'address', address } : undefined;
|
|
37
|
+
}
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
|
40
|
+
const fail = (reason) => Object.freeze({ ok: false, reason });
|
|
41
|
+
function selfBinding() {
|
|
42
|
+
return Object.freeze({ ok: true, identityKind: 'self', key: SELF_KEY, presentation: EMPTY });
|
|
43
|
+
}
|
|
44
|
+
function declaredBinding(center, scope, name, viaCenter) {
|
|
45
|
+
return Object.freeze({
|
|
46
|
+
ok: true,
|
|
47
|
+
identityKind: 'declared',
|
|
48
|
+
key: JSON.stringify([V1, 'declared', center, scope, name]),
|
|
49
|
+
presentation: Object.freeze({ center, scope, name }),
|
|
50
|
+
connect: Object.freeze({ viaCenter }),
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
function addressBinding(raw) {
|
|
54
|
+
const u = tupleOriginUrlOf(raw);
|
|
55
|
+
if (u === undefined || !carriesNoCredentialSlots(u))
|
|
56
|
+
return fail('address-invalid');
|
|
57
|
+
const address = engineNamespaceKeyFor(raw);
|
|
58
|
+
return Object.freeze({
|
|
59
|
+
ok: true,
|
|
60
|
+
identityKind: 'address',
|
|
61
|
+
key: JSON.stringify([V1, 'address', address]),
|
|
62
|
+
presentation: Object.freeze({ address }),
|
|
63
|
+
connect: Object.freeze({ url: raw }),
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
export function sessionEngineBindingFor(input) {
|
|
67
|
+
try {
|
|
68
|
+
if (!isObj(input))
|
|
69
|
+
return fail('input-invalid');
|
|
70
|
+
const role = readOwnDataValue(input, 'role');
|
|
71
|
+
const row = slotReadOf(input, 'row');
|
|
72
|
+
const address = slotReadOf(input, 'address');
|
|
73
|
+
const center = slotReadOf(input, 'center');
|
|
74
|
+
if (role === 'self') {
|
|
75
|
+
return row.presence === 'absent' && address.presence === 'absent' && center.presence === 'absent' ? selfBinding() : fail('input-invalid');
|
|
76
|
+
}
|
|
77
|
+
if (role !== 'external')
|
|
78
|
+
return fail('input-invalid');
|
|
79
|
+
const rowGiven = row.presence !== 'absent';
|
|
80
|
+
if (rowGiven === (address.presence !== 'absent'))
|
|
81
|
+
return fail('input-invalid');
|
|
82
|
+
if (!rowGiven) {
|
|
83
|
+
if (center.presence !== 'absent')
|
|
84
|
+
return fail('input-invalid');
|
|
85
|
+
return address.presence === 'present' && typeof address.value === 'string' ? addressBinding(address.value) : fail('address-invalid');
|
|
86
|
+
}
|
|
87
|
+
if (row.presence !== 'present' || !isObj(row.value))
|
|
88
|
+
return fail('row-incomplete');
|
|
89
|
+
const r = row.value;
|
|
90
|
+
const name = readOwnDataNonEmptyString(r, 'name');
|
|
91
|
+
const scope = readOwnDataNonEmptyString(r, 'scope');
|
|
92
|
+
const viaCenter = readOwnDataNonEmptyString(r, 'viaCenter');
|
|
93
|
+
if (name === undefined || scope === undefined || viaCenter === undefined || !isCenterRelativePath(viaCenter))
|
|
94
|
+
return fail('row-incomplete');
|
|
95
|
+
if (center.presence !== 'present' || typeof center.value !== 'string' || tupleOriginUrlOf(center.value) === undefined)
|
|
96
|
+
return fail('center-invalid');
|
|
97
|
+
return declaredBinding(engineNamespaceKeyFor(center.value), scope, name, viaCenter);
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
return fail('input-invalid');
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
function assignmentOf(kindRaw, keyRaw, connectSlot) {
|
|
104
|
+
if (kindRaw !== 'local' && kindRaw !== 'cloud')
|
|
105
|
+
return undefined;
|
|
106
|
+
if (typeof keyRaw !== 'string')
|
|
107
|
+
return undefined;
|
|
108
|
+
const decoded = decodeKey(keyRaw);
|
|
109
|
+
if (decoded === undefined)
|
|
110
|
+
return undefined;
|
|
111
|
+
const connectAbsent = connectSlot.presence === 'absent' || (connectSlot.presence === 'present' && connectSlot.value === undefined);
|
|
112
|
+
let identity;
|
|
113
|
+
if (decoded.identityKind === 'self') {
|
|
114
|
+
if (!connectAbsent)
|
|
115
|
+
return undefined;
|
|
116
|
+
identity = selfBinding();
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
if (connectSlot.presence !== 'present' || !isObj(connectSlot.value))
|
|
120
|
+
return undefined;
|
|
121
|
+
const c = connectSlot.value;
|
|
122
|
+
if (decoded.identityKind === 'address') {
|
|
123
|
+
const url = readOwnDataValue(c, 'url');
|
|
124
|
+
if (typeof url !== 'string')
|
|
125
|
+
return undefined;
|
|
126
|
+
const re = addressBinding(url);
|
|
127
|
+
if (!re.ok || re.key !== keyRaw)
|
|
128
|
+
return undefined;
|
|
129
|
+
identity = re;
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
const viaCenter = readOwnDataNonEmptyString(c, 'viaCenter');
|
|
133
|
+
if (viaCenter === undefined || !isCenterRelativePath(viaCenter))
|
|
134
|
+
return undefined;
|
|
135
|
+
identity = declaredBinding(decoded.center, decoded.scope, decoded.name, viaCenter);
|
|
136
|
+
if (identity.key !== keyRaw)
|
|
137
|
+
return undefined;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return Object.freeze({ kind: kindRaw, identity });
|
|
141
|
+
}
|
|
142
|
+
function sameAssignment(a, b) {
|
|
143
|
+
if (a.kind !== b.kind || a.identity.key !== b.identity.key || a.identity.identityKind !== b.identity.identityKind)
|
|
144
|
+
return false;
|
|
145
|
+
if (a.identity.identityKind === 'address' && b.identity.identityKind === 'address')
|
|
146
|
+
return a.identity.connect.url === b.identity.connect.url;
|
|
147
|
+
if (a.identity.identityKind === 'declared' && b.identity.identityKind === 'declared')
|
|
148
|
+
return a.identity.connect.viaCenter === b.identity.connect.viaCenter;
|
|
149
|
+
return true;
|
|
150
|
+
}
|
|
151
|
+
function viewOf(a) {
|
|
152
|
+
const id = a.identity;
|
|
153
|
+
if (id.identityKind === 'self')
|
|
154
|
+
return Object.freeze({ kind: a.kind, identityKind: 'self', identity: Object.freeze({ key: id.key, presentation: id.presentation }) });
|
|
155
|
+
if (id.identityKind === 'declared')
|
|
156
|
+
return Object.freeze({ kind: a.kind, identityKind: 'declared', identity: Object.freeze({ key: id.key, presentation: id.presentation }) });
|
|
157
|
+
return Object.freeze({ kind: a.kind, identityKind: 'address', identity: Object.freeze({ key: id.key, presentation: id.presentation }) });
|
|
158
|
+
}
|
|
159
|
+
function snapshotOf(a) {
|
|
160
|
+
const id = a.identity;
|
|
161
|
+
if (id.identityKind === 'address')
|
|
162
|
+
return { kind: a.kind, key: id.key, connect: { url: id.connect.url } };
|
|
163
|
+
if (id.identityKind === 'declared')
|
|
164
|
+
return { kind: a.kind, key: id.key, connect: { viaCenter: id.connect.viaCenter } };
|
|
165
|
+
return { kind: a.kind, key: id.key };
|
|
166
|
+
}
|
|
167
|
+
export function isSessionEngineView(v) {
|
|
168
|
+
try {
|
|
169
|
+
if (!isObj(v))
|
|
170
|
+
return false;
|
|
171
|
+
const kind = ownSendableField(v, 'kind');
|
|
172
|
+
if (kind !== 'local' && kind !== 'cloud')
|
|
173
|
+
return false;
|
|
174
|
+
const identityKind = ownSendableField(v, 'identityKind');
|
|
175
|
+
const identity = ownSendableField(v, 'identity');
|
|
176
|
+
if (!isObj(identity))
|
|
177
|
+
return false;
|
|
178
|
+
const key = ownSendableField(identity, 'key');
|
|
179
|
+
const presentation = ownSendableField(identity, 'presentation');
|
|
180
|
+
if (typeof key !== 'string' || !isObj(presentation))
|
|
181
|
+
return false;
|
|
182
|
+
const decoded = decodeKey(key);
|
|
183
|
+
if (decoded === undefined || decoded.identityKind !== identityKind)
|
|
184
|
+
return false;
|
|
185
|
+
const fields = decoded.identityKind === 'self' ? {} : decoded.identityKind === 'declared' ? { center: decoded.center, scope: decoded.scope, name: decoded.name } : { address: decoded.address };
|
|
186
|
+
if (Reflect.ownKeys(presentation).length !== Object.keys(fields).length)
|
|
187
|
+
return false;
|
|
188
|
+
return Object.keys(fields).every((k) => ownSendableField(presentation, k) === fields[k]);
|
|
189
|
+
}
|
|
190
|
+
catch {
|
|
191
|
+
return false;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
function entryIdOf(record, key) {
|
|
195
|
+
const engines = slotReadOf(record, 'engines');
|
|
196
|
+
if (engines.presence !== 'present' || !isObj(engines.value))
|
|
197
|
+
return undefined;
|
|
198
|
+
const entry = slotReadOf(engines.value, key);
|
|
199
|
+
if (entry.presence !== 'present' || !isObj(entry.value))
|
|
200
|
+
return undefined;
|
|
201
|
+
return readOwnDataNonEmptyString(entry.value, 'engineSessionId');
|
|
202
|
+
}
|
|
203
|
+
function hasHistory(record) {
|
|
204
|
+
const engines = slotReadOf(record, 'engines');
|
|
205
|
+
if (engines.presence === 'unreadable')
|
|
206
|
+
return true;
|
|
207
|
+
if (engines.presence === 'present' && engines.value !== undefined) {
|
|
208
|
+
if (!isObj(engines.value))
|
|
209
|
+
return true;
|
|
210
|
+
if (Reflect.ownKeys(engines.value).length > 0)
|
|
211
|
+
return true;
|
|
212
|
+
}
|
|
213
|
+
const top = slotReadOf(record, 'engineSessionId');
|
|
214
|
+
if (top.presence === 'unreadable')
|
|
215
|
+
return true;
|
|
216
|
+
return top.presence === 'present' && top.value !== undefined && top.value !== '';
|
|
217
|
+
}
|
|
218
|
+
export function readSessionEngine(record) {
|
|
219
|
+
try {
|
|
220
|
+
if (record === undefined || record === null)
|
|
221
|
+
return NONE;
|
|
222
|
+
if (!isObj(record))
|
|
223
|
+
return UNRESOLVED;
|
|
224
|
+
const snap = slotReadOf(record, 'boundEngine');
|
|
225
|
+
if (snap.presence === 'unreadable')
|
|
226
|
+
return UNRESOLVED;
|
|
227
|
+
if (snap.presence === 'present' && snap.value !== undefined) {
|
|
228
|
+
if (!isObj(snap.value))
|
|
229
|
+
return UNRESOLVED;
|
|
230
|
+
const s = snap.value;
|
|
231
|
+
const binding = assignmentOf(readOwnDataValue(s, 'kind'), readOwnDataValue(s, 'key'), slotReadOf(s, 'connect'));
|
|
232
|
+
if (binding === undefined)
|
|
233
|
+
return UNRESOLVED;
|
|
234
|
+
const uuid = entryIdOf(record, binding.identity.key);
|
|
235
|
+
if (uuid === undefined)
|
|
236
|
+
return UNRESOLVED;
|
|
237
|
+
return Object.freeze({ kind: 'bound', binding, engine: viewOf(binding), uuid });
|
|
238
|
+
}
|
|
239
|
+
return hasHistory(record) ? LEGACY : NONE;
|
|
240
|
+
}
|
|
241
|
+
catch {
|
|
242
|
+
return UNRESOLVED;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
const NONE = Object.freeze({ kind: 'none' });
|
|
246
|
+
const LEGACY = Object.freeze({ kind: 'legacy' });
|
|
247
|
+
const UNRESOLVED = Object.freeze({ kind: 'unresolved' });
|
|
248
|
+
function judgeNotice(a) {
|
|
249
|
+
return a.identity.identityKind === 'self' && a.kind !== 'local' ? msg('session.engine.selfNotLocal') : undefined;
|
|
250
|
+
}
|
|
251
|
+
function committed(a) {
|
|
252
|
+
const notice = judgeNotice(a);
|
|
253
|
+
const engine = viewOf(a);
|
|
254
|
+
return Object.freeze(notice === undefined ? { kind: 'committed', engine } : { kind: 'committed', engine, notice });
|
|
255
|
+
}
|
|
256
|
+
const unresolvedCommit = (reason) => Object.freeze({ kind: 'unresolved', reason });
|
|
257
|
+
const STORE_FAILED = Object.freeze({ kind: 'store-failed' });
|
|
258
|
+
function requestAssignmentOf(raw) {
|
|
259
|
+
if (!isObj(raw))
|
|
260
|
+
return undefined;
|
|
261
|
+
const identity = readOwnDataValue(raw, 'identity');
|
|
262
|
+
if (!isObj(identity) || readOwnDataValue(identity, 'ok') !== true)
|
|
263
|
+
return undefined;
|
|
264
|
+
const a = assignmentOf(readOwnDataValue(raw, 'kind'), readOwnDataValue(identity, 'key'), slotReadOf(identity, 'connect'));
|
|
265
|
+
if (a === undefined || readOwnDataValue(identity, 'identityKind') !== a.identity.identityKind)
|
|
266
|
+
return undefined;
|
|
267
|
+
return a;
|
|
268
|
+
}
|
|
269
|
+
function legacyKeyOf(a) {
|
|
270
|
+
const id = a.identity;
|
|
271
|
+
if (id.identityKind === 'self')
|
|
272
|
+
return 'local';
|
|
273
|
+
if (id.identityKind === 'address')
|
|
274
|
+
return engineNamespaceKeyFor(id.connect.url);
|
|
275
|
+
const center = tupleOriginUrlOf(id.presentation.center);
|
|
276
|
+
return center === undefined ? undefined : engineNamespaceKeyFor(center.origin + id.connect.viaCenter);
|
|
277
|
+
}
|
|
278
|
+
const nextOf = (step) => (Object.hasOwn(step, 'next') ? step.next : undefined);
|
|
279
|
+
function firstWrite(prior, session, a, now) {
|
|
280
|
+
const engines = { ...(prior?.engines ?? {}) };
|
|
281
|
+
const existing = Object.hasOwn(engines, a.identity.key) ? engines[a.identity.key] : undefined;
|
|
282
|
+
Object.defineProperty(engines, a.identity.key, {
|
|
283
|
+
value: { ...existing, engineSessionId: session.uuid, updatedAt: now },
|
|
284
|
+
writable: true,
|
|
285
|
+
enumerable: true,
|
|
286
|
+
configurable: true,
|
|
287
|
+
});
|
|
288
|
+
return { ...prior, shellSessionId: session.shellSessionId, boundEngine: snapshotOf(a), engines, updatedAt: now };
|
|
289
|
+
}
|
|
290
|
+
function commitStep(prior, session, arm, a, chosenByUser) {
|
|
291
|
+
const reading = readSessionEngine(prior);
|
|
292
|
+
if (prior !== undefined && prior !== null) {
|
|
293
|
+
const handle = isObj(prior) ? readOwnDataValue(prior, 'shellSessionId') : undefined;
|
|
294
|
+
if (handle !== session.shellSessionId) {
|
|
295
|
+
return { result: reading.kind === 'bound' ? Object.freeze({ kind: 'conflict', bound: reading.engine }) : unresolvedCommit('record-mismatch') };
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
if (reading.kind === 'unresolved')
|
|
299
|
+
return { result: unresolvedCommit('record-unreadable') };
|
|
300
|
+
if (reading.kind === 'bound') {
|
|
301
|
+
if (sameAssignment(reading.binding, a) && reading.uuid === session.uuid)
|
|
302
|
+
return { result: committed(a) };
|
|
303
|
+
return { result: Object.freeze({ kind: 'conflict', bound: reading.engine }) };
|
|
304
|
+
}
|
|
305
|
+
const now = new Date().toISOString();
|
|
306
|
+
if (reading.kind === 'none') {
|
|
307
|
+
if (arm !== 'create')
|
|
308
|
+
return { result: unresolvedCommit('record-unbound') };
|
|
309
|
+
return { result: committed(a), next: firstWrite(prior, session, a, now) };
|
|
310
|
+
}
|
|
311
|
+
if (arm !== 'recover')
|
|
312
|
+
return { result: unresolvedCommit('record-legacy') };
|
|
313
|
+
const oldKey = legacyKeyOf(a);
|
|
314
|
+
const proven = oldKey !== undefined &&
|
|
315
|
+
isObj(prior) &&
|
|
316
|
+
entryIdOf(prior, oldKey) === session.uuid &&
|
|
317
|
+
(a.identity.identityKind !== 'declared' || chosenByUser) &&
|
|
318
|
+
(entryIdOf(prior, a.identity.key) ?? session.uuid) === session.uuid;
|
|
319
|
+
if (!proven)
|
|
320
|
+
return { result: unresolvedCommit('recover-unproven') };
|
|
321
|
+
return { result: committed(a), next: firstWrite(prior, session, a, now) };
|
|
322
|
+
}
|
|
323
|
+
export function commitSessionEngine(store, session, request) {
|
|
324
|
+
let readMergeWrite;
|
|
325
|
+
let ref;
|
|
326
|
+
let arm;
|
|
327
|
+
let assignment;
|
|
328
|
+
let chosenByUser = false;
|
|
329
|
+
try {
|
|
330
|
+
if (!isObj(store) || !isObj(session) || !isObj(request))
|
|
331
|
+
return unresolvedCommit('request-invalid');
|
|
332
|
+
const rmw = methodOf(store, 'readMergeWrite');
|
|
333
|
+
if (rmw === undefined)
|
|
334
|
+
return unresolvedCommit('request-invalid');
|
|
335
|
+
readMergeWrite = (build) => rmw.call(store, build);
|
|
336
|
+
const shellSessionId = readOwnDataNonEmptyString(session, 'shellSessionId');
|
|
337
|
+
const uuid = readOwnDataNonEmptyString(session, 'uuid');
|
|
338
|
+
if (shellSessionId === undefined || uuid === undefined)
|
|
339
|
+
return unresolvedCommit('request-invalid');
|
|
340
|
+
ref = Object.freeze({ shellSessionId, uuid });
|
|
341
|
+
const armRaw = readOwnDataValue(request, 'arm');
|
|
342
|
+
if (armRaw !== 'create' && armRaw !== 'resume' && armRaw !== 'recover')
|
|
343
|
+
return unresolvedCommit('request-invalid');
|
|
344
|
+
arm = armRaw;
|
|
345
|
+
const a = requestAssignmentOf(readOwnDataValue(request, 'binding'));
|
|
346
|
+
if (a === undefined)
|
|
347
|
+
return unresolvedCommit('request-invalid');
|
|
348
|
+
assignment = a;
|
|
349
|
+
if (arm === 'recover')
|
|
350
|
+
chosenByUser = readOwnDataValue(request, 'chosenByUser') === true;
|
|
351
|
+
}
|
|
352
|
+
catch {
|
|
353
|
+
return unresolvedCommit('request-invalid');
|
|
354
|
+
}
|
|
355
|
+
let step;
|
|
356
|
+
try {
|
|
357
|
+
const returned = readMergeWrite((prior) => {
|
|
358
|
+
step = commitStep(prior, ref, arm, assignment, chosenByUser);
|
|
359
|
+
return nextOf(step);
|
|
360
|
+
});
|
|
361
|
+
if (step === undefined)
|
|
362
|
+
return STORE_FAILED;
|
|
363
|
+
if (nextOf(step) !== undefined && !isObj(returned))
|
|
364
|
+
return STORE_FAILED;
|
|
365
|
+
return step.result;
|
|
366
|
+
}
|
|
367
|
+
catch {
|
|
368
|
+
return STORE_FAILED;
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
function methodOf(o, key) {
|
|
372
|
+
try {
|
|
373
|
+
const v = o[key];
|
|
374
|
+
return typeof v === 'function' ? v : undefined;
|
|
375
|
+
}
|
|
376
|
+
catch {
|
|
377
|
+
return undefined;
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
const REFUSAL_KEYS = {
|
|
381
|
+
'not-wired': 'session.engine.dispatch.notWired',
|
|
382
|
+
'scope-mismatch': 'session.engine.dispatch.scopeMismatch',
|
|
383
|
+
'scope-unproven': 'session.engine.dispatch.scopeUnproven',
|
|
384
|
+
unresolved: 'session.engine.dispatch.unresolved',
|
|
385
|
+
};
|
|
386
|
+
const refused = (refusal) => Object.freeze({ kind: 'refused', refusal, message: msg(REFUSAL_KEYS[refusal]) });
|
|
387
|
+
function authOf(ctx) {
|
|
388
|
+
const slot = slotReadOf(ctx, 'auth');
|
|
389
|
+
if (slot.presence === 'absent' || (slot.presence === 'present' && slot.value === undefined))
|
|
390
|
+
return { kind: 'none' };
|
|
391
|
+
if (slot.presence !== 'present' || !isObj(slot.value))
|
|
392
|
+
return { kind: 'unknown' };
|
|
393
|
+
const a = slot.value;
|
|
394
|
+
const kind = readOwnDataValue(a, 'kind');
|
|
395
|
+
if (kind === 'token')
|
|
396
|
+
return { kind: 'token' };
|
|
397
|
+
if (kind !== 'registry')
|
|
398
|
+
return { kind: 'unknown' };
|
|
399
|
+
const registryUrl = readOwnDataValue(a, 'registryUrl');
|
|
400
|
+
const u = typeof registryUrl === 'string' ? tupleOriginUrlOf(registryUrl) : undefined;
|
|
401
|
+
if (u === undefined || typeof registryUrl !== 'string')
|
|
402
|
+
return { kind: 'unknown' };
|
|
403
|
+
const scopeSlot = slotReadOf(a, 'scope');
|
|
404
|
+
if (scopeSlot.presence === 'unreadable')
|
|
405
|
+
return { kind: 'unknown' };
|
|
406
|
+
const scope = scopeSlot.presence === 'present' && typeof scopeSlot.value === 'string' && scopeSlot.value !== '' ? scopeSlot.value : undefined;
|
|
407
|
+
return { kind: 'registry', center: engineNamespaceKeyFor(registryUrl), origin: u.origin, scope };
|
|
408
|
+
}
|
|
409
|
+
function addressSetOf(ctx, key) {
|
|
410
|
+
const out = new Set();
|
|
411
|
+
const v = readOwnDataValue(ctx, key);
|
|
412
|
+
if (!Array.isArray(v))
|
|
413
|
+
return out;
|
|
414
|
+
const n = readOwnDataValue(v, 'length');
|
|
415
|
+
if (typeof n !== 'number' || !Number.isSafeInteger(n) || n < 0)
|
|
416
|
+
return out;
|
|
417
|
+
for (let i = 0; i < n; i += 1) {
|
|
418
|
+
const s = readOwnDataValue(v, String(i));
|
|
419
|
+
if (typeof s === 'string' && tupleOriginUrlOf(s) !== undefined)
|
|
420
|
+
out.add(engineNamespaceKeyFor(s));
|
|
421
|
+
}
|
|
422
|
+
return out;
|
|
423
|
+
}
|
|
424
|
+
export function sessionDispatchTarget(reading, ctx) {
|
|
425
|
+
try {
|
|
426
|
+
if (!isObj(reading) || readOwnDataValue(reading, 'kind') !== 'bound')
|
|
427
|
+
return refused('unresolved');
|
|
428
|
+
const a = requestAssignmentOf(readOwnDataValue(reading, 'binding'));
|
|
429
|
+
if (a === undefined)
|
|
430
|
+
return refused('unresolved');
|
|
431
|
+
if (!isObj(ctx))
|
|
432
|
+
return refused('not-wired');
|
|
433
|
+
const id = readOwnDataNonEmptyString(ctx, 'id');
|
|
434
|
+
if (id === undefined)
|
|
435
|
+
return refused('not-wired');
|
|
436
|
+
const identity = a.identity;
|
|
437
|
+
if (identity.identityKind === 'self') {
|
|
438
|
+
return readOwnDataValue(ctx, 'selfSpawned') === true ? Object.freeze({ kind: 'self', wiringSnapshotId: id }) : refused('not-wired');
|
|
439
|
+
}
|
|
440
|
+
const auth = authOf(ctx);
|
|
441
|
+
if (identity.identityKind === 'declared') {
|
|
442
|
+
if (auth.kind !== 'registry' || auth.center !== identity.presentation.center || auth.scope === undefined)
|
|
443
|
+
return refused('scope-unproven');
|
|
444
|
+
if (auth.scope !== identity.presentation.scope)
|
|
445
|
+
return refused('scope-mismatch');
|
|
446
|
+
return Object.freeze({ kind: 'center', url: auth.origin + identity.connect.viaCenter, wiringSnapshotId: id });
|
|
447
|
+
}
|
|
448
|
+
const url = identity.connect.url;
|
|
449
|
+
const u = tupleOriginUrlOf(url);
|
|
450
|
+
if (u === undefined)
|
|
451
|
+
return refused('unresolved');
|
|
452
|
+
const address = engineNamespaceKeyFor(url);
|
|
453
|
+
const viaOtherOrigin = auth.kind === 'registry' && auth.origin !== u.origin;
|
|
454
|
+
const explicitDirect = auth.kind === 'none' && addressSetOf(ctx, 'explicitAddresses').has(address) && u.pathname.replace(/\/+$/, '') === '';
|
|
455
|
+
if (!viaOtherOrigin && !explicitDirect)
|
|
456
|
+
return refused('scope-unproven');
|
|
457
|
+
if (!addressSetOf(ctx, 'wiredAddresses').has(address))
|
|
458
|
+
return refused('not-wired');
|
|
459
|
+
return Object.freeze({ kind: 'address', url, wiringSnapshotId: id });
|
|
460
|
+
}
|
|
461
|
+
catch {
|
|
462
|
+
return refused('unresolved');
|
|
463
|
+
}
|
|
464
|
+
}
|
package/dist/sessionMap.d.ts
CHANGED
|
@@ -15,15 +15,25 @@ export interface SessionMapRecord {
|
|
|
15
15
|
reason: string;
|
|
16
16
|
at: string;
|
|
17
17
|
};
|
|
18
|
+
boundEngine?: SessionEngineSnapshot;
|
|
18
19
|
updatedAt: string;
|
|
19
20
|
}
|
|
21
|
+
export interface SessionEngineSnapshot {
|
|
22
|
+
kind: 'local' | 'cloud';
|
|
23
|
+
key: string;
|
|
24
|
+
connect?: {
|
|
25
|
+
url: string;
|
|
26
|
+
} | {
|
|
27
|
+
viaCenter: string;
|
|
28
|
+
};
|
|
29
|
+
}
|
|
20
30
|
export declare function engineNamespaceKeyFor(baseUrl: string | undefined): string;
|
|
21
31
|
export type SessionMapMergeVerdict = {
|
|
22
32
|
ok: true;
|
|
23
33
|
record: SessionMapRecord;
|
|
24
34
|
} | {
|
|
25
35
|
ok: false;
|
|
26
|
-
reason: 'no-shell-session-id' | 'no-engine-session-id';
|
|
36
|
+
reason: 'no-shell-session-id' | 'no-engine-session-id' | 'bound-entry-conflict';
|
|
27
37
|
};
|
|
28
38
|
export declare function mergeSessionMapRecord(prior: SessionMapRecord | undefined, partial: Partial<SessionMapRecord> & {
|
|
29
39
|
shellSessionId?: string;
|