@astrosheep/square 0.4.0 → 0.4.2
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.d.ts +1 -3
- package/dist/artifact.js +12 -36
- package/dist/attention-presentation.d.ts +2 -22
- package/dist/attention-presentation.js +9 -12
- package/dist/boundary-presentation.d.ts +3 -14
- package/dist/boundary-presentation.js +29 -104
- package/dist/card-presentation.d.ts +1 -0
- package/dist/card-presentation.js +2 -0
- package/dist/catch-decisions.js +1 -7
- package/dist/claude-boundary-state.d.ts +20 -0
- package/dist/claude-boundary-state.js +84 -0
- package/dist/claude-hook.d.ts +2 -0
- package/dist/claude-hook.js +231 -0
- package/dist/claude-mcp-context.d.ts +1 -1
- package/dist/claude-mcp-context.js +12 -3
- package/dist/cli/context.js +7 -9
- package/dist/cli/observation-commands.d.ts +4 -1
- package/dist/cli/observation-commands.js +37 -4
- package/dist/cli/registry.js +5 -2
- package/dist/codex-address.d.ts +2 -2
- package/dist/codex-boundary-state.d.ts +1 -5
- package/dist/codex-boundary-state.js +0 -4
- package/dist/codex-hook.d.ts +7 -10
- package/dist/codex-hook.js +69 -33
- package/dist/codex-queue.d.ts +10 -11
- package/dist/codex-queue.js +32 -32
- package/dist/codex-watch.d.ts +2 -0
- package/dist/codex-watch.js +100 -0
- package/dist/decisions.js +2 -2
- package/dist/delivery-deferral.d.ts +8 -17
- package/dist/delivery-deferral.js +0 -28
- package/dist/delivery-frame.d.ts +7 -0
- package/dist/delivery-frame.js +11 -0
- package/dist/delivery-ledger-sqlite.d.ts +97 -0
- package/dist/delivery-ledger-sqlite.js +496 -0
- package/dist/delivery-ledger.d.ts +196 -0
- package/dist/delivery-ledger.js +268 -0
- package/dist/delivery-lifetime.d.ts +6 -0
- package/dist/delivery-lifetime.js +45 -0
- package/dist/harness-claude.js +3 -4
- package/dist/harness-links.js +63 -7
- package/dist/harness.js +12 -17
- package/dist/help.js +4 -1
- package/dist/http-delivery.d.ts +5 -9
- package/dist/http-delivery.js +20 -77
- package/dist/inbox.d.ts +6 -49
- package/dist/inbox.js +24 -371
- package/dist/index.d.ts +6 -3
- package/dist/index.js +4 -1
- package/dist/mcp.js +2 -3
- package/dist/model.d.ts +7 -47
- package/dist/model.js +1 -7
- package/dist/notifications.d.ts +24 -20
- package/dist/notifications.js +39 -108
- package/dist/operation-control.d.ts +4 -0
- package/dist/operation-control.js +20 -0
- package/dist/packages/agent-delivery/src/claude-native.d.ts +2 -0
- package/dist/packages/agent-delivery/src/claude-native.js +5 -0
- package/dist/packages/agent-delivery/src/codex-boundary.d.ts +11 -6
- package/dist/packages/agent-delivery/src/codex-boundary.js +31 -40
- package/dist/packages/agent-delivery/src/codex-hook.d.ts +17 -12
- package/dist/packages/agent-delivery/src/codex-hook.js +26 -39
- package/dist/packages/agent-delivery/src/codex.d.ts +3 -0
- package/dist/packages/agent-delivery/src/codex.js +41 -4
- package/dist/packages/agent-delivery/src/index.d.ts +3 -1
- package/dist/packages/agent-delivery/src/index.js +1 -1
- package/dist/packages/agent-delivery/src/paseo.js +11 -2
- package/dist/packages/agent-delivery/src/types.d.ts +1 -0
- package/dist/paseo-delivery.d.ts +5 -5
- package/dist/paseo-delivery.js +19 -97
- package/dist/paseo.d.ts +1 -1
- package/dist/paseo.js +1 -1
- package/dist/plugins/opencode/index.d.ts +5 -3
- package/dist/plugins/opencode/index.js +99 -21
- package/dist/plugins/opencode-shared/delivery.d.ts +23 -0
- package/dist/plugins/opencode-shared/delivery.js +109 -0
- package/dist/plugins/opencode-v1/index.d.ts +28 -0
- package/dist/plugins/opencode-v1/index.js +41 -0
- package/dist/plugins/opencode-v1/runtime.d.ts +56 -0
- package/dist/plugins/opencode-v1/runtime.js +152 -0
- package/dist/plugins/opencode-v1/transport.d.ts +13 -0
- package/dist/plugins/opencode-v1/transport.js +50 -0
- package/dist/plugins/paseo/shared/card-presentation.d.ts +10 -0
- package/dist/plugins/paseo/shared/card-presentation.js +7 -0
- package/dist/ports.d.ts +31 -90
- package/dist/session-lifecycle.d.ts +8 -7
- package/dist/session-lifecycle.js +40 -42
- package/dist/sqlite-square.d.ts +14 -23
- package/dist/sqlite-square.js +132 -139
- package/dist/square-api.js +4 -7
- package/dist/square-core.d.ts +0 -1
- package/dist/square-domain.d.ts +5 -17
- package/dist/square-domain.js +104 -221
- package/dist/square-facade.d.ts +18 -15
- package/dist/square-post.d.ts +53 -0
- package/dist/square-post.js +4 -0
- package/dist/square-posting.d.ts +13 -0
- package/dist/square-posting.js +174 -0
- package/dist/square-producer-sqlite.d.ts +11 -0
- package/dist/square-producer-sqlite.js +210 -0
- package/dist/square-sqlite.d.ts +15 -25
- package/dist/square-sqlite.js +150 -226
- package/dist/views.d.ts +2 -2
- package/dist/views.js +0 -1
- package/dist/wake-sink.d.ts +4 -11
- package/dist/wake-sink.js +8 -32
- package/dist/wake-transports.d.ts +4 -7
- package/dist/wake-transports.js +7 -39
- package/examples/symmetric-domains.mjs +29 -249
- package/guides/change-waits.md +13 -53
- package/guides/claude-native.md +7 -171
- package/guides/codex-delivery.md +55 -80
- package/guides/delivery-primitives.md +48 -207
- package/guides/mcp.md +1 -1
- package/guides/operation-cancellation.md +2 -5
- package/guides/participant-ownership.md +25 -89
- package/guides/pi-native-delivery.md +19 -56
- package/guides/pi-tools.md +6 -8
- package/guides/square-api.md +113 -615
- package/package.json +8 -8
- package/plugins/claude/.claude-plugin/plugin.json +2 -3
- package/plugins/claude/hooks/hooks.json +11 -1
- package/plugins/codex/.codex-plugin/plugin.json +1 -1
- package/plugins/codex/hooks/hooks.json +11 -23
- package/plugins/opencode/index.ts +91 -23
- package/plugins/opencode-shared/delivery.ts +91 -0
- package/plugins/opencode-v1/index.ts +36 -0
- package/plugins/opencode-v1/runtime.ts +134 -0
- package/plugins/opencode-v1/transport.ts +41 -0
- package/plugins/paseo/OVERVIEW.md +5 -5
- package/plugins/paseo/README.md +7 -6
- package/plugins/paseo/client/markdown.tsx +5 -5
- package/plugins/paseo/client/square-message.tsx +28 -24
- package/plugins/paseo/client/transform.ts +8 -5
- package/plugins/paseo/shared/card-presentation.ts +16 -0
- package/plugins/paseo/shared/message.ts +6 -11
- package/plugins/pi/square-pi.js +156 -417
- package/dist/channel-artifact.d.ts +0 -10
- package/dist/channel-artifact.js +0 -55
- package/dist/channel-delivery.d.ts +0 -11
- package/dist/channel-delivery.js +0 -51
- package/dist/channel-domain.d.ts +0 -3
- package/dist/channel-domain.js +0 -83
- package/dist/channel-facade.d.ts +0 -76
- package/dist/channel-facade.js +0 -1
- package/dist/channel-internal.d.ts +0 -126
- package/dist/channel-internal.js +0 -440
- package/dist/channel-metadata.d.ts +0 -11
- package/dist/channel-metadata.js +0 -1
- package/dist/channel-ports.d.ts +0 -241
- package/dist/channel-ports.js +0 -1
- package/dist/channel-presentation.d.ts +0 -17
- package/dist/channel-presentation.js +0 -22
- package/dist/channel-sqlite-schema.d.ts +0 -13
- package/dist/channel-sqlite-schema.js +0 -81
- package/dist/channel-transport.d.ts +0 -62
- package/dist/channel-transport.js +0 -1
- package/dist/channel.d.ts +0 -84
- package/dist/channel.js +0 -60
- package/dist/claude-delivery-status.d.ts +0 -13
- package/dist/claude-delivery-status.js +0 -46
- package/dist/claude-delivery.d.ts +0 -12
- package/dist/claude-delivery.js +0 -108
- package/dist/claude-mod.d.ts +0 -8
- package/dist/claude-mod.js +0 -172
- package/dist/claude-transport.d.ts +0 -5
- package/dist/claude-transport.js +0 -58
- package/dist/cmd/notify-once.d.ts +0 -2
- package/dist/cmd/notify-once.js +0 -29
- package/dist/delivery-attempts.d.ts +0 -52
- package/dist/delivery-attempts.js +0 -73
- package/dist/delivery-effects.d.ts +0 -139
- package/dist/delivery-effects.js +0 -163
- package/dist/delivery-health.d.ts +0 -51
- package/dist/delivery-health.js +0 -173
- package/dist/delivery-operations.d.ts +0 -22
- package/dist/delivery-operations.js +0 -198
- package/dist/delivery-primitives.d.ts +0 -5
- package/dist/delivery-primitives.js +0 -3
- package/dist/delivery.d.ts +0 -56
- package/dist/delivery.js +0 -80
- package/dist/plugins/opencode/delivery.d.ts +0 -19
- package/dist/plugins/opencode/delivery.js +0 -223
- package/dist/presentation-operations.d.ts +0 -5
- package/dist/presentation-operations.js +0 -86
- package/dist/sqlite-channel.d.ts +0 -15
- package/dist/sqlite-channel.js +0 -600
- package/dist/square-index.d.ts +0 -16
- package/dist/square-index.js +0 -106
- package/dist/wake-preview.d.ts +0 -7
- package/dist/wake-preview.js +0 -15
- package/plugins/claude/hooks/register.js +0 -132
- package/plugins/claude/types.d.ts +0 -7
- package/plugins/opencode/delivery.ts +0 -198
- /package/dist/{channel-values.d.ts → square-values.d.ts} +0 -0
- /package/dist/{channel-values.js → square-values.js} +0 -0
package/dist/sqlite-square.js
CHANGED
|
@@ -5,9 +5,9 @@ import { squareLocation } from './square-location.js';
|
|
|
5
5
|
import crypto from 'node:crypto';
|
|
6
6
|
import { setTimeout as sleep } from 'node:timers/promises';
|
|
7
7
|
import { InternalSquareError, SquareError, isSquareError, nameKey, validateName } from './model.js';
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
8
|
+
import { checkControl, failure, squareClock } from './operation-control.js';
|
|
9
|
+
import { validateMetadataMatch } from './delivery-deferral.js';
|
|
10
|
+
import { flushSquarePosts, reconcileSquareDelivery, readSquareSessions, ensureInitialDeliverySession } from './square-posting.js';
|
|
11
11
|
import { attentionChange, coreDone, coreListening, decideAct, decideJoin, resolveKnownName, validateDoneBody } from './decisions.js';
|
|
12
12
|
import { WATCH_HEARTBEAT_MS, inSquareCount, presenceAnchor } from './runtime.js';
|
|
13
13
|
import { catchLimit, decideCatch, observeCatchSelection, selectCatchPage } from './catch-decisions.js';
|
|
@@ -16,17 +16,15 @@ import { expressHint } from './hints.js';
|
|
|
16
16
|
import { asSeatRef, participantAuthority, requireJoinName, requireOwner } from './seats.js';
|
|
17
17
|
import { recoveryObservation, entryPresentation, queryStatus, queryParticipants, catchPresence, parseRequiredActivityId, toPublicActivity, toPerceivedActivity, publicActivities, selectHistory, NON_READ, HISTORY_MAX_LIMIT, HISTORY_DEFAULT_LIMIT } from './views.js';
|
|
18
18
|
import { sessionInboxCounts } from './inbox.js';
|
|
19
|
-
import { squareIndexPath } from './square-index.js';
|
|
20
19
|
import { participantIdentity } from './participant-identity.js';
|
|
21
20
|
import { joinRecoveryCommand } from './presentation.js';
|
|
22
21
|
import { acquireWatchLease, ownsWatchLease, pulseWatchLease, releaseWatchLease } from './wakes.js';
|
|
23
|
-
import { squareWakeProjection } from './wake-preview.js';
|
|
24
22
|
import { createArtifactPort, createSquare, diagnoseSquareFile, prepareSquareBuild } from './artifact.js';
|
|
25
23
|
import { activityQueryFilter } from './activity-query.js';
|
|
26
24
|
import { discoverSquares } from './list.js';
|
|
27
25
|
import { streamSquare } from './stream.js';
|
|
28
26
|
export { createSquareResourceOwner } from './artifact.js';
|
|
29
|
-
export { squareClock } from './
|
|
27
|
+
export { squareClock } from './operation-control.js';
|
|
30
28
|
export { formatActivityId, parseActivityId, MAX_IDENTITY_SET_SIZE } from './square-core.js';
|
|
31
29
|
export { CATCH_DEFAULT_LIMIT, CATCH_MAX_LIMIT } from './catch-decisions.js';
|
|
32
30
|
export { HISTORY_DEFAULT_LIMIT, HISTORY_MAX_LIMIT } from './views.js';
|
|
@@ -46,21 +44,20 @@ export class SqliteSquare {
|
|
|
46
44
|
location;
|
|
47
45
|
artifact;
|
|
48
46
|
clock;
|
|
49
|
-
|
|
47
|
+
env;
|
|
48
|
+
closesArtifact;
|
|
50
49
|
deliveryLocation;
|
|
51
|
-
|
|
52
|
-
constructor(location, artifact, clock, wakeTransport, indexPath, closesArtifact = true, deliveryLocation = location) {
|
|
50
|
+
constructor(location, artifact, clock, env, closesArtifact = true, deliveryLocation = location) {
|
|
53
51
|
this.location = location;
|
|
54
52
|
this.artifact = artifact;
|
|
55
53
|
this.clock = clock;
|
|
56
|
-
this.
|
|
54
|
+
this.env = env;
|
|
55
|
+
this.closesArtifact = closesArtifact;
|
|
57
56
|
this.deliveryLocation = deliveryLocation;
|
|
58
|
-
this.channel = Channel.fromPort({ location, artifact: channelArtifact(artifact), clock,
|
|
59
|
-
...(wakeTransport === undefined ? {} : { deliverEffect: message => deliverPending({ artifact: channelArtifact(artifact),
|
|
60
|
-
preparePresentation: squareWakeProjection(artifact), transport: wakeTransport, location: deliveryLocation,
|
|
61
|
-
...(message === undefined ? {} : { message }), now: clock() }) }),
|
|
62
|
-
...(indexPath === undefined ? {} : { indexPath }), closesArtifact });
|
|
63
57
|
}
|
|
58
|
+
reconcile() { return reconcileSquareDelivery(this.artifact, this.deliveryLocation, this.env, this.clock); }
|
|
59
|
+
// Posting is retryable after commit; a delivery failure cannot make a landed write unsent.
|
|
60
|
+
async flush() { await flushSquarePosts(this.artifact, this.deliveryLocation, this.env, this.clock).catch(() => undefined); }
|
|
64
61
|
static async at(input, control) {
|
|
65
62
|
const env = { ...(input.env ?? process.env) }, location = squareLocation({ ...input, env });
|
|
66
63
|
const clock = squareClock(env, input.clock);
|
|
@@ -69,7 +66,7 @@ export class SqliteSquare {
|
|
|
69
66
|
const artifact = borrowed ?? createArtifactPort(location, undefined, control?.signal);
|
|
70
67
|
try {
|
|
71
68
|
await artifact.read(facts => facts.header(), control?.signal);
|
|
72
|
-
return new SqliteSquare(location, artifact, clock,
|
|
69
|
+
return new SqliteSquare(location, artifact, clock, env, borrowed === undefined, await canonicalPath(location));
|
|
73
70
|
}
|
|
74
71
|
catch (error) {
|
|
75
72
|
if (borrowed === undefined)
|
|
@@ -89,18 +86,15 @@ export class SqliteSquare {
|
|
|
89
86
|
}
|
|
90
87
|
static inMemory(input) {
|
|
91
88
|
const env = { ...(input.env ?? process.env) };
|
|
92
|
-
return new SqliteSquare(`memory://${crypto.randomUUID()}`, createArtifactPort(':memory:', prepareSquareBuild(input, input.markdown)), squareClock(env, input.clock),
|
|
89
|
+
return new SqliteSquare(`memory://${crypto.randomUUID()}`, createArtifactPort(':memory:', prepareSquareBuild(input, input.markdown)), squareClock(env, input.clock), env);
|
|
93
90
|
}
|
|
94
|
-
/**
|
|
91
|
+
/** Join establishes membership and local producer custody in one transaction. */
|
|
95
92
|
async joinSeat(name, options, control) {
|
|
96
93
|
checkControl(control);
|
|
97
|
-
const
|
|
98
|
-
if (!Number.isSafeInteger(last) || last < 1 || last > HISTORY_MAX_LIMIT)
|
|
99
|
-
throw new SquareError('invalid_args', 'Join history limit must be between 1 and 100');
|
|
100
|
-
const owner = requireOwner(options?.owner), wakeAddress = options.wakeAddress, now = this.clock();
|
|
94
|
+
const owner = requireOwner(options?.owner), now = this.clock();
|
|
101
95
|
const initial = !options.takeover ? undefined : (await this.artifact.read(facts => facts.participant(name)?.joined ? facts.seat(name) : undefined, control?.signal)).value;
|
|
102
|
-
const authority = initial === undefined ? { kind: 'join', participant: name, owner
|
|
103
|
-
: { kind: 'takeover', participant: initial.participant, owner, expectedGeneration: initial.generation
|
|
96
|
+
const authority = initial === undefined ? { kind: 'join', participant: name, owner }
|
|
97
|
+
: { kind: 'takeover', participant: initial.participant, owner, expectedGeneration: initial.generation };
|
|
104
98
|
const committed = (await this.artifact.transactAs(authority, facts => {
|
|
105
99
|
const participant = facts.participant(name)?.name ?? name;
|
|
106
100
|
const current = facts.participant(participant), currentSeat = facts.seat(participant);
|
|
@@ -114,10 +108,8 @@ export class SqliteSquare {
|
|
|
114
108
|
else if (current?.joined) {
|
|
115
109
|
if (currentSeat === undefined || currentSeat.owner !== owner)
|
|
116
110
|
throw new SquareError('already_joined', `${participantIdentity(participant)} is held by another owner; take it over explicitly`);
|
|
117
|
-
if (currentSeat.attachment
|
|
118
|
-
|
|
119
|
-
else if (wakeAddress !== undefined && (wakeAddress.kind !== 'paseo' || currentSeat.wakeAddress === undefined || currentSeat.wakeAddress.kind === 'paseo'))
|
|
120
|
-
facts.updateWakeAddress(asSeatRef(currentSeat), wakeAddress);
|
|
111
|
+
if (currentSeat.attachment !== 'attached')
|
|
112
|
+
throw new SquareError('already_joined', `${participantIdentity(participant)} is away; resume the host session first`);
|
|
121
113
|
kind = 'reconnected';
|
|
122
114
|
}
|
|
123
115
|
if (kind !== 'reconnected') {
|
|
@@ -128,12 +120,11 @@ export class SqliteSquare {
|
|
|
128
120
|
}
|
|
129
121
|
const seat = facts.seat(participant);
|
|
130
122
|
if (seat === undefined)
|
|
131
|
-
throw new SquareError('invalid_args', 'The join activity did not establish
|
|
123
|
+
throw new SquareError('invalid_args', 'The join activity did not establish participant custody.');
|
|
132
124
|
return { seat, activity, kind,
|
|
133
125
|
...(!options.observe ? {} : { observation: { ...this.observation(inSquareCount(facts), seat.participant, now),
|
|
134
|
-
deliveryAvailable:
|
|
126
|
+
deliveryAvailable: false } }) };
|
|
135
127
|
}, control?.signal)).value;
|
|
136
|
-
await this.channel.remember(owner);
|
|
137
128
|
return committed;
|
|
138
129
|
}
|
|
139
130
|
async requiredSeat(name, { owner }) {
|
|
@@ -143,10 +134,10 @@ export class SqliteSquare {
|
|
|
143
134
|
const participant = facts.participant(name), seat = facts.seat(name);
|
|
144
135
|
if (!participant?.joined || seat === undefined || seat.owner !== owner || seat.attachment !== 'attached') {
|
|
145
136
|
const reason = participant === undefined ? 'has never stepped into this square'
|
|
146
|
-
: !participant.joined ? 'needs
|
|
137
|
+
: !participant.joined ? 'needs to join first'
|
|
147
138
|
: seat !== undefined && seat.owner !== owner ? 'is not held by this owner; join before writing'
|
|
148
|
-
: seat?.attachment === 'detached' ? 'is away
|
|
149
|
-
: 'needs a current
|
|
139
|
+
: seat?.attachment === 'detached' ? 'is away; resume the host session first'
|
|
140
|
+
: 'needs a current participant seat; join first';
|
|
150
141
|
throw new SquareError('already_joined', `${participantIdentity(participant?.name ?? name)} ${reason}`, {
|
|
151
142
|
reason: 'needs_seat', join: joinRecoveryCommand(this.location, participant?.name ?? name),
|
|
152
143
|
});
|
|
@@ -154,53 +145,6 @@ export class SqliteSquare {
|
|
|
154
145
|
return seat;
|
|
155
146
|
})).value;
|
|
156
147
|
}
|
|
157
|
-
async reattachSeat(name, { owner, wakeAddress }, control) {
|
|
158
|
-
checkControl(control);
|
|
159
|
-
validateName(name);
|
|
160
|
-
requireOwner(owner);
|
|
161
|
-
const captured = (await this.artifact.read(facts => facts.seat(name), control?.signal)).value;
|
|
162
|
-
if (captured === undefined || captured.owner !== owner)
|
|
163
|
-
return null;
|
|
164
|
-
const seat = (await this.artifact.transactAs({ kind: 'join', participant: name, owner, wakeAddress }, facts => {
|
|
165
|
-
const current = facts.seat(name);
|
|
166
|
-
if (!facts.participant(name)?.joined || current === undefined || current.generation !== captured.generation || current.owner !== owner)
|
|
167
|
-
return null;
|
|
168
|
-
if (current.attachment === 'detached')
|
|
169
|
-
facts.reattachSeat(asSeatRef(current), wakeAddress);
|
|
170
|
-
else if (wakeAddress !== undefined && (wakeAddress.kind !== 'paseo' || current.wakeAddress === undefined || current.wakeAddress.kind === 'paseo'))
|
|
171
|
-
facts.updateWakeAddress(asSeatRef(current), wakeAddress);
|
|
172
|
-
return facts.seat(name);
|
|
173
|
-
}, control?.signal)).value;
|
|
174
|
-
if (seat !== null)
|
|
175
|
-
await this.channel.remember(owner);
|
|
176
|
-
return seat;
|
|
177
|
-
}
|
|
178
|
-
async endHeldSeat(name, identity) {
|
|
179
|
-
const captured = (await this.artifact.read(facts => {
|
|
180
|
-
const seat = facts.seat(name);
|
|
181
|
-
return seat?.generation === identity.generation && seat.owner === identity.owner ? seat : undefined;
|
|
182
|
-
})).value;
|
|
183
|
-
if (captured === undefined)
|
|
184
|
-
return null;
|
|
185
|
-
return (await this.artifact.transactAs({ kind: 'host-cleanup', seat: captured }, facts => {
|
|
186
|
-
const current = facts.seat(name);
|
|
187
|
-
if (current === undefined || current.generation !== captured.generation || current.owner !== captured.owner)
|
|
188
|
-
return null;
|
|
189
|
-
return { activity: toPublicActivity(facts.land(coreDone(facts, current.participant, '', this.clock()))) };
|
|
190
|
-
})).value;
|
|
191
|
-
}
|
|
192
|
-
async cancelHeld(name, identity) {
|
|
193
|
-
const captured = (await this.artifact.read(facts => {
|
|
194
|
-
const seat = facts.seat(name);
|
|
195
|
-
return seat?.generation === identity.generation && seat.owner === identity.owner ? seat : undefined;
|
|
196
|
-
})).value;
|
|
197
|
-
if (captured === undefined)
|
|
198
|
-
return false;
|
|
199
|
-
return (await this.artifact.transactAs({ kind: 'participant', seat: captured }, facts => {
|
|
200
|
-
const boundary = facts.channel.header().lastMessageIndex;
|
|
201
|
-
return boundary < 0 ? false : facts.channel.cancelThrough(captured, boundary);
|
|
202
|
-
})).value;
|
|
203
|
-
}
|
|
204
148
|
observation(standingCount, participant, now = this.clock()) {
|
|
205
149
|
return { location: this.location, standingCount, now,
|
|
206
150
|
...(participant === undefined ? {} : { participant }) };
|
|
@@ -208,6 +152,28 @@ export class SqliteSquare {
|
|
|
208
152
|
async contextObservation(participant, control) {
|
|
209
153
|
return (await this.artifact.read(facts => this.observation(inSquareCount(facts), participant), control?.signal)).value;
|
|
210
154
|
}
|
|
155
|
+
/** Host liveness is a read-only, non-atomic overlay; it never changes membership. */
|
|
156
|
+
async withHostPresence(select, control) {
|
|
157
|
+
const seats = (await this.artifact.read(facts => facts.roster().filter(person => person.joined)
|
|
158
|
+
.flatMap(person => { const seat = facts.seat(person.name); return seat === undefined ? [] : [seat]; }), control?.signal)).value;
|
|
159
|
+
const sessions = await readSquareSessions(seats, this.env);
|
|
160
|
+
const captured = new Map(seats.map(seat => [nameKey(seat.participant), seat]));
|
|
161
|
+
return (await this.artifact.read(facts => {
|
|
162
|
+
const seat = (name) => {
|
|
163
|
+
const current = facts.seat(name);
|
|
164
|
+
if (current === undefined)
|
|
165
|
+
return undefined;
|
|
166
|
+
const before = captured.get(nameKey(current.participant));
|
|
167
|
+
const attached = before?.owner === current.owner && before.generation === current.generation
|
|
168
|
+
&& sessions.get(current.owner)?.state === 'attached';
|
|
169
|
+
return { ...current, attachment: attached ? 'attached' : 'detached' };
|
|
170
|
+
};
|
|
171
|
+
return select(Object.assign({}, facts, { seat }), name => {
|
|
172
|
+
const current = seat(name);
|
|
173
|
+
return current?.attachment === 'attached' && (sessions.get(current.owner)?.routes.length ?? 0) > 0;
|
|
174
|
+
});
|
|
175
|
+
}, control?.signal)).value;
|
|
176
|
+
}
|
|
211
177
|
handle(seat) { return new SqliteSquare.ParticipantHandle(seat.participant, this, seat); }
|
|
212
178
|
// The nested handle uses its resource's private dependencies without copying
|
|
213
179
|
// them into a second context.
|
|
@@ -215,14 +181,12 @@ export class SqliteSquare {
|
|
|
215
181
|
name;
|
|
216
182
|
owner;
|
|
217
183
|
seat;
|
|
218
|
-
endpoint;
|
|
219
184
|
constructor(name, owner, seat) {
|
|
220
185
|
this.name = name;
|
|
221
186
|
this.owner = owner;
|
|
222
187
|
this.seat = seat;
|
|
223
|
-
this.endpoint = new ChannelEndpoint(owner.channel, seat);
|
|
224
188
|
}
|
|
225
|
-
get generation() { return this.
|
|
189
|
+
get generation() { return this.seat.generation; }
|
|
226
190
|
async express(bodyOrInput, optionsOrControl = {}, operationControl) {
|
|
227
191
|
const square = this.owner;
|
|
228
192
|
const input = typeof bodyOrInput === 'object' && bodyOrInput !== null ? bodyOrInput : undefined;
|
|
@@ -233,12 +197,14 @@ export class SqliteSquare {
|
|
|
233
197
|
let landedId;
|
|
234
198
|
try {
|
|
235
199
|
checkControl(control);
|
|
200
|
+
await square.reconcile();
|
|
236
201
|
name = (await square.artifact.read(facts => resolveKnownName(facts, this.name), control?.signal)).value;
|
|
237
202
|
const seat = this.seat;
|
|
238
203
|
const context = !options.observe ? undefined : (await square.artifact.read(facts => expressionContext(facts, name), control?.signal)).value;
|
|
239
204
|
while (true) {
|
|
240
205
|
checkControl(control);
|
|
241
206
|
try {
|
|
207
|
+
await square.reconcile();
|
|
242
208
|
effect = 'unknown';
|
|
243
209
|
const now = square.clock();
|
|
244
210
|
const reply = rejectUnsentActivity(() => {
|
|
@@ -267,21 +233,17 @@ export class SqliteSquare {
|
|
|
267
233
|
return proposed;
|
|
268
234
|
});
|
|
269
235
|
const stored = facts.land(decision.act);
|
|
270
|
-
|
|
271
|
-
const activity = stored.kind === 'say' ? facts.activities([stored.index])[0] : stored;
|
|
272
|
-
if (activity === undefined)
|
|
273
|
-
throw new SquareError('io', 'The landed activity is missing.');
|
|
274
|
-
return { stored, activity, standingCount: inSquareCount(facts),
|
|
236
|
+
return { stored, standingCount: inSquareCount(facts),
|
|
275
237
|
ownActivityCount: facts.participant(name).sayCount, hardCap: facts.header().hardCap,
|
|
276
238
|
...(decision.unmatchedMentions === undefined ? {} : { unmatchedMentions: decision.unmatchedMentions }),
|
|
277
239
|
...(decision.replyAuthorNotHere === undefined ? {} : { replyAuthorNotHere: decision.replyAuthorNotHere }) };
|
|
278
240
|
}, control?.signal)).value;
|
|
279
241
|
landedId = formatActivityId(committed.stored.index);
|
|
280
242
|
effect = 'landed';
|
|
281
|
-
await square.
|
|
282
|
-
const { stored,
|
|
243
|
+
await square.flush();
|
|
244
|
+
const { stored, standingCount, ownActivityCount, hardCap, ...metadata } = committed;
|
|
283
245
|
const hint = expressHint(ownActivityCount);
|
|
284
|
-
return { activity: toPublicActivity(
|
|
246
|
+
return { activity: toPublicActivity(stored), ...metadata,
|
|
285
247
|
...(hint === undefined ? {} : { hint }), ...(context === undefined ? {} : { observation: {
|
|
286
248
|
...square.observation(standingCount, name, now), ownActivityCount, hardCap, context, participant: name,
|
|
287
249
|
} }) };
|
|
@@ -304,10 +266,11 @@ export class SqliteSquare {
|
|
|
304
266
|
}
|
|
305
267
|
async listener(verb, target, options, control) {
|
|
306
268
|
const square = this.owner;
|
|
307
|
-
const name = (await square.artifact.read(facts => resolveKnownName(facts, this.name), control?.signal)).value;
|
|
308
269
|
checkControl(control);
|
|
270
|
+
await square.reconcile();
|
|
271
|
+
const name = (await square.artifact.read(facts => resolveKnownName(facts, this.name), control?.signal)).value;
|
|
309
272
|
const seat = this.seat, now = square.clock();
|
|
310
|
-
|
|
273
|
+
const result = (await square.artifact.transactAs(participantAuthority(seat), facts => {
|
|
311
274
|
const act = attentionChange(facts, verb, name, target, now);
|
|
312
275
|
const activity = act === undefined ? null : toPublicActivity(facts.land(act));
|
|
313
276
|
return { activity, ...(!options.observe ? {} : { observation: {
|
|
@@ -315,6 +278,8 @@ export class SqliteSquare {
|
|
|
315
278
|
target: activity?.target ?? target,
|
|
316
279
|
} }) };
|
|
317
280
|
}, control?.signal)).value;
|
|
281
|
+
await square.flush();
|
|
282
|
+
return result;
|
|
318
283
|
}
|
|
319
284
|
listen(target, options = {}, control) { return this.listener('listen', target, options, control); }
|
|
320
285
|
ignore(target, options = {}, control) { return this.listener('ignore', target, options, control); }
|
|
@@ -328,6 +293,7 @@ export class SqliteSquare {
|
|
|
328
293
|
}
|
|
329
294
|
/** Receipt selection rechecks the lease inside the writer, not at its last heartbeat. */
|
|
330
295
|
async catchPage(name, seat, options, control, leaseId) {
|
|
296
|
+
await this.owner.reconcile();
|
|
331
297
|
return (await this.owner.artifact.transactAs(participantAuthority(seat), facts => {
|
|
332
298
|
if (leaseId !== undefined && facts.lease(name)?.leaseId !== leaseId)
|
|
333
299
|
return null;
|
|
@@ -346,27 +312,35 @@ export class SqliteSquare {
|
|
|
346
312
|
}, square.clock()))).value;
|
|
347
313
|
if (reason === 'drained')
|
|
348
314
|
reason = view.terminalStatus ?? reason;
|
|
315
|
+
await square.flush();
|
|
349
316
|
if (leaseId !== undefined) {
|
|
350
317
|
await releaseWatchLease(square.artifact, seat, leaseId).catch(() => undefined);
|
|
351
318
|
leaseId = undefined;
|
|
352
319
|
}
|
|
353
|
-
let presence;
|
|
320
|
+
let presence, deliveryAvailable = false;
|
|
354
321
|
if (options.observe) {
|
|
355
322
|
try {
|
|
356
|
-
|
|
323
|
+
const observed = await square.withHostPresence((facts, available) => {
|
|
324
|
+
const data = catchPresence(facts, square.clock());
|
|
325
|
+
return { presence: { ...data, participants: data.participants.map(person => ({ ...person, deliveryAvailable: available(person.name) })) },
|
|
326
|
+
deliveryAvailable: available(view.participant) };
|
|
327
|
+
}, control);
|
|
328
|
+
presence = observed.presence;
|
|
329
|
+
deliveryAvailable = observed.deliveryAvailable;
|
|
357
330
|
}
|
|
358
331
|
catch { /* Optional presence cannot erase the completed selection or receipts. */ }
|
|
359
332
|
}
|
|
360
333
|
return { activities: view.activities, remaining: view.remaining, reason,
|
|
361
334
|
...(view.hint === undefined ? {} : { hint: view.hint }), ...(!options.observe ? {} : { observation: {
|
|
362
335
|
...square.observation(view.standingCount, view.participant, view.now), participant: view.participant,
|
|
363
|
-
deliveryAvailable
|
|
336
|
+
deliveryAvailable,
|
|
364
337
|
ownActivityCount: view.ownActivityCount, hardCap: view.hardCap,
|
|
365
338
|
...(presence === undefined ? { enrichmentUnavailable: true } : { presence }),
|
|
366
339
|
} }) };
|
|
367
340
|
};
|
|
368
341
|
try {
|
|
369
342
|
checkControl(control);
|
|
343
|
+
await square.reconcile();
|
|
370
344
|
validateName(name);
|
|
371
345
|
if (!Number.isFinite(idle) || idle < 0)
|
|
372
346
|
throw new SquareError('invalid_args', 'Catch idle duration must be a non-negative number');
|
|
@@ -441,7 +415,7 @@ export class SqliteSquare {
|
|
|
441
415
|
const limit = options.limit === undefined ? 100 : options.limit;
|
|
442
416
|
if (!Number.isSafeInteger(limit) || limit < 1 || limit > 100)
|
|
443
417
|
throw new SquareError('invalid_args', 'Pending limit must be a positive integer no greater than 100.');
|
|
444
|
-
// Pending follows the shared archive cursor: act/N with before/after
|
|
418
|
+
// Pending follows the shared archive cursor: act/N with before/after.
|
|
445
419
|
const shared = activityQueryFilter(options);
|
|
446
420
|
const filter = { kinds: ['say'], unseenOnly: true,
|
|
447
421
|
...(shared.indexes === undefined ? {} : { indexes: shared.indexes }),
|
|
@@ -457,45 +431,52 @@ export class SqliteSquare {
|
|
|
457
431
|
remaining: facts.directedCount(this.name, filter) - heads.items.length };
|
|
458
432
|
}, control?.signal)).value;
|
|
459
433
|
}
|
|
460
|
-
ack(
|
|
434
|
+
ack(input, control) {
|
|
461
435
|
const square = this.owner;
|
|
436
|
+
checkControl(control);
|
|
462
437
|
return square.artifact.transactAs(participantAuthority(this.seat), facts => {
|
|
438
|
+
if (!Array.isArray(input)) {
|
|
439
|
+
const exact = input;
|
|
440
|
+
if (exact?.future !== 'exact')
|
|
441
|
+
throw new SquareError('invalid_args', 'Ack requires an exact future predicate.');
|
|
442
|
+
validateName(exact.from);
|
|
443
|
+
return { consumed: facts.ackMatching(asSeatRef(this.seat), { from: exact.from, match: validateMetadataMatch(exact.match), future: 'exact' }, square.clock()) };
|
|
444
|
+
}
|
|
463
445
|
const indexes = [];
|
|
464
|
-
for (const id of
|
|
446
|
+
for (const id of input) {
|
|
465
447
|
const activity = facts.activity(parseRequiredActivityId(id));
|
|
466
|
-
if (activity?.kind !== 'say'
|
|
448
|
+
if (activity?.kind !== 'say')
|
|
467
449
|
throw new SquareError('invalid_args', `${id} is not addressed to you.`, { reason: 'not_addressed', activityId: id });
|
|
468
450
|
const head = facts.directed(this.name, { indexes: [activity.index], kinds: ['say'] }, { edge: 'oldest', limit: 1 }).items[0];
|
|
469
451
|
if (head === undefined)
|
|
470
452
|
throw new SquareError('invalid_args', `${id} is not addressed to you.`, { reason: 'not_addressed', activityId: id });
|
|
471
|
-
indexes.push(activity.
|
|
453
|
+
indexes.push(activity.index);
|
|
472
454
|
}
|
|
473
|
-
return { consumed: facts.
|
|
455
|
+
return { consumed: facts.markSeen(this.name, indexes, square.clock()) };
|
|
474
456
|
}, control?.signal).then(result => result.value);
|
|
475
457
|
}
|
|
476
|
-
deferDelivery(input, control) {
|
|
477
|
-
return this.endpoint.deferDelivery(input, control);
|
|
478
|
-
}
|
|
479
|
-
renewDeliveryDeferral(id, durationMs, control) {
|
|
480
|
-
return this.endpoint.renewDeliveryDeferral(id, durationMs, control);
|
|
481
|
-
}
|
|
482
|
-
releaseDeliveryDeferral(id, control) {
|
|
483
|
-
return this.endpoint.releaseDeliveryDeferral(id, control);
|
|
484
|
-
}
|
|
485
458
|
async done(body, options = {}, control) {
|
|
486
459
|
validateDoneBody(body);
|
|
460
|
+
checkControl(control);
|
|
487
461
|
const square = this.owner;
|
|
462
|
+
await square.reconcile();
|
|
488
463
|
const name = (await square.artifact.read(facts => resolveKnownName(facts, this.name), control?.signal)).value;
|
|
489
464
|
const seat = this.seat, now = square.clock();
|
|
490
|
-
|
|
465
|
+
const result = (await square.artifact.transactAs(participantAuthority(seat), facts => {
|
|
491
466
|
const stored = facts.land(coreDone(facts, name, body ?? '', now));
|
|
492
467
|
return { activity: toPublicActivity(stored), ...(!options.observe ? {} : { observation: square.observation(inSquareCount(facts), name, now),
|
|
493
468
|
}) };
|
|
494
469
|
}, control?.signal)).value;
|
|
470
|
+
await square.flush();
|
|
471
|
+
return result;
|
|
495
472
|
}
|
|
496
473
|
};
|
|
497
|
-
send(input, control) {
|
|
498
|
-
|
|
474
|
+
async send(input, control) {
|
|
475
|
+
checkControl(control);
|
|
476
|
+
await this.reconcile();
|
|
477
|
+
const result = (await this.artifact.transactAs({ kind: 'send', actor: input.from }, facts => facts.insertNotice(input, this.clock()), control?.signal)).value;
|
|
478
|
+
await this.flush();
|
|
479
|
+
return result;
|
|
499
480
|
}
|
|
500
481
|
async participant(name, options) {
|
|
501
482
|
return this.handle(await this.requiredSeat(name, options));
|
|
@@ -505,28 +486,36 @@ export class SqliteSquare {
|
|
|
505
486
|
try {
|
|
506
487
|
checkControl(control);
|
|
507
488
|
name = requireJoinName(requested);
|
|
489
|
+
const last = options.last ?? HISTORY_DEFAULT_LIMIT;
|
|
490
|
+
if (!Number.isSafeInteger(last) || last < 1 || last > HISTORY_MAX_LIMIT)
|
|
491
|
+
throw new SquareError('invalid_args', 'Join history limit must be between 1 and 100');
|
|
492
|
+
if (!await ensureInitialDeliverySession(requireOwner(options.owner), this.env, options.wakeAddress))
|
|
493
|
+
throw new SquareError('already_joined', `${participantIdentity(name)} is away; resume the host session first`, { reason: 'needs_seat' });
|
|
494
|
+
await this.reconcile();
|
|
508
495
|
const committed = await this.joinSeat(name, options, control);
|
|
496
|
+
await this.flush();
|
|
509
497
|
const participant = this.handle(committed.seat);
|
|
510
498
|
const result = { participant, activity: committed.activity, kind: committed.kind,
|
|
511
499
|
...(committed.observation === undefined ? {} : { observation: committed.observation }) };
|
|
512
500
|
if (!options.observe)
|
|
513
501
|
return result;
|
|
514
|
-
let entry;
|
|
502
|
+
let entry, deliveryAvailable = false;
|
|
515
503
|
try {
|
|
516
|
-
|
|
504
|
+
const observed = await this.withHostPresence((facts, available) => ({
|
|
505
|
+
entry: entryPresentation(facts, participant.name, options.last ?? HISTORY_DEFAULT_LIMIT),
|
|
506
|
+
deliveryAvailable: available(participant.name),
|
|
507
|
+
}), control);
|
|
508
|
+
entry = observed.entry;
|
|
509
|
+
deliveryAvailable = observed.deliveryAvailable;
|
|
517
510
|
}
|
|
518
511
|
catch { /* Keep the committed join even when optional history is unavailable. */ }
|
|
519
|
-
return { ...result, observation: { ...committed.observation,
|
|
512
|
+
return { ...result, observation: { ...committed.observation, deliveryAvailable,
|
|
520
513
|
...(entry === undefined ? { enrichmentUnavailable: true } : { entry }) } };
|
|
521
514
|
}
|
|
522
515
|
catch (error) {
|
|
523
516
|
throw failure(error, { operation: 'join', subject: 'caller', participant: name });
|
|
524
517
|
}
|
|
525
518
|
}
|
|
526
|
-
async reattach(name, { owner, wakeAddress }, control) {
|
|
527
|
-
const seat = await this.reattachSeat(name, { owner, wakeAddress }, control);
|
|
528
|
-
return seat === null ? null : this.handle(seat);
|
|
529
|
-
}
|
|
530
519
|
async history(query = {}, control) {
|
|
531
520
|
if (query.limit !== undefined && query.limit !== null && (!Number.isSafeInteger(query.limit) || query.limit < 1 || query.limit > HISTORY_MAX_LIMIT))
|
|
532
521
|
throw new SquareError('invalid_args', `History limit must be a positive integer no greater than ${HISTORY_MAX_LIMIT}`);
|
|
@@ -558,12 +547,22 @@ export class SqliteSquare {
|
|
|
558
547
|
}, control?.signal)).value;
|
|
559
548
|
}
|
|
560
549
|
async status(options = {}, control) {
|
|
561
|
-
return
|
|
550
|
+
return this.withHostPresence((facts, available) => {
|
|
551
|
+
const result = queryStatus(facts, { location: this.location, now: this.clock() }, options.viewer, options.observe === true);
|
|
552
|
+
return { ...result, participants: result.participants.map(person => ({ ...person, deliveryAvailable: available(person.name) })) };
|
|
553
|
+
}, control);
|
|
562
554
|
}
|
|
555
|
+
/** Local mode reads only World-known facts; it does not verify host attachment. */
|
|
563
556
|
async participants(options = {}, control) {
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
557
|
+
if (options.local)
|
|
558
|
+
return (await this.artifact.read(facts => {
|
|
559
|
+
const result = queryParticipants(facts, { location: this.location, now: this.clock() }, options.observe === true);
|
|
560
|
+
return { ...result, participants: result.participants.map(person => ({ ...person, deliveryAvailable: false })) };
|
|
561
|
+
}, control?.signal)).value;
|
|
562
|
+
return this.withHostPresence((facts, available) => {
|
|
563
|
+
const result = queryParticipants(facts, { location: this.location, now: this.clock() }, options.observe === true);
|
|
564
|
+
return { ...result, participants: result.participants.map(person => ({ ...person, deliveryAvailable: available(person.name) })) };
|
|
565
|
+
}, control);
|
|
567
566
|
}
|
|
568
567
|
async recovery(requested, control) {
|
|
569
568
|
const facts = requested === undefined ? undefined : (await this.artifact.read(facts => recoveryObservation(facts, requested, this.clock()), control?.signal).catch(() => undefined))?.value;
|
|
@@ -575,18 +574,12 @@ export class SqliteSquare {
|
|
|
575
574
|
return streamSquare(this.location, options, control);
|
|
576
575
|
}
|
|
577
576
|
async seatsOf(owner) {
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
return this.cancelHeld(name, identity);
|
|
583
|
-
}
|
|
584
|
-
detach(name, identity) {
|
|
585
|
-
return this.channel.detach(name, identity);
|
|
586
|
-
}
|
|
587
|
-
endHeld(name, identity) {
|
|
588
|
-
return this.endHeldSeat(name, identity);
|
|
577
|
+
requireOwner(owner);
|
|
578
|
+
return (await this.artifact.read(facts => facts.seatsForOwner(owner)
|
|
579
|
+
.filter(seat => facts.participant(seat.participant)?.joined && seat.attachment === 'attached')
|
|
580
|
+
.map(seat => ({ name: seat.participant, generation: seat.generation })))).value;
|
|
589
581
|
}
|
|
582
|
+
close() { return this.closesArtifact ? this.artifact.close() : Promise.resolve(); }
|
|
590
583
|
}
|
|
591
584
|
export function diagnoseSquare(input, control) { checkControl(control); return diagnoseSquareFile(squareLocation(input)); }
|
|
592
585
|
export function discover(input, options = {}, control) {
|
|
@@ -598,10 +591,10 @@ export function discover(input, options = {}, control) {
|
|
|
598
591
|
export async function inbox(input, owner, options = {}, control) {
|
|
599
592
|
checkControl(control);
|
|
600
593
|
requireOwner(owner);
|
|
601
|
-
const
|
|
594
|
+
const limit = options.limit ?? 20;
|
|
602
595
|
if (!Number.isSafeInteger(limit) || limit < 1 || limit > 100)
|
|
603
596
|
throw new SquareError('invalid_args', 'Inbox limit must be between 1 and 100');
|
|
604
|
-
const rows = await sessionInboxCounts({ owner,
|
|
597
|
+
const rows = await sessionInboxCounts({ owner, cwd: input.cwd }, control?.signal);
|
|
605
598
|
checkControl(control);
|
|
606
599
|
const compare = (left, right) => left < right ? -1 : left > right ? 1 : 0;
|
|
607
600
|
rows.sort((a, b) => compare(a.squarePath, b.squarePath) || compare(nameKey(a.name), nameKey(b.name)) || compare(a.name, b.name));
|
package/dist/square-api.js
CHANGED
|
@@ -1,12 +1,8 @@
|
|
|
1
1
|
import { SqliteSquare } from './sqlite-square.js';
|
|
2
2
|
import { SquareError } from './model.js';
|
|
3
3
|
import { requireOwner } from './seats.js';
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
build: async (input, control) => SqliteSquare.build({ ...input, wakeTransport: await resolveWakeTransport(input) }, control), inMemory: SqliteSquare.inMemory };
|
|
7
|
-
const resolveWakeTransport = (input) => input.wakeTransport !== undefined
|
|
8
|
-
? Promise.resolve(input.wakeTransport)
|
|
9
|
-
: createDefaultWakeTransport(input.env ?? process.env).catch(() => undefined);
|
|
4
|
+
export const Square = { at: (input, control) => SqliteSquare.at(input, control),
|
|
5
|
+
build: (input, control) => SqliteSquare.build(input, control), inMemory: SqliteSquare.inMemory };
|
|
10
6
|
export { requireOwner, requireJoinName } from './seats.js';
|
|
11
7
|
export { squareLocation } from './square-location.js';
|
|
12
8
|
export async function selectOwnSeat(square, owner, name, options) {
|
|
@@ -15,7 +11,8 @@ export async function selectOwnSeat(square, owner, name, options) {
|
|
|
15
11
|
const caller = requireOwner(owner);
|
|
16
12
|
if (name !== undefined)
|
|
17
13
|
return square.participant(name, { owner: caller });
|
|
18
|
-
|
|
14
|
+
// Selection is local producer custody, not a ledger attachment check.
|
|
15
|
+
const seats = await square.seatsOf(caller);
|
|
19
16
|
if (seats.length !== 1) {
|
|
20
17
|
if (options?.optional)
|
|
21
18
|
return undefined;
|
package/dist/square-core.d.ts
CHANGED
package/dist/square-domain.d.ts
CHANGED
|
@@ -1,12 +1,6 @@
|
|
|
1
|
-
import { type ActDraft, type Seat
|
|
2
|
-
import { type EndpointGeneration } from './message.js';
|
|
1
|
+
import { type ActDraft, type Seat } from './model.js';
|
|
3
2
|
import type { ArtifactWriteAuthority, AttentionFact, LandedRecipient, ParticipantFact, SeatRef, SquareRead, SquareWrite } from './ports.js';
|
|
4
|
-
import type {
|
|
5
|
-
import type { WatchLease } from './model.js';
|
|
6
|
-
/** Pending messages the live catch currently owns; the lower pipeline only needs this coverage. */
|
|
7
|
-
export declare function catchCoverage(read: SquareRead, name: string, lease: WatchLease): number[];
|
|
8
|
-
/** Artifact-private landing effect; sender capabilities never expose another recipient's claim. */
|
|
9
|
-
export declare function extendLandingCatchCoverage(read: SquareRead, putClaim: ChannelWrite['putReceiveClaim'], activity: StoredAct, audience: readonly LandedRecipient[]): void;
|
|
3
|
+
import type { ProducerWrite } from './square-post.js';
|
|
10
4
|
export interface LandingEffect {
|
|
11
5
|
readonly activity: ActDraft & {
|
|
12
6
|
readonly index: number;
|
|
@@ -23,29 +17,23 @@ export interface LandingEffect {
|
|
|
23
17
|
export interface LandingFacts {
|
|
24
18
|
readonly actor?: ParticipantFact;
|
|
25
19
|
readonly standing: readonly ParticipantFact[];
|
|
26
|
-
|
|
27
|
-
readonly generations: ReadonlyMap<string, EndpointGeneration>;
|
|
20
|
+
readonly seats: ReadonlyMap<string, Seat>;
|
|
28
21
|
readonly incoming: readonly AttentionFact[];
|
|
29
22
|
readonly outgoing: readonly AttentionFact[];
|
|
30
23
|
readonly replyAuthor?: string;
|
|
31
24
|
}
|
|
32
|
-
/** The single landing transition, shared by both adapters and explicit rebuild. */
|
|
33
25
|
export declare function deriveLanding(activity: ActDraft & {
|
|
34
26
|
readonly index: number;
|
|
35
27
|
}, facts: LandingFacts): LandingEffect;
|
|
36
28
|
export declare function landingFacts(read: SquareRead, activity: ActDraft): LandingFacts;
|
|
37
|
-
export interface LandingWriter extends Pick<SquareWrite, 'putLease' | 'removeLease' | '
|
|
38
|
-
/** Artifact-private endpoint persistence used only by this gate's lifecycle transition. */
|
|
29
|
+
export interface LandingWriter extends Pick<SquareWrite, 'putLease' | 'removeLease' | 'markSeen' | 'setSeatAttachment'>, ProducerWrite {
|
|
39
30
|
storeSeat(seat: Seat): boolean;
|
|
40
|
-
removeSeat(seat:
|
|
31
|
+
removeSeat(seat: SeatRef): boolean;
|
|
41
32
|
applyLanding(effect: LandingEffect): void;
|
|
42
|
-
readonly channel: ChannelWrite;
|
|
43
33
|
}
|
|
44
34
|
export interface SquareWriteGate {
|
|
45
35
|
readonly facts: SquareWrite;
|
|
46
36
|
complete(): void;
|
|
47
37
|
}
|
|
48
|
-
/** Read probes and writes share the same captured-coordinate and attachment fence. */
|
|
49
38
|
export declare function assertCurrentSeat(read: SquareRead, expected: SeatRef, allowDetached?: boolean): void;
|
|
50
|
-
/** The artifact transaction supplies one captured authority; every mutation checks it here. */
|
|
51
39
|
export declare function wrapSquareWrite(read: SquareRead, writes: LandingWriter, authority: ArtifactWriteAuthority): SquareWriteGate;
|