@agentshouse/app-bridge 0.1.0-c58a055eeaa71 → 0.1.0-c70153aac6ee3
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/README.md +3 -1
- package/dist/calls.d.ts +117 -0
- package/dist/calls.js +1 -0
- package/dist/index.d.ts +23 -10
- package/dist/mdmodel/blocks.d.ts +10 -0
- package/dist/mdmodel/condition.d.ts +149 -0
- package/dist/mdmodel/definition.d.ts +65 -0
- package/dist/mdmodel/divide.d.ts +2 -0
- package/dist/mdmodel/document.d.ts +15 -0
- package/dist/mdmodel/fields.d.ts +5 -0
- package/dist/mdmodel/index.d.ts +18 -0
- package/dist/mdmodel/paths.d.ts +17 -0
- package/dist/mdmodel/profile.d.ts +5 -0
- package/dist/mdmodel/project.d.ts +20 -0
- package/dist/mdmodel/references.d.ts +3 -0
- package/dist/mdmodel/types.d.ts +143 -0
- package/dist/mdmodel/validate.d.ts +7 -0
- package/dist/mdmodel/version.d.ts +1 -0
- package/dist/mdmodel/yaml.d.ts +55 -0
- package/dist/mdruntime/acquisition.d.ts +13 -0
- package/dist/mdruntime/adapter.d.ts +477 -0
- package/dist/mdruntime/binary.d.ts +22 -0
- package/dist/mdruntime/change-set.d.ts +34 -0
- package/dist/mdruntime/change.d.ts +88 -0
- package/dist/mdruntime/client.d.ts +81 -0
- package/dist/mdruntime/collection.d.ts +38 -0
- package/dist/mdruntime/connection.d.ts +138 -0
- package/dist/mdruntime/conversation.d.ts +103 -0
- package/dist/mdruntime/durability.d.ts +14 -0
- package/dist/mdruntime/failure.d.ts +12 -0
- package/dist/mdruntime/file.d.ts +19 -0
- package/dist/mdruntime/model.d.ts +56 -0
- package/dist/mdruntime/observation.d.ts +29 -0
- package/dist/mdruntime/open.d.ts +1 -0
- package/dist/mdruntime/outcome.d.ts +46 -0
- package/dist/mdruntime/overlay.d.ts +26 -0
- package/dist/mdruntime/query.d.ts +246 -0
- package/dist/mdruntime/reach.d.ts +45 -0
- package/dist/mdruntime/readiness.d.ts +52 -0
- package/dist/mdruntime/recovery.d.ts +24 -0
- package/dist/mdruntime/replica.d.ts +45 -0
- package/dist/mdruntime/room-draft.d.ts +143 -0
- package/dist/mdruntime/rows.d.ts +36 -0
- package/dist/mdruntime/save.d.ts +63 -0
- package/dist/mdruntime/search.d.ts +83 -0
- package/dist/mdruntime/shared.d.ts +10 -0
- package/dist/mdruntime/status.d.ts +26 -0
- package/dist/mdruntime/store.d.ts +159 -0
- package/dist/mdruntime/transfer.d.ts +9 -0
- package/dist/mdruntime/turn.d.ts +6 -0
- package/dist/mdruntime/wire.d.ts +104 -0
- package/dist/test-host.d.ts +5 -5
- package/dist/test-host.js +56 -21
- package/docs/families.md +40 -2
- package/package.json +1 -4
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import type { ChangeSet } from './change-set.js';
|
|
2
|
+
import { type CoveredRoom, type Filter, type PendingRoom } from './query.js';
|
|
3
|
+
import type { Open } from './open.js';
|
|
4
|
+
export type DocumentPart = Open<'fields' | 'sections' | 'preamble' | 'path'>;
|
|
5
|
+
export type SearchRequest = {
|
|
6
|
+
text: string;
|
|
7
|
+
documents?: Filter;
|
|
8
|
+
conversations?: readonly string[];
|
|
9
|
+
limit?: number;
|
|
10
|
+
};
|
|
11
|
+
export type DocumentHit = {
|
|
12
|
+
room: string;
|
|
13
|
+
path: string;
|
|
14
|
+
type: string;
|
|
15
|
+
score: number;
|
|
16
|
+
matches: Readonly<Record<string, readonly DocumentPart[]>>;
|
|
17
|
+
};
|
|
18
|
+
export type MessageHit = {
|
|
19
|
+
conversation: string;
|
|
20
|
+
identity: string;
|
|
21
|
+
score: number;
|
|
22
|
+
matches: Readonly<Record<string, readonly Open<'text'>[]>>;
|
|
23
|
+
};
|
|
24
|
+
export type SearchCoverage = {
|
|
25
|
+
rooms: readonly CoveredRoom[];
|
|
26
|
+
conversations: readonly string[];
|
|
27
|
+
index: string;
|
|
28
|
+
overlay: readonly string[];
|
|
29
|
+
};
|
|
30
|
+
export type PendingConversation = {
|
|
31
|
+
conversation: string;
|
|
32
|
+
awaits: 'index';
|
|
33
|
+
};
|
|
34
|
+
export type SearchPending = {
|
|
35
|
+
pending: readonly (PendingRoom | PendingConversation)[];
|
|
36
|
+
};
|
|
37
|
+
export type SearchHits = {
|
|
38
|
+
documents: readonly DocumentHit[];
|
|
39
|
+
messages: readonly MessageHit[];
|
|
40
|
+
};
|
|
41
|
+
export type SearchResult = (SearchHits & {
|
|
42
|
+
coverage: SearchCoverage;
|
|
43
|
+
}) | SearchPending;
|
|
44
|
+
export type SearchedDocument = {
|
|
45
|
+
room: string;
|
|
46
|
+
path: string;
|
|
47
|
+
type: string;
|
|
48
|
+
fields: Readonly<Record<string, unknown>>;
|
|
49
|
+
preamble: string;
|
|
50
|
+
sections: Readonly<Record<string, string>>;
|
|
51
|
+
};
|
|
52
|
+
export type SearchedMessage = {
|
|
53
|
+
conversation: string;
|
|
54
|
+
identity: string;
|
|
55
|
+
text: string;
|
|
56
|
+
};
|
|
57
|
+
export type SearchSource = {
|
|
58
|
+
room(room: string): readonly string[];
|
|
59
|
+
document(room: string, path: string): SearchedDocument | null;
|
|
60
|
+
};
|
|
61
|
+
export type SearchPlan = {
|
|
62
|
+
text: string;
|
|
63
|
+
documents: unknown;
|
|
64
|
+
conversations: readonly string[] | null;
|
|
65
|
+
limit: number | null;
|
|
66
|
+
};
|
|
67
|
+
export type SearchIndex = {
|
|
68
|
+
generation(): string;
|
|
69
|
+
rooms(): ReadonlySet<string>;
|
|
70
|
+
conversations(): ReadonlySet<string>;
|
|
71
|
+
indexRoom(room: string): Promise<void>;
|
|
72
|
+
indexMessages(conversation: string, messages: readonly SearchedMessage[], whole: boolean): void;
|
|
73
|
+
forget(rooms: readonly string[]): void;
|
|
74
|
+
changed(set: ChangeSet): void;
|
|
75
|
+
changes(): number;
|
|
76
|
+
caughtUp(): Promise<void>;
|
|
77
|
+
search(plan: SearchPlan, documents: readonly {
|
|
78
|
+
room: string;
|
|
79
|
+
path: string;
|
|
80
|
+
}[] | null, conversations: readonly string[]): SearchHits;
|
|
81
|
+
};
|
|
82
|
+
export declare function searchPlanOf(input: unknown): SearchPlan;
|
|
83
|
+
export declare function createSearchIndex(source: SearchSource): SearchIndex;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export type Paths<V> = Readonly<Record<string, V>>;
|
|
2
|
+
type Weigh<V> = (key: string, value: V) => number;
|
|
3
|
+
export declare function shared<V>(map: Paths<V>): Paths<V>;
|
|
4
|
+
export declare function patched<V>(base: Paths<V>, set: Iterable<readonly [string, V]>, removed?: Iterable<string>): Paths<V>;
|
|
5
|
+
export declare function tally<V>(map: Paths<V>, weigh: Weigh<V>): number;
|
|
6
|
+
export declare function sizeOf<V>(map: Paths<V>): number;
|
|
7
|
+
export declare function differing<V>(left: Paths<V>, right: Paths<V>, same?: (left: V, right: V) => boolean): ReadonlySet<string>;
|
|
8
|
+
export declare function drafted<V>(base: Paths<V>): Record<string, V>;
|
|
9
|
+
export declare function settled<V>(draft: Record<string, V>): Paths<V>;
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { Open } from './open.js';
|
|
2
|
+
import type { ProviderRefusal } from './adapter.js';
|
|
3
|
+
import type { ReturnReason } from './room-draft.js';
|
|
4
|
+
export type AttentionEntry = {
|
|
5
|
+
room: string;
|
|
6
|
+
path: string;
|
|
7
|
+
returned: ReturnReason;
|
|
8
|
+
} | {
|
|
9
|
+
room: string;
|
|
10
|
+
refusal: ProviderRefusal;
|
|
11
|
+
};
|
|
12
|
+
export type SyncStatus = {
|
|
13
|
+
state: Open<'pending' | 'syncing' | 'synced'>;
|
|
14
|
+
lastCompleted: string | null;
|
|
15
|
+
providerUnreachable: boolean;
|
|
16
|
+
attentionRequired: readonly AttentionEntry[];
|
|
17
|
+
reset: string | null;
|
|
18
|
+
};
|
|
19
|
+
export type CycleProgress = {
|
|
20
|
+
complete: boolean;
|
|
21
|
+
reachable: boolean;
|
|
22
|
+
};
|
|
23
|
+
export declare const STARTING: SyncStatus;
|
|
24
|
+
export declare function transferring(status: SyncStatus): SyncStatus;
|
|
25
|
+
export declare function saving(status: SyncStatus): SyncStatus;
|
|
26
|
+
export declare function same(one: SyncStatus, other: SyncStatus): boolean;
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import type { ModelState } from './model.js';
|
|
2
|
+
import type { Capability, HeadChange, Member, OperationScopes, ProviderLimit, ReplicaAdmission, TypedSelection } from './adapter.js';
|
|
3
|
+
import type { AcceptedMessage, KeptReceipt } from './adapter.js';
|
|
4
|
+
import type { ChangeBatch } from './change.js';
|
|
5
|
+
import { type HeldBinary } from './overlay.js';
|
|
6
|
+
import type { ChatDraftFile } from './file.js';
|
|
7
|
+
import type { Submission } from './outcome.js';
|
|
8
|
+
import type { RoomDraftRecord, SavedDraft } from './room-draft.js';
|
|
9
|
+
export declare const STORE_SCHEMA = 25;
|
|
10
|
+
export declare const AUTHORED_SCHEMA = 2;
|
|
11
|
+
export type ReplicaRecord = {
|
|
12
|
+
locator: string;
|
|
13
|
+
name: string;
|
|
14
|
+
handle: string;
|
|
15
|
+
operations: OperationScopes;
|
|
16
|
+
replica: ReplicaAdmission;
|
|
17
|
+
model: ModelState;
|
|
18
|
+
typedSelection: TypedSelection | null;
|
|
19
|
+
selectionModel: ModelState;
|
|
20
|
+
providerOwnedPaths: readonly string[];
|
|
21
|
+
roomVersion: string;
|
|
22
|
+
transfer: string;
|
|
23
|
+
documents: Readonly<Record<string, string>>;
|
|
24
|
+
binaries: Readonly<Record<string, HeldBinary>>;
|
|
25
|
+
revisions: Readonly<Record<string, string>>;
|
|
26
|
+
changes: Readonly<Record<string, HeadChange>>;
|
|
27
|
+
written: Readonly<Record<string, string>>;
|
|
28
|
+
};
|
|
29
|
+
export type StagedLayer = Pick<ReplicaRecord, 'documents' | 'binaries' | 'revisions' | 'changes' | 'written'>;
|
|
30
|
+
export type TransferRecord = {
|
|
31
|
+
locator: string;
|
|
32
|
+
transfer: string;
|
|
33
|
+
selection: string;
|
|
34
|
+
from: string;
|
|
35
|
+
last: string;
|
|
36
|
+
pageToken: string | null;
|
|
37
|
+
models: {
|
|
38
|
+
collection: ModelState;
|
|
39
|
+
selection: ModelState;
|
|
40
|
+
};
|
|
41
|
+
};
|
|
42
|
+
export type PendingState = {
|
|
43
|
+
readonly drafts: readonly SavedDraft[];
|
|
44
|
+
readonly submission: Submission;
|
|
45
|
+
readonly lost: boolean;
|
|
46
|
+
readonly upload?: unknown;
|
|
47
|
+
readonly accepted?: string;
|
|
48
|
+
};
|
|
49
|
+
export type TargetRecord = {
|
|
50
|
+
established: boolean;
|
|
51
|
+
search: boolean;
|
|
52
|
+
};
|
|
53
|
+
export type QueueRecord = {
|
|
54
|
+
locator: string;
|
|
55
|
+
pending: readonly {
|
|
56
|
+
batch: ChangeBatch;
|
|
57
|
+
state: PendingState;
|
|
58
|
+
}[];
|
|
59
|
+
};
|
|
60
|
+
export type PresentationRecord = {
|
|
61
|
+
app: string;
|
|
62
|
+
value: unknown;
|
|
63
|
+
};
|
|
64
|
+
export type HeldConversation = {
|
|
65
|
+
conversation: string;
|
|
66
|
+
read: string | null | undefined;
|
|
67
|
+
partial: boolean;
|
|
68
|
+
};
|
|
69
|
+
export type ConversationWrite = {
|
|
70
|
+
conversation: string;
|
|
71
|
+
messages: readonly AcceptedMessage[];
|
|
72
|
+
read?: {
|
|
73
|
+
at: string | null;
|
|
74
|
+
partial: boolean;
|
|
75
|
+
};
|
|
76
|
+
};
|
|
77
|
+
export type ChatSubmission = {
|
|
78
|
+
readonly operation: string;
|
|
79
|
+
readonly text: string;
|
|
80
|
+
readonly files: readonly ChatDraftFile[];
|
|
81
|
+
readonly turn: string | null;
|
|
82
|
+
};
|
|
83
|
+
export type ChatDraftRecord = {
|
|
84
|
+
conversation: string;
|
|
85
|
+
text: string;
|
|
86
|
+
files: readonly ChatDraftFile[];
|
|
87
|
+
revision: string;
|
|
88
|
+
submitted?: readonly ChatSubmission[];
|
|
89
|
+
};
|
|
90
|
+
export type RecordWrite = {
|
|
91
|
+
next: ReplicaRecord;
|
|
92
|
+
previous: ReplicaRecord | null;
|
|
93
|
+
stored?: StagedLayer;
|
|
94
|
+
};
|
|
95
|
+
export type AuthoredWrite = {
|
|
96
|
+
locator: string;
|
|
97
|
+
queue: readonly ChangeBatch[];
|
|
98
|
+
saved?: ReadonlyMap<string, readonly SavedDraft[]>;
|
|
99
|
+
roomDrafts?: readonly RoomDraftRecord[];
|
|
100
|
+
consumedRoomDrafts?: readonly string[];
|
|
101
|
+
};
|
|
102
|
+
export type RuntimeStore = {
|
|
103
|
+
all(): Promise<readonly ReplicaRecord[]>;
|
|
104
|
+
keepAuthored(input: AuthoredWrite): Promise<void>;
|
|
105
|
+
write(input: RecordWrite): Promise<void>;
|
|
106
|
+
revokeModels(records: readonly ReplicaRecord[]): Promise<void>;
|
|
107
|
+
lastCompleted(): Promise<string | null>;
|
|
108
|
+
complete(at: string): Promise<void>;
|
|
109
|
+
providerLimits(): Promise<readonly ProviderLimit[]>;
|
|
110
|
+
capabilities(): Promise<readonly Capability[]>;
|
|
111
|
+
declare(limits: readonly ProviderLimit[], capabilities: readonly Capability[]): Promise<void>;
|
|
112
|
+
member(): Promise<Member | null>;
|
|
113
|
+
keepMember(member: Member | null): Promise<void>;
|
|
114
|
+
targets(): Promise<Readonly<Record<string, TargetRecord>>>;
|
|
115
|
+
keepTargets(targets: Readonly<Record<string, TargetRecord>>): Promise<void>;
|
|
116
|
+
queues(): Promise<readonly QueueRecord[]>;
|
|
117
|
+
submit(locator: string, id: string, submission: Submission, lost: boolean): Promise<void>;
|
|
118
|
+
accept(locator: string, id: string, roomVersion: string): Promise<void>;
|
|
119
|
+
keepUpload(locator: string, id: string, upload: unknown): Promise<void>;
|
|
120
|
+
roomDrafts(): Promise<readonly RoomDraftRecord[]>;
|
|
121
|
+
presentation(): Promise<readonly PresentationRecord[]>;
|
|
122
|
+
present(record: PresentationRecord): Promise<void>;
|
|
123
|
+
conversations(): Promise<readonly HeldConversation[]>;
|
|
124
|
+
keepMessages(write: ConversationWrite): Promise<void>;
|
|
125
|
+
messageWindow(conversation: string, limit: number | undefined): Promise<AcceptedMessage[]>;
|
|
126
|
+
messagesAfter(conversation: string, identity: string | null): Promise<AcceptedMessage[]>;
|
|
127
|
+
messageIdentities(conversation: string): Promise<readonly string[]>;
|
|
128
|
+
turnArrived(conversation: string, turn: string): Promise<boolean>;
|
|
129
|
+
dropConversations(conversations: readonly string[]): Promise<void>;
|
|
130
|
+
chatDrafts(): Promise<readonly ChatDraftRecord[]>;
|
|
131
|
+
keepChatDraft(record: ChatDraftRecord): Promise<void>;
|
|
132
|
+
dropChatDraft(conversation: string): Promise<void>;
|
|
133
|
+
keepRoomDraft(record: RoomDraftRecord): Promise<void>;
|
|
134
|
+
discardRoomDraft(locator: string, path: string): Promise<void>;
|
|
135
|
+
fences(): Promise<readonly string[]>;
|
|
136
|
+
erase(locators: readonly string[]): Promise<void>;
|
|
137
|
+
discard(locator: string): Promise<void>;
|
|
138
|
+
transfers(): Promise<readonly TransferRecord[]>;
|
|
139
|
+
staged(record: TransferRecord): Promise<StagedLayer>;
|
|
140
|
+
stage(record: TransferRecord, page: StagedLayer): Promise<void>;
|
|
141
|
+
abandon(locator: string): Promise<void>;
|
|
142
|
+
receivedHeads(): Promise<readonly KeptReceipt[]>;
|
|
143
|
+
receivedParts(key: string, count: number): Promise<readonly unknown[]>;
|
|
144
|
+
keepReceived(key: string, head: unknown, part?: {
|
|
145
|
+
index: number;
|
|
146
|
+
value: unknown;
|
|
147
|
+
}): Promise<void>;
|
|
148
|
+
dropReceived(keys: readonly string[]): Promise<void>;
|
|
149
|
+
generation(): Promise<string | null>;
|
|
150
|
+
rememberGeneration(value: string): Promise<void>;
|
|
151
|
+
close(): void;
|
|
152
|
+
};
|
|
153
|
+
export declare function authoredHolder(): Promise<string | null>;
|
|
154
|
+
export declare function authoredBy(holder: string): Promise<boolean>;
|
|
155
|
+
export declare function authoredBinding(): Promise<string | null>;
|
|
156
|
+
export declare function bindAuthored(binding: string): Promise<void>;
|
|
157
|
+
export declare function removeRuntimeStore(holder?: string): Promise<boolean>;
|
|
158
|
+
export declare function openDatabase(name: string, version: number, upgrade: (opening: IDBOpenDBRequest, oldVersion: number) => void): Promise<IDBDatabase>;
|
|
159
|
+
export declare function openRuntimeStore(fenced: (locator: string) => boolean): Promise<RuntimeStore>;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export declare function yielded(): Promise<void>;
|
|
2
|
+
export declare const ROW_WEIGHT = 256;
|
|
3
|
+
export type Later<T> = T | Promise<T>;
|
|
4
|
+
export declare function after<T, R>(value: Later<T>, next: (value: T) => R): Later<R>;
|
|
5
|
+
export declare function inUnits<T>(items: Iterable<T>, each: (item: T) => number): Later<void>;
|
|
6
|
+
export declare function inChunks<T>(items: readonly T[], weigh: (item: T) => number, each: (chunk: readonly T[]) => void): Promise<void>;
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import type { ConnectionRefusal } from './connection.js';
|
|
2
|
+
import type { Described } from './failure.js';
|
|
3
|
+
export type RuntimePort = {
|
|
4
|
+
postMessage(message: unknown): void;
|
|
5
|
+
addEventListener(type: 'message' | 'close', listener: (event: {
|
|
6
|
+
data?: unknown;
|
|
7
|
+
}) => void): void;
|
|
8
|
+
start(): void;
|
|
9
|
+
};
|
|
10
|
+
export type WireReach = 'within' | 'app' | 'runtime' | 'actions' | 'whole';
|
|
11
|
+
declare const MEMBERS: {
|
|
12
|
+
readonly rooms: 'within';
|
|
13
|
+
readonly query: 'within';
|
|
14
|
+
readonly search: 'within';
|
|
15
|
+
readonly types: 'within';
|
|
16
|
+
readonly save: 'within';
|
|
17
|
+
readonly history: 'within';
|
|
18
|
+
readonly 'binaryFile.read': 'within';
|
|
19
|
+
readonly 'binaryFile.readReference': 'within';
|
|
20
|
+
readonly call: 'actions';
|
|
21
|
+
readonly reached: 'within';
|
|
22
|
+
readonly log: 'whole';
|
|
23
|
+
readonly persistence: 'runtime';
|
|
24
|
+
readonly retry: 'runtime';
|
|
25
|
+
readonly reauthorize: 'runtime';
|
|
26
|
+
readonly 'roomDraft.list': 'within';
|
|
27
|
+
readonly 'roomDraft.read': 'within';
|
|
28
|
+
readonly 'roomDraft.write': 'within';
|
|
29
|
+
readonly 'roomDraft.discard': 'within';
|
|
30
|
+
readonly 'presentation.read': 'app';
|
|
31
|
+
readonly 'presentation.write': 'app';
|
|
32
|
+
readonly 'conversation.list': 'within';
|
|
33
|
+
readonly 'conversation.read': 'within';
|
|
34
|
+
readonly 'conversation.create': 'within';
|
|
35
|
+
readonly 'conversation.send': 'within';
|
|
36
|
+
readonly 'conversation.answer': 'within';
|
|
37
|
+
readonly 'conversation.interrupt': 'within';
|
|
38
|
+
readonly 'conversation.kill': 'within';
|
|
39
|
+
readonly 'conversation.cancel': 'within';
|
|
40
|
+
readonly 'conversation.delete': 'within';
|
|
41
|
+
readonly 'chatDraft.write': 'within';
|
|
42
|
+
readonly 'chatDraft.discard': 'within';
|
|
43
|
+
};
|
|
44
|
+
declare const TOPICS: {
|
|
45
|
+
readonly rooms: 'within';
|
|
46
|
+
readonly readiness: 'within';
|
|
47
|
+
readonly 'connection-refusal': 'runtime';
|
|
48
|
+
readonly 'storage-loss': 'runtime';
|
|
49
|
+
readonly 'deployment-facts': 'runtime';
|
|
50
|
+
readonly 'sync-status': 'within';
|
|
51
|
+
readonly 'service-mode': 'runtime';
|
|
52
|
+
readonly member: 'runtime';
|
|
53
|
+
readonly query: 'within';
|
|
54
|
+
readonly queue: 'within';
|
|
55
|
+
readonly 'room-drafts': 'within';
|
|
56
|
+
readonly presentation: 'app';
|
|
57
|
+
readonly conversation: 'within';
|
|
58
|
+
readonly conversations: 'within';
|
|
59
|
+
readonly agents: 'within';
|
|
60
|
+
};
|
|
61
|
+
export declare const WIRE_REACH: {
|
|
62
|
+
readonly members: Readonly<Record<string, WireReach>>;
|
|
63
|
+
readonly topics: Readonly<Record<string, WireReach>>;
|
|
64
|
+
};
|
|
65
|
+
export type WireMember = keyof typeof MEMBERS;
|
|
66
|
+
export type WireTopic = keyof typeof TOPICS;
|
|
67
|
+
export type WireRequest = {
|
|
68
|
+
kind: 'hello';
|
|
69
|
+
} | {
|
|
70
|
+
kind: 'call';
|
|
71
|
+
id: number;
|
|
72
|
+
member: WireMember;
|
|
73
|
+
input: readonly unknown[];
|
|
74
|
+
} | {
|
|
75
|
+
kind: 'observe';
|
|
76
|
+
id: number;
|
|
77
|
+
topic: WireTopic;
|
|
78
|
+
input: readonly unknown[];
|
|
79
|
+
} | {
|
|
80
|
+
kind: 'stop';
|
|
81
|
+
id: number;
|
|
82
|
+
};
|
|
83
|
+
export type WireAnswer = {
|
|
84
|
+
kind: 'result';
|
|
85
|
+
id: number;
|
|
86
|
+
value: unknown;
|
|
87
|
+
} | ({
|
|
88
|
+
kind: 'failure';
|
|
89
|
+
id: number;
|
|
90
|
+
} & Described) | {
|
|
91
|
+
kind: 'event';
|
|
92
|
+
id: number;
|
|
93
|
+
value: unknown;
|
|
94
|
+
} | {
|
|
95
|
+
kind: 'refusal';
|
|
96
|
+
refusal: ConnectionRefusal;
|
|
97
|
+
} | {
|
|
98
|
+
kind: 'ended';
|
|
99
|
+
};
|
|
100
|
+
export declare const AUTHORIZATION_ENDED = "the host authorization ended";
|
|
101
|
+
export declare const PORT_CLOSED = "the port closed";
|
|
102
|
+
export declare function request(message: unknown): WireRequest | null;
|
|
103
|
+
export declare function answer(message: unknown): WireAnswer | null;
|
|
104
|
+
export {};
|
package/dist/test-host.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { MdRuntimeClient } from '
|
|
2
|
-
import type { HouseAnalyticsChoice, HouseAppMessage, HouseExternalAnswer, HouseExternalRequest,
|
|
1
|
+
import type { MdRuntimeClient } from './mdruntime/client.js';
|
|
2
|
+
import type { HouseActivation, HouseAnalyticsChoice, HouseAppMessage, HouseExternalAnswer, HouseExternalRequest, HouseNavigationMode, HouseRefusal, HouseSourceDownload, HouseSourceTop, HouseStatus, HouseTab, HouseTask } from './index.js';
|
|
3
3
|
export interface HouseBridgeNavigation {
|
|
4
4
|
readonly mode: HouseNavigationMode;
|
|
5
5
|
readonly address: string;
|
|
@@ -15,13 +15,13 @@ export interface HouseBridgeTestHost {
|
|
|
15
15
|
publish(status: HouseStatus): void;
|
|
16
16
|
message(message: HouseAppMessage): void;
|
|
17
17
|
attachRuntime(runtime: MdRuntimeClient): void;
|
|
18
|
+
checkpoint(): Promise<HouseTask>;
|
|
19
|
+
restore(task: HouseTask | null): Promise<boolean>;
|
|
20
|
+
settle(activation: HouseActivation): void;
|
|
18
21
|
}
|
|
19
22
|
export interface HouseBridgeTestHostOptions {
|
|
20
23
|
readonly address?: string;
|
|
21
24
|
readonly status?: HouseStatus;
|
|
22
|
-
readonly images?: readonly (HouseImageCopy & {
|
|
23
|
-
readonly room: string;
|
|
24
|
-
})[];
|
|
25
25
|
readonly sources?: readonly {
|
|
26
26
|
readonly top: HouseSourceTop;
|
|
27
27
|
readonly download: HouseSourceDownload;
|
package/dist/test-host.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const HOST_ORIGIN = 'https://house.invalid';
|
|
2
|
-
const ADDRESS_MAX_CHARS =
|
|
2
|
+
const ADDRESS_MAX_CHARS = 64 * 1024;
|
|
3
3
|
function sameOriginPath(value) {
|
|
4
4
|
if (typeof value !== 'string')
|
|
5
5
|
return null;
|
|
@@ -29,6 +29,21 @@ function navigationRefused(address) {
|
|
|
29
29
|
address,
|
|
30
30
|
});
|
|
31
31
|
}
|
|
32
|
+
function followHeld(listeners, listener, held) {
|
|
33
|
+
let following = true;
|
|
34
|
+
queueMicrotask(() => {
|
|
35
|
+
if (!following)
|
|
36
|
+
return;
|
|
37
|
+
listeners.add(listener);
|
|
38
|
+
const value = held();
|
|
39
|
+
if (value !== null)
|
|
40
|
+
listener(value);
|
|
41
|
+
});
|
|
42
|
+
return () => {
|
|
43
|
+
following = false;
|
|
44
|
+
listeners.delete(listener);
|
|
45
|
+
};
|
|
46
|
+
}
|
|
32
47
|
export function createHouseBridgeTestHost(options = {}) {
|
|
33
48
|
const navigations = [];
|
|
34
49
|
const ceremonies = [];
|
|
@@ -42,6 +57,7 @@ export function createHouseBridgeTestHost(options = {}) {
|
|
|
42
57
|
let published = options.status ?? null;
|
|
43
58
|
let shown = null;
|
|
44
59
|
let seen = null;
|
|
60
|
+
let cooperation = null;
|
|
45
61
|
let attached = () => { };
|
|
46
62
|
const runtime = new Promise((resolve) => {
|
|
47
63
|
attached = resolve;
|
|
@@ -63,7 +79,17 @@ export function createHouseBridgeTestHost(options = {}) {
|
|
|
63
79
|
});
|
|
64
80
|
}
|
|
65
81
|
function navigate(mode, asked) {
|
|
66
|
-
|
|
82
|
+
let path = asked;
|
|
83
|
+
if (/^https?:\/\//i.test(asked)) {
|
|
84
|
+
try {
|
|
85
|
+
const target = new URL(asked);
|
|
86
|
+
path = target.origin === HOST_ORIGIN ? target.pathname + target.search + target.hash : '';
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
path = '';
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
const target = sameOriginPath(path);
|
|
67
93
|
if (target === null)
|
|
68
94
|
return Promise.reject(navigationRefused(asked));
|
|
69
95
|
navigations.push({ mode, address: target });
|
|
@@ -76,10 +102,7 @@ export function createHouseBridgeTestHost(options = {}) {
|
|
|
76
102
|
runtime,
|
|
77
103
|
address: () => shown,
|
|
78
104
|
onAddress(listener) {
|
|
79
|
-
addressListeners
|
|
80
|
-
return () => {
|
|
81
|
-
addressListeners.delete(listener);
|
|
82
|
-
};
|
|
105
|
+
return followHeld(addressListeners, listener, () => shown);
|
|
83
106
|
},
|
|
84
107
|
push: (asked) => navigate('push', asked),
|
|
85
108
|
replace: (asked) => navigate('replace', asked),
|
|
@@ -96,17 +119,6 @@ export function createHouseBridgeTestHost(options = {}) {
|
|
|
96
119
|
setTab(tab) {
|
|
97
120
|
tabs.push(tab);
|
|
98
121
|
},
|
|
99
|
-
readAttachment(room, attachment) {
|
|
100
|
-
const image = options.images?.find((entry) => entry.room === room && entry.attachment === attachment);
|
|
101
|
-
return Promise.resolve(image === undefined
|
|
102
|
-
? null
|
|
103
|
-
: {
|
|
104
|
-
attachment: image.attachment,
|
|
105
|
-
copy: image.copy,
|
|
106
|
-
name: image.name,
|
|
107
|
-
media_type: image.media_type,
|
|
108
|
-
});
|
|
109
|
-
},
|
|
110
122
|
sourceTop: (app) => Promise.resolve(options.sources?.find((entry) => entry.top.app_ref === app)?.top ?? null),
|
|
111
123
|
sourceDownload: (app) => Promise.resolve(options.sources?.find((entry) => entry.top.app_ref === app)?.download ?? null),
|
|
112
124
|
callExternal(request) {
|
|
@@ -117,10 +129,7 @@ export function createHouseBridgeTestHost(options = {}) {
|
|
|
117
129
|
readSiteScreenshot: (site) => Promise.resolve(options.siteScreenshots?.[site] ?? null),
|
|
118
130
|
status: () => seen,
|
|
119
131
|
onStatus(listener) {
|
|
120
|
-
statusListeners
|
|
121
|
-
return () => {
|
|
122
|
-
statusListeners.delete(listener);
|
|
123
|
-
};
|
|
132
|
+
return followHeld(statusListeners, listener, () => seen);
|
|
124
133
|
},
|
|
125
134
|
messages(listener) {
|
|
126
135
|
messageListeners.add(listener);
|
|
@@ -136,7 +145,19 @@ export function createHouseBridgeTestHost(options = {}) {
|
|
|
136
145
|
consents.push(choice);
|
|
137
146
|
publish({ ...published, analytics: { measures: true, choice } });
|
|
138
147
|
},
|
|
148
|
+
cooperate(given) {
|
|
149
|
+
cooperation = given;
|
|
150
|
+
return () => {
|
|
151
|
+
if (cooperation === given)
|
|
152
|
+
cooperation = null;
|
|
153
|
+
};
|
|
154
|
+
},
|
|
139
155
|
};
|
|
156
|
+
function cooperating() {
|
|
157
|
+
if (cooperation === null)
|
|
158
|
+
throw new Error('the App registered no cooperation');
|
|
159
|
+
return cooperation;
|
|
160
|
+
}
|
|
140
161
|
Object.defineProperty(globalThis, 'houseBridge', { value: bridge, configurable: true });
|
|
141
162
|
if (published !== null)
|
|
142
163
|
publish(published);
|
|
@@ -161,5 +182,19 @@ export function createHouseBridgeTestHost(options = {}) {
|
|
|
161
182
|
attachRuntime(client) {
|
|
162
183
|
attached(client);
|
|
163
184
|
},
|
|
185
|
+
async checkpoint() {
|
|
186
|
+
const held = cooperating();
|
|
187
|
+
await held.checkpoint();
|
|
188
|
+
await held.persist();
|
|
189
|
+
return JSON.parse(JSON.stringify((await held.capture()) ?? null));
|
|
190
|
+
},
|
|
191
|
+
async restore(task) {
|
|
192
|
+
const held = cooperating();
|
|
193
|
+
await held.restore(task);
|
|
194
|
+
return (await held.ready()) === true;
|
|
195
|
+
},
|
|
196
|
+
settle(activation) {
|
|
197
|
+
cooperating().settle(activation);
|
|
198
|
+
},
|
|
164
199
|
};
|
|
165
200
|
}
|
package/docs/families.md
CHANGED
|
@@ -39,10 +39,21 @@
|
|
|
39
39
|
whether the page measures and the visitor's stored analytics choice, and
|
|
40
40
|
`serviceMode`: `open`, `write-halted` while House refuses writes, so the
|
|
41
41
|
App can stop retrying them, or `null` while the runtime holds no House
|
|
42
|
-
connection. Every status field is camelCase.
|
|
42
|
+
connection. Every status field is camelCase. `onStatus(listener)` and
|
|
43
|
+
`onAddress(listener)` hand a listener the status and the address the bridge
|
|
44
|
+
already holds, then each change.
|
|
43
45
|
The App reports the visitor's choice with `analyticsConsent('accept')` or
|
|
44
46
|
`analyticsConsent('decline')`; the shell hands it to House's analytics loader, and
|
|
45
47
|
the choice never reaches House.
|
|
48
|
+
- **Handoff** - when House hands its runtime over to a newer build, the App keeps
|
|
49
|
+
running, its `runtime` client and observations included: a call it makes
|
|
50
|
+
meanwhile waits for the newer runtime, however long that takes, and is
|
|
51
|
+
answered once, by it; each observation goes on with the newer runtime's
|
|
52
|
+
values; and the status and the address arrive again. A runtime that ended
|
|
53
|
+
before answering has its reads answered by the next one; since it may have
|
|
54
|
+
applied any other call, an act on House is answered the outcome
|
|
55
|
+
`transport-uncertainty`, and every other call, a Save or a draft write among
|
|
56
|
+
them, fails with the retryable code `transport-uncertainty`.
|
|
46
57
|
- **Site image read** - given a Published Room and an original attachment
|
|
47
58
|
reference, it answers the web copy's path and metadata, or `null` when no
|
|
48
59
|
copy exists. The original bytes never cross this bridge at a Site.
|
|
@@ -82,6 +93,30 @@
|
|
|
82
93
|
after its latest release, as a JPEG `Blob`, or `null` when House holds none
|
|
83
94
|
or does not answer. A Site's own renderer reads none.
|
|
84
95
|
|
|
96
|
+
- **Cooperation** - `cooperate({ checkpoint, persist, capture, restore,
|
|
97
|
+
ready, settle })` lets House activate a newer release of the App while it
|
|
98
|
+
runs, keeping the User's task; the function it returns withdraws it.
|
|
99
|
+
Register it in the entry script, before the first draw, or House treats the
|
|
100
|
+
page as not cooperating and the newer release waits for the App's next
|
|
101
|
+
open. When a newer release is stored, House calls `checkpoint()`, which
|
|
102
|
+
resolves at the App's next safe checkpoint and may never resolve, then
|
|
103
|
+
`persist()`, which makes authored work durable, then `capture()`, which
|
|
104
|
+
answers the meaningful task the App owns, such as the selected record,
|
|
105
|
+
filters, cursor, selection and scroll position, as JSON of at most 65,536
|
|
106
|
+
characters; House keeps the address itself. In the newer release House
|
|
107
|
+
calls `restore(task)`, or `restore(null)` when it opens the release without
|
|
108
|
+
a task, then `ready()`, the App's own check that its local data and
|
|
109
|
+
capabilities work, and finally `settle('committed')` once the release is
|
|
110
|
+
active or `settle('abandoned')` when House returns to the release before
|
|
111
|
+
it, restoring the same task there. A release House opens already active is
|
|
112
|
+
settled `'committed'` at once, after `restore(task)` when House hands it a
|
|
113
|
+
task, and a cooperation registered after House settled is settled at its
|
|
114
|
+
registration. Until `settle('committed')` House fails the release's outside
|
|
115
|
+
calls at once, as offline, those of the workers it starts included, and
|
|
116
|
+
refuses its Saves, write acts and external calls with the retryable code
|
|
117
|
+
`house_trial_withheld`, so a start-up effect is not repeated; run start-up
|
|
118
|
+
effects after `settle('committed')`.
|
|
119
|
+
|
|
85
120
|
## The test host
|
|
86
121
|
|
|
87
122
|
`createHouseBridgeTestHost(options)` plays House in one page: it installs a
|
|
@@ -104,4 +139,7 @@ given by Site identifier, answers every `install()` `'manual'`, as a browser
|
|
|
104
139
|
with no install prompt does, answers every `notifications()` `'unavailable'`,
|
|
105
140
|
as a browser without push does, settles every `setBadge`, delivers each App
|
|
106
141
|
message `message({ from, body })` plays, and hands `bridge.runtime` the MD
|
|
107
|
-
Runtime client `attachRuntime(client)` gives it.
|
|
142
|
+
Runtime client `attachRuntime(client)` gives it. `checkpoint()` runs the
|
|
143
|
+
registered cooperation's checkpoint, persist and capture and answers the task,
|
|
144
|
+
`restore(task)` runs its restore and answers its readiness check, and
|
|
145
|
+
`settle(activation)` hands it the outcome.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agentshouse/app-bridge",
|
|
3
|
-
"version": "0.1.0-
|
|
3
|
+
"version": "0.1.0-c70153aac6ee3",
|
|
4
4
|
"description": "Types of the agents.house App bridge House hands every App: navigation, the tab title and icon, ceremonies, installation, notifications and the icon badge, status, Site image reads, App release code, App and Site screenshot reads, and App messages, with an accessor and an in-page test host.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -18,9 +18,6 @@
|
|
|
18
18
|
"default": "./dist/test-host.js"
|
|
19
19
|
}
|
|
20
20
|
},
|
|
21
|
-
"dependencies": {
|
|
22
|
-
"@agentshouse/mdruntime": "0.1.0-c967d1ca66fee"
|
|
23
|
-
},
|
|
24
21
|
"files": [
|
|
25
22
|
"dist",
|
|
26
23
|
"docs",
|