@astrosheep/square 0.3.94 → 0.3.96
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/artifact.js +1 -1
- package/dist/attention-presentation.d.ts +5 -4
- package/dist/attention-presentation.js +18 -8
- package/dist/attention.d.ts +19 -0
- package/dist/attention.js +30 -0
- package/dist/boundary-presentation.js +50 -48
- package/dist/catch-decisions.d.ts +1 -2
- package/dist/catch-decisions.js +41 -21
- package/dist/channel.d.ts +72 -0
- package/dist/channel.js +86 -0
- package/dist/claude-delivery.js +2 -1
- package/dist/cli/context.js +0 -2
- package/dist/cli/express-presentation.js +3 -3
- package/dist/cli/json.js +1 -1
- package/dist/cli/program.js +1 -1
- package/dist/cli/registry.js +1 -3
- package/dist/cli/square-commands.d.ts +0 -2
- package/dist/cli/square-commands.js +21 -27
- package/dist/decisions.d.ts +0 -5
- package/dist/decisions.js +0 -13
- package/dist/delivery-attempts.d.ts +52 -0
- package/dist/delivery-attempts.js +73 -0
- package/dist/delivery-effects.d.ts +139 -0
- package/dist/delivery-effects.js +163 -0
- package/dist/delivery-operations.js +43 -68
- package/dist/delivery-primitives.d.ts +5 -0
- package/dist/delivery-primitives.js +3 -0
- package/dist/delivery.d.ts +1 -1
- package/dist/delivery.js +8 -7
- package/dist/help.js +4 -6
- package/dist/http-delivery.d.ts +16 -0
- package/dist/http-delivery.js +101 -0
- package/dist/inbox.js +3 -1
- package/dist/mcp.js +65 -63
- package/dist/model.d.ts +10 -6
- package/dist/model.js +20 -1
- package/dist/notifications.js +2 -0
- package/dist/operation-presentation.d.ts +1 -2
- package/dist/operation-presentation.js +12 -20
- package/dist/ports.d.ts +8 -14
- package/dist/presentation-operations.d.ts +15 -19
- package/dist/presentation-operations.js +47 -57
- package/dist/presentation.d.ts +2 -9
- package/dist/presentation.js +13 -48
- package/dist/receive.d.ts +66 -0
- package/dist/receive.js +54 -0
- package/dist/runtime.d.ts +0 -1
- package/dist/runtime.js +2 -3
- package/dist/sqlite-square.d.ts +3 -2
- package/dist/sqlite-square.js +83 -57
- package/dist/square-api.d.ts +1 -1
- package/dist/square-api.js +1 -1
- package/dist/square-core.d.ts +1 -9
- package/dist/square-domain.js +29 -36
- package/dist/square-facade.d.ts +25 -23
- package/dist/square-legacy-framing.d.ts +2 -0
- package/dist/square-legacy-framing.js +8 -0
- package/dist/square-migration.d.ts +3 -1
- package/dist/square-migration.js +46 -13
- package/dist/square-receive.d.ts +6 -0
- package/dist/square-receive.js +18 -0
- package/dist/square-sqlite.d.ts +5 -3
- package/dist/square-sqlite.js +100 -92
- package/dist/square-tools.d.ts +1 -0
- package/dist/square-tools.js +12 -12
- package/dist/views.d.ts +2 -3
- package/dist/views.js +14 -19
- package/dist/wakes.d.ts +0 -3
- package/dist/wakes.js +3 -5
- package/examples/symmetric-domains.mjs +250 -0
- package/guides/application-facade-delivery-evidence.md +5 -5
- package/guides/attention-primitive.md +32 -0
- package/guides/change-waits.md +2 -2
- package/guides/codex-delivery.md +1 -1
- package/guides/delivery-primitives.md +180 -0
- package/guides/mcp.md +1 -1
- package/guides/migration.md +12 -6
- package/guides/participant-ownership.md +1 -1
- package/guides/pi-tools.md +2 -2
- package/guides/primitive-catch-consolidation.md +5 -5
- package/guides/primitive-history-consolidation.md +2 -2
- package/guides/primitive-status-consolidation.md +3 -3
- package/guides/primitive-storage-consolidation.md +1 -1
- package/guides/receive-primitive.md +90 -0
- package/guides/row-runtime-delivery-evidence.md +1 -1
- package/guides/row-storage-design.md +17 -23
- package/guides/square-api.md +77 -10
- package/guides/symmetric-domains.md +92 -0
- package/package.json +18 -1
- package/plugins/claude/.claude-plugin/plugin.json +1 -1
- package/plugins/claude/skills/square/SKILL.md +2 -6
- package/plugins/codex/.codex-plugin/plugin.json +1 -1
- package/plugins/paseo/client/marble.ts +7 -0
- package/plugins/paseo/client/markdown.tsx +65 -9
- package/plugins/paseo/client/palette.ts +43 -20
- package/plugins/paseo/client/square-message.tsx +57 -48
- package/plugins/paseo/shared/message.ts +1 -2
- package/plugins/pi/square-pi.js +6 -4
- package/skills/square/SKILL.md +2 -6
package/dist/runtime.d.ts
CHANGED
|
@@ -4,7 +4,6 @@ export declare const WATCH_HEARTBEAT_MS: number;
|
|
|
4
4
|
export declare const WATCH_STALE_MS: number;
|
|
5
5
|
export declare const THROTTLE_WINDOW_MS: number;
|
|
6
6
|
export declare const UNREAD_BLOCK_GRACE_MS: number;
|
|
7
|
-
export declare const HELD_WAIT_BUDGET_MS: number;
|
|
8
7
|
export declare const FACT_PAGE_SIZE = 100;
|
|
9
8
|
export declare function inSquareCount(facts: SquareRead): number;
|
|
10
9
|
export declare function terminalStatusFor(current: ParticipantFact | undefined, hardCap: number | null, counts: ParticipantCounts): 'capped' | 'quorum' | undefined;
|
package/dist/runtime.js
CHANGED
|
@@ -12,7 +12,6 @@ export const WATCH_HEARTBEAT_MS = parseIntegerEnv('SQUARE_WATCH_HEARTBEAT_MS', 6
|
|
|
12
12
|
export const WATCH_STALE_MS = parseIntegerEnv('SQUARE_WATCH_STALE_MS', 180000);
|
|
13
13
|
export const THROTTLE_WINDOW_MS = parseIntegerEnv('SQUARE_THROTTLE_WINDOW_MS', 60000);
|
|
14
14
|
export const UNREAD_BLOCK_GRACE_MS = parseIntegerEnv('SQUARE_UNREAD_BLOCK_GRACE_MS', 90000);
|
|
15
|
-
export const HELD_WAIT_BUDGET_MS = parseIntegerEnv('SQUARE_HELD_WAIT_BUDGET_MS', 10 * 60 * 1000);
|
|
16
15
|
export const FACT_PAGE_SIZE = 100;
|
|
17
16
|
export function inSquareCount(facts) { return facts.participantCounts().joined; }
|
|
18
17
|
export function terminalStatusFor(current, hardCap, counts) {
|
|
@@ -33,8 +32,8 @@ export function readCursor(facts, name) {
|
|
|
33
32
|
const boundary = facts.participant(name)?.lastJoinIndex ?? -1;
|
|
34
33
|
const block = facts.directed(name, { afterIndex: boundary, unseenOnly: true }, { edge: 'oldest', limit: 1 }).items[0]?.index;
|
|
35
34
|
const last = facts.activityHeads({
|
|
36
|
-
afterIndex: boundary, ...(block === undefined ? {} : { beforeIndex: block }),
|
|
37
|
-
kinds: ['join', 'done', 'say', '
|
|
35
|
+
afterIndex: boundary, ...(block === undefined ? {} : { beforeIndex: block }),
|
|
36
|
+
kinds: ['join', 'done', 'say', 'listen', 'ignore', 'unlisten'],
|
|
38
37
|
}, { edge: 'newest', limit: 1 }).items[0]?.index;
|
|
39
38
|
return Math.max(boundary, last ?? boundary);
|
|
40
39
|
}
|
package/dist/sqlite-square.d.ts
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { type Owner } from './model.js';
|
|
2
|
-
import type { HistoryQuery, HistoryResult, JoinOptions, JoinResult, LifecycleResult, ObservationOptions, OperationControl, Participant, SquareAtInput, SquareBuildInput, SquareLocation, StatusOptions, StatusResult, ParticipantsResult, RecoveryResult, DiscoveryOptions, InboxOptions, InboxResult, StreamOptions, StreamRecord, Activity, PerceivedActivity } from './square-facade.js';
|
|
2
|
+
import type { HistoryQuery, HistoryResult, JoinOptions, JoinResult, LifecycleResult, ObservationOptions, OperationControl, Participant, SquareAtInput, SquareBuildInput, SquareLocation, StatusOptions, StatusResult, ParticipantsResult, RecoveryResult, DiscoveryOptions, InboxOptions, InboxResult, StreamOptions, StreamRecord, Activity, PerceivedActivity, ChannelSendInput, ChannelSendResult } from './square-facade.js';
|
|
3
3
|
export type * from './square-facade.js';
|
|
4
4
|
export { createSquareResourceOwner } from './artifact.js';
|
|
5
5
|
export { formatActivityId, parseActivityId, MAX_IDENTITY_SET_SIZE } from './square-core.js';
|
|
6
6
|
export { CATCH_DEFAULT_LIMIT, CATCH_MAX_LIMIT } from './catch-decisions.js';
|
|
7
|
-
export { HELD_WAIT_BUDGET_MS } from './runtime.js';
|
|
8
7
|
export { HISTORY_DEFAULT_LIMIT, HISTORY_MAX_LIMIT } from './views.js';
|
|
9
8
|
export { DEFAULT_LIST_DEPTH, MAX_LIST_DEPTH, DEFAULT_LIST_LIMIT, MAX_LIST_LIMIT } from './list.js';
|
|
10
9
|
export declare function squareClock(env: NodeJS.ProcessEnv, clock?: () => number): () => number;
|
|
@@ -27,6 +26,8 @@ export declare class SqliteSquare {
|
|
|
27
26
|
private contextObservation;
|
|
28
27
|
private handle;
|
|
29
28
|
private static readonly ParticipantHandle;
|
|
29
|
+
/** Direct messages use explicit recipients, not participant expression admission or body attention. */
|
|
30
|
+
send(input: ChannelSendInput, control?: OperationControl): Promise<ChannelSendResult>;
|
|
30
31
|
participant(name: string, { owner }: {
|
|
31
32
|
readonly owner: Owner;
|
|
32
33
|
}): Promise<Participant>;
|
package/dist/sqlite-square.js
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
|
-
import { formatActivityId } from './square-core.js';
|
|
1
|
+
import { formatActivityId, MAX_IDENTITY_SET_SIZE } from './square-core.js';
|
|
2
2
|
import { assertCurrentSeat } from './square-domain.js';
|
|
3
3
|
import { canonicalPath } from './canonical-path.js';
|
|
4
4
|
import { validateMetadataMatch, validateDeferralDuration, validateDeferralId } from './delivery-deferral.js';
|
|
5
5
|
import { squareLocation } from './square-location.js';
|
|
6
6
|
import crypto from 'node:crypto';
|
|
7
7
|
import { setTimeout as sleep } from 'node:timers/promises';
|
|
8
|
-
import { InternalSquareError, SquareError, isSquareError, nameKey, validateName } from './model.js';
|
|
9
|
-
import { coreDone,
|
|
10
|
-
import {
|
|
8
|
+
import { activityMetadataHasContent, InternalSquareError, SquareError, isSquareError, nameKey, sameName, validateActivityMetadata, validateName } from './model.js';
|
|
9
|
+
import { coreDone, coreIgnore, coreListen, coreListening, coreUnlisten, decideAct, decideJoin, resolveKnownName, validateDoneBody } from './decisions.js';
|
|
10
|
+
import { WATCH_HEARTBEAT_MS, inSquareCount, presenceAnchor } from './runtime.js';
|
|
11
11
|
import { catchLimit, decideCatch, observeCatchSelection, selectCatchPage } from './catch-decisions.js';
|
|
12
12
|
import { expressionContext } from './activity-feed.js';
|
|
13
13
|
import { expressHint } from './hints.js';
|
|
14
|
+
import { ATTENTION_BODY_MAX } from './attention-presentation.js';
|
|
14
15
|
import { asSeatRef, participantAuthority, requireOwner, requireJoinName } from './seats.js';
|
|
15
16
|
import { recoveryObservation, entryPresentation, snapshot, queryStatus, queryParticipants, catchPresence, parseRequiredActivityId, toPublicActivity, publicActivities, selectHistory, NON_READ, HISTORY_DEFAULT_LIMIT, HISTORY_MAX_LIMIT } from './views.js';
|
|
16
17
|
import { sessionInboxCounts } from './inbox.js';
|
|
@@ -26,7 +27,6 @@ import { streamSquare } from './stream.js';
|
|
|
26
27
|
export { createSquareResourceOwner } from './artifact.js';
|
|
27
28
|
export { formatActivityId, parseActivityId, MAX_IDENTITY_SET_SIZE } from './square-core.js';
|
|
28
29
|
export { CATCH_DEFAULT_LIMIT, CATCH_MAX_LIMIT } from './catch-decisions.js';
|
|
29
|
-
export { HELD_WAIT_BUDGET_MS } from './runtime.js';
|
|
30
30
|
export { HISTORY_DEFAULT_LIMIT, HISTORY_MAX_LIMIT } from './views.js';
|
|
31
31
|
export { DEFAULT_LIST_DEPTH, MAX_LIST_DEPTH, DEFAULT_LIST_LIMIT, MAX_LIST_LIMIT } from './list.js';
|
|
32
32
|
function checkControl(control) {
|
|
@@ -115,12 +115,12 @@ export class SqliteSquare {
|
|
|
115
115
|
if (this.indexPath !== undefined)
|
|
116
116
|
await rememberSquarePath(this.location, owner, this.indexPath).catch(() => undefined);
|
|
117
117
|
}
|
|
118
|
-
observation(standingCount,
|
|
119
|
-
return { location: this.location, standingCount,
|
|
118
|
+
observation(standingCount, participant, now = this.clock()) {
|
|
119
|
+
return { location: this.location, standingCount, now,
|
|
120
120
|
...(participant === undefined ? {} : { participant }) };
|
|
121
121
|
}
|
|
122
122
|
async contextObservation(participant, control) {
|
|
123
|
-
return (await this.artifact.read(facts => this.observation(inSquareCount(facts),
|
|
123
|
+
return (await this.artifact.read(facts => this.observation(inSquareCount(facts), participant), control?.signal)).value;
|
|
124
124
|
}
|
|
125
125
|
handle(seat) { return new SqliteSquare.ParticipantHandle(seat.participant, this, seat); }
|
|
126
126
|
// The nested handle uses its resource's private dependencies without copying
|
|
@@ -134,6 +134,7 @@ export class SqliteSquare {
|
|
|
134
134
|
this.owner = owner;
|
|
135
135
|
this.seat = seat;
|
|
136
136
|
}
|
|
137
|
+
get generation() { return this.seat.generation; }
|
|
137
138
|
async express(bodyOrInput, optionsOrControl = {}, operationControl) {
|
|
138
139
|
const square = this.owner;
|
|
139
140
|
const input = typeof bodyOrInput === 'object' && bodyOrInput !== null ? bodyOrInput : undefined;
|
|
@@ -142,7 +143,6 @@ export class SqliteSquare {
|
|
|
142
143
|
const control = input === undefined ? operationControl : optionsOrControl;
|
|
143
144
|
let name = this.name, effect = 'unsent';
|
|
144
145
|
let landedId;
|
|
145
|
-
let heldWaitedMs = 0;
|
|
146
146
|
try {
|
|
147
147
|
checkControl(control);
|
|
148
148
|
name = (await square.artifact.read(facts => resolveKnownName(facts, this.name), control?.signal)).value;
|
|
@@ -167,12 +167,9 @@ export class SqliteSquare {
|
|
|
167
167
|
// Decoding selected rows is storage work, not proof of safe admission refusal.
|
|
168
168
|
const proposed = decideAct(facts, { name, body, force: options.force ?? false, metadata: options.metadata, now, mentions: options.mentions,
|
|
169
169
|
...(options.reach === undefined ? {} : { reach: options.reach }), ...(options.noMention === undefined ? {} : { noMention: options.noMention }), ...(reply === undefined ? {} : { reply }) });
|
|
170
|
-
const holder = proposed.type === 'held' ? facts.hold().actor : undefined;
|
|
171
170
|
const decision = rejectUnsentActivity(() => {
|
|
172
171
|
if (proposed.type === 'blocked')
|
|
173
172
|
throw new SquareError('behind', `${participantIdentity(name)} has pending activity`, { pending: proposed.activitySummaries.reduce((count, summary) => count + summary.count, 0) });
|
|
174
|
-
if (proposed.type === 'held')
|
|
175
|
-
throw new SquareError('held', 'The square is held', { ...(holder === undefined ? {} : { holder }), ...(proposed.reason === undefined ? {} : { holdReason: proposed.reason }) });
|
|
176
173
|
if (proposed.type === 'capped')
|
|
177
174
|
throw new SquareError('capped', `${participantIdentity(name)} reached the activity cap`);
|
|
178
175
|
if (proposed.type === 'throttled')
|
|
@@ -181,7 +178,7 @@ export class SqliteSquare {
|
|
|
181
178
|
throw new SquareError('bell_quota', `${participantIdentity(name)} cannot ring the bell yet`, { retryAfterMs: Math.max(1, proposed.nextAt - now) });
|
|
182
179
|
return proposed;
|
|
183
180
|
});
|
|
184
|
-
return { stored: facts.land(decision.act), standingCount: inSquareCount(facts),
|
|
181
|
+
return { stored: facts.land(decision.act), standingCount: inSquareCount(facts),
|
|
185
182
|
ownActivityCount: facts.participant(name).sayCount, hardCap: facts.header().hardCap,
|
|
186
183
|
...(decision.unmatchedMentions === undefined ? {} : { unmatchedMentions: decision.unmatchedMentions }),
|
|
187
184
|
...(decision.replyAuthorNotHere === undefined ? {} : { replyAuthorNotHere: decision.replyAuthorNotHere }) };
|
|
@@ -190,33 +187,20 @@ export class SqliteSquare {
|
|
|
190
187
|
effect = 'landed';
|
|
191
188
|
if (square.wakeTransport !== undefined)
|
|
192
189
|
await deliverPending({ artifact: square.artifact, transport: square.wakeTransport, location: square.deliveryLocation, activity: committed.stored.index, now }).catch(() => undefined);
|
|
193
|
-
const { stored, standingCount,
|
|
190
|
+
const { stored, standingCount, ownActivityCount, hardCap, ...metadata } = committed;
|
|
194
191
|
const hint = expressHint(ownActivityCount);
|
|
195
192
|
return { activity: toPublicActivity(stored), ...metadata,
|
|
196
193
|
...(hint === undefined ? {} : { hint }), ...(context === undefined ? {} : { observation: {
|
|
197
|
-
...square.observation(standingCount,
|
|
194
|
+
...square.observation(standingCount, name, now), ownActivityCount, hardCap, context, participant: name,
|
|
198
195
|
} }) };
|
|
199
196
|
}
|
|
200
197
|
catch (error) {
|
|
201
198
|
if (effect !== 'landed' && isSquareError(error) && error.facts?.activityUnsent === true)
|
|
202
199
|
effect = 'unsent';
|
|
203
|
-
if (effect === 'landed' || !isSquareError(error) || options.noWait ||
|
|
200
|
+
if (effect === 'landed' || !isSquareError(error) || options.noWait || error.code !== 'throttled')
|
|
204
201
|
throw error;
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
control?.onProgress?.({ kind: 'waiting', reason: error.code,
|
|
208
|
-
...(error.code === 'throttled' ? { delayMs: error.facts?.retryAfterMs ?? 1 } : {}),
|
|
209
|
-
...(error.facts?.holder === undefined ? {} : { holder: error.facts.holder }),
|
|
210
|
-
...(error.facts?.holdReason === undefined ? {} : { holdReason: error.facts.holdReason }) });
|
|
211
|
-
if (error.code === 'throttled')
|
|
212
|
-
await sleep(error.facts?.retryAfterMs ?? 1, undefined, { signal: control?.signal });
|
|
213
|
-
else {
|
|
214
|
-
const started = Date.now();
|
|
215
|
-
const observation = await square.artifact.read(facts => facts.hold().active, control?.signal);
|
|
216
|
-
if (observation.value)
|
|
217
|
-
await square.artifact.changed(observation.version, Math.max(1, HELD_WAIT_BUDGET_MS - heldWaitedMs), control?.signal);
|
|
218
|
-
heldWaitedMs += Date.now() - started;
|
|
219
|
-
}
|
|
202
|
+
control?.onProgress?.({ kind: 'waiting', reason: 'throttled', delayMs: error.facts?.retryAfterMs ?? 1 });
|
|
203
|
+
await sleep(error.facts?.retryAfterMs ?? 1, undefined, { signal: control?.signal });
|
|
220
204
|
}
|
|
221
205
|
}
|
|
222
206
|
}
|
|
@@ -235,7 +219,7 @@ export class SqliteSquare {
|
|
|
235
219
|
const act = verb === 'listen' ? coreListen(facts, name, target, now) : verb === 'ignore' ? coreIgnore(facts, name, target, now) : coreUnlisten(facts, name, target, now);
|
|
236
220
|
const activity = act === undefined ? null : toPublicActivity(facts.land(act));
|
|
237
221
|
return { activity, ...(!options.observe ? {} : { observation: {
|
|
238
|
-
...square.observation(inSquareCount(facts),
|
|
222
|
+
...square.observation(inSquareCount(facts), name, now), participant: name,
|
|
239
223
|
target: activity?.target ?? target,
|
|
240
224
|
} }) };
|
|
241
225
|
}, control?.signal)).value;
|
|
@@ -247,7 +231,7 @@ export class SqliteSquare {
|
|
|
247
231
|
const square = this.owner;
|
|
248
232
|
return (await square.artifact.read(facts => {
|
|
249
233
|
const name = resolveKnownName(facts, this.name);
|
|
250
|
-
return { listening: coreListening(facts, name), ...(!options.observe ? {} : { observation: square.observation(inSquareCount(facts),
|
|
234
|
+
return { listening: coreListening(facts, name), ...(!options.observe ? {} : { observation: square.observation(inSquareCount(facts), name) }) };
|
|
251
235
|
}, control?.signal)).value;
|
|
252
236
|
}
|
|
253
237
|
/** Receipt selection rechecks the lease inside the writer, not at its last heartbeat. */
|
|
@@ -283,7 +267,7 @@ export class SqliteSquare {
|
|
|
283
267
|
}
|
|
284
268
|
return { activities: view.activities, remaining: view.remaining, reason,
|
|
285
269
|
...(view.hint === undefined ? {} : { hint: view.hint }), ...(!options.observe ? {} : { observation: {
|
|
286
|
-
...square.observation(view.standingCount, view.
|
|
270
|
+
...square.observation(view.standingCount, view.participant, view.now), participant: view.participant,
|
|
287
271
|
deliveryAvailable: view.deliveryAvailable,
|
|
288
272
|
ownActivityCount: view.ownActivityCount, hardCap: view.hardCap,
|
|
289
273
|
...(presence === undefined ? { enrichmentUnavailable: true } : { presence }),
|
|
@@ -325,7 +309,8 @@ export class SqliteSquare {
|
|
|
325
309
|
return await complete(undefined, 'already-active');
|
|
326
310
|
leaseId = start.leaseId;
|
|
327
311
|
control?.onProgress?.({ kind: 'catch-started', participant: name, idleMs: idle, replacementRequested: options.replace ?? false, replaced: start.replaced });
|
|
328
|
-
|
|
312
|
+
const quietSince = square.clock();
|
|
313
|
+
let nextHeartbeat = start.heartbeatAt + WATCH_HEARTBEAT_MS;
|
|
329
314
|
while (true) {
|
|
330
315
|
checkControl(control);
|
|
331
316
|
// Arm before selecting: a commit during selection must not be missed.
|
|
@@ -337,21 +322,16 @@ export class SqliteSquare {
|
|
|
337
322
|
return await complete(undefined, pulse.status);
|
|
338
323
|
if (pulse.heartbeatAt !== undefined)
|
|
339
324
|
nextHeartbeat = pulse.heartbeatAt + WATCH_HEARTBEAT_MS;
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
}
|
|
347
|
-
if (pulse.type === 'held' || wasHeld)
|
|
348
|
-
quietSince = square.clock();
|
|
349
|
-
wasHeld = pulse.type === 'held';
|
|
350
|
-
if (!wasHeld && square.clock() - quietSince >= idle) {
|
|
325
|
+
const caught = await this.catchPage(name, seat, selection, control, leaseId);
|
|
326
|
+
if (caught === null)
|
|
327
|
+
return await complete(undefined, 'replaced');
|
|
328
|
+
if (caught.activities.length > 0)
|
|
329
|
+
return await complete(caught);
|
|
330
|
+
if (square.clock() - quietSince >= idle) {
|
|
351
331
|
const owns = await ownsWatchLease(square.artifact, seat, square.clock(), leaseId, control?.signal);
|
|
352
332
|
return await complete(undefined, owns ? 'idle' : 'replaced');
|
|
353
333
|
}
|
|
354
|
-
const deadline = Math.min(nextHeartbeat,
|
|
334
|
+
const deadline = Math.min(nextHeartbeat, quietSince + idle);
|
|
355
335
|
await square.artifact.changed(baseline, Math.max(0, deadline - square.clock()), control?.signal);
|
|
356
336
|
}
|
|
357
337
|
}
|
|
@@ -392,22 +372,68 @@ export class SqliteSquare {
|
|
|
392
372
|
const square = this.owner, seat = this.seat;
|
|
393
373
|
return (await square.artifact.transactAs(participantAuthority(seat), facts => facts.releaseDeliveryDeferral(asSeatRef(seat), id, square.clock()), control?.signal)).value;
|
|
394
374
|
}
|
|
395
|
-
async
|
|
396
|
-
|
|
397
|
-
validateDoneBody(body);
|
|
375
|
+
async done(body, options = {}, control) {
|
|
376
|
+
validateDoneBody(body);
|
|
398
377
|
const square = this.owner;
|
|
399
378
|
const name = (await square.artifact.read(facts => resolveKnownName(facts, this.name), control?.signal)).value;
|
|
400
379
|
const seat = this.seat, now = square.clock();
|
|
401
380
|
return (await square.artifact.transactAs(participantAuthority(seat), facts => {
|
|
402
|
-
const stored = facts.land(
|
|
403
|
-
return { activity: toPublicActivity(stored), ...(!options.observe ? {} : { observation: square.observation(inSquareCount(facts),
|
|
381
|
+
const stored = facts.land(coreDone(facts, name, body ?? '', now));
|
|
382
|
+
return { activity: toPublicActivity(stored), ...(!options.observe ? {} : { observation: square.observation(inSquareCount(facts), name, now),
|
|
404
383
|
}) };
|
|
405
384
|
}, control?.signal)).value;
|
|
406
385
|
}
|
|
407
|
-
hold(reason, options = {}, control) { return this.lifecycle('hold', reason, options, control); }
|
|
408
|
-
resume(options = {}, control) { return this.lifecycle('resume', undefined, options, control); }
|
|
409
|
-
done(body, options = {}, control) { return this.lifecycle('done', body, options, control); }
|
|
410
386
|
};
|
|
387
|
+
/** Direct messages use explicit recipients, not participant expression admission or body attention. */
|
|
388
|
+
async send(input, control) {
|
|
389
|
+
checkControl(control);
|
|
390
|
+
const { from, to, body, truncate = ATTENTION_BODY_MAX } = input;
|
|
391
|
+
if (typeof from !== 'string')
|
|
392
|
+
throw new SquareError('invalid_args', 'Channel sender must be a name.');
|
|
393
|
+
validateName(from);
|
|
394
|
+
const targets = typeof to === 'string' ? [to] : to;
|
|
395
|
+
if (!Array.isArray(targets) || targets.length < 1 || targets.length > MAX_IDENTITY_SET_SIZE)
|
|
396
|
+
throw new SquareError('invalid_args', `Channel needs between 1 and ${MAX_IDENTITY_SET_SIZE} recipients.`);
|
|
397
|
+
const unique = [];
|
|
398
|
+
for (const target of targets) {
|
|
399
|
+
if (typeof target !== 'string')
|
|
400
|
+
throw new SquareError('invalid_args', 'Channel recipients must be names.');
|
|
401
|
+
validateName(target);
|
|
402
|
+
if (!unique.some(name => sameName(name, target)))
|
|
403
|
+
unique.push(target);
|
|
404
|
+
}
|
|
405
|
+
if (typeof body !== 'string' || body.trim() === '')
|
|
406
|
+
throw new SquareError('invalid_args', 'Channel body must be non-empty.');
|
|
407
|
+
if (truncate !== false && (!Number.isSafeInteger(truncate) || truncate < 1))
|
|
408
|
+
throw new SquareError('invalid_args', 'Channel truncate must be false or a positive integer.');
|
|
409
|
+
const fullBody = body.replace(/\r\n/g, '\n');
|
|
410
|
+
const preview = truncate !== false && fullBody.length > truncate
|
|
411
|
+
? `${fullBody.slice(0, truncate).trimEnd()}… (truncated ${fullBody.length - truncate} chars)`
|
|
412
|
+
: undefined;
|
|
413
|
+
const delivery = preview === undefined ? { mode: 'direct' } : { mode: 'direct', preview };
|
|
414
|
+
const metadata = validateActivityMetadata(input.metadata);
|
|
415
|
+
const { stored, resolvedTo } = (await this.artifact.transactAs({ kind: 'send', actor: from }, facts => {
|
|
416
|
+
const standing = facts.roster().filter(p => p.joined), resolvedTo = [], missing = [];
|
|
417
|
+
for (const target of unique) {
|
|
418
|
+
const recipient = standing.find(p => sameName(p.name, target));
|
|
419
|
+
if (recipient === undefined || facts.seat(recipient.name)?.attachment !== 'attached')
|
|
420
|
+
missing.push(target);
|
|
421
|
+
else
|
|
422
|
+
resolvedTo.push(recipient.name);
|
|
423
|
+
}
|
|
424
|
+
if (missing.length > 0)
|
|
425
|
+
throw new SquareError('invalid_args', `Channel recipients are not standing: ${missing.join(', ')}`, {
|
|
426
|
+
reason: 'not_standing', targets: missing, activityUnsent: true,
|
|
427
|
+
});
|
|
428
|
+
return { stored: facts.land({ kind: 'say', actor: from, at: this.clock(), body: fullBody,
|
|
429
|
+
...(activityMetadataHasContent(metadata) ? { metadata } : {}), delivery, mentions: resolvedTo }), resolvedTo };
|
|
430
|
+
}, control?.signal)).value;
|
|
431
|
+
if (this.wakeTransport !== undefined)
|
|
432
|
+
await deliverPending({ artifact: this.artifact, transport: this.wakeTransport, location: this.deliveryLocation,
|
|
433
|
+
activity: stored.index, now: stored.at }).catch(() => undefined);
|
|
434
|
+
return { id: formatActivityId(stored.index), at: stored.at, from: stored.actor, to: resolvedTo, body: preview ?? fullBody,
|
|
435
|
+
...(stored.kind !== 'say' || stored.metadata === undefined ? {} : { metadata: stored.metadata }) };
|
|
436
|
+
}
|
|
411
437
|
async participant(name, { owner }) {
|
|
412
438
|
validateName(name);
|
|
413
439
|
requireOwner(owner);
|
|
@@ -467,7 +493,7 @@ export class SqliteSquare {
|
|
|
467
493
|
if (seat === undefined)
|
|
468
494
|
throw new SquareError('invalid_args', 'The join activity did not establish its artifact seat.');
|
|
469
495
|
return { participant: this.handle(seat), activity, kind,
|
|
470
|
-
...(!options.observe ? {} : { observation: { ...this.observation(inSquareCount(facts),
|
|
496
|
+
...(!options.observe ? {} : { observation: { ...this.observation(inSquareCount(facts), seat.participant, now),
|
|
471
497
|
deliveryAvailable: seat.wakeAddress !== undefined } }) };
|
|
472
498
|
}, control?.signal)).value;
|
|
473
499
|
await this.publishSeat(owner);
|
|
@@ -535,7 +561,7 @@ export class SqliteSquare {
|
|
|
535
561
|
if (indexes.includes(anchor))
|
|
536
562
|
(presenceAnchors[anchor] ??= []).push(participant.name);
|
|
537
563
|
}
|
|
538
|
-
return { activities, observation: { ...this.observation(inSquareCount(facts)
|
|
564
|
+
return { activities, observation: { ...this.observation(inSquareCount(facts)), ...selected,
|
|
539
565
|
sayNumbers: facts.sayOrdinals(indexes), presenceAnchors } };
|
|
540
566
|
}, control?.signal)).value;
|
|
541
567
|
}
|
package/dist/square-api.d.ts
CHANGED
|
@@ -16,4 +16,4 @@ export declare function selectOwnSeat(square: Pick<SqliteSquare, 'participant' |
|
|
|
16
16
|
}): Promise<Participant | undefined>;
|
|
17
17
|
export { ACTIVITY_METADATA_MAX_BYTES } from './model.js';
|
|
18
18
|
export { localUserOwner, harnessOwner, decodeHarnessOwner } from './owner.js';
|
|
19
|
-
export { squareClock, createSquareResourceOwner, formatActivityId, parseActivityId, MAX_IDENTITY_SET_SIZE, CATCH_DEFAULT_LIMIT, CATCH_MAX_LIMIT,
|
|
19
|
+
export { squareClock, createSquareResourceOwner, formatActivityId, parseActivityId, MAX_IDENTITY_SET_SIZE, CATCH_DEFAULT_LIMIT, CATCH_MAX_LIMIT, HISTORY_DEFAULT_LIMIT, HISTORY_MAX_LIMIT, DEFAULT_LIST_DEPTH, MAX_LIST_DEPTH, DEFAULT_LIST_LIMIT, MAX_LIST_LIMIT, diagnoseSquare, migrateSquare, discover, inbox } from './sqlite-square.js';
|
package/dist/square-api.js
CHANGED
|
@@ -27,4 +27,4 @@ export async function selectOwnSeat(square, owner, name, options) {
|
|
|
27
27
|
}
|
|
28
28
|
export { ACTIVITY_METADATA_MAX_BYTES } from './model.js';
|
|
29
29
|
export { localUserOwner, harnessOwner, decodeHarnessOwner } from './owner.js';
|
|
30
|
-
export { squareClock, createSquareResourceOwner, formatActivityId, parseActivityId, MAX_IDENTITY_SET_SIZE, CATCH_DEFAULT_LIMIT, CATCH_MAX_LIMIT,
|
|
30
|
+
export { squareClock, createSquareResourceOwner, formatActivityId, parseActivityId, MAX_IDENTITY_SET_SIZE, CATCH_DEFAULT_LIMIT, CATCH_MAX_LIMIT, HISTORY_DEFAULT_LIMIT, HISTORY_MAX_LIMIT, DEFAULT_LIST_DEPTH, MAX_LIST_DEPTH, DEFAULT_LIST_LIMIT, MAX_LIST_LIMIT, diagnoseSquare, migrateSquare, discover, inbox } from './sqlite-square.js';
|
package/dist/square-core.d.ts
CHANGED
|
@@ -26,18 +26,10 @@ export type Act = {
|
|
|
26
26
|
at?: number;
|
|
27
27
|
body?: string;
|
|
28
28
|
metadata?: import('./model.js').ActivityMetadata;
|
|
29
|
+
delivery?: import('./model.js').ActivityDelivery;
|
|
29
30
|
mentions?: readonly Participant[];
|
|
30
31
|
reach?: Reach;
|
|
31
32
|
reply?: number;
|
|
32
|
-
} | {
|
|
33
|
-
kind: 'hold';
|
|
34
|
-
actor?: Participant;
|
|
35
|
-
at?: number;
|
|
36
|
-
body?: string;
|
|
37
|
-
} | {
|
|
38
|
-
kind: 'resume';
|
|
39
|
-
actor?: Participant;
|
|
40
|
-
at?: number;
|
|
41
33
|
} | {
|
|
42
34
|
kind: 'read';
|
|
43
35
|
actor: Participant;
|
package/dist/square-domain.js
CHANGED
|
@@ -1,35 +1,22 @@
|
|
|
1
|
-
import { SquareError, formatActivityId, parseActivityId, sameName, validateOwner, validateName } from './model.js';
|
|
1
|
+
import { SquareError, formatActivityId, parseActivityId, sameName, validateActivityDelivery, validateOwner, validateName } from './model.js';
|
|
2
|
+
import { resolveAudience } from './attention.js';
|
|
2
3
|
/** The single landing transition, shared by both adapters and explicit rebuild. */
|
|
3
4
|
export function deriveLanding(activity, facts) {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
const
|
|
7
|
-
const recipient = facts.standing.find(
|
|
8
|
-
if (recipient
|
|
9
|
-
|
|
10
|
-
return;
|
|
11
|
-
if (activity.reach !== 'bell' && facts.incoming.some((item) => item.kind === 'ignore' && sameName(item.listener, recipient)))
|
|
12
|
-
return;
|
|
13
|
-
audience.push({ recipient, route });
|
|
14
|
-
};
|
|
15
|
-
if (activity.reach === 'bell') {
|
|
16
|
-
for (const peer of facts.standing)
|
|
17
|
-
add(peer.name, 'bell');
|
|
18
|
-
}
|
|
19
|
-
else {
|
|
20
|
-
for (const mention of activity.mentions ?? [])
|
|
21
|
-
add(mention, 'mention');
|
|
22
|
-
if (facts.replyAuthor !== undefined)
|
|
23
|
-
add(facts.replyAuthor, 'reply');
|
|
24
|
-
for (const peer of facts.standing) {
|
|
25
|
-
if (facts.incoming.some((item) => item.kind === 'listen' && sameName(item.listener, peer.name)))
|
|
26
|
-
add(peer.name, 'attention');
|
|
27
|
-
}
|
|
5
|
+
if (activity.kind === 'say' && activity.delivery?.mode === 'direct') {
|
|
6
|
+
const audience = [];
|
|
7
|
+
for (const mention of activity.mentions ?? []) {
|
|
8
|
+
const recipient = facts.standing.find(item => sameName(item.name, mention))?.name;
|
|
9
|
+
if (recipient !== undefined && !audience.some(item => sameName(item.recipient, recipient)))
|
|
10
|
+
audience.push({ recipient, route: 'mention' });
|
|
28
11
|
}
|
|
12
|
+
return { activity, audience };
|
|
29
13
|
}
|
|
14
|
+
const audience = activity.kind === 'say' ? resolveAudience({
|
|
15
|
+
actor: activity.actor, recipients: facts.standing.map((item) => item.name),
|
|
16
|
+
mentions: activity.mentions, replyAuthor: facts.replyAuthor, reach: activity.reach,
|
|
17
|
+
incoming: facts.incoming, sameIdentity: sameName,
|
|
18
|
+
}) : [];
|
|
30
19
|
const actor = activity.actor;
|
|
31
|
-
if (actor === undefined)
|
|
32
|
-
return { activity, audience };
|
|
33
20
|
const previous = facts.actor ?? { name: actor, firstIndex: activity.index, joined: false, done: false, sayCount: 0 };
|
|
34
21
|
const participant = {
|
|
35
22
|
...previous,
|
|
@@ -57,7 +44,7 @@ export function deriveLanding(activity, facts) {
|
|
|
57
44
|
}
|
|
58
45
|
export function landingFacts(read, activity) {
|
|
59
46
|
return {
|
|
60
|
-
actor:
|
|
47
|
+
actor: read.participant(activity.actor),
|
|
61
48
|
standing: activity.kind === 'say' ? read.roster().filter((item) => item.joined) : [],
|
|
62
49
|
incoming: activity.kind === 'say' ? read.incomingAttention(activity.actor) : [],
|
|
63
50
|
outgoing: activity.kind === 'listen' || activity.kind === 'ignore' || activity.kind === 'unlisten' ? read.attention(activity.actor) : [],
|
|
@@ -82,15 +69,15 @@ export function wrapSquareWrite(read, writes, authority) {
|
|
|
82
69
|
throw new SquareError('invalid_args', 'Artifact writes require an explicit authority.');
|
|
83
70
|
const { applyLanding, ...mutations } = writes;
|
|
84
71
|
const seated = authority.kind === 'participant' || authority.kind === 'host-cleanup';
|
|
85
|
-
const expectedName = seated ? authority.seat?.participant : authority.participant;
|
|
86
|
-
if (!['participant', 'host-cleanup', 'join', 'takeover'].includes(authority.kind) || typeof expectedName !== 'string')
|
|
72
|
+
const expectedName = seated ? authority.seat?.participant : authority.kind === 'send' ? authority.actor : authority.participant;
|
|
73
|
+
if (!['participant', 'host-cleanup', 'join', 'takeover', 'send'].includes(authority.kind) || typeof expectedName !== 'string')
|
|
87
74
|
throw new SquareError('invalid_args', 'Artifact write authority is malformed.');
|
|
88
75
|
validateName(expectedName);
|
|
89
76
|
if (seated) {
|
|
90
77
|
validateOwner(authority.seat.owner);
|
|
91
78
|
validateGeneration(authority.seat.generation);
|
|
92
79
|
}
|
|
93
|
-
else {
|
|
80
|
+
else if (authority.kind !== 'send') {
|
|
94
81
|
validateOwner(authority.owner);
|
|
95
82
|
if (authority.kind === 'takeover')
|
|
96
83
|
validateGeneration(authority.expectedGeneration);
|
|
@@ -122,7 +109,7 @@ export function wrapSquareWrite(read, writes, authority) {
|
|
|
122
109
|
reconnectSeat = seat;
|
|
123
110
|
}
|
|
124
111
|
}
|
|
125
|
-
else {
|
|
112
|
+
else if (authority.kind === 'takeover') {
|
|
126
113
|
const current = read.seat(expectedName);
|
|
127
114
|
if (current === undefined || current.generation !== authority.expectedGeneration)
|
|
128
115
|
throw new SquareError('already_joined', 'The participant seat changed before takeover.');
|
|
@@ -136,7 +123,13 @@ export function wrapSquareWrite(read, writes, authority) {
|
|
|
136
123
|
validateName(actor);
|
|
137
124
|
if (!sameName(actor, expectedName))
|
|
138
125
|
throw new SquareError('already_joined', 'Activity actor does not match the artifact authority.');
|
|
139
|
-
if (
|
|
126
|
+
if (activity.kind === 'say')
|
|
127
|
+
validateActivityDelivery(activity.delivery);
|
|
128
|
+
if (authority.kind === 'send') {
|
|
129
|
+
if (activity.kind !== 'say' || activity.delivery?.mode !== 'direct' || activity.reach !== undefined || activity.reply !== undefined)
|
|
130
|
+
throw new SquareError('invalid_args', 'Send authority may only land direct messages without bell or reply.');
|
|
131
|
+
}
|
|
132
|
+
else if (authority.kind === 'participant') {
|
|
140
133
|
assertSeat(authority.seat);
|
|
141
134
|
if (activity.kind === 'join')
|
|
142
135
|
throw new SquareError('invalid_args', 'A participant seat can only be re-established by join.');
|
|
@@ -172,7 +165,7 @@ export function wrapSquareWrite(read, writes, authority) {
|
|
|
172
165
|
const stored = { ...activity, index };
|
|
173
166
|
applyLanding(deriveLanding(stored, landingFacts(read, stored)));
|
|
174
167
|
if (stored.kind === 'join') {
|
|
175
|
-
if (
|
|
168
|
+
if (authority.kind !== 'join' && authority.kind !== 'takeover')
|
|
176
169
|
throw new SquareError('invalid_args', 'Seat authority cannot establish another seat.');
|
|
177
170
|
const seat = {
|
|
178
171
|
participant: stored.actor,
|
|
@@ -225,8 +218,8 @@ export function wrapSquareWrite(read, writes, authority) {
|
|
|
225
218
|
},
|
|
226
219
|
cancelThrough(seat, through) {
|
|
227
220
|
assertSeat(seat);
|
|
228
|
-
if (!Number.isSafeInteger(through) || through < 0 || through
|
|
229
|
-
throw new SquareError('invalid_args', 'Cancellation boundary must
|
|
221
|
+
if (!Number.isSafeInteger(through) || through < 0 || through >= read.header().nextActIndex)
|
|
222
|
+
throw new SquareError('invalid_args', 'Cancellation boundary must be an assigned activity index below the allocator.');
|
|
230
223
|
return mutations.cancelThrough(seat, through);
|
|
231
224
|
},
|
|
232
225
|
markSeen(name, indexes, at) {
|
package/dist/square-facade.d.ts
CHANGED
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
import type { DeliveryDeferral, MetadataMatch } from './delivery-deferral.js';
|
|
2
2
|
export type { DeliveryDeferral, MetadataMatch, MetadataScalar } from './delivery-deferral.js';
|
|
3
3
|
import type { ActivityId, Perception, Reach } from './square-core.js';
|
|
4
|
-
import type { Owner, StoredAct, WakeAddress, ActivityMetadata, DirectedNotificationRoute } from './model.js';
|
|
4
|
+
import type { Owner, StoredAct, WakeAddress, ActivityMetadata, ActivityDelivery, DirectedNotificationRoute } from './model.js';
|
|
5
5
|
import type { WakeTransportPort, SquareResourceOwner } from './ports.js';
|
|
6
6
|
export type { ActivityId, Perception, Reach } from './square-core.js';
|
|
7
|
-
export type { Owner, WakeAddress, ActivityMetadata, JsonValue, DirectedNotificationRoute } from './model.js';
|
|
8
|
-
/** Indexed archive event, including read
|
|
7
|
+
export type { Owner, WakeAddress, ActivityMetadata, ActivityDelivery, JsonValue, DirectedNotificationRoute } from './model.js';
|
|
8
|
+
/** Indexed archive event, including read bookkeeping. */
|
|
9
9
|
export type ArchiveRecord = Readonly<StoredAct>;
|
|
10
10
|
export interface Activity {
|
|
11
11
|
readonly id: ActivityId;
|
|
12
12
|
readonly at: number;
|
|
13
|
-
readonly kind: 'join' | 'say' | 'done' | '
|
|
13
|
+
readonly kind: 'join' | 'say' | 'done' | 'listen' | 'ignore' | 'unlisten';
|
|
14
14
|
readonly actor: string;
|
|
15
15
|
readonly body?: string;
|
|
16
16
|
readonly metadata?: ActivityMetadata;
|
|
17
|
+
readonly delivery?: ActivityDelivery;
|
|
17
18
|
readonly mentions: readonly string[];
|
|
18
19
|
readonly reach?: Reach;
|
|
19
20
|
readonly target?: string;
|
|
@@ -49,6 +50,22 @@ export interface ExpressResult {
|
|
|
49
50
|
readonly hint?: string;
|
|
50
51
|
readonly observation?: ExpressObservation;
|
|
51
52
|
}
|
|
53
|
+
export type ChannelTruncate = number | false;
|
|
54
|
+
export interface ChannelSendInput {
|
|
55
|
+
readonly from: string;
|
|
56
|
+
readonly to: string | readonly string[];
|
|
57
|
+
readonly body: string;
|
|
58
|
+
readonly truncate?: ChannelTruncate;
|
|
59
|
+
readonly metadata?: ActivityMetadata;
|
|
60
|
+
}
|
|
61
|
+
export interface ChannelSendResult {
|
|
62
|
+
readonly id: ActivityId;
|
|
63
|
+
readonly at: number;
|
|
64
|
+
readonly from: string;
|
|
65
|
+
readonly to: readonly string[];
|
|
66
|
+
readonly body: string;
|
|
67
|
+
readonly metadata?: ActivityMetadata;
|
|
68
|
+
}
|
|
52
69
|
export interface ListenerChangeResult {
|
|
53
70
|
readonly activity: Activity | null;
|
|
54
71
|
readonly observation?: ListenerObservation;
|
|
@@ -85,10 +102,8 @@ export interface CatchWaitStart {
|
|
|
85
102
|
}
|
|
86
103
|
export type OperationProgress = {
|
|
87
104
|
readonly kind: 'waiting';
|
|
88
|
-
readonly reason: '
|
|
105
|
+
readonly reason: 'throttled';
|
|
89
106
|
readonly delayMs?: number;
|
|
90
|
-
readonly holder?: string;
|
|
91
|
-
readonly holdReason?: string;
|
|
92
107
|
} | ({
|
|
93
108
|
readonly kind: 'catch-started';
|
|
94
109
|
readonly participant: string;
|
|
@@ -135,10 +150,6 @@ export interface SquareSnapshot {
|
|
|
135
150
|
readonly actCount: number;
|
|
136
151
|
readonly hardCap: number | null;
|
|
137
152
|
readonly throttlePerMinute?: number;
|
|
138
|
-
readonly held: {
|
|
139
|
-
readonly by: string;
|
|
140
|
-
readonly reason?: string;
|
|
141
|
-
} | null;
|
|
142
153
|
readonly participants: readonly Pick<ParticipantSummary, 'name' | 'presence' | 'listening'>[];
|
|
143
154
|
delivered(name: string, id: ActivityId): boolean;
|
|
144
155
|
}
|
|
@@ -176,6 +187,7 @@ export interface JoinResult {
|
|
|
176
187
|
}
|
|
177
188
|
export interface Participant {
|
|
178
189
|
readonly name: string;
|
|
190
|
+
readonly generation: ActivityId;
|
|
179
191
|
express(body: string | undefined, options?: ExpressOptions, control?: OperationControl): Promise<ExpressResult>;
|
|
180
192
|
express(input: ExpressInput, control?: OperationControl): Promise<ExpressResult>;
|
|
181
193
|
listen(target: string, options?: ObservationOptions, control?: OperationControl): Promise<ListenerChangeResult>;
|
|
@@ -183,8 +195,6 @@ export interface Participant {
|
|
|
183
195
|
unlisten(target: string, options?: ObservationOptions, control?: OperationControl): Promise<ListenerChangeResult>;
|
|
184
196
|
listening(options?: ObservationOptions, control?: OperationControl): Promise<ListeningResult>;
|
|
185
197
|
catch(options?: CatchOptions, control?: OperationControl): Promise<CatchResult>;
|
|
186
|
-
hold(reason?: string, options?: ObservationOptions, control?: OperationControl): Promise<LifecycleResult>;
|
|
187
|
-
resume(options?: ObservationOptions, control?: OperationControl): Promise<LifecycleResult>;
|
|
188
198
|
/** Leave without a message. Only an omitted or empty body is accepted. */
|
|
189
199
|
done(body?: string, options?: ObservationOptions, control?: OperationControl): Promise<LifecycleResult>;
|
|
190
200
|
deferDelivery(input: Readonly<{
|
|
@@ -220,12 +230,6 @@ export interface StatusResult {
|
|
|
220
230
|
readonly participants: readonly ParticipantSummary[];
|
|
221
231
|
readonly now: number;
|
|
222
232
|
readonly throttlePerMinute?: number;
|
|
223
|
-
/** Non-null whenever held; by is present with an actor and omitted only for historical actorless holds. */
|
|
224
|
-
readonly held: {
|
|
225
|
-
readonly by?: string;
|
|
226
|
-
readonly reason?: string;
|
|
227
|
-
readonly at?: number;
|
|
228
|
-
} | null;
|
|
229
233
|
readonly latestActivity?: Activity;
|
|
230
234
|
readonly observation?: StatusObservation;
|
|
231
235
|
}
|
|
@@ -267,7 +271,6 @@ export interface InboxResult {
|
|
|
267
271
|
export interface RecoveryResult {
|
|
268
272
|
readonly participant?: string;
|
|
269
273
|
readonly standingCount?: number;
|
|
270
|
-
readonly held?: boolean;
|
|
271
274
|
readonly ownActivityCount?: number;
|
|
272
275
|
readonly hardCap?: number | null;
|
|
273
276
|
readonly activitySummaries?: readonly UnreadActivitySummary[];
|
|
@@ -310,7 +313,6 @@ export interface CatchPresence {
|
|
|
310
313
|
export interface SquareObservation {
|
|
311
314
|
readonly location: string;
|
|
312
315
|
readonly standingCount: number;
|
|
313
|
-
readonly held: boolean;
|
|
314
316
|
readonly now: number;
|
|
315
317
|
readonly participant?: string;
|
|
316
318
|
}
|
|
@@ -320,7 +322,7 @@ export interface JoinObservation extends SquareObservation {
|
|
|
320
322
|
/** The receipt succeeded, but optional recent-history/context enrichment was unavailable. */
|
|
321
323
|
readonly enrichmentUnavailable?: true;
|
|
322
324
|
}
|
|
323
|
-
export interface ExpressionObservation extends Pick<SquareObservation, 'standingCount' | '
|
|
325
|
+
export interface ExpressionObservation extends Pick<SquareObservation, 'standingCount' | 'now'> {
|
|
324
326
|
readonly ownActivityCount: number;
|
|
325
327
|
readonly hardCap: number | null;
|
|
326
328
|
}
|
|
@@ -361,7 +363,7 @@ export interface ListenerObservation extends SquareObservation {
|
|
|
361
363
|
readonly participant: string;
|
|
362
364
|
readonly target: string;
|
|
363
365
|
}
|
|
364
|
-
export interface StatusObservation extends Omit<SquareObservation, 'now'
|
|
366
|
+
export interface StatusObservation extends Omit<SquareObservation, 'now'>, PresenceClassification {
|
|
365
367
|
readonly knownParticipantCount: number;
|
|
366
368
|
readonly latestPerception?: Perception;
|
|
367
369
|
readonly joins: readonly {
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { DatabaseSync } from 'node:sqlite';
|
|
2
2
|
export declare const FORMAT4_ADDED_OBJECTS: ReadonlySet<string>;
|
|
3
3
|
export declare const FORMAT4_REPLACED_OBJECTS: ReadonlySet<string>;
|
|
4
|
+
/** Historical activity framing only; no runtime activity decoder accepts these kinds. */
|
|
5
|
+
export declare function legacyActivitySchema(currentSchemaSql: string): string;
|
|
4
6
|
/**
|
|
5
7
|
* Read-only recognition of the exact row framing accepted by explicit migration.
|
|
6
8
|
* It inspects identity, owned schema and journal mode only; it never reads row
|