@agentshouse/app-bridge 0.1.0-ce42efd6bfc0c → 0.1.0-ce67b9fcd1972

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/calls.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  export interface HouseCalls {
2
2
  readonly 'access.read': {
3
3
  readonly room_ref: string;
4
+ readonly statistics?: boolean;
4
5
  };
5
6
  readonly 'conversation.answer': {
6
7
  readonly answer: {
package/dist/index.d.ts CHANGED
@@ -1,7 +1,6 @@
1
- import type { MdRuntimeClient } from './mdruntime/client.js';
1
+ import type { MdRuntimeClient, Open } from './mdruntime/client.js';
2
2
  import type { HouseCalls } from './calls.js';
3
3
  export type { HouseCalls } from './calls.js';
4
- type Open<Value extends string> = Value | (string & {});
5
4
  export type HouseCallInput<Name extends string> = Name extends keyof HouseCalls ? HouseCalls[Name] : unknown;
6
5
  export interface HouseRuntime extends Omit<MdRuntimeClient, 'call'> {
7
6
  call<Name extends Open<keyof HouseCalls>>(name: Name, input: HouseCallInput<Name>): ReturnType<MdRuntimeClient['call']>;
@@ -73,6 +72,7 @@ export interface HouseExternalRequest {
73
72
  readonly body_base64?: string;
74
73
  readonly account?: string;
75
74
  readonly slot?: string;
75
+ readonly room_ref?: string;
76
76
  }
77
77
  export type HouseExternalAnswer = {
78
78
  readonly status: number;
@@ -110,6 +110,20 @@ export interface HouseBrowserRefused extends Error {
110
110
  readonly code: string;
111
111
  readonly retryable: boolean;
112
112
  }
113
+ export interface HouseTrialWithheld {
114
+ readonly code: Open<'house_trial_withheld'>;
115
+ readonly retryable: true;
116
+ }
117
+ export type HouseTask = unknown;
118
+ export type HouseActivation = Open<'committed' | 'abandoned'>;
119
+ export interface HouseCooperation {
120
+ checkpoint(): Promise<void> | void;
121
+ persist(): Promise<void> | void;
122
+ capture(): Promise<HouseTask> | HouseTask;
123
+ restore(task: HouseTask | null): Promise<void> | void;
124
+ ready(): Promise<boolean> | boolean;
125
+ settle(activation: HouseActivation): void;
126
+ }
113
127
  export interface HouseBridge {
114
128
  readonly runtime: Promise<HouseRuntime>;
115
129
  address(): string | null;
@@ -130,6 +144,7 @@ export interface HouseBridge {
130
144
  onStatus(listener: (status: HouseStatus) => void): () => void;
131
145
  messages(listener: (message: HouseAppMessage) => void): () => void;
132
146
  analyticsConsent(choice: HouseAnalyticsChoice): void;
147
+ cooperate(cooperation: HouseCooperation): () => void;
133
148
  }
134
149
  export interface HouseHeld {
135
150
  readonly houseBridge: HouseBridge;
@@ -120,7 +120,6 @@ export type ItemFacts = {
120
120
  readonly source: string | null;
121
121
  readonly address: string | null;
122
122
  readonly has_attachment: boolean;
123
- readonly provider: string | null;
124
123
  readonly container: string | null;
125
124
  readonly author: string | null;
126
125
  readonly headers: Readonly<Record<string, string>>;
@@ -29,12 +29,26 @@ export type Shape = {
29
29
  readonly schema: Readonly<Record<string, unknown>>;
30
30
  readonly defs: Readonly<Record<string, unknown>>;
31
31
  };
32
+ export type RuleValue = string | number | boolean | null;
33
+ export type Transition = {
34
+ readonly from: RuleValue;
35
+ readonly to: RuleValue;
36
+ readonly roles?: readonly string[];
37
+ };
38
+ export type FieldRules = {
39
+ readonly changeRoles?: readonly string[];
40
+ readonly initialRoles?: readonly string[];
41
+ readonly transitions?: readonly Transition[];
42
+ };
32
43
  export type Definition = {
33
44
  readonly name: string;
34
45
  readonly memberDocument: boolean;
35
46
  readonly frontmatter: ValueFacts;
36
47
  readonly fields: Readonly<Record<string, ValueFacts>>;
37
48
  readonly sections: Readonly<Record<string, SectionSpec>>;
49
+ readonly rules: Readonly<Record<string, FieldRules>>;
50
+ readonly createRoles?: readonly string[];
51
+ readonly deleteRoles?: readonly string[];
38
52
  readonly shape: Shape;
39
53
  };
40
54
  export type Failure = {
@@ -10,9 +10,9 @@ export { MARKDOWN_SYNTAX_PROFILE } from './profile.js';
10
10
  export { project } from './project.js';
11
11
  export { references } from './references.js';
12
12
  export { ARRAY_INDEX, ATTACHMENT, crossedFacts, escapePointer, itemFacts, memberFacts, pointerFacts, pointerSegments, } from './definition.js';
13
- export type { Definition, JsonType, PatternFacts, PointerFacts, SectionSpec, Shape, ValueFacts, } from './definition.js';
13
+ export type { Definition, FieldRules, JsonType, PatternFacts, PointerFacts, RuleValue, SectionSpec, Shape, Transition, ValueFacts, } from './definition.js';
14
14
  export type { ApplyResult, BodyResult, Change, Division, DivisionContext, Document, DocumentCheck, Frontmatter, FrontmatterResult, Library, ModelVerification, Link, LinkOccurrence, ParseResult, Projection, ProjectionContext, Reached, Reference, Refusal, Span, Validation, ValidationContext, VerifiedModel, } from './types.js';
15
15
  export { checkDocument, resolves, sectionReferences, validate, verify } from './validate.js';
16
16
  export { VERSION } from './version.js';
17
- export { equalValue, frontmatterValue } from './yaml.js';
17
+ export { bodyAfterFrontmatter, equalValue, frontmatterValue } from './yaml.js';
18
18
  export type { FrontmatterValue } from './yaml.js';
@@ -238,17 +238,15 @@ export type ContractUnavailable = ProviderRefusal & {
238
238
  export type DiscoverResult = Discovery | TransportUncertainty | RevokedAuthorization | ContractUnavailable;
239
239
  export type PageToken = string;
240
240
  export type ChangeAuthor = {
241
- kind: 'user';
241
+ kind: Open<'user' | 'site'>;
242
242
  id: string;
243
243
  name: string;
244
- } | {
245
- kind: 'site';
244
+ };
245
+ export type Member = {
246
+ kind: Open<'user'>;
246
247
  id: string;
247
248
  name: string;
248
249
  };
249
- export type Member = Extract<ChangeAuthor, {
250
- kind: 'user';
251
- }>;
252
250
  export type HeadChange = {
253
251
  author: ChangeAuthor | null;
254
252
  time: string;
@@ -279,6 +277,7 @@ export type BootstrapPage = {
279
277
  models?: RoomModels;
280
278
  documents: Readonly<Record<string, string>>;
281
279
  revisions: Readonly<Record<string, string>>;
280
+ fileIds?: Readonly<Record<string, string>>;
282
281
  changes: Readonly<Record<string, HeadChange>>;
283
282
  binaryFiles: Readonly<Record<string, BinaryFile>>;
284
283
  pageToken?: PageToken;
@@ -298,6 +297,7 @@ export type RefreshPage = {
298
297
  models?: RoomModels;
299
298
  documents: Readonly<Record<string, string>>;
300
299
  revisions: Readonly<Record<string, string>>;
300
+ fileIds?: Readonly<Record<string, string>>;
301
301
  changes: Readonly<Record<string, HeadChange>>;
302
302
  binaryFiles: Readonly<Record<string, BinaryFile>>;
303
303
  removals: readonly string[];
@@ -326,6 +326,7 @@ export type MutationResult = {
326
326
  roomVersion: string;
327
327
  documents: Readonly<Record<string, string>>;
328
328
  revisions: Readonly<Record<string, string>>;
329
+ fileIds?: Readonly<Record<string, string>>;
329
330
  changes: Readonly<Record<string, HeadChange>>;
330
331
  removals: readonly string[];
331
332
  binaryFiles?: Readonly<Record<string, BinaryFile>>;
@@ -399,6 +400,13 @@ export type BinaryResult = {
399
400
  } | (ProviderRefusal & {
400
401
  kind: 'rejected';
401
402
  }) | AdapterFailure;
403
+ export type BinaryLinkResult = {
404
+ kind: 'link';
405
+ url: string;
406
+ name: string;
407
+ } | (ProviderRefusal & {
408
+ kind: 'rejected';
409
+ }) | AdapterFailure;
402
410
  export type ActionRequest = {
403
411
  name: string;
404
412
  input: unknown;
@@ -425,9 +433,12 @@ export type RoomStreamEvent = {
425
433
  } | {
426
434
  kind: 'closed';
427
435
  revoked: boolean;
436
+ lost: boolean;
428
437
  } | {
429
438
  kind: 'opening';
430
439
  expired: readonly string[];
440
+ } | {
441
+ kind: 'authority-changed';
431
442
  } | {
432
443
  kind: 'room-version';
433
444
  locator: string;
@@ -466,6 +477,9 @@ export type Adapter = {
466
477
  mutate(authorization: Authorization, request: MutationRequest, keep: (upload: unknown) => Promise<void>): Promise<MutationResult>;
467
478
  history(authorization: Authorization, request: HistoryRequest): Promise<HistoryResult>;
468
479
  binary(authorization: Authorization, request: BinaryRequest): Promise<BinaryResult>;
480
+ link(authorization: Authorization, request: Extract<BinaryRequest, {
481
+ kind: 'path';
482
+ }>): Promise<BinaryLinkResult>;
469
483
  referrerScope(referrer: unknown): ReferrerScope | null;
470
484
  action(authorization: Authorization, request: ActionRequest): Promise<ActionResult>;
471
485
  reached(locator: string, roomVersion: string, target: string): boolean;
@@ -1,9 +1,9 @@
1
- import type { AppRoom, ConnectionRefusal, HistoryQuery, RoomSchemas, SavedRoomDraft, SaveResult } from './connection.js';
1
+ import type { AppRoom, ConnectionRefusal, HistoryQuery, RoomSchemas, SavedParts, SavedRoomDraft, SaveResult } from './connection.js';
2
2
  import type { Member, ServiceMode } from './adapter.js';
3
3
  import type { ChatDraft, ConversationAgent, ConversationEntry, ConversationOptions, ConversationView } from './conversation.js';
4
4
  import { type Observation } from './observation.js';
5
5
  import type { BinaryReference } from './binary.js';
6
- import type { BinaryAnswer, CallResult, HistoryAnswer, Offline, QueueEntry } from './outcome.js';
6
+ import type { BinaryAnswer, BinaryLinkAnswer, CallResult, HistoryAnswer, Offline, QueueEntry } from './outcome.js';
7
7
  import type { DocumentQuery, DocumentResult, GroupQuery, GroupResult, PendingResult } from './query.js';
8
8
  import type { RoomDraft, RoomDraftParts, RoomDraftWrite } from './room-draft.js';
9
9
  import type { SearchRequest, SearchResult } from './search.js';
@@ -25,9 +25,11 @@ export type MdRuntimeClient = {
25
25
  discard(room: string, path: string, revision: string): Promise<RoomDraftWrite>;
26
26
  };
27
27
  save(room: string, roomDrafts: readonly SavedRoomDraft[]): Promise<SaveResult>;
28
+ saveParts(room: string, parts: readonly SavedParts[]): Promise<SaveResult>;
28
29
  presentation: {
29
30
  read(): Promise<unknown>;
30
31
  write(value: unknown): Promise<void>;
32
+ edit(members: Readonly<Record<string, unknown>>): Promise<void>;
31
33
  };
32
34
  conversation: {
33
35
  list(): Promise<readonly ConversationEntry[]>;
@@ -42,11 +44,13 @@ export type MdRuntimeClient = {
42
44
  };
43
45
  chatDraft: {
44
46
  write(conversation: string, draft: ChatDraft, revision?: string): Promise<void>;
47
+ prepend(conversation: string, draft: ChatDraft): Promise<void>;
45
48
  discard(conversation: string): Promise<void>;
46
49
  };
47
50
  history(locator: string, path: string, query?: HistoryQuery): Promise<HistoryAnswer>;
48
51
  binaryFile: {
49
52
  read(room: string, path: string, revision?: string): Promise<BinaryAnswer>;
53
+ link(room: string, path: string, revision?: string): Promise<BinaryLinkAnswer>;
50
54
  readReference(reference: BinaryReference): Promise<BinaryAnswer>;
51
55
  };
52
56
  call(name: string, input: unknown): Promise<CallResult>;
@@ -78,4 +82,5 @@ export type MdRuntimeClient = {
78
82
  export declare function connectMdRuntime(port: RuntimePort): MdRuntimeClient;
79
83
  export declare function inTurn(client: MdRuntimeClient, work: () => Promise<void>): Promise<void>;
80
84
  export type { Observation } from './observation.js';
81
- export type { RuntimePort } from './wire.js';
85
+ export type { Open } from './open.js';
86
+ export { unanswered, type RuntimePort, type WireMember } from './wire.js';
@@ -1,20 +1,21 @@
1
1
  import { type TypesResult } from './model.js';
2
2
  import { type Observation } from './observation.js';
3
3
  import { type DocumentQuery, type DocumentResult, type GroupQuery, type GroupResult, type PendingResult } from './query.js';
4
+ import { type EntrySeed } from './seed.js';
4
5
  import { type SearchRequest, type SearchResult } from './search.js';
5
6
  import { type Adapter, type Authorization, type Member, type ProviderRefusal, type ServiceMode } from './adapter.js';
6
7
  import { type ChatDraftSurface, type ConversationAgent, type ConversationEntry, type ConversationOptions, type ConversationSurface, type ConversationView } from './conversation.js';
7
8
  import { type WrittenBy } from './change.js';
8
9
  import type { Open } from './open.js';
9
10
  import { type BinaryReference } from './binary.js';
10
- import { type BinaryAnswer, type CallResult, type HistoryAnswer, type QueueEntry } from './outcome.js';
11
+ import { type BinaryAnswer, type BinaryLinkAnswer, type CallResult, type HistoryAnswer, type QueueEntry } from './outcome.js';
11
12
  import { type Recovery } from './recovery.js';
12
13
  import { type SaveRefusal } from './save.js';
13
- import { type RoomDraft, type RoomDraftWrite } from './room-draft.js';
14
+ import { type RoomDraft, type RoomDraftParts, type RoomDraftWrite } from './room-draft.js';
14
15
  import { type SyncStatus } from './status.js';
15
16
  import { type RuntimeShell } from './durability.js';
16
17
  import { type RuntimeDemand } from './acquisition.js';
17
- import { type CapacityCause, type CodeAvailability, type Persistence, type Readiness } from './readiness.js';
18
+ import { type CapacityCause, type CodeAvailability, type Persistence, type Readiness, type SearchObligation } from './readiness.js';
18
19
  import { type NarrowedView, type PortReach, type RuntimeView } from './reach.js';
19
20
  export type AppTypedSelection = {
20
21
  roots: readonly string[];
@@ -63,6 +64,10 @@ export type SavedRoomDraft = {
63
64
  readonly path: string;
64
65
  readonly revision: string;
65
66
  };
67
+ export type SavedParts = {
68
+ readonly path: string;
69
+ readonly parts: RoomDraftParts;
70
+ };
66
71
  export type RoomDraftSurface = {
67
72
  list(): Promise<readonly RoomDraft[]>;
68
73
  read(room: string, path: string): RoomDraft | null;
@@ -72,9 +77,11 @@ export type RoomDraftSurface = {
72
77
  export type PresentationSurface = {
73
78
  read(app: string): Promise<unknown>;
74
79
  write(app: string, value: unknown): Promise<void>;
80
+ edit(app: string, members: Readonly<Record<string, unknown>>): Promise<void>;
75
81
  };
76
82
  export type BinaryFileSurface = {
77
83
  read(room: string, path: string, revision?: string): Promise<BinaryAnswer>;
84
+ link(room: string, path: string, revision?: string): Promise<BinaryLinkAnswer>;
78
85
  readReference(reference: BinaryReference): Promise<BinaryAnswer>;
79
86
  };
80
87
  export type HistoryQuery = {
@@ -95,6 +102,7 @@ export type MdRuntime = {
95
102
  chatDraft: ChatDraftSurface;
96
103
  presentation: PresentationSurface;
97
104
  save(room: string, roomDrafts: readonly SavedRoomDraft[], writtenBy?: WrittenBy): Promise<SaveResult>;
105
+ saveParts(room: string, parts: readonly SavedParts[], writtenBy?: WrittenBy): Promise<SaveResult>;
98
106
  history(locator: string, path: string, query?: HistoryQuery): Promise<HistoryAnswer>;
99
107
  binaryFile: BinaryFileSurface;
100
108
  call(name: string, input: unknown): Promise<CallResult>;
@@ -126,8 +134,10 @@ export type ReadinessPort = {
126
134
  readonly target: string;
127
135
  readonly code: CodeAvailability;
128
136
  readonly capacity: CapacityCause | null;
137
+ readonly search: SearchObligation;
129
138
  };
130
139
  export type ComposedRuntime = RuntimeView & {
140
+ seed(entry: EntrySeed): void;
131
141
  stop(): Promise<void>;
132
142
  lose(locators: readonly string[]): Promise<void>;
133
143
  acquire(demand: RuntimeDemand): void;
@@ -36,10 +36,14 @@ export type ChatDraft = {
36
36
  };
37
37
  export type ConversationOptions = {
38
38
  limit?: number;
39
+ after?: string;
40
+ total?: true;
39
41
  };
40
42
  export type ConversationView = {
41
43
  conversation: string;
42
44
  messages: readonly ConversationMessage[];
45
+ next?: string;
46
+ total?: number;
43
47
  turn: RunningTurn | null;
44
48
  questions: readonly unknown[];
45
49
  process: {
@@ -64,6 +68,7 @@ export type ConversationSurface = {
64
68
  };
65
69
  export type ChatDraftSurface = {
66
70
  write(conversation: string, draft: ChatDraft, revision?: string): Promise<void>;
71
+ prepend(conversation: string, draft: ChatDraft): Promise<void>;
67
72
  discard(conversation: string): Promise<void>;
68
73
  };
69
74
  export type ConversationDependencies = {
@@ -89,6 +94,7 @@ export type ConversationStore = {
89
94
  known(): boolean;
90
95
  reconnected(): void;
91
96
  reopened(): void;
97
+ lost(): void;
92
98
  watch(conversation: string, options: ConversationOptions, deliver: (view: ConversationView) => void): () => void;
93
99
  watchList(deliver: (entries: readonly ConversationEntry[]) => void): () => void;
94
100
  watchAgents(deliver: (agents: readonly ConversationAgent[]) => void): () => void;
@@ -100,4 +106,5 @@ export type ConversationStore = {
100
106
  };
101
107
  export declare function unheldView(conversation: string): ConversationView;
102
108
  export declare const SESSION_STARTED = "Session started";
109
+ export declare function newChat(agent: string): string;
103
110
  export declare function createConversationStore(deps: ConversationDependencies): ConversationStore;
@@ -29,12 +29,13 @@ export type ModelState = {
29
29
  types: VerifiedModel['types'];
30
30
  };
31
31
  export type TypesResult = {
32
- status: 'unavailable';
32
+ status: Open<'unavailable'>;
33
33
  reason: ModelUnavailableReason;
34
+ types: null;
34
35
  schema?: string | null;
35
36
  revision?: string | null;
36
37
  } | {
37
- status: 'current' | 'cached';
38
+ status: Open<'current' | 'cached'>;
38
39
  identity: string;
39
40
  version: string;
40
41
  verifiedWith: ModelIdentity;
@@ -14,6 +14,8 @@ export type QueryChange = {
14
14
  removed: readonly RowKey[];
15
15
  order: readonly RowKey[] | null;
16
16
  coverage?: QueryCoverage;
17
+ next?: string | null;
18
+ total?: number;
17
19
  };
18
20
  export type QueryMessage = KeyedResult | QueryChange;
19
21
  export type Observed = {
@@ -1,4 +1,4 @@
1
- import type { ActionResult, AdapterFailure, BinaryResult, HistoryResult, ProviderRefusal, RoomVersionAt, ScopedRefusal } from './adapter.js';
1
+ import type { ActionResult, AdapterFailure, BinaryLinkResult, BinaryResult, HistoryResult, ProviderRefusal, RoomVersionAt, ScopedRefusal } from './adapter.js';
2
2
  import type { ChangeBatch } from './change.js';
3
3
  type Refused<Kind extends string> = ProviderRefusal & {
4
4
  kind: Kind;
@@ -18,8 +18,14 @@ export type BinaryAnswer = {
18
18
  kind: 'binary';
19
19
  blob: Blob;
20
20
  } | Refused<'rejected'> | Refused<'absent'> | Failure;
21
- export declare function absentBinary(path: string): BinaryAnswer;
21
+ export type BinaryLinkAnswer = {
22
+ kind: 'link';
23
+ url: string;
24
+ name: string;
25
+ } | Refused<'rejected'> | Refused<'absent'> | Failure;
26
+ export declare function absentBinary(path: string): Refused<'absent'>;
22
27
  export declare function binaryAnswer(result: BinaryResult): BinaryAnswer;
28
+ export declare function binaryLinkAnswer(result: BinaryLinkResult): BinaryLinkAnswer;
23
29
  export type Offline = {
24
30
  readonly kind: 'offline';
25
31
  };
@@ -2,6 +2,7 @@ import type { BinaryFile, HeadChange } from './adapter.js';
2
2
  import type { ChangeBatch } from './change.js';
3
3
  export type Heads = {
4
4
  revisions: Readonly<Record<string, string>>;
5
+ fileIds: Readonly<Record<string, string>>;
5
6
  changes: Readonly<Record<string, HeadChange>>;
6
7
  };
7
8
  export type HeldBinary = ({
@@ -1,6 +1,7 @@
1
1
  import { type Definition } from '../mdmodel/index.js';
2
2
  import type { HeadChange } from './adapter.js';
3
3
  import type { BinaryFileRecord } from './binary.js';
4
+ import type { Open } from './open.js';
4
5
  export type Value = string | number | boolean | null;
5
6
  export type Predicate = Value | {
6
7
  $eq: Value;
@@ -37,6 +38,8 @@ export type Filter = {
37
38
  types?: readonly string[];
38
39
  where?: Where;
39
40
  pathPrefix?: string;
41
+ folder?: string;
42
+ paths?: readonly string[];
40
43
  hop?: Related & {
41
44
  field: string;
42
45
  };
@@ -44,7 +47,7 @@ export type Filter = {
44
47
  field?: string;
45
48
  };
46
49
  };
47
- export type Key = 'room' | 'path' | 'type' | {
50
+ export type Key = 'room' | 'path' | 'type' | 'folder' | {
48
51
  field: string;
49
52
  };
50
53
  export type Select = 'all' | {
@@ -54,6 +57,7 @@ export type Select = 'all' | {
54
57
  markdown?: true;
55
58
  backlinks?: true;
56
59
  change?: true;
60
+ fileId?: true;
57
61
  };
58
62
  export type OrderOptions = {
59
63
  nulls?: 'first' | 'last';
@@ -69,6 +73,8 @@ export type DocumentQuery = Filter & {
69
73
  direction?: Direction;
70
74
  } & OrderOptions)[];
71
75
  limit?: number;
76
+ after?: string;
77
+ total?: true;
72
78
  };
73
79
  export type GroupQuery = Filter & {
74
80
  groupBy: readonly Exclude<Key, 'path'>[];
@@ -77,6 +83,8 @@ export type GroupQuery = Filter & {
77
83
  direction?: Direction;
78
84
  }[];
79
85
  limit?: number;
86
+ after?: string;
87
+ total?: true;
80
88
  };
81
89
  export type LocalQuery = DocumentQuery | GroupQuery;
82
90
  export type Backlink = {
@@ -94,6 +102,7 @@ export type QueryDocument = {
94
102
  markdown?: string;
95
103
  backlinks?: readonly Backlink[];
96
104
  change?: HeadChange | null;
105
+ fileId?: string | null;
97
106
  binaryFile?: BinaryFileRecord;
98
107
  };
99
108
  export type QueryGroup = {
@@ -110,7 +119,7 @@ export type QueryCoverage = {
110
119
  indexes: readonly string[];
111
120
  overlay: readonly string[];
112
121
  };
113
- export type Awaits = 'acquisition' | 'preparation' | 'index';
122
+ export type Awaits = Open<'acquisition' | 'preparation' | 'index'>;
114
123
  export type PendingRoom = {
115
124
  room: string;
116
125
  awaits: Awaits;
@@ -120,9 +129,13 @@ export type PendingResult = {
120
129
  };
121
130
  export type DocumentRows = {
122
131
  documents: readonly QueryDocument[];
132
+ next?: string;
133
+ total?: number;
123
134
  };
124
135
  export type GroupRows = {
125
136
  groups: readonly QueryGroup[];
137
+ next?: string;
138
+ total?: number;
126
139
  };
127
140
  export type QueryRows = DocumentRows | GroupRows;
128
141
  export type DocumentResult = DocumentRows & {
@@ -186,6 +199,8 @@ export type KeyPlan = {
186
199
  of: 'path';
187
200
  } | {
188
201
  of: 'type';
202
+ } | {
203
+ of: 'folder';
189
204
  } | {
190
205
  of: 'field';
191
206
  field: string;
@@ -198,6 +213,7 @@ export type DocumentShape = {
198
213
  markdown: boolean;
199
214
  backlinks: boolean;
200
215
  change: boolean;
216
+ fileId: boolean;
201
217
  orderBy: readonly {
202
218
  key: KeyPlan;
203
219
  options: OrderOptions & {
@@ -217,10 +233,17 @@ export type PlanReach = {
217
233
  rooms: readonly string[];
218
234
  documents: readonly string[];
219
235
  };
236
+ export type Continuation = {
237
+ text: string;
238
+ values: readonly unknown[] | null;
239
+ };
220
240
  export type Plan = {
241
+ key: string;
221
242
  rooms: readonly string[] | null;
222
243
  reach: PlanReach | null;
223
244
  root: Scope;
245
+ folder: string | null;
246
+ paths: readonly string[] | null;
224
247
  hop: (Scope & {
225
248
  field: string;
226
249
  }) | null;
@@ -229,6 +252,8 @@ export type Plan = {
229
252
  }) | null;
230
253
  shape: DocumentShape | GroupShape;
231
254
  limit: number | null;
255
+ after: Continuation | null;
256
+ total: boolean;
232
257
  };
233
258
  export declare class QueryError extends Error {
234
259
  readonly code: QueryErrorCode;
@@ -239,8 +264,10 @@ type Entries = Readonly<Record<string, unknown>>;
239
264
  export declare function invalid(at: string, problem: string): never;
240
265
  export declare function plain(value: unknown): value is Entries;
241
266
  export declare function known(value: Entries, allowed: readonly string[], at: string): void;
267
+ export declare function flag(input: unknown, at: string): boolean;
242
268
  export declare function planOf(input: unknown, facts: HeldRooms, reach?: PlanReach | null): Plan;
243
269
  export declare function limitOf(input: unknown): number | null;
244
270
  export declare function filterOf(input: unknown, facts: HeldRooms, reach?: PlanReach | null): Plan;
271
+ export declare function queryKey(query: unknown): string;
245
272
  export declare function identityOf(plan: Plan): string;
246
273
  export {};
@@ -2,7 +2,7 @@ import type { ReferrerScope } from './adapter.js';
2
2
  import type { MdRuntime, ReadinessPort, RuntimeTopic } from './connection.js';
3
3
  import type { Plan, PlanReach, QueryResult } from './query.js';
4
4
  import type { Readiness } from './readiness.js';
5
- import type { SearchResult } from './search.js';
5
+ import { type SearchResult } from './search.js';
6
6
  export type ReachedDocument = {
7
7
  readonly room: string;
8
8
  readonly path: string;
@@ -27,7 +27,6 @@ export type Reachable = RuntimeView & {
27
27
  query(plan: Plan): Promise<QueryResult>;
28
28
  watchPlan(plan: Plan, deliver: (message: unknown) => void): () => void;
29
29
  search(input: unknown, reach: PortReach | null): Promise<SearchResult>;
30
- searching(target: string): void;
31
30
  watchReadiness(port: ReadinessPort, reach: PortReach | null, deliver: (readiness: Readiness) => void): () => void;
32
31
  referrerScope(referrer: unknown): ReferrerScope | null;
33
32
  };
@@ -41,5 +41,9 @@ type Accepted = Extract<MutationResult, {
41
41
  export declare function applyReturned(confirmed: ConfirmedLayer, submitted: ChangeBatch, accepted: Accepted, roomVersion: string, writtenAt: string): Staged;
42
42
  export declare function replicaOf(confirmed: ConfirmedLayer, queue: readonly ChangeBatch[], previous?: Replica): Replica;
43
43
  export declare function landed(batch: ChangeBatch, confirmed: ConfirmedLayer, current?: Readonly<Record<string, string>>): boolean;
44
- export declare function withdrawals(confirmed: ConfirmedLayer, queue: readonly ChangeBatch[], withdrawable: (batch: ChangeBatch) => boolean, local: boolean): readonly ChangeBatch[];
44
+ export type Standing = {
45
+ readonly withdrawn: readonly ChangeBatch[];
46
+ readonly kept: readonly ChangeBatch[];
47
+ };
48
+ export declare function standing(confirmed: ConfirmedLayer, queue: readonly ChangeBatch[], withdrawable: (batch: ChangeBatch) => boolean, local: boolean): Standing;
45
49
  export {};
@@ -87,7 +87,7 @@ type ChangedUnderneath = {
87
87
  readonly file?: string | null;
88
88
  };
89
89
  export type ReturnReason = ProviderRefusal & {
90
- readonly kind: 'conflicted' | 'rejected' | 'expired' | 'withdrawn';
90
+ readonly kind: Open<'conflicted' | 'rejected' | 'expired' | 'withdrawn'>;
91
91
  };
92
92
  export declare function returnedBy(kind: 'expired' | 'withdrawn'): ReturnReason;
93
93
  export type RoomDraft = {
@@ -130,6 +130,18 @@ export declare function underneath(parts: HeldParts, path: string, visible: Visi
130
130
  export declare function heldFile(blob: Blob, base: string | null): Promise<HeldFile>;
131
131
  export declare function binaryBase(visible: VisibleLayer | undefined, path: string): string | null;
132
132
  export declare function changedParts(path: string, report: ChangedUnderneath): readonly ChangedPart[];
133
+ export type TextParts = {
134
+ readonly fields?: Readonly<Record<string, {
135
+ readonly value: unknown;
136
+ }>>;
137
+ readonly sections?: Readonly<Record<string, {
138
+ readonly value: string;
139
+ }>>;
140
+ readonly preamble?: {
141
+ readonly value: string;
142
+ };
143
+ };
144
+ export declare function partsAfter(markdown: string, parts: TextParts): string;
133
145
  export declare function returnedInto(existing: HeldParts | undefined, returned: HeldParts): HeldParts;
134
146
  export declare function moveTarget(move: {
135
147
  readonly to: string;
@@ -13,8 +13,10 @@ export type DocumentRow = {
13
13
  values: Fields;
14
14
  reached: Readonly<Record<string, readonly unknown[]>>;
15
15
  directories: readonly string[];
16
+ folder: string;
16
17
  text: string | null;
17
18
  change: HeadChange | null;
19
+ fileId: string | null;
18
20
  binary: BinaryFileRecord | null;
19
21
  };
20
22
  export type ReferenceRow = {
@@ -32,5 +34,5 @@ export type Row = DocumentRow | ReferenceRow;
32
34
  export declare function documentKey(room: string, path: string): string;
33
35
  export declare function roomOfKey(key: string): string;
34
36
  export declare function markdownPath(path: string): boolean;
35
- export declare function rowsOf(room: string, path: string, document: Frontmatter | null, composition: Composition, change: HeadChange | null, binary: BinaryFileRecord | null): readonly Row[];
37
+ export declare function rowsOf(room: string, path: string, document: Frontmatter | null, composition: Composition, change: HeadChange | null, fileId: string | null, binary: BinaryFileRecord | null): readonly Row[];
36
38
  export {};
@@ -38,6 +38,7 @@ export type BatchResult = {
38
38
  refusal: SaveRefusal;
39
39
  };
40
40
  export declare function providerRewritten(batch: ChangeBatch, visible: VisibleLayer): ChangeBatch;
41
+ export declare function queuedDocuments(queue: readonly ChangeBatch[]): ReadonlySet<string>;
41
42
  export type Requeued = {
42
43
  kind: 'requeued';
43
44
  queue: readonly ChangeBatch[];
@@ -1,3 +1,4 @@
1
+ import type { ProviderRefusal } from './adapter.js';
1
2
  import type { ChangeSet } from './change-set.js';
2
3
  import { type CoveredRoom, type Filter, type PendingRoom } from './query.js';
3
4
  import type { Open } from './open.js';
@@ -5,8 +6,11 @@ export type DocumentPart = Open<'fields' | 'sections' | 'preamble' | 'path'>;
5
6
  export type SearchRequest = {
6
7
  text: string;
7
8
  documents?: Filter;
9
+ collection?: true;
8
10
  conversations?: readonly string[];
9
11
  limit?: number;
12
+ after?: string;
13
+ total?: true;
10
14
  };
11
15
  export type DocumentHit = {
12
16
  room: string;
@@ -29,18 +33,30 @@ export type SearchCoverage = {
29
33
  };
30
34
  export type PendingConversation = {
31
35
  conversation: string;
32
- awaits: 'index';
33
- };
34
- export type SearchPending = {
35
- pending: readonly (PendingRoom | PendingConversation)[];
36
+ awaits: Open<'index'>;
36
37
  };
37
38
  export type SearchHits = {
38
39
  documents: readonly DocumentHit[];
39
40
  messages: readonly MessageHit[];
40
41
  };
41
- export type SearchResult = (SearchHits & {
42
+ export type SearchWindow = SearchHits & {
43
+ next?: string;
44
+ total?: {
45
+ documents: number;
46
+ messages: number;
47
+ };
48
+ };
49
+ export type SearchPending = SearchHits & {
50
+ pending: readonly (PendingRoom | PendingConversation)[];
51
+ coverage: SearchCoverage;
52
+ };
53
+ export type SearchUndeclared = ProviderRefusal & {
54
+ kind: 'undeclared';
55
+ };
56
+ export type SearchResult = (SearchWindow & {
42
57
  coverage: SearchCoverage;
43
- }) | SearchPending;
58
+ }) | SearchPending | SearchUndeclared;
59
+ export declare function undeclaredSearch(): SearchUndeclared;
44
60
  export type SearchedDocument = {
45
61
  room: string;
46
62
  path: string;
@@ -58,11 +74,15 @@ export type SearchSource = {
58
74
  room(room: string): readonly string[];
59
75
  document(room: string, path: string): SearchedDocument | null;
60
76
  };
77
+ type HitCursor = readonly [number, string, string] | readonly [] | null;
61
78
  export type SearchPlan = {
62
79
  text: string;
63
80
  documents: unknown;
81
+ collection: boolean;
64
82
  conversations: readonly string[] | null;
65
83
  limit: number | null;
84
+ after: readonly [HitCursor, HitCursor] | null;
85
+ total: boolean;
66
86
  };
67
87
  export type SearchIndex = {
68
88
  generation(): string;
@@ -77,7 +97,8 @@ export type SearchIndex = {
77
97
  search(plan: SearchPlan, documents: readonly {
78
98
  room: string;
79
99
  path: string;
80
- }[] | null, conversations: readonly string[]): SearchHits;
100
+ }[] | null, conversations: readonly string[], rooms: ReadonlySet<string> | null, selections: ReadonlyMap<string, readonly string[]> | null): SearchWindow;
81
101
  };
82
102
  export declare function searchPlanOf(input: unknown): SearchPlan;
83
103
  export declare function createSearchIndex(source: SearchSource): SearchIndex;
104
+ export {};
@@ -0,0 +1,15 @@
1
+ import type { KeyedResult } from './observation.js';
2
+ import type { QueryRows } from './query.js';
3
+ export type EntrySeed = {
4
+ readonly at: Readonly<Record<string, string>>;
5
+ readonly queries: readonly {
6
+ readonly query: unknown;
7
+ readonly rows: QueryRows;
8
+ }[];
9
+ };
10
+ export type Seeded = {
11
+ readonly rows: QueryRows;
12
+ readonly at: Readonly<Record<string, string>>;
13
+ };
14
+ export declare function entrySeedOf(value: unknown): EntrySeed | null;
15
+ export declare function seededResult(seed: Seeded): KeyedResult;
@@ -7,7 +7,7 @@ import type { ChatDraftFile } from './file.js';
7
7
  import type { Submission } from './outcome.js';
8
8
  import type { RoomDraftRecord, SavedDraft } from './room-draft.js';
9
9
  export declare const STORE_SCHEMA = 25;
10
- export declare const AUTHORED_SCHEMA = 2;
10
+ export declare const AUTHORED_SCHEMA = 3;
11
11
  export type ReplicaRecord = {
12
12
  locator: string;
13
13
  name: string;
@@ -23,10 +23,11 @@ export type ReplicaRecord = {
23
23
  documents: Readonly<Record<string, string>>;
24
24
  binaries: Readonly<Record<string, HeldBinary>>;
25
25
  revisions: Readonly<Record<string, string>>;
26
+ fileIds: Readonly<Record<string, string>>;
26
27
  changes: Readonly<Record<string, HeadChange>>;
27
28
  written: Readonly<Record<string, string>>;
28
29
  };
29
- export type StagedLayer = Pick<ReplicaRecord, 'documents' | 'binaries' | 'revisions' | 'changes' | 'written'>;
30
+ export type StagedLayer = Pick<ReplicaRecord, 'documents' | 'binaries' | 'revisions' | 'fileIds' | 'changes' | 'written'>;
30
31
  export type TransferRecord = {
31
32
  locator: string;
32
33
  transfer: string;
@@ -48,7 +49,6 @@ export type PendingState = {
48
49
  };
49
50
  export type TargetRecord = {
50
51
  established: boolean;
51
- search: boolean;
52
52
  };
53
53
  export type QueueRecord = {
54
54
  locator: string;
@@ -66,6 +66,10 @@ export type HeldConversation = {
66
66
  read: string | null | undefined;
67
67
  partial: boolean;
68
68
  };
69
+ export type MessageWindow = {
70
+ messages: AcceptedMessage[];
71
+ more: boolean;
72
+ };
69
73
  export type ConversationWrite = {
70
74
  conversation: string;
71
75
  messages: readonly AcceptedMessage[];
@@ -86,6 +90,12 @@ export type ChatDraftRecord = {
86
90
  files: readonly ChatDraftFile[];
87
91
  revision: string;
88
92
  submitted?: readonly ChatSubmission[];
93
+ moves?: readonly string[];
94
+ };
95
+ export type CallRecord = {
96
+ readonly operation: string;
97
+ readonly name: string;
98
+ readonly input: unknown;
89
99
  };
90
100
  export type RecordWrite = {
91
101
  next: ReplicaRecord;
@@ -95,6 +105,7 @@ export type RecordWrite = {
95
105
  export type AuthoredWrite = {
96
106
  locator: string;
97
107
  queue: readonly ChangeBatch[];
108
+ founded?: readonly ChangeBatch[];
98
109
  saved?: ReadonlyMap<string, readonly SavedDraft[]>;
99
110
  roomDrafts?: readonly RoomDraftRecord[];
100
111
  consumedRoomDrafts?: readonly string[];
@@ -122,14 +133,18 @@ export type RuntimeStore = {
122
133
  present(record: PresentationRecord): Promise<void>;
123
134
  conversations(): Promise<readonly HeldConversation[]>;
124
135
  keepMessages(write: ConversationWrite): Promise<void>;
125
- messageWindow(conversation: string, limit: number | undefined): Promise<AcceptedMessage[]>;
136
+ messageWindow(conversation: string, limit: number, before: readonly [string, string] | null): Promise<MessageWindow>;
137
+ messageCount(conversation: string): Promise<number>;
126
138
  messagesAfter(conversation: string, identity: string | null): Promise<AcceptedMessage[]>;
127
139
  messageIdentities(conversation: string): Promise<readonly string[]>;
128
140
  turnArrived(conversation: string, turn: string): Promise<boolean>;
129
141
  dropConversations(conversations: readonly string[]): Promise<void>;
130
142
  chatDrafts(): Promise<readonly ChatDraftRecord[]>;
131
- keepChatDraft(record: ChatDraftRecord): Promise<void>;
143
+ keepChatDrafts(records: readonly ChatDraftRecord[]): Promise<void>;
132
144
  dropChatDraft(conversation: string): Promise<void>;
145
+ calls(): Promise<readonly CallRecord[]>;
146
+ keepCall(record: CallRecord): Promise<void>;
147
+ dropCall(operation: string): Promise<void>;
133
148
  keepRoomDraft(record: RoomDraftRecord): Promise<void>;
134
149
  discardRoomDraft(locator: string, path: string): Promise<void>;
135
150
  fences(): Promise<readonly string[]>;
@@ -155,4 +170,5 @@ export declare function authoredBy(holder: string): Promise<boolean>;
155
170
  export declare function authoredBinding(): Promise<string | null>;
156
171
  export declare function bindAuthored(binding: string): Promise<void>;
157
172
  export declare function removeRuntimeStore(holder?: string): Promise<boolean>;
173
+ export declare function openDatabase(name: string, version: number, upgrade: (opening: IDBOpenDBRequest, oldVersion: number) => void): Promise<IDBDatabase>;
158
174
  export declare function openRuntimeStore(fenced: (locator: string) => boolean): Promise<RuntimeStore>;
@@ -8,38 +8,152 @@ export type RuntimePort = {
8
8
  start(): void;
9
9
  };
10
10
  export type WireReach = 'within' | 'app' | 'runtime' | 'actions' | 'whole';
11
+ export type WireEffect = 'read' | 'write' | 'action';
12
+ export type WireCall = {
13
+ readonly reach: WireReach;
14
+ readonly effect: WireEffect;
15
+ };
11
16
  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';
17
+ readonly rooms: {
18
+ readonly reach: 'within';
19
+ readonly effect: 'read';
20
+ };
21
+ readonly query: {
22
+ readonly reach: 'within';
23
+ readonly effect: 'read';
24
+ };
25
+ readonly search: {
26
+ readonly reach: 'within';
27
+ readonly effect: 'read';
28
+ };
29
+ readonly types: {
30
+ readonly reach: 'within';
31
+ readonly effect: 'read';
32
+ };
33
+ readonly save: {
34
+ readonly reach: 'within';
35
+ readonly effect: 'write';
36
+ };
37
+ readonly saveParts: {
38
+ readonly reach: 'within';
39
+ readonly effect: 'write';
40
+ };
41
+ readonly history: {
42
+ readonly reach: 'within';
43
+ readonly effect: 'read';
44
+ };
45
+ readonly 'binaryFile.read': {
46
+ readonly reach: 'within';
47
+ readonly effect: 'read';
48
+ };
49
+ readonly 'binaryFile.link': {
50
+ readonly reach: 'within';
51
+ readonly effect: 'read';
52
+ };
53
+ readonly 'binaryFile.readReference': {
54
+ readonly reach: 'within';
55
+ readonly effect: 'read';
56
+ };
57
+ readonly call: {
58
+ readonly reach: 'actions';
59
+ readonly effect: 'action';
60
+ };
61
+ readonly reached: {
62
+ readonly reach: 'within';
63
+ readonly effect: 'read';
64
+ };
65
+ readonly log: {
66
+ readonly reach: 'whole';
67
+ readonly effect: 'read';
68
+ };
69
+ readonly persistence: {
70
+ readonly reach: 'runtime';
71
+ readonly effect: 'read';
72
+ };
73
+ readonly retry: {
74
+ readonly reach: 'runtime';
75
+ readonly effect: 'write';
76
+ };
77
+ readonly reauthorize: {
78
+ readonly reach: 'runtime';
79
+ readonly effect: 'write';
80
+ };
81
+ readonly 'roomDraft.list': {
82
+ readonly reach: 'within';
83
+ readonly effect: 'read';
84
+ };
85
+ readonly 'roomDraft.read': {
86
+ readonly reach: 'within';
87
+ readonly effect: 'read';
88
+ };
89
+ readonly 'roomDraft.write': {
90
+ readonly reach: 'within';
91
+ readonly effect: 'write';
92
+ };
93
+ readonly 'roomDraft.discard': {
94
+ readonly reach: 'within';
95
+ readonly effect: 'write';
96
+ };
97
+ readonly 'presentation.read': {
98
+ readonly reach: 'app';
99
+ readonly effect: 'read';
100
+ };
101
+ readonly 'presentation.write': {
102
+ readonly reach: 'app';
103
+ readonly effect: 'write';
104
+ };
105
+ readonly 'presentation.edit': {
106
+ readonly reach: 'app';
107
+ readonly effect: 'write';
108
+ };
109
+ readonly 'conversation.list': {
110
+ readonly reach: 'within';
111
+ readonly effect: 'read';
112
+ };
113
+ readonly 'conversation.read': {
114
+ readonly reach: 'within';
115
+ readonly effect: 'read';
116
+ };
117
+ readonly 'conversation.create': {
118
+ readonly reach: 'within';
119
+ readonly effect: 'action';
120
+ };
121
+ readonly 'conversation.send': {
122
+ readonly reach: 'within';
123
+ readonly effect: 'action';
124
+ };
125
+ readonly 'conversation.answer': {
126
+ readonly reach: 'within';
127
+ readonly effect: 'action';
128
+ };
129
+ readonly 'conversation.interrupt': {
130
+ readonly reach: 'within';
131
+ readonly effect: 'action';
132
+ };
133
+ readonly 'conversation.kill': {
134
+ readonly reach: 'within';
135
+ readonly effect: 'action';
136
+ };
137
+ readonly 'conversation.cancel': {
138
+ readonly reach: 'within';
139
+ readonly effect: 'action';
140
+ };
141
+ readonly 'conversation.delete': {
142
+ readonly reach: 'within';
143
+ readonly effect: 'action';
144
+ };
145
+ readonly 'chatDraft.write': {
146
+ readonly reach: 'within';
147
+ readonly effect: 'write';
148
+ };
149
+ readonly 'chatDraft.prepend': {
150
+ readonly reach: 'within';
151
+ readonly effect: 'write';
152
+ };
153
+ readonly 'chatDraft.discard': {
154
+ readonly reach: 'within';
155
+ readonly effect: 'write';
156
+ };
43
157
  };
44
158
  declare const TOPICS: {
45
159
  readonly rooms: 'within';
@@ -58,8 +172,8 @@ declare const TOPICS: {
58
172
  readonly conversations: 'within';
59
173
  readonly agents: 'within';
60
174
  };
61
- export declare const WIRE_REACH: {
62
- readonly members: Readonly<Record<string, WireReach>>;
175
+ export declare const WIRE: {
176
+ readonly members: Readonly<Record<string, WireCall>>;
63
177
  readonly topics: Readonly<Record<string, WireReach>>;
64
178
  };
65
179
  export type WireMember = keyof typeof MEMBERS;
@@ -97,6 +211,10 @@ export type WireAnswer = {
97
211
  } | {
98
212
  kind: 'ended';
99
213
  };
214
+ export declare function unanswered(call: {
215
+ readonly id: number;
216
+ readonly member: WireMember;
217
+ }): WireAnswer | null;
100
218
  export declare const AUTHORIZATION_ENDED = "the host authorization ended";
101
219
  export declare const PORT_CLOSED = "the port closed";
102
220
  export declare function request(message: unknown): WireRequest | null;
@@ -1,5 +1,5 @@
1
1
  import type { MdRuntimeClient } from './mdruntime/client.js';
2
- import type { HouseAnalyticsChoice, HouseAppMessage, HouseExternalAnswer, HouseExternalRequest, HouseNavigationMode, HouseRefusal, HouseSourceDownload, HouseSourceTop, HouseStatus, HouseTab } from './index.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,6 +15,9 @@ 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;
package/dist/test-host.js CHANGED
@@ -57,6 +57,7 @@ export function createHouseBridgeTestHost(options = {}) {
57
57
  let published = options.status ?? null;
58
58
  let shown = null;
59
59
  let seen = null;
60
+ let cooperation = null;
60
61
  let attached = () => { };
61
62
  const runtime = new Promise((resolve) => {
62
63
  attached = resolve;
@@ -144,7 +145,19 @@ export function createHouseBridgeTestHost(options = {}) {
144
145
  consents.push(choice);
145
146
  publish({ ...published, analytics: { measures: true, choice } });
146
147
  },
148
+ cooperate(given) {
149
+ cooperation = given;
150
+ return () => {
151
+ if (cooperation === given)
152
+ cooperation = null;
153
+ };
154
+ },
147
155
  };
156
+ function cooperating() {
157
+ if (cooperation === null)
158
+ throw new Error('the App registered no cooperation');
159
+ return cooperation;
160
+ }
148
161
  Object.defineProperty(globalThis, 'houseBridge', { value: bridge, configurable: true });
149
162
  if (published !== null)
150
163
  publish(published);
@@ -169,5 +182,19 @@ export function createHouseBridgeTestHost(options = {}) {
169
182
  attachRuntime(client) {
170
183
  attached(client);
171
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
+ },
172
199
  };
173
200
  }
package/docs/families.md CHANGED
@@ -12,7 +12,9 @@
12
12
  purpose-bound authenticated pages. The shell navigates only to a same-origin
13
13
  absolute path, carries its current address as the return target, and the page
14
14
  returns there when it completes. An App names an address House gave it in a
15
- reading and composes none.
15
+ reading and composes one only for `/bind/<app_ref>`, where the User binds
16
+ its Rooms and connects its account slots, with `?slot=<name>` to open at one
17
+ slot.
16
18
  - **Installation** - `install()` offers the page as a Home-screen app. Where the
17
19
  browser has an install prompt ready the shell shows it and the call resolves
18
20
  `'accepted'` or `'dismissed'` with the User's choice, spending that prompt;
@@ -45,6 +47,15 @@
45
47
  The App reports the visitor's choice with `analyticsConsent('accept')` or
46
48
  `analyticsConsent('decline')`; the shell hands it to House's analytics loader, and
47
49
  the choice never reaches House.
50
+ - **Handoff** - when House hands its runtime over to a newer build, the App keeps
51
+ running, its `runtime` client and observations included: a call it makes
52
+ meanwhile waits for the newer runtime, however long that takes, and is
53
+ answered once, by it; each observation goes on with the newer runtime's
54
+ values; and the status and the address arrive again. A runtime that ended
55
+ before answering has its reads answered by the next one; since it may have
56
+ applied any other call, an act on House is answered the outcome
57
+ `transport-uncertainty`, and every other call, a Save or a draft write among
58
+ them, fails with the retryable code `transport-uncertainty`.
48
59
  - **Site image read** - given a Published Room and an original attachment
49
60
  reference, it answers the web copy's path and metadata, or `null` when no
50
61
  copy exists. The original bytes never cross this bridge at a Site.
@@ -58,14 +69,15 @@
58
69
  refusal is House's `{ error: { code, retryable } }`, `app_release_not_found` for an
59
70
  App with no release; a read House does not answer, or one that outlived
60
71
  the browser's signed-in User, is `null`.
61
- - **External calls** - `callExternal({ url, method, headers, body, slot })`
72
+ - **External calls** - `callExternal({ url, method, headers, body, slot, room_ref })`
62
73
  has House's server send an HTTPS request to one of the release's declared
63
74
  external origins and resolves with the service's `status`, `headers` and its
64
75
  body as `body` text or `body_base64`, or a refusal as House's
65
76
  `{ error: { code, retryable } }`, or `null` when House does not answer. House fills in the
66
- App and its running release; naming an account slot places the key of the
67
- account the User connected to it, which the App never sees, and naming none
68
- sends no key. A Site's call names no slot, and the House panel names an
77
+ App and its running release; naming an account slot and one of the App's
78
+ bound Rooms places the key of the account that Room connects to the slot,
79
+ when the User holds one of the account's roles there, which the App never
80
+ sees, and naming neither sends no key. A Site's call names no slot, and the House panel names an
69
81
  `account` instead. `body_base64` replaces `body` for bytes.
70
82
  - **App messages** - `messages(listener)` hands the listener each message
71
83
  another holder of this App sends to this User's running copies, as `from`,
@@ -84,6 +96,31 @@
84
96
  after its latest release, as a JPEG `Blob`, or `null` when House holds none
85
97
  or does not answer. A Site's own renderer reads none.
86
98
 
99
+ - **Cooperation** - `cooperate({ checkpoint, persist, capture, restore,
100
+ ready, settle })` lets House activate a newer release of the App while it
101
+ runs, keeping the User's task; the function it returns withdraws it.
102
+ Register it in the entry script, before the first draw, or House treats the
103
+ page as not cooperating and the newer release waits for the App's next
104
+ open. When a newer release is stored, House calls `checkpoint()`, which
105
+ resolves at the App's next safe checkpoint and may never resolve, then
106
+ `persist()`, which makes authored work durable, then `capture()`, which
107
+ answers the meaningful task the App owns, such as the selected record,
108
+ filters, cursor, selection and scroll position, as JSON of at most 65,536
109
+ characters; House keeps the address itself. In the newer release House
110
+ calls `restore(task)` once its document has drawn, so the scroll position
111
+ and focus it sets hold, or `restore(null)` when it opens the release without
112
+ a task, then `ready()`, the App's own check that its local data and
113
+ capabilities work, and finally `settle('committed')` once the release is
114
+ active or `settle('abandoned')` when House returns to the release before
115
+ it, restoring the same task there. A release House opens already active is
116
+ settled `'committed'` at once, after `restore(task)` when House hands it a
117
+ task, and a cooperation registered after House settled is settled at its
118
+ registration. Until `settle('committed')` House fails the release's outside
119
+ calls at once, as offline, those of the workers it starts included, and
120
+ refuses its Saves, write acts and external calls with the retryable code
121
+ `house_trial_withheld`, so a start-up effect is not repeated; run start-up
122
+ effects after `settle('committed')`.
123
+
87
124
  ## The test host
88
125
 
89
126
  `createHouseBridgeTestHost(options)` plays House in one page: it installs a
@@ -106,4 +143,7 @@ given by Site identifier, answers every `install()` `'manual'`, as a browser
106
143
  with no install prompt does, answers every `notifications()` `'unavailable'`,
107
144
  as a browser without push does, settles every `setBadge`, delivers each App
108
145
  message `message({ from, body })` plays, and hands `bridge.runtime` the MD
109
- Runtime client `attachRuntime(client)` gives it.
146
+ Runtime client `attachRuntime(client)` gives it. `checkpoint()` runs the
147
+ registered cooperation's checkpoint, persist and capture and answers the task,
148
+ `restore(task)` runs its restore and answers its readiness check, and
149
+ `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-ce42efd6bfc0c",
3
+ "version": "0.1.0-ce67b9fcd1972",
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",