@astrosheep/square 0.3.105 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/activity-feed.js +1 -1
- package/dist/artifact-store.d.ts +41 -0
- package/dist/artifact-store.js +272 -0
- package/dist/artifact.d.ts +8 -12
- package/dist/artifact.js +66 -343
- package/dist/attention-presentation.d.ts +33 -7
- package/dist/attention-presentation.js +33 -69
- package/dist/boundary-presentation.d.ts +0 -2
- package/dist/boundary-presentation.js +17 -22
- package/dist/catch-decisions.d.ts +2 -2
- package/dist/catch-decisions.js +14 -4
- package/dist/catch-selection.d.ts +8 -0
- package/dist/catch-selection.js +5 -0
- package/dist/channel-artifact.d.ts +10 -0
- package/dist/channel-artifact.js +55 -0
- package/dist/channel-delivery.d.ts +11 -0
- package/dist/channel-delivery.js +51 -0
- package/dist/channel-domain.d.ts +3 -0
- package/dist/channel-domain.js +83 -0
- package/dist/channel-facade.d.ts +76 -0
- package/dist/channel-facade.js +1 -0
- package/dist/channel-internal.d.ts +126 -0
- package/dist/channel-internal.js +440 -0
- package/dist/channel-metadata.d.ts +11 -0
- package/dist/channel-metadata.js +1 -0
- package/dist/channel-ports.d.ts +241 -0
- package/dist/channel-ports.js +1 -0
- package/dist/channel-presentation.d.ts +17 -0
- package/dist/channel-presentation.js +22 -0
- package/dist/channel-sqlite-schema.d.ts +13 -0
- package/dist/channel-sqlite-schema.js +81 -0
- package/dist/channel-transport.d.ts +62 -0
- package/dist/channel-transport.js +1 -0
- package/dist/channel-values.d.ts +27 -0
- package/dist/channel-values.js +90 -0
- package/dist/channel.d.ts +31 -21
- package/dist/channel.js +42 -74
- package/dist/claude-delivery-status.js +1 -1
- package/dist/claude-delivery.d.ts +2 -5
- package/dist/claude-delivery.js +56 -103
- package/dist/claude-mod.js +4 -4
- package/dist/claude-transport.d.ts +5 -0
- package/dist/claude-transport.js +58 -0
- package/dist/cli/context.d.ts +2 -2
- package/dist/cli/context.js +0 -1
- package/dist/cli/maintenance-commands.d.ts +0 -4
- package/dist/cli/maintenance-commands.js +2 -29
- package/dist/cli/program.js +1 -1
- package/dist/cli/registry.js +1 -2
- package/dist/codex-address.d.ts +1 -1
- package/dist/codex-queue.d.ts +2 -2
- package/dist/codex-queue.js +1 -3
- package/dist/decisions.js +3 -3
- package/dist/delivery-deferral.d.ts +9 -18
- package/dist/delivery-deferral.js +4 -4
- package/dist/delivery-health.d.ts +4 -4
- package/dist/delivery-health.js +11 -11
- package/dist/delivery-operations.d.ts +15 -2
- package/dist/delivery-operations.js +60 -30
- package/dist/delivery.d.ts +44 -33
- package/dist/delivery.js +49 -75
- package/dist/help.js +1 -6
- package/dist/http-delivery.d.ts +2 -2
- package/dist/http-delivery.js +2 -4
- package/dist/inbox.d.ts +10 -18
- package/dist/inbox.js +44 -53
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/mcp.d.ts +2 -1
- package/dist/mcp.js +40 -70
- package/dist/message.d.ts +7 -0
- package/dist/message.js +23 -0
- package/dist/model.d.ts +41 -77
- package/dist/model.js +7 -139
- package/dist/neutral.d.ts +72 -0
- package/dist/neutral.js +27 -0
- package/dist/notifications.d.ts +2 -8
- package/dist/notifications.js +15 -50
- package/dist/operation-presentation.d.ts +1 -2
- package/dist/operation-presentation.js +1 -7
- package/dist/owner.d.ts +2 -2
- package/dist/owner.js +1 -1
- package/dist/paseo-delivery.d.ts +1 -1
- package/dist/paseo-delivery.js +2 -4
- package/dist/paseo-timeline.js +1 -0
- package/dist/plugins/opencode/delivery.js +27 -42
- package/dist/ports.d.ts +46 -168
- package/dist/presentation-operations.d.ts +1 -14
- package/dist/presentation-operations.js +16 -16
- package/dist/presentation.d.ts +5 -5
- package/dist/presentation.js +1 -0
- package/dist/runtime.js +2 -2
- package/dist/search.js +1 -1
- package/dist/sqlite-channel.d.ts +15 -0
- package/dist/sqlite-channel.js +600 -0
- package/dist/sqlite-framing.d.ts +8 -0
- package/dist/sqlite-framing.js +31 -0
- package/dist/sqlite-square.d.ts +12 -13
- package/dist/sqlite-square.js +192 -248
- package/dist/sqlite-values.d.ts +21 -0
- package/dist/sqlite-values.js +78 -0
- package/dist/square-api.d.ts +1 -1
- package/dist/square-api.js +1 -1
- package/dist/square-core.d.ts +1 -1
- package/dist/square-domain.d.ts +21 -7
- package/dist/square-domain.js +93 -94
- package/dist/square-facade.d.ts +12 -66
- package/dist/square-index.d.ts +1 -1
- package/dist/square-index.js +1 -1
- package/dist/square-location.d.ts +6 -1
- package/dist/square-location.js +1 -1
- package/dist/square-receive.d.ts +2 -3
- package/dist/square-sqlite.d.ts +45 -44
- package/dist/square-sqlite.js +308 -764
- package/dist/square-tools.d.ts +8 -0
- package/dist/square-tools.js +39 -0
- package/dist/views.d.ts +6 -6
- package/dist/views.js +15 -9
- package/dist/wake-preview.d.ts +7 -0
- package/dist/wake-preview.js +15 -0
- package/dist/wake-sink.d.ts +2 -2
- package/dist/wake-sink.js +1 -1
- package/dist/wake-transports.d.ts +7 -0
- package/dist/wake-transports.js +42 -0
- package/guides/claude-native.md +13 -10
- package/guides/codex-delivery.md +3 -1
- package/guides/participant-ownership.md +1 -1
- package/guides/row-runtime-delivery-evidence.md +2 -0
- package/guides/row-storage-design.md +19 -44
- package/guides/square-api.md +137 -60
- package/package.json +3 -3
- package/plugins/claude/.claude-plugin/plugin.json +1 -1
- package/plugins/claude/types.d.ts +1 -1
- package/plugins/codex/.codex-plugin/plugin.json +1 -1
- package/plugins/opencode/delivery.ts +28 -41
- package/plugins/pi/square-pi.js +28 -51
- package/dist/square-legacy-framing.d.ts +0 -11
- package/dist/square-legacy-framing.js +0 -64
- package/dist/square-migration-host-ledger.d.ts +0 -26
- package/dist/square-migration-host-ledger.js +0 -169
- package/dist/square-migration.d.ts +0 -30
- package/dist/square-migration.js +0 -599
- package/guides/migration.md +0 -156
|
@@ -4,9 +4,8 @@ import { withFileLock } from './file-lock.js';
|
|
|
4
4
|
import { createArtifactPort } from './artifact.js';
|
|
5
5
|
import { preparePendingPresentation } from './presentation-operations.js';
|
|
6
6
|
import { presentPreparedBatch } from './delivery-effects.js';
|
|
7
|
-
import { sessionInbox, projectBoundaryEligibility,
|
|
8
|
-
import {
|
|
9
|
-
export { pendingAtBoundary };
|
|
7
|
+
import { sessionInbox, projectBoundaryEligibility, pendingKey } from './inbox.js';
|
|
8
|
+
import { projectChannelNotification, projectNotification, renderSquareReminder } from './attention-presentation.js';
|
|
10
9
|
const CONTEXT_MAX = 1200;
|
|
11
10
|
export function renderPendingAtBoundary(inbox) {
|
|
12
11
|
return renderBoundary(inbox).context;
|
|
@@ -15,26 +14,23 @@ function renderBoundary(inbox) {
|
|
|
15
14
|
const queued = inbox.flatMap((membership) => membership.notifications.map((notification) => ({ membership, notification })));
|
|
16
15
|
const blocks = [];
|
|
17
16
|
const agoraBlocks = [];
|
|
18
|
-
|
|
19
|
-
let remainingAgora = queued.filter(({ notification }) => notification.delivery?.mode !== 'direct').length;
|
|
17
|
+
let remainingAgora = queued.filter(({ notification }) => notification.route !== undefined).length;
|
|
20
18
|
const entries = [];
|
|
21
19
|
let omitted = 0;
|
|
22
20
|
const omission = (count) => `${count} more ${count === 1 ? 'activity' : 'activities'} not shown.`;
|
|
23
21
|
for (const entry of queued) {
|
|
24
22
|
const { membership, notification } = entry;
|
|
25
23
|
// The omission line represents the rest of this batch too, but never consumes its bodies.
|
|
26
|
-
const coverage = { membership,
|
|
24
|
+
const coverage = { membership, messageIndex: notification.messageIndex, markSeen: false };
|
|
27
25
|
entries.push(coverage);
|
|
28
|
-
const
|
|
29
|
-
squarePath: membership.location,
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
});
|
|
37
|
-
if (notification.delivery?.mode !== 'direct') {
|
|
26
|
+
const projected = notification.route === undefined
|
|
27
|
+
? projectChannelNotification({ squarePath: membership.location, recipient: membership.seat.participant,
|
|
28
|
+
actor: notification.actor, body: notification.body, ...(notification.preview === undefined ? {} : { preview: notification.preview }) })
|
|
29
|
+
: projectNotification({ squarePath: membership.location, actIndex: notification.actIndex ?? notification.messageIndex,
|
|
30
|
+
recipient: membership.seat.participant, actor: notification.actor, route: notification.route,
|
|
31
|
+
body: notification.body, ...(notification.preview === undefined ? {} : { preview: notification.preview }) });
|
|
32
|
+
const block = projected.text;
|
|
33
|
+
if ('agora' in projected && projected.agora) {
|
|
38
34
|
remainingAgora -= 1;
|
|
39
35
|
const omittedAfter = omitted + remainingAgora;
|
|
40
36
|
const prospective = renderSquareReminder([...agoraBlocks, block, ...(omittedAfter > 0 ? [omission(omittedAfter)] : [])]);
|
|
@@ -45,11 +41,10 @@ function renderBoundary(inbox) {
|
|
|
45
41
|
agoraBlocks.push(block);
|
|
46
42
|
}
|
|
47
43
|
blocks.push(block);
|
|
48
|
-
|
|
49
|
-
coverage.markSeen = !attentionBodyIsClipped(notification.body, notification.delivery);
|
|
44
|
+
coverage.markSeen = !projected.clipped;
|
|
50
45
|
}
|
|
51
46
|
return {
|
|
52
|
-
context: renderSquareReminder([...blocks, ...(omitted > 0 ? [omission(omitted)] : [])]
|
|
47
|
+
context: renderSquareReminder([...blocks, ...(omitted > 0 ? [omission(omitted)] : [])]),
|
|
53
48
|
entries,
|
|
54
49
|
};
|
|
55
50
|
}
|
|
@@ -74,9 +69,9 @@ async function presentPendingAtBoundaryUnlocked(identity, present, lookup = sess
|
|
|
74
69
|
artifacts.set(location, artifact);
|
|
75
70
|
}
|
|
76
71
|
const claim = await preparePendingPresentation({ artifact, location, participant: seat.participant,
|
|
77
|
-
|
|
72
|
+
message: entry.messageIndex, seat, markSeen: entry.markSeen, signal });
|
|
78
73
|
if (claim !== undefined)
|
|
79
|
-
claims.push({ key: pendingKey(entry.membership, entry.
|
|
74
|
+
claims.push({ key: pendingKey(entry.membership, entry.messageIndex), claim });
|
|
80
75
|
}
|
|
81
76
|
}
|
|
82
77
|
catch (error) {
|
|
@@ -87,7 +82,7 @@ async function presentPendingAtBoundaryUnlocked(identity, present, lookup = sess
|
|
|
87
82
|
const report = await presentPreparedBatch(claims.map(({ claim }) => claim), eligibleClaims => {
|
|
88
83
|
const eligible = new Set(claims.filter(({ claim }) => eligibleClaims.includes(claim)).map(({ key }) => key));
|
|
89
84
|
const delivered = pending.map(membership => ({ ...membership,
|
|
90
|
-
notifications: membership.notifications.filter(note => eligible.has(pendingKey(membership, note.
|
|
85
|
+
notifications: membership.notifications.filter(note => eligible.has(pendingKey(membership, note.messageIndex))),
|
|
91
86
|
})).filter(membership => membership.notifications.length > 0);
|
|
92
87
|
return { payload: { context: renderBoundary(delivered).context, delivered }, included: eligibleClaims };
|
|
93
88
|
}, payload => present(payload.context, payload.delivered), { signal });
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type HydratedAct } from './model.js';
|
|
2
2
|
import type { ActivityIndex, DirectedFilter, SquareRead, SquareWrite } from './ports.js';
|
|
3
3
|
import type { CatchOptions, CatchReason, PerceivedActivity } from './square-facade.js';
|
|
4
4
|
export interface CatchSelection {
|
|
@@ -14,7 +14,7 @@ export interface CatchSelection {
|
|
|
14
14
|
readonly hint?: string;
|
|
15
15
|
}
|
|
16
16
|
/** Capture a selected page (or an empty completion) without opening another resource. */
|
|
17
|
-
export declare function observeCatchSelection(facts: SquareRead, participant: string, activities: readonly
|
|
17
|
+
export declare function observeCatchSelection(facts: SquareRead, participant: string, activities: readonly HydratedAct[], filter: DirectedFilter, at: number, remaining?: number): CatchSelection;
|
|
18
18
|
export declare const CATCH_DEFAULT_LIMIT = 10;
|
|
19
19
|
export declare const CATCH_MAX_LIMIT = 100;
|
|
20
20
|
export declare function catchLimit(value: number | undefined): number;
|
package/dist/catch-decisions.js
CHANGED
|
@@ -33,7 +33,7 @@ function catchPageSelection(facts, requestedName, options) {
|
|
|
33
33
|
const participant = resolveKnownName(facts, requestedName);
|
|
34
34
|
const limit = catchLimit(options.limit);
|
|
35
35
|
const senders = options.from?.map(name => resolveKnownName(facts, name));
|
|
36
|
-
const filter = { unseenOnly: true, ...(senders === undefined ? {} : { senders }), ...(options.mention === true ? { attentionOnly: true } : {}) };
|
|
36
|
+
const filter = { kinds: ['say'], unseenOnly: true, ...(senders === undefined ? {} : { senders }), ...(options.mention === true ? { attentionOnly: true } : {}) };
|
|
37
37
|
return { participant, filter, selection: { kind: 'page', query: filter, limit } };
|
|
38
38
|
}
|
|
39
39
|
/** Select non-ID catch coordinates without hydrating bodies or recording receipts. */
|
|
@@ -44,7 +44,7 @@ export function selectCatchPage(facts, requestedName, options) {
|
|
|
44
44
|
/** Selection, receipts and resulting cursor belong to one artifact write transaction. */
|
|
45
45
|
export function decideCatch(facts, requestedName, options, at) {
|
|
46
46
|
let viewer;
|
|
47
|
-
let filter = { unseenOnly: true };
|
|
47
|
+
let filter = { kinds: ['say'], unseenOnly: true };
|
|
48
48
|
let selection;
|
|
49
49
|
if (options.id !== undefined) {
|
|
50
50
|
viewer = resolveKnownName(facts, requestedName);
|
|
@@ -64,9 +64,19 @@ export function decideCatch(facts, requestedName, options, at) {
|
|
|
64
64
|
}
|
|
65
65
|
let consumed;
|
|
66
66
|
try {
|
|
67
|
+
// Receipts are recorded by message coordinate; the batch hydration above already resolved each selected say.
|
|
68
|
+
let selected = new Map();
|
|
67
69
|
consumed = consumeReceived({
|
|
68
70
|
...squareReceiveRead(facts),
|
|
69
|
-
|
|
71
|
+
load(keys) { selected = facts.activities(keys).reduce((map, item) => map.set(item.index, item), new Map()); return selected; },
|
|
72
|
+
addressed(recipient, index) {
|
|
73
|
+
const head = facts.directed(recipient, { indexes: [index], kinds: ['say'] }, { edge: 'oldest', limit: 1 }).items[0];
|
|
74
|
+
return head === undefined ? undefined : { key: head.index, via: head.route };
|
|
75
|
+
},
|
|
76
|
+
insertReceipt: (ref, time) => {
|
|
77
|
+
const item = selected.get(ref.item);
|
|
78
|
+
return item?.kind === 'say' && facts.channel.markSeen(ref.recipient, [item.messageIndex], time) > 0;
|
|
79
|
+
},
|
|
70
80
|
}, viewer, selection, at);
|
|
71
81
|
}
|
|
72
82
|
catch (error) {
|
|
@@ -85,7 +95,7 @@ export function decideCatch(facts, requestedName, options, at) {
|
|
|
85
95
|
const delivered = consumed.items.map(item => item.data);
|
|
86
96
|
const observed = observeCatchSelection(facts, viewer, delivered, filter, at, consumed.remaining);
|
|
87
97
|
// Receipts are the durable catch count: everything directed here minus what is still unseen.
|
|
88
|
-
const caught = facts.directedCount(viewer, {}) - facts.directedCount(viewer, { unseenOnly: true });
|
|
98
|
+
const caught = facts.directedCount(viewer, { kinds: ['say'] }) - facts.directedCount(viewer, { kinds: ['say'], unseenOnly: true });
|
|
89
99
|
// An exact id catch is a targeted fetch and stays repeatable, so it carries no nudge.
|
|
90
100
|
const hint = options.id === undefined ? catchHint(caught - consumed.newlyConsumed, caught) : undefined;
|
|
91
101
|
return hint === undefined ? observed : { ...observed, hint };
|
|
@@ -4,3 +4,11 @@ export declare function matchesCatchSelection(actor: string, audience: Audience,
|
|
|
4
4
|
readonly participants?: readonly string[];
|
|
5
5
|
readonly mention?: string;
|
|
6
6
|
}, replyAuthor?: string): boolean;
|
|
7
|
+
/** One directed arrival and the upper reason it reached its recipient. */
|
|
8
|
+
export interface RoutedNotification {
|
|
9
|
+
readonly actor: string;
|
|
10
|
+
readonly route: import('./model.js').DirectedNotificationRoute;
|
|
11
|
+
readonly recipient: string;
|
|
12
|
+
}
|
|
13
|
+
/** A live catch owns every matching notification, independent of its page size. */
|
|
14
|
+
export declare function leaseOwnsNotification(lease: import('./model.js').WatchLease, notification: RoutedNotification): boolean;
|
package/dist/catch-selection.js
CHANGED
|
@@ -12,3 +12,8 @@ export function matchesCatchSelection(actor, audience, filter, replyAuthor) {
|
|
|
12
12
|
return audienceIncludes(audience, filter.mention)
|
|
13
13
|
|| (replyAuthor !== undefined && sameName(replyAuthor, filter.mention));
|
|
14
14
|
}
|
|
15
|
+
/** A live catch owns every matching notification, independent of its page size. */
|
|
16
|
+
export function leaseOwnsNotification(lease, notification) {
|
|
17
|
+
return matchesCatchSelection(notification.actor, notification.route === 'bell' ? { kind: 'bell' }
|
|
18
|
+
: { kind: 'mentions', names: notification.route === 'mention' ? [notification.recipient] : [] }, lease.filter ?? {}, notification.route === 'reply' ? notification.recipient : undefined);
|
|
19
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type StoreTransaction } from './artifact-store.js';
|
|
2
|
+
import type { ChannelArtifact, ChannelRead, ChannelWrite } from './channel-ports.js';
|
|
3
|
+
import type { WakeTransportPort, WakeProjection } from './channel-transport.js';
|
|
4
|
+
export declare function channelReads(channel: ChannelRead, guard: StoreTransaction['guard']): ChannelRead;
|
|
5
|
+
export declare function channelWrites(channel: ChannelWrite, guard: StoreTransaction['guard']): ChannelWrite;
|
|
6
|
+
/** Native Channel factories use only lower SQL and the shared physical-store lifetime. */
|
|
7
|
+
export declare function openChannelArtifact(location: string, signal?: AbortSignal): ChannelArtifact;
|
|
8
|
+
export declare function createMemoryChannelArtifact(description?: string): ChannelArtifact;
|
|
9
|
+
export declare function createChannelArtifactFile(location: string, description: string, force: boolean, signal?: AbortSignal): Promise<void>;
|
|
10
|
+
export declare function channelCourier(artifact: ChannelArtifact, transport: WakeTransportPort, location: string, clock: () => number, preparePresentation?: WakeProjection): (message?: number) => Promise<void>;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { createArtifactStore, createStoreFile, replaceStoreFile } from './artifact-store.js';
|
|
2
|
+
import { channelStoreFormat, initializeStandaloneChannel } from './channel-sqlite-schema.js';
|
|
3
|
+
import { createChannelSqlite } from './sqlite-channel.js';
|
|
4
|
+
import { wrapChannelWrite } from './channel-domain.js';
|
|
5
|
+
import { deliverPending } from './delivery-operations.js';
|
|
6
|
+
import { InternalSquareError } from './neutral.js';
|
|
7
|
+
const readMethods = [
|
|
8
|
+
'header', 'message', 'messages', 'messageHeads', 'messageCount', 'addresses', 'receipt', 'receiptFacts',
|
|
9
|
+
'directed', 'directedCount', 'endpoint', 'endpointsForOwner', 'endpoints', 'deliveryEvidence', 'deliveryByToken',
|
|
10
|
+
'cancelledThrough', 'deliveryDeferrals', 'receiveClaims', 'claimLease', 'suppressed',
|
|
11
|
+
];
|
|
12
|
+
export function channelReads(channel, guard) {
|
|
13
|
+
return Object.fromEntries(readMethods.map(name => [name, guard(channel[name])]));
|
|
14
|
+
}
|
|
15
|
+
export function channelWrites(channel, guard) {
|
|
16
|
+
return Object.fromEntries(Object.entries(channel).filter(([, value]) => typeof value === 'function')
|
|
17
|
+
.map(([name, value]) => [name, guard(value)]));
|
|
18
|
+
}
|
|
19
|
+
function channelPort(location, initialize, signal) {
|
|
20
|
+
const store = createArtifactStore(location, channelStoreFormat, initialize, signal);
|
|
21
|
+
const port = {
|
|
22
|
+
read: (select, signal) => store.run(false, ({ db, guard }) => select(channelReads(createChannelSqlite(db), guard)), signal),
|
|
23
|
+
transactAs: (authority, change, signal) => store.run(true, ({ db, guard, track }) => {
|
|
24
|
+
const channel = createChannelSqlite(db);
|
|
25
|
+
track(channel);
|
|
26
|
+
return change(wrapChannelWrite(channelReads(channel, guard), channelWrites(channel, guard), authority));
|
|
27
|
+
}, signal),
|
|
28
|
+
async claimDelivery(input, signal) { return (await port.transactAs({ kind: 'participant', seat: input.seat }, facts => facts.claimDelivery(input), signal)).value; },
|
|
29
|
+
async prepareDelivery(input, signal) { return (await port.transactAs({ kind: 'participant', seat: input.seat }, facts => facts.prepareDelivery(input), signal)).value; },
|
|
30
|
+
async completeDelivery(input, signal) { return (await port.transactAs({ kind: 'participant', seat: input.seat }, facts => facts.completeDelivery(input), signal)).value; },
|
|
31
|
+
async cancelDeliveries(seat, through, signal) {
|
|
32
|
+
return (await port.transactAs({ kind: 'participant', seat }, facts => {
|
|
33
|
+
const boundary = through ?? facts.header().lastMessageIndex;
|
|
34
|
+
return boundary < 0 ? false : facts.cancelThrough(seat, boundary);
|
|
35
|
+
}, signal)).value;
|
|
36
|
+
},
|
|
37
|
+
changed: store.changed, close: store.close,
|
|
38
|
+
};
|
|
39
|
+
return port;
|
|
40
|
+
}
|
|
41
|
+
/** Native Channel factories use only lower SQL and the shared physical-store lifetime. */
|
|
42
|
+
export function openChannelArtifact(location, signal) { return channelPort(location, undefined, signal); }
|
|
43
|
+
export function createMemoryChannelArtifact(description = '# Channel\n') {
|
|
44
|
+
return channelPort(':memory:', db => initializeStandaloneChannel(db, 0, description));
|
|
45
|
+
}
|
|
46
|
+
export async function createChannelArtifactFile(location, description, force, signal) {
|
|
47
|
+
if (force)
|
|
48
|
+
await replaceStoreFile(location, channelStoreFormat, (db, revision) => initializeStandaloneChannel(db, revision, description), signal);
|
|
49
|
+
else if (!await createStoreFile(location, channelStoreFormat, db => initializeStandaloneChannel(db, 0, description), signal))
|
|
50
|
+
throw new InternalSquareError('conflict', `Refusing to overwrite existing square: ${location}\nPass -f to overwrite.`);
|
|
51
|
+
}
|
|
52
|
+
export function channelCourier(artifact, transport, location, clock, preparePresentation) {
|
|
53
|
+
return (message) => deliverPending({ artifact, transport, location, now: clock(),
|
|
54
|
+
...(preparePresentation === undefined ? {} : { preparePresentation }), ...(message === undefined ? {} : { message }) });
|
|
55
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ChannelRead, ChannelDeliveryEvidence as DeliveryEvidence, MessageHead } from './channel-ports.js';
|
|
2
|
+
/** Presentation custody blocks a wake, independently of native wake acceptance. */
|
|
3
|
+
export declare function presentationBlocksWake(evidence: readonly DeliveryEvidence[], now: number): boolean;
|
|
4
|
+
/** Preselection only: an expired wake dispatch is uncertain, never safe automatic replay. */
|
|
5
|
+
export declare function automaticWakeEligible(evidence: readonly DeliveryEvidence[], now: number): boolean;
|
|
6
|
+
/** One lower pending message: attached, unconsumed and not suppressed by a live claim. */
|
|
7
|
+
export declare function pendingHeadAt(facts: ChannelRead, name: string, index: number, now?: number): MessageHead | undefined;
|
|
8
|
+
/** Lower pending selection for one recipient, oldest first. */
|
|
9
|
+
export declare function pendingMessageHeads(facts: ChannelRead, name: string, now?: number, suppress?: boolean): MessageHead[];
|
|
10
|
+
/** Lower recipients of one message that still owe a wake; other endpoints are untouched. */
|
|
11
|
+
export declare function pendingAddresses(facts: ChannelRead, index: number, now?: number): readonly MessageHead[];
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { automaticDispatchEligible, presentationBlocksDispatch } from './delivery-attempts.js';
|
|
2
|
+
function custody(evidence) {
|
|
3
|
+
return evidence.map(row => ({ purpose: row.kind === 'wake' ? 'dispatch' : 'presentation', outcome: row.outcome, expiresAt: row.expiresAt }));
|
|
4
|
+
}
|
|
5
|
+
/** Presentation custody blocks a wake, independently of native wake acceptance. */
|
|
6
|
+
export function presentationBlocksWake(evidence, now) {
|
|
7
|
+
return presentationBlocksDispatch(custody(evidence), now);
|
|
8
|
+
}
|
|
9
|
+
/** Preselection only: an expired wake dispatch is uncertain, never safe automatic replay. */
|
|
10
|
+
export function automaticWakeEligible(evidence, now) {
|
|
11
|
+
return automaticDispatchEligible(custody(evidence), now);
|
|
12
|
+
}
|
|
13
|
+
/** One lower pending message: attached, unconsumed and not suppressed by a live claim. */
|
|
14
|
+
export function pendingHeadAt(facts, name, index, now = Date.now()) {
|
|
15
|
+
const endpoint = facts.endpoint(name);
|
|
16
|
+
if (endpoint === undefined || endpoint.attachment !== 'attached' || facts.receipt(endpoint.participant, index))
|
|
17
|
+
return undefined;
|
|
18
|
+
if (facts.suppressed(endpoint.participant, endpoint.generation, index, now))
|
|
19
|
+
return undefined;
|
|
20
|
+
return facts.directed(endpoint.participant, { afterIndex: index - 1, throughIndex: index, currentGeneration: true }, { edge: 'oldest', limit: 1 }).items[0];
|
|
21
|
+
}
|
|
22
|
+
/** Lower pending selection for one recipient, oldest first. */
|
|
23
|
+
export function pendingMessageHeads(facts, name, now = Date.now(), suppress = true) {
|
|
24
|
+
const endpoint = facts.endpoint(name);
|
|
25
|
+
if (endpoint === undefined || endpoint.attachment !== 'attached')
|
|
26
|
+
return [];
|
|
27
|
+
const heads = [];
|
|
28
|
+
let afterIndex = -1;
|
|
29
|
+
for (;;) {
|
|
30
|
+
const page = facts.directed(endpoint.participant, { afterIndex, unseenOnly: true, currentGeneration: true }, { edge: 'oldest', limit: 100 });
|
|
31
|
+
for (const head of page.items)
|
|
32
|
+
if (!suppress || !facts.suppressed(endpoint.participant, endpoint.generation, head.index, now))
|
|
33
|
+
heads.push(head);
|
|
34
|
+
if (!page.hasMore)
|
|
35
|
+
break;
|
|
36
|
+
afterIndex = page.items.at(-1).index;
|
|
37
|
+
}
|
|
38
|
+
return heads;
|
|
39
|
+
}
|
|
40
|
+
/** Lower recipients of one message that still owe a wake; other endpoints are untouched. */
|
|
41
|
+
export function pendingAddresses(facts, index, now = Date.now()) {
|
|
42
|
+
return facts.addresses(index).flatMap(({ recipient, generation }) => {
|
|
43
|
+
const current = facts.endpoint(recipient);
|
|
44
|
+
if (current === undefined || current.attachment !== 'attached')
|
|
45
|
+
return [];
|
|
46
|
+
if (generation !== undefined && current.generation !== generation)
|
|
47
|
+
return [];
|
|
48
|
+
const head = pendingHeadAt(facts, recipient, index, now);
|
|
49
|
+
return head === undefined ? [] : [head];
|
|
50
|
+
});
|
|
51
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { ChannelRead, ChannelWrite, ChannelWriteAuthority } from './channel-ports.js';
|
|
2
|
+
/** Endpoint custody and operation authority without participant membership or social events. */
|
|
3
|
+
export declare function wrapChannelWrite(read: ChannelRead, write: ChannelWrite, authority: ChannelWriteAuthority): ChannelWrite;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { SquareError, validateOwner } from './neutral.js';
|
|
2
|
+
import { sameName, validateName } from './channel-values.js';
|
|
3
|
+
import { validateEndpointGeneration } from './message.js';
|
|
4
|
+
/** Endpoint custody and operation authority without participant membership or social events. */
|
|
5
|
+
export function wrapChannelWrite(read, write, authority) {
|
|
6
|
+
if (!authority || !['send', 'endpoint', 'endpoint-cleanup', 'participant'].includes(authority.kind))
|
|
7
|
+
throw new SquareError('invalid_args', 'Channel writes require an explicit authority.');
|
|
8
|
+
const name = authority.kind === 'send' ? authority.actor : authority.kind === 'endpoint' ? authority.participant : authority.seat.participant;
|
|
9
|
+
validateName(name);
|
|
10
|
+
if (authority.kind !== 'send')
|
|
11
|
+
validateOwner(authority.kind === 'endpoint' ? authority.owner : authority.seat.owner);
|
|
12
|
+
const fail = () => { throw new SquareError('already_joined', 'This operation needs its captured Channel endpoint.'); };
|
|
13
|
+
const captured = authority.kind === 'participant' || authority.kind === 'endpoint-cleanup' ? authority.seat : undefined;
|
|
14
|
+
if (captured)
|
|
15
|
+
validateEndpointGeneration(captured.generation);
|
|
16
|
+
function current(ref, allowDetached = false) {
|
|
17
|
+
const actual = read.endpoint(ref.participant);
|
|
18
|
+
if (!actual || !sameName(ref.participant, name) || actual.owner !== ref.owner || actual.generation !== ref.generation
|
|
19
|
+
|| !allowDetached && actual.attachment !== 'attached')
|
|
20
|
+
fail();
|
|
21
|
+
}
|
|
22
|
+
function own(ref, allowDetached = false) {
|
|
23
|
+
if (authority.kind === 'endpoint') {
|
|
24
|
+
if (!sameName(ref.participant, name) || ref.owner !== authority.owner)
|
|
25
|
+
fail();
|
|
26
|
+
}
|
|
27
|
+
else if (!captured || !sameName(ref.participant, captured.participant) || ref.owner !== captured.owner || ref.generation !== captured.generation)
|
|
28
|
+
fail();
|
|
29
|
+
current(ref, allowDetached);
|
|
30
|
+
}
|
|
31
|
+
if (authority.kind === 'participant')
|
|
32
|
+
current(authority.seat);
|
|
33
|
+
const forbidden = () => { throw new SquareError('invalid_args', 'This Channel authority does not permit that mutation.'); };
|
|
34
|
+
const facts = Object.assign({}, read, Object.fromEntries(Object.keys(write)
|
|
35
|
+
.filter(key => !(key in read)).map(key => [key, forbidden])));
|
|
36
|
+
if (authority.kind === 'send' || authority.kind === 'participant') {
|
|
37
|
+
facts.publishMessage = draft => {
|
|
38
|
+
if (!sameName(draft.from, name))
|
|
39
|
+
fail();
|
|
40
|
+
if (captured)
|
|
41
|
+
current(captured);
|
|
42
|
+
return write.publishMessage(draft);
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
if (authority.kind === 'endpoint') {
|
|
46
|
+
facts.storeEndpoint = endpoint => {
|
|
47
|
+
if (!sameName(endpoint.participant, name) || endpoint.owner !== authority.owner)
|
|
48
|
+
fail();
|
|
49
|
+
return write.storeEndpoint(endpoint);
|
|
50
|
+
};
|
|
51
|
+
facts.reattachEndpoint = (ref, address) => { own(ref, true); return write.reattachEndpoint(ref, address); };
|
|
52
|
+
}
|
|
53
|
+
if (authority.kind === 'endpoint' || authority.kind === 'participant')
|
|
54
|
+
facts.updateWakeAddress = (ref, address) => { own(ref); return write.updateWakeAddress(ref, address); };
|
|
55
|
+
if (authority.kind === 'endpoint-cleanup') {
|
|
56
|
+
// Cleanup races are harmless; storage compares the captured owner and generation.
|
|
57
|
+
const cleanup = (ref) => {
|
|
58
|
+
if (!captured || !sameName(ref.participant, captured.participant) || ref.owner !== captured.owner || ref.generation !== captured.generation)
|
|
59
|
+
fail();
|
|
60
|
+
};
|
|
61
|
+
facts.detachEndpoint = ref => { cleanup(ref); return write.detachEndpoint(ref); };
|
|
62
|
+
facts.removeEndpoint = ref => { cleanup(ref); return write.removeEndpoint(ref); };
|
|
63
|
+
}
|
|
64
|
+
if (authority.kind === 'participant') {
|
|
65
|
+
facts.markSeen = (recipient, indexes, at) => { own({ ...authority.seat, participant: recipient }); return write.markSeen(recipient, indexes, at); };
|
|
66
|
+
facts.cancelThrough = (ref, through) => {
|
|
67
|
+
own(ref);
|
|
68
|
+
if (!Number.isSafeInteger(through) || through < 0 || through >= read.header().nextMessageIndex)
|
|
69
|
+
throw new SquareError('invalid_args', 'Cancellation boundary must be an assigned message index below the allocator.');
|
|
70
|
+
return write.cancelThrough(ref, through);
|
|
71
|
+
};
|
|
72
|
+
facts.claimDelivery = input => { own(input.seat); return write.claimDelivery(input); };
|
|
73
|
+
facts.prepareDelivery = input => { own(input.seat); return write.prepareDelivery(input); };
|
|
74
|
+
facts.completeDelivery = input => { own(input.seat); return write.completeDelivery(input); };
|
|
75
|
+
facts.observeNativeDelivery = input => { own(input.seat); return write.observeNativeDelivery(input); };
|
|
76
|
+
facts.putDeliveryDeferral = (ref, ...args) => { own(ref); return write.putDeliveryDeferral(ref, ...args); };
|
|
77
|
+
facts.renewDeliveryDeferral = (ref, ...args) => { own(ref); return write.renewDeliveryDeferral(ref, ...args); };
|
|
78
|
+
facts.releaseDeliveryDeferral = (ref, ...args) => { own(ref); return write.releaseDeliveryDeferral(ref, ...args); };
|
|
79
|
+
facts.putReceiveClaim = claim => { own({ ...authority.seat, participant: claim.owner, generation: claim.generation }); return write.putReceiveClaim(claim); };
|
|
80
|
+
facts.removeReceiveClaim = (owner, namespace, id) => { own({ ...authority.seat, participant: owner }); return write.removeReceiveClaim(owner, namespace, id); };
|
|
81
|
+
}
|
|
82
|
+
return facts;
|
|
83
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import type { MessageMetadata } from './channel-values.js';
|
|
2
|
+
import type { MetadataMatch } from './channel-metadata.js';
|
|
3
|
+
import type { MessageId } from './message.js';
|
|
4
|
+
export type ChannelTruncate = number | false;
|
|
5
|
+
export interface ChannelSendInput {
|
|
6
|
+
readonly from: string;
|
|
7
|
+
readonly to: string | readonly string[];
|
|
8
|
+
readonly body: string;
|
|
9
|
+
readonly truncate?: ChannelTruncate;
|
|
10
|
+
readonly metadata?: MessageMetadata;
|
|
11
|
+
}
|
|
12
|
+
export interface ChannelSendResult {
|
|
13
|
+
readonly id: MessageId;
|
|
14
|
+
readonly at: number;
|
|
15
|
+
readonly from: string;
|
|
16
|
+
readonly to: readonly string[];
|
|
17
|
+
readonly body: string;
|
|
18
|
+
readonly metadata?: MessageMetadata;
|
|
19
|
+
}
|
|
20
|
+
export interface ChannelEndpointSummary {
|
|
21
|
+
readonly name: string;
|
|
22
|
+
readonly generation: string;
|
|
23
|
+
readonly attachment: 'attached' | 'detached';
|
|
24
|
+
readonly deliveryAvailable: boolean;
|
|
25
|
+
readonly unreadCount: number;
|
|
26
|
+
readonly lastActiveAt?: number;
|
|
27
|
+
}
|
|
28
|
+
export interface ChannelMessage {
|
|
29
|
+
readonly id: MessageId;
|
|
30
|
+
readonly at: number;
|
|
31
|
+
readonly from: string;
|
|
32
|
+
readonly to: readonly string[];
|
|
33
|
+
readonly body: string;
|
|
34
|
+
readonly metadata?: MessageMetadata;
|
|
35
|
+
}
|
|
36
|
+
export interface ChannelPendingResult {
|
|
37
|
+
readonly messages: readonly ChannelMessage[];
|
|
38
|
+
readonly remaining: number;
|
|
39
|
+
}
|
|
40
|
+
export interface MessageCursor {
|
|
41
|
+
readonly id: MessageId;
|
|
42
|
+
readonly direction: 'before' | 'after';
|
|
43
|
+
}
|
|
44
|
+
export interface MessageSearch {
|
|
45
|
+
readonly text: string;
|
|
46
|
+
readonly mode: 'literal' | 'regex';
|
|
47
|
+
}
|
|
48
|
+
export interface MessageQuery {
|
|
49
|
+
readonly at?: readonly MessageId[];
|
|
50
|
+
readonly from?: readonly string[];
|
|
51
|
+
readonly match?: MetadataMatch;
|
|
52
|
+
readonly search?: MessageSearch;
|
|
53
|
+
readonly cursor?: MessageCursor;
|
|
54
|
+
}
|
|
55
|
+
export interface ChannelHistoryQuery extends MessageQuery {
|
|
56
|
+
readonly limit?: number | null;
|
|
57
|
+
readonly order?: 'asc' | 'desc';
|
|
58
|
+
}
|
|
59
|
+
export interface ChannelPendingOptions extends MessageQuery {
|
|
60
|
+
readonly limit?: number;
|
|
61
|
+
}
|
|
62
|
+
export interface ChannelHistoryResult {
|
|
63
|
+
readonly messages: readonly ChannelMessage[];
|
|
64
|
+
}
|
|
65
|
+
export interface ChannelReceiveResult extends ChannelPendingResult {
|
|
66
|
+
readonly consumed: number;
|
|
67
|
+
readonly remaining: number;
|
|
68
|
+
}
|
|
69
|
+
export interface AckResult {
|
|
70
|
+
readonly consumed: number;
|
|
71
|
+
}
|
|
72
|
+
export interface ChannelEndpointHold {
|
|
73
|
+
readonly name: string;
|
|
74
|
+
readonly generation: string;
|
|
75
|
+
readonly attachment: 'attached' | 'detached';
|
|
76
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { type MetadataMatch } from './delivery-deferral.js';
|
|
2
|
+
import { type Owner } from './neutral.js';
|
|
3
|
+
import { type WakeAddress } from './channel-values.js';
|
|
4
|
+
import { type HarnessSessionChannel } from './participant-identity.js';
|
|
5
|
+
import type { ChannelWriteAuthority, ChannelArtifact, EndpointFact, EndpointRef } from './channel-ports.js';
|
|
6
|
+
import type { WakeTransportPort } from './channel-transport.js';
|
|
7
|
+
import { validateEndpointGeneration, type MessageId } from './message.js';
|
|
8
|
+
import type { AckResult, ChannelEndpointSummary, ChannelReceiveResult, ChannelPendingResult, ChannelHistoryResult, ChannelSendInput, ChannelSendResult, ChannelHistoryQuery, ChannelPendingOptions, ChannelEndpointHold } from './channel-facade.js';
|
|
9
|
+
import type { DeliveryDeferral } from './delivery-deferral.js';
|
|
10
|
+
import type { OperationControl, OperationFailureDetail } from './neutral.js';
|
|
11
|
+
export { harnessOwner, decodeHarnessOwner, localUserOwner } from './owner.js';
|
|
12
|
+
export type { MessageMetadata } from './channel-values.js';
|
|
13
|
+
export type { MessageSearch, ChannelTruncate, ChannelPendingOptions, MessageCursor, MessageQuery, ChannelPendingResult, ChannelHistoryResult, ChannelHistoryQuery, AckResult, ChannelEndpointSummary, ChannelMessage, ChannelReceiveResult } from './channel-facade.js';
|
|
14
|
+
export type { MessageId } from './message.js';
|
|
15
|
+
export type { ChannelArtifact } from './channel-ports.js';
|
|
16
|
+
export type { ChannelSendInput, ChannelSendResult, DeliveryDeferral, MetadataMatch, OperationControl, Owner, WakeAddress, WakeTransportPort, HarnessSessionChannel };
|
|
17
|
+
export interface ResolvedHarnessSession {
|
|
18
|
+
readonly channel: HarnessSessionChannel;
|
|
19
|
+
readonly sessionId: string;
|
|
20
|
+
readonly agentId?: string;
|
|
21
|
+
readonly owner: Owner;
|
|
22
|
+
readonly wakeAddress?: WakeAddress;
|
|
23
|
+
}
|
|
24
|
+
export declare function resolveHarnessSession(env?: NodeJS.ProcessEnv): ResolvedHarnessSession | undefined;
|
|
25
|
+
export interface ChannelOpenInput {
|
|
26
|
+
readonly path: string;
|
|
27
|
+
readonly cwd?: string;
|
|
28
|
+
readonly env?: NodeJS.ProcessEnv;
|
|
29
|
+
readonly clock?: () => number;
|
|
30
|
+
/** Transport for post-commit custody; `false` disables delivery for this handle. */
|
|
31
|
+
readonly wakeTransport?: WakeTransportPort | false;
|
|
32
|
+
}
|
|
33
|
+
export interface ChannelCreateInput extends ChannelOpenInput {
|
|
34
|
+
readonly force?: boolean;
|
|
35
|
+
readonly description?: string;
|
|
36
|
+
}
|
|
37
|
+
/** Every dependency one Channel needs; the artifact is already opened and narrowed. */
|
|
38
|
+
export interface ChannelPortInit {
|
|
39
|
+
readonly location: string;
|
|
40
|
+
readonly artifact: ChannelArtifact;
|
|
41
|
+
readonly clock: () => number;
|
|
42
|
+
readonly deliverEffect?: (message?: number) => Promise<void>;
|
|
43
|
+
readonly indexPath?: string;
|
|
44
|
+
readonly closesArtifact?: boolean;
|
|
45
|
+
}
|
|
46
|
+
type EndpointOptions = {
|
|
47
|
+
readonly owner: Owner;
|
|
48
|
+
readonly wakeAddress?: WakeAddress;
|
|
49
|
+
};
|
|
50
|
+
export declare function checkControl(control?: OperationControl): void;
|
|
51
|
+
export declare function squareClock(env: NodeJS.ProcessEnv, clock?: () => number): () => number;
|
|
52
|
+
export declare function failure(error: unknown, detail: OperationFailureDetail): Error;
|
|
53
|
+
/** Foundational point-to-point endpoint and messaging resource over one artifact port. */
|
|
54
|
+
export declare class Channel {
|
|
55
|
+
readonly location: string;
|
|
56
|
+
readonly artifact: ChannelArtifact;
|
|
57
|
+
readonly clock: () => number;
|
|
58
|
+
private readonly deliverEffect?;
|
|
59
|
+
private readonly indexPath?;
|
|
60
|
+
private readonly closesArtifact;
|
|
61
|
+
private constructor();
|
|
62
|
+
/** Internal composition point for upper resources; no wrapping square is involved. */
|
|
63
|
+
static fromPort(init: ChannelPortInit): Channel;
|
|
64
|
+
static open(input: ChannelOpenInput, control?: OperationControl): Promise<Channel>;
|
|
65
|
+
static create(input: ChannelCreateInput, control?: OperationControl): Promise<Channel>;
|
|
66
|
+
static inMemory(input?: Omit<ChannelCreateInput, 'path' | 'force'>): Channel;
|
|
67
|
+
remember(owner: Owner): Promise<void>;
|
|
68
|
+
/** Establish a new opaque endpoint generation, or take over the existing one explicitly. */
|
|
69
|
+
attach(name: string, options: EndpointOptions & {
|
|
70
|
+
readonly takeover?: boolean;
|
|
71
|
+
}, control?: OperationControl): Promise<ChannelEndpoint>;
|
|
72
|
+
/** Restore an exact standing endpoint without changing its generation. */
|
|
73
|
+
reattach(name: string, { owner, wakeAddress }: Pick<EndpointOptions, 'owner' | 'wakeAddress'>, control?: OperationControl): Promise<ChannelEndpoint | null>;
|
|
74
|
+
private reattachEndpoint;
|
|
75
|
+
/** Select one attached endpoint held by an exact owner. */
|
|
76
|
+
endpoint(name: string, { owner }: {
|
|
77
|
+
readonly owner: Owner;
|
|
78
|
+
}): Promise<ChannelEndpoint>;
|
|
79
|
+
endpointsOf(owner: Owner): Promise<readonly ChannelEndpointHold[]>;
|
|
80
|
+
listEndpoints(control?: OperationControl): Promise<readonly ChannelEndpointSummary[]>;
|
|
81
|
+
detach(name: string, identity: {
|
|
82
|
+
readonly owner: Owner;
|
|
83
|
+
readonly generation: string;
|
|
84
|
+
}): Promise<true | null>;
|
|
85
|
+
cancelDeliveries(name: string, identity: {
|
|
86
|
+
readonly owner: Owner;
|
|
87
|
+
readonly generation: string;
|
|
88
|
+
}, control?: OperationControl): Promise<boolean>;
|
|
89
|
+
remove(name: string, identity: {
|
|
90
|
+
readonly owner: Owner;
|
|
91
|
+
readonly generation: string;
|
|
92
|
+
}): Promise<boolean>;
|
|
93
|
+
private held;
|
|
94
|
+
/** Commit one message, then run the shared custody runner outside the transaction. */
|
|
95
|
+
send(input: ChannelSendInput, control?: OperationControl): Promise<ChannelSendResult>;
|
|
96
|
+
sendAs(authority: ChannelWriteAuthority, input: ChannelSendInput, control?: OperationControl): Promise<ChannelSendResult>;
|
|
97
|
+
/** Shared post-commit custody runner. */
|
|
98
|
+
deliver(message?: number): Promise<void>;
|
|
99
|
+
history(query?: ChannelHistoryQuery, control?: OperationControl): Promise<ChannelHistoryResult>;
|
|
100
|
+
close(): Promise<void>;
|
|
101
|
+
}
|
|
102
|
+
/** Captures one recipient endpoint through the channel's own storage, never a wrapped square. */
|
|
103
|
+
export declare class ChannelEndpoint {
|
|
104
|
+
private readonly channel;
|
|
105
|
+
private readonly endpointFact;
|
|
106
|
+
constructor(channel: Channel, endpointFact: EndpointFact);
|
|
107
|
+
get name(): string;
|
|
108
|
+
get generation(): string;
|
|
109
|
+
get ref(): EndpointRef;
|
|
110
|
+
private get storage();
|
|
111
|
+
private get participant();
|
|
112
|
+
pending(options?: ChannelPendingOptions, control?: OperationControl): Promise<ChannelPendingResult>;
|
|
113
|
+
ack(ids: readonly MessageId[], control?: OperationControl): Promise<AckResult>;
|
|
114
|
+
/** Select and consume matching unconsumed messages in one transaction. */
|
|
115
|
+
receive(options?: ChannelPendingOptions, control?: OperationControl): Promise<ChannelReceiveResult>;
|
|
116
|
+
deferDelivery(input: Readonly<{
|
|
117
|
+
match: MetadataMatch;
|
|
118
|
+
durationMs: number;
|
|
119
|
+
}>, control?: OperationControl): Promise<DeliveryDeferral>;
|
|
120
|
+
renewDeliveryDeferral(id: string, durationMs: number, control?: OperationControl): Promise<DeliveryDeferral | null>;
|
|
121
|
+
releaseDeliveryDeferral(id: string, control?: OperationControl): Promise<boolean>;
|
|
122
|
+
send(input: Omit<ChannelSendInput, 'from'>, control?: OperationControl): Promise<ChannelSendResult>;
|
|
123
|
+
/** Standalone Channel retirement; it ends no Agora membership. */
|
|
124
|
+
leave(control?: OperationControl): Promise<void>;
|
|
125
|
+
}
|
|
126
|
+
export { validateEndpointGeneration };
|