@astrosheep/square 0.3.93 → 0.3.95
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.d.ts +3 -5
- package/dist/activity-feed.js +16 -14
- package/dist/artifact.js +3 -3
- package/dist/attention.d.ts +19 -0
- package/dist/attention.js +30 -0
- package/dist/boundary-presentation.d.ts +2 -2
- package/dist/boundary-presentation.js +33 -40
- package/dist/catch-decisions.d.ts +5 -8
- package/dist/catch-decisions.js +45 -25
- package/dist/claude-delivery-status.js +10 -4
- package/dist/claude-delivery.js +19 -11
- package/dist/claude-mod.js +24 -53
- package/dist/cli/context.d.ts +9 -4
- package/dist/cli/context.js +30 -27
- package/dist/cli/express-presentation.d.ts +3 -1
- package/dist/cli/express-presentation.js +28 -16
- package/dist/cli/json.d.ts +3 -0
- package/dist/cli/json.js +14 -0
- package/dist/cli/mcp-server-command.js +2 -2
- package/dist/cli/observation-commands.d.ts +1 -3
- package/dist/cli/observation-commands.js +43 -56
- package/dist/cli/program.js +3 -3
- package/dist/cli/registry.js +7 -6
- package/dist/cli/square-commands.d.ts +0 -2
- package/dist/cli/square-commands.js +30 -44
- package/dist/codex-hook.d.ts +3 -2
- package/dist/codex-hook.js +13 -4
- package/dist/codex-queue.js +4 -4
- package/dist/decisions.d.ts +5 -16
- package/dist/decisions.js +9 -33
- package/dist/delivery-attempts.d.ts +52 -0
- package/dist/delivery-attempts.js +73 -0
- package/dist/delivery-deferral.js +2 -2
- package/dist/delivery-effects.d.ts +139 -0
- package/dist/delivery-effects.js +163 -0
- package/dist/delivery-health.d.ts +0 -1
- package/dist/delivery-health.js +1 -3
- package/dist/delivery-operations.d.ts +2 -2
- package/dist/delivery-operations.js +76 -101
- 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 +7 -6
- package/dist/help.js +14 -14
- package/dist/http-delivery.d.ts +16 -0
- package/dist/http-delivery.js +101 -0
- package/dist/inbox.d.ts +9 -22
- package/dist/inbox.js +23 -27
- package/dist/index.d.ts +1 -3
- package/dist/index.js +1 -1
- package/dist/mcp.d.ts +3 -0
- package/dist/mcp.js +23 -24
- package/dist/model.d.ts +12 -21
- package/dist/model.js +5 -8
- package/dist/notifications.d.ts +1 -1
- package/dist/notifications.js +8 -5
- package/dist/operation-presentation.d.ts +6 -6
- package/dist/operation-presentation.js +55 -58
- package/dist/owner.d.ts +11 -0
- package/dist/owner.js +32 -0
- package/dist/paseo-delivery.d.ts +4 -1
- package/dist/paseo-delivery.js +7 -12
- package/dist/paseo-state.d.ts +2 -2
- package/dist/paseo-state.js +6 -4
- package/dist/plugins/opencode/delivery.js +27 -15
- package/dist/ports.d.ts +18 -47
- package/dist/presentation-operations.d.ts +14 -19
- package/dist/presentation-operations.js +51 -61
- package/dist/presentation.d.ts +7 -17
- package/dist/presentation.js +46 -91
- package/dist/receive.d.ts +66 -0
- package/dist/receive.js +54 -0
- package/dist/runtime.d.ts +1 -8
- package/dist/runtime.js +2 -17
- package/dist/seats.d.ts +2 -3
- package/dist/seats.js +7 -15
- package/dist/session-lifecycle.d.ts +6 -2
- package/dist/session-lifecycle.js +39 -11
- package/dist/sqlite-square.d.ts +36 -23
- package/dist/sqlite-square.js +162 -211
- package/dist/square-api.d.ts +16 -11
- package/dist/square-api.js +27 -23
- package/dist/square-core.d.ts +0 -14
- package/dist/square-core.js +0 -9
- package/dist/square-domain.d.ts +4 -2
- package/dist/square-domain.js +65 -52
- package/dist/square-facade.d.ts +47 -105
- package/dist/square-index.d.ts +5 -13
- package/dist/square-index.js +13 -38
- package/dist/square-legacy-framing.d.ts +2 -0
- package/dist/square-legacy-framing.js +8 -0
- package/dist/square-location.d.ts +1 -14
- package/dist/square-location.js +4 -70
- package/dist/square-migration-host-ledger.d.ts +2 -2
- package/dist/square-migration-host-ledger.js +6 -5
- package/dist/square-migration.d.ts +4 -1
- package/dist/square-migration.js +93 -38
- package/dist/square-receive.d.ts +6 -0
- package/dist/square-receive.js +18 -0
- package/dist/square-sqlite.d.ts +9 -3
- package/dist/square-sqlite.js +139 -114
- package/dist/square-tools.d.ts +7 -10
- package/dist/square-tools.js +21 -61
- package/dist/stream.js +4 -5
- package/dist/views.d.ts +23 -13
- package/dist/views.js +47 -53
- package/dist/wakes.d.ts +1 -5
- package/dist/wakes.js +4 -6
- package/examples/symmetric-domains.mjs +250 -0
- package/guides/application-facade-delivery-evidence.md +6 -6
- package/guides/attention-primitive.md +32 -0
- package/guides/change-waits.md +2 -2
- package/guides/claude-native.md +18 -9
- package/guides/codex-delivery.md +17 -6
- package/guides/delivery-primitives.md +180 -0
- package/guides/mcp-connection-lifetime.md +1 -1
- package/guides/mcp.md +3 -3
- package/guides/migration.md +148 -151
- package/guides/operation-cancellation.md +1 -1
- package/guides/participant-ownership.md +78 -47
- package/guides/pi-tools.md +34 -5
- 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 +22 -28
- package/guides/square-api.md +314 -91
- package/guides/symmetric-domains.md +92 -0
- package/package.json +14 -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/opencode/delivery.ts +27 -17
- package/plugins/paseo/client/palette.ts +18 -18
- package/plugins/paseo/client/square-message.tsx +17 -23
- package/plugins/pi/square-pi.js +17 -17
- package/skills/square/SKILL.md +2 -6
- package/dist/square-backend.d.ts +0 -13
- package/dist/square-backend.js +0 -1
- package/dist/square-stdio.d.ts +0 -22
- package/dist/square-stdio.js +0 -235
- package/dist/stdio-server.d.ts +0 -3
- package/dist/stdio-server.js +0 -212
- package/guides/backends.md +0 -193
package/dist/square-sqlite.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { DatabaseSync as MemoryDatabase } from 'node:sqlite';
|
|
2
|
-
import {
|
|
2
|
+
import { SquareError, nameKey, isWakeRouteKind, validateOwner, validateActivityMetadata, activityMetadataHasContent } from './model.js';
|
|
3
3
|
import { validateMetadataMatch, matchingDeferrals, validateDeferralId } from './delivery-deferral.js';
|
|
4
4
|
import { deriveLanding, landingFacts } from './square-domain.js';
|
|
5
|
-
import {
|
|
5
|
+
import { claimAttempt, prepareAttempt, settleAttempt } from './delivery-attempts.js';
|
|
6
|
+
import { legacyRowFramingIssue, legacyActivitySchema } from './square-legacy-framing.js';
|
|
7
|
+
import { receive, recordConsumed } from './receive.js';
|
|
6
8
|
export function emptyRuntimeState(nextActIndex = 0) {
|
|
7
9
|
return { nextActIndex, observations: {}, leases: {} };
|
|
8
10
|
}
|
|
@@ -11,7 +13,10 @@ const V1_USER_VERSION = 1;
|
|
|
11
13
|
export const V2_USER_VERSION = 2;
|
|
12
14
|
export const V3_USER_VERSION = 3;
|
|
13
15
|
export const V4_USER_VERSION = 4;
|
|
14
|
-
export const
|
|
16
|
+
export const V5_USER_VERSION = 5;
|
|
17
|
+
export const V6_USER_VERSION = 6;
|
|
18
|
+
export const V7_USER_VERSION = 7;
|
|
19
|
+
export const CURRENT_USER_VERSION = 8;
|
|
15
20
|
export const V1_SNAPSHOT_TABLE = 'square_snapshot';
|
|
16
21
|
const V1_SNAPSHOT_DDL = `CREATE TABLE ${V1_SNAPSHOT_TABLE} (id INTEGER PRIMARY KEY CHECK(id=1), revision INTEGER NOT NULL CHECK(revision>=0), state TEXT NOT NULL)`;
|
|
17
22
|
const V1_SNAPSHOT_COLUMNS = [
|
|
@@ -56,18 +61,16 @@ export function validateLegacyFraming(database, applicationId, location = '') {
|
|
|
56
61
|
function normalizedLegacySql(sql) {
|
|
57
62
|
return sql.trim().replace(/\s+/g, ' ').replace(/\s*(>=|[(),=])\s*/g, '$1');
|
|
58
63
|
}
|
|
59
|
-
const CURRENT_ACTIVITY_KIND_CHECK = "kind IN ('join','done','say','
|
|
64
|
+
const CURRENT_ACTIVITY_KIND_CHECK = "kind IN ('join','done','say','read','listen','ignore','unlisten')";
|
|
60
65
|
export const ACTIVITIES_TABLE_SQL = `CREATE TABLE activities (
|
|
61
66
|
act_index INTEGER PRIMARY KEY CHECK (act_index BETWEEN 0 AND 9007199254740991),
|
|
62
67
|
at REAL NOT NULL,
|
|
63
68
|
kind TEXT NOT NULL CHECK (${CURRENT_ACTIVITY_KIND_CHECK}),
|
|
64
|
-
actor_json TEXT COLLATE BINARY,
|
|
65
|
-
actor_key_json TEXT COLLATE BINARY,
|
|
69
|
+
actor_json TEXT COLLATE BINARY NOT NULL,
|
|
70
|
+
actor_key_json TEXT COLLATE BINARY NOT NULL,
|
|
66
71
|
reach TEXT CHECK (reach = 'bell'),
|
|
67
72
|
reply_index INTEGER CHECK (reply_index >= 0 AND reply_index < act_index),
|
|
68
73
|
payload_json TEXT NOT NULL CHECK (json_valid(payload_json)),
|
|
69
|
-
CHECK ((actor_json IS NULL) = (actor_key_json IS NULL)),
|
|
70
|
-
CHECK (kind IN ('hold','resume') OR actor_json IS NOT NULL),
|
|
71
74
|
CHECK (kind = 'say' OR (reach IS NULL AND reply_index IS NULL))
|
|
72
75
|
);`;
|
|
73
76
|
export const ACTIVITY_INDEXES_SQL = [
|
|
@@ -87,6 +90,7 @@ export const DELIVERY_DEFERRALS_SQL = `CREATE TABLE delivery_deferrals (
|
|
|
87
90
|
PRIMARY KEY (participant_key_json,generation_json,deferral_id_json)
|
|
88
91
|
) WITHOUT ROWID;
|
|
89
92
|
CREATE INDEX delivery_deferral_expiry ON delivery_deferrals(participant_key_json,generation_json,expires_at);`;
|
|
93
|
+
const ATTACHMENT_COLUMN_SQL = "attachment TEXT NOT NULL DEFAULT 'attached' CHECK (attachment IN ('attached','detached'))";
|
|
90
94
|
export const SCHEMA_SQL = `CREATE TABLE square_meta (
|
|
91
95
|
id INTEGER PRIMARY KEY CHECK (id = 1),
|
|
92
96
|
revision INTEGER NOT NULL CHECK (revision BETWEEN 0 AND 9007199254740991),
|
|
@@ -119,13 +123,12 @@ CREATE TABLE catch_leases (
|
|
|
119
123
|
CREATE TABLE seats (
|
|
120
124
|
participant_key_json TEXT COLLATE BINARY PRIMARY KEY NOT NULL,
|
|
121
125
|
participant_json TEXT NOT NULL,
|
|
122
|
-
|
|
123
|
-
session_json TEXT NOT NULL,
|
|
124
|
-
agent_json TEXT,
|
|
126
|
+
owner_json TEXT NOT NULL,
|
|
125
127
|
generation_json TEXT NOT NULL,
|
|
126
|
-
wake_address_json TEXT CHECK (wake_address_json IS NULL OR json_valid(wake_address_json))
|
|
128
|
+
wake_address_json TEXT CHECK (wake_address_json IS NULL OR json_valid(wake_address_json)),
|
|
129
|
+
${ATTACHMENT_COLUMN_SQL}
|
|
127
130
|
) WITHOUT ROWID;
|
|
128
|
-
CREATE INDEX
|
|
131
|
+
CREATE INDEX seat_owner ON seats(owner_json);
|
|
129
132
|
CREATE TABLE delivery_evidence (
|
|
130
133
|
participant_key_json TEXT COLLATE BINARY NOT NULL,
|
|
131
134
|
participant_json TEXT NOT NULL,
|
|
@@ -180,7 +183,13 @@ CREATE TABLE landed_audience (
|
|
|
180
183
|
UNIQUE (act_index, recipient_order)
|
|
181
184
|
) WITHOUT ROWID;
|
|
182
185
|
CREATE INDEX audience_recipient ON landed_audience(recipient_key_json, act_index);`;
|
|
183
|
-
export const
|
|
186
|
+
export const FORMAT7_SCHEMA_SQL = legacyActivitySchema(SCHEMA_SQL);
|
|
187
|
+
export const FORMAT6_SCHEMA_SQL = FORMAT7_SCHEMA_SQL.replace(` owner_json TEXT NOT NULL,\n generation_json TEXT NOT NULL,`, ` channel_json TEXT NOT NULL,\n session_json TEXT NOT NULL,\n agent_json TEXT,\n generation_json TEXT NOT NULL,`).replace('CREATE INDEX seat_owner ON seats(owner_json);', 'CREATE INDEX seat_body ON seats(channel_json, session_json, agent_json);');
|
|
188
|
+
export const FORMAT5_SCHEMA_SQL = FORMAT6_SCHEMA_SQL.replace(`,\n ${ATTACHMENT_COLUMN_SQL}`, '');
|
|
189
|
+
export const FORMAT4_SCHEMA_SQL = FORMAT5_SCHEMA_SQL.replace(DELIVERY_DEFERRALS_SQL, '');
|
|
190
|
+
const FORMAT7_SCHEMA = FORMAT7_SCHEMA_SQL.split(';').map(s => s.trim()).filter(Boolean).map(normalizedSql).sort();
|
|
191
|
+
const FORMAT6_SCHEMA = FORMAT6_SCHEMA_SQL.split(';').map(s => s.trim()).filter(Boolean).map(normalizedSql).sort();
|
|
192
|
+
const FORMAT5_SCHEMA = FORMAT5_SCHEMA_SQL.split(';').map(s => s.trim()).filter(Boolean).map(normalizedSql).sort();
|
|
184
193
|
const EXPECTED_SCHEMA_SQL = SCHEMA_SQL.split(';').map(s => s.trim()).filter(Boolean).map(normalizedSql).sort();
|
|
185
194
|
const FORMAT4_SCHEMA = FORMAT4_SCHEMA_SQL.split(';').map(s => s.trim()).filter(Boolean).map(normalizedSql).sort();
|
|
186
195
|
const encode = JSON.stringify;
|
|
@@ -238,17 +247,17 @@ function immutable(value) {
|
|
|
238
247
|
}
|
|
239
248
|
return value;
|
|
240
249
|
}
|
|
241
|
-
const kinds = ['join', 'done', 'say', '
|
|
250
|
+
const kinds = ['join', 'done', 'say', 'read', 'listen', 'ignore', 'unlisten'];
|
|
242
251
|
function head(row) {
|
|
243
252
|
const index = integer(row.act_index), at = finite(row.at);
|
|
244
253
|
requireFact(kinds.includes(string(row.kind)));
|
|
245
|
-
const actor =
|
|
246
|
-
requireFact(
|
|
254
|
+
const actor = decoded(row.actor_json, true);
|
|
255
|
+
requireFact(row.actor_key_json === key(actor));
|
|
247
256
|
requireFact(row.reach === null || row.kind === 'say' && row.reach === 'bell');
|
|
248
257
|
if (row.reply_index !== null)
|
|
249
258
|
requireFact(row.kind === 'say' && integer(row.reply_index) < index);
|
|
250
259
|
return immutable({
|
|
251
|
-
index, at, kind: row.kind,
|
|
260
|
+
index, at, kind: row.kind, actor, ...(row.reach === null ? {} : { reach: 'bell' }), ...(row.reply_index === null ? {} : { reply: row.reply_index })
|
|
252
261
|
});
|
|
253
262
|
}
|
|
254
263
|
export function validateStoredActivity(value) {
|
|
@@ -256,13 +265,8 @@ export function validateStoredActivity(value) {
|
|
|
256
265
|
integer(a.index);
|
|
257
266
|
finite(a.at);
|
|
258
267
|
requireFact(kinds.includes(string(a.kind)));
|
|
259
|
-
const common = ['kind', 'at', 'index'];
|
|
260
|
-
|
|
261
|
-
common.push('actor');
|
|
262
|
-
string(a.actor, true);
|
|
263
|
-
}
|
|
264
|
-
else if (Object.hasOwn(a, 'actor'))
|
|
265
|
-
string(a.actor, true);
|
|
268
|
+
const common = ['kind', 'at', 'index', 'actor'];
|
|
269
|
+
string(a.actor, true);
|
|
266
270
|
switch (a.kind) {
|
|
267
271
|
case 'say':
|
|
268
272
|
shape(a, [...common], ['body', 'mentions', 'reach', 'reply', 'metadata']);
|
|
@@ -286,8 +290,7 @@ export function validateStoredActivity(value) {
|
|
|
286
290
|
requireFact(integer(a.reply) < a.index);
|
|
287
291
|
break;
|
|
288
292
|
case 'done':
|
|
289
|
-
|
|
290
|
-
shape(a, common, ['body', ...(a.kind === 'hold' ? ['actor'] : [])]);
|
|
293
|
+
shape(a, common, ['body']);
|
|
291
294
|
if (Object.hasOwn(a, 'body'))
|
|
292
295
|
string(a.body);
|
|
293
296
|
break;
|
|
@@ -301,14 +304,14 @@ export function validateStoredActivity(value) {
|
|
|
301
304
|
shape(a, [...common, 'target']);
|
|
302
305
|
string(a.target, true);
|
|
303
306
|
break;
|
|
304
|
-
default: shape(a, common
|
|
307
|
+
default: shape(a, common);
|
|
305
308
|
}
|
|
306
309
|
return value;
|
|
307
310
|
}
|
|
308
311
|
function activity(row) {
|
|
309
312
|
const h = head(row), payload = object(json(row.payload_json));
|
|
310
313
|
// Payload cannot shadow indexed structural columns.
|
|
311
|
-
const allowed = h.kind === 'say' ? ['body', 'mentions', 'metadata'] : h.kind === 'done'
|
|
314
|
+
const allowed = h.kind === 'say' ? ['body', 'mentions', 'metadata'] : h.kind === 'done' ? ['body'] : h.kind === 'read' ? ['through'] : h.kind === 'listen' || h.kind === 'ignore' || h.kind === 'unlisten' ? ['target'] : [];
|
|
312
315
|
requireFact(Object.keys(payload).every(k => allowed.includes(k)));
|
|
313
316
|
return immutable(validateStoredActivity({ ...h, ...payload }));
|
|
314
317
|
}
|
|
@@ -372,17 +375,19 @@ function wakeAddress(value) {
|
|
|
372
375
|
stableJson(entries);
|
|
373
376
|
return immutable({ kind: address.kind, address: entries });
|
|
374
377
|
}
|
|
375
|
-
function
|
|
376
|
-
const
|
|
377
|
-
|
|
378
|
-
return
|
|
378
|
+
function ownerFrom(row) {
|
|
379
|
+
const owner = decoded(row.owner_json, true);
|
|
380
|
+
validateOwner(owner);
|
|
381
|
+
return owner;
|
|
379
382
|
}
|
|
380
383
|
function seat(row) {
|
|
381
384
|
const participant = decoded(row.participant_json, true);
|
|
382
385
|
requireFact(row.participant_key_json === key(participant));
|
|
383
386
|
const generation = activityId(decoded(row.generation_json, true));
|
|
384
387
|
const parsedWake = row.wake_address_json === null ? undefined : wakeAddress(json(row.wake_address_json));
|
|
385
|
-
|
|
388
|
+
requireFact(row.attachment === 'attached' || row.attachment === 'detached', 'seat attachment is malformed.');
|
|
389
|
+
requireFact(row.attachment !== 'detached' || parsedWake === undefined, 'a detached seat has a wake address.');
|
|
390
|
+
return immutable({ participant, owner: ownerFrom(row), generation, attachment: row.attachment, ...(parsedWake === undefined ? {} : { wakeAddress: parsedWake }) });
|
|
386
391
|
}
|
|
387
392
|
function nativeCorrelation(value) {
|
|
388
393
|
const item = shape(value, ['harness'], ['token', 'messageId', 'payloadHash']);
|
|
@@ -395,8 +400,7 @@ function nativeCorrelation(value) {
|
|
|
395
400
|
...(item.messageId === undefined ? {} : { messageId: item.messageId }),
|
|
396
401
|
...(item.payloadHash === undefined ? {} : { payloadHash: item.payloadHash }) });
|
|
397
402
|
}
|
|
398
|
-
function deliveryEvidence(row) {
|
|
399
|
-
const payload = object(json(row.payload_json));
|
|
403
|
+
function deliveryEvidence(row, payload = object(json(row.payload_json))) {
|
|
400
404
|
const participant = decoded(row.participant_json, true);
|
|
401
405
|
requireFact(row.participant_key_json === key(participant));
|
|
402
406
|
const generation = activityId(decoded(row.generation_json, true));
|
|
@@ -453,7 +457,7 @@ export function validateRowFraming(db, version, location = '') {
|
|
|
453
457
|
const identity = db.prepare('SELECT application_id,user_version FROM pragma_application_id,pragma_user_version').get();
|
|
454
458
|
requireFact(identity.application_id === APPLICATION_ID, 'unrelated SQLite database.');
|
|
455
459
|
requireFact(identity.user_version === version, 'unsupported SQLite format version.');
|
|
456
|
-
validateOwnedSchema(db, version === V4_USER_VERSION ? FORMAT4_SCHEMA : EXPECTED_SCHEMA_SQL, location);
|
|
460
|
+
validateOwnedSchema(db, version === V4_USER_VERSION ? FORMAT4_SCHEMA : version === V5_USER_VERSION ? FORMAT5_SCHEMA : version === V6_USER_VERSION ? FORMAT6_SCHEMA : version === V7_USER_VERSION ? FORMAT7_SCHEMA : EXPECTED_SCHEMA_SQL, location);
|
|
457
461
|
}
|
|
458
462
|
export function validateSqliteHeader(db, location = '') {
|
|
459
463
|
const identity = db.prepare('SELECT application_id,user_version FROM pragma_application_id,pragma_user_version').get();
|
|
@@ -462,7 +466,7 @@ export function validateSqliteHeader(db, location = '') {
|
|
|
462
466
|
validateLegacyFraming(db, APPLICATION_ID, location);
|
|
463
467
|
throw new SquareError('invalid_args', `Square artifact at ${location} needs migration.\nStop sessions using it, back it up, then migrate and verify before restarting.`, { reason: 'migration_required' });
|
|
464
468
|
}
|
|
465
|
-
if (identity.user_version === V2_USER_VERSION || identity.user_version === V3_USER_VERSION || identity.user_version === V4_USER_VERSION) {
|
|
469
|
+
if (identity.user_version === V2_USER_VERSION || identity.user_version === V3_USER_VERSION || identity.user_version === V4_USER_VERSION || identity.user_version === V5_USER_VERSION || identity.user_version === V6_USER_VERSION || identity.user_version === V7_USER_VERSION) {
|
|
466
470
|
validateRowFraming(db, identity.user_version, location);
|
|
467
471
|
throw new SquareError('invalid_args', `Square artifact at ${location} needs migration.\nStop sessions using it, back it up, then migrate and verify before restarting.`, { reason: 'migration_required' });
|
|
468
472
|
}
|
|
@@ -486,8 +490,6 @@ function activitySelection(filter, alias = 'a') {
|
|
|
486
490
|
add(`${alias}.act_index <= ?`, integer(filter.throughIndex, -1));
|
|
487
491
|
if (filter.afterAt !== undefined)
|
|
488
492
|
add(`${alias}.at > ?`, finite(filter.afterAt));
|
|
489
|
-
if (filter.actorRequired)
|
|
490
|
-
terms.push(`${alias}.actor_json IS NOT NULL`);
|
|
491
493
|
for (const [column, values] of [['act_index', filter.indexes], ['kind', filter.kinds], [filter.actorMatch === 'exact' ? 'actor_json' : 'actor_key_json', filter.actors?.map(name => filter.actorMatch === 'exact' ? encode(name) : key(name))]]) {
|
|
492
494
|
if (values !== undefined) {
|
|
493
495
|
if (column === 'act_index')
|
|
@@ -532,7 +534,7 @@ export function createSqliteDriver(db) {
|
|
|
532
534
|
}
|
|
533
535
|
function directedHead(row, recipient) {
|
|
534
536
|
const h = head(row);
|
|
535
|
-
requireFact(h.kind === 'say'
|
|
537
|
+
requireFact(h.kind === 'say');
|
|
536
538
|
return immutable({
|
|
537
539
|
index: h.index, at: h.at, actor: h.actor, recipient, route: routeKind(row.route)
|
|
538
540
|
});
|
|
@@ -543,23 +545,22 @@ export function createSqliteDriver(db) {
|
|
|
543
545
|
const latestSeats = `seats s JOIN participants p ON p.name_key_json=s.participant_key_json
|
|
544
546
|
JOIN activities a ON a.act_index=p.last_join_index AND a.kind='join' AND a.actor_key_json=p.name_key_json
|
|
545
547
|
AND s.generation_json='"act/'||a.act_index||'"'`;
|
|
546
|
-
function
|
|
547
|
-
|
|
548
|
-
return immutable(all(`SELECT s.* FROM ${latestSeats} WHERE p
|
|
548
|
+
function ownerSeats(owner) {
|
|
549
|
+
validateOwner(owner);
|
|
550
|
+
return immutable(all(`SELECT s.* FROM ${latestSeats} WHERE p.joined=1 AND s.owner_json=? ORDER BY s.participant_key_json`, [encode(owner)]).map(seat));
|
|
549
551
|
}
|
|
550
552
|
const read = {
|
|
551
553
|
seat(name) {
|
|
552
554
|
const r = one(`SELECT s.* FROM ${latestSeats} WHERE p.joined=1 AND s.participant_key_json=?`, [key(name)]);
|
|
553
555
|
return r ? seat(r) : undefined;
|
|
554
556
|
},
|
|
555
|
-
|
|
556
|
-
completedSeatsForBody: body => bodySeats(body, 'done'),
|
|
557
|
+
seatsForOwner: ownerSeats,
|
|
557
558
|
deliveryEvidence(participant, generation, activityIndex) {
|
|
558
559
|
const args = [key(participant), encode(generation)];
|
|
559
560
|
const filter = activityIndex === undefined ? '' : ' AND act_index=?';
|
|
560
561
|
if (activityIndex !== undefined)
|
|
561
562
|
args.push(integer(Number(activityIndex.slice(4))));
|
|
562
|
-
return immutable(all(`SELECT * FROM delivery_evidence WHERE participant_key_json=? AND generation_json=?${filter} ORDER BY act_index,kind,attempt_n`, args).map(deliveryEvidence));
|
|
563
|
+
return immutable(all(`SELECT * FROM delivery_evidence WHERE participant_key_json=? AND generation_json=?${filter} ORDER BY act_index,kind,attempt_n`, args).map(row => deliveryEvidence(row)));
|
|
563
564
|
},
|
|
564
565
|
deliveryByToken(claimToken) {
|
|
565
566
|
const row = one('SELECT * FROM delivery_evidence WHERE claim_token_json=?', [encode(claimToken)]);
|
|
@@ -589,18 +590,6 @@ export function createSqliteDriver(db) {
|
|
|
589
590
|
roster: () => immutable(all('SELECT * FROM participants ORDER BY first_index').map(participant)),
|
|
590
591
|
attention: name => immutable(attentionRows('t.listener_key_json=?', [key(name)])),
|
|
591
592
|
incomingAttention: name => immutable(attentionRows('t.target_key_json=?', [key(name)])),
|
|
592
|
-
hold() {
|
|
593
|
-
const r = one("SELECT * FROM activities WHERE kind IN ('hold','resume') ORDER BY act_index DESC LIMIT 1");
|
|
594
|
-
if (!r)
|
|
595
|
-
return immutable({ active: false });
|
|
596
|
-
const a = activity(r);
|
|
597
|
-
if (a.kind === 'resume')
|
|
598
|
-
return immutable({ active: false });
|
|
599
|
-
requireFact(a.kind === 'hold');
|
|
600
|
-
return immutable({
|
|
601
|
-
active: true, at: a.at, ...(a.body === undefined ? {} : { reason: a.body }), ...(a.actor === undefined ? {} : { actor: a.actor })
|
|
602
|
-
});
|
|
603
|
-
},
|
|
604
593
|
activity(index) {
|
|
605
594
|
const r = one('SELECT * FROM activities WHERE act_index=?', [integer(index)]);
|
|
606
595
|
return r ? activity(r) : undefined;
|
|
@@ -678,7 +667,7 @@ export function createSqliteDriver(db) {
|
|
|
678
667
|
const groups = indices.map(r => {
|
|
679
668
|
const rows = all(`SELECT a.act_index,a.at,a.kind,a.actor_json,a.actor_key_json,a.reach,a.reply_index,p.name_json,d.route FROM ${pendingFrom} WHERE ${pendingWhere} AND d.act_index=? ORDER BY d.recipient_order`, [integer(r.act_index)]);
|
|
680
669
|
const h = head(rows[0]);
|
|
681
|
-
requireFact(h.kind === 'say'
|
|
670
|
+
requireFact(h.kind === 'say');
|
|
682
671
|
return {
|
|
683
672
|
index: h.index, at: h.at, actor: h.actor, recipients: rows.map(v => ({ recipient: decoded(v.name_json, true), route: routeKind(v.route) }))
|
|
684
673
|
};
|
|
@@ -713,14 +702,14 @@ export function createSqliteDriver(db) {
|
|
|
713
702
|
};
|
|
714
703
|
const writes = {
|
|
715
704
|
storeSeat(value) {
|
|
716
|
-
|
|
705
|
+
validateOwner(value.owner);
|
|
717
706
|
activityId(value.generation);
|
|
718
707
|
string(value.participant, true);
|
|
719
708
|
const existing = read.seat(value.participant);
|
|
720
709
|
if (existing !== undefined && stableJson(existing) === stableJson(value))
|
|
721
710
|
return false;
|
|
722
711
|
const wake = value.wakeAddress === undefined ? null : encode(value.wakeAddress);
|
|
723
|
-
run('INSERT INTO seats(participant_key_json,participant_json,
|
|
712
|
+
run('INSERT INTO seats(participant_key_json,participant_json,owner_json,generation_json,wake_address_json,attachment) VALUES(?,?,?,?,?,?) ON CONFLICT(participant_key_json) DO UPDATE SET participant_json=excluded.participant_json,owner_json=excluded.owner_json,generation_json=excluded.generation_json,wake_address_json=excluded.wake_address_json,attachment=excluded.attachment', [key(value.participant), encode(value.participant), encode(value.owner), encode(value.generation), wake, value.attachment]);
|
|
724
713
|
run('DELETE FROM catch_leases WHERE owner_json=?', [encode(value.participant)]);
|
|
725
714
|
run('DELETE FROM delivery_deferrals WHERE participant_key_json=?', [key(value.participant)]);
|
|
726
715
|
deliveryChanged = true;
|
|
@@ -739,12 +728,28 @@ export function createSqliteDriver(db) {
|
|
|
739
728
|
deliveryChanged = true;
|
|
740
729
|
return count > 0;
|
|
741
730
|
},
|
|
731
|
+
reattachSeat(value, address) {
|
|
732
|
+
const current = read.seat(value.participant);
|
|
733
|
+
if (current?.attachment !== 'detached')
|
|
734
|
+
return false;
|
|
735
|
+
run("UPDATE seats SET attachment='attached',wake_address_json=? WHERE participant_key_json=? AND generation_json=?", [address === undefined ? null : encode(wakeAddress(address)), key(value.participant), encode(value.generation)]);
|
|
736
|
+
deliveryChanged = true;
|
|
737
|
+
return true;
|
|
738
|
+
},
|
|
739
|
+
detachSeat(value) {
|
|
740
|
+
const count = run("UPDATE seats SET attachment='detached',wake_address_json=NULL WHERE participant_key_json=? AND generation_json=? AND attachment='attached'", [key(value.participant), encode(value.generation)]);
|
|
741
|
+
if (!count)
|
|
742
|
+
return false;
|
|
743
|
+
run('DELETE FROM catch_leases WHERE owner_json=?', [encode(value.participant)]);
|
|
744
|
+
run('DELETE FROM delivery_deferrals WHERE participant_key_json=? AND generation_json=?', [key(value.participant), encode(value.generation)]);
|
|
745
|
+
deliveryChanged = true;
|
|
746
|
+
return true;
|
|
747
|
+
},
|
|
742
748
|
removeSeat(value) {
|
|
743
|
-
// Done hides current authority; retain only its latest coordinate for exact-body resume.
|
|
744
749
|
const row = one(`SELECT s.* FROM ${latestSeats} WHERE p.done=1 AND s.participant_key_json=?`, [key(value.participant)]);
|
|
745
|
-
if (row === undefined || decoded(row.generation_json) !== value.generation)
|
|
750
|
+
if (row === undefined || decoded(row.generation_json) !== value.generation || ownerFrom(row) !== value.owner)
|
|
746
751
|
return false;
|
|
747
|
-
run('
|
|
752
|
+
run('DELETE FROM seats WHERE participant_key_json=?', [key(value.participant)]);
|
|
748
753
|
run('DELETE FROM catch_leases WHERE owner_json=?', [encode(value.participant)]);
|
|
749
754
|
run('DELETE FROM delivery_deferrals WHERE participant_key_json=?', [key(value.participant)]);
|
|
750
755
|
changed = true;
|
|
@@ -765,7 +770,10 @@ export function createSqliteDriver(db) {
|
|
|
765
770
|
const a = validateStoredActivity(effect.activity);
|
|
766
771
|
requireFact(a.index >= read.header().nextActIndex && a.index < Number.MAX_SAFE_INTEGER, 'activity index cannot advance.');
|
|
767
772
|
const { index, at, kind, actor, reach, reply, ...payload } = a;
|
|
768
|
-
|
|
773
|
+
receive({
|
|
774
|
+
insertItem: () => { run('INSERT INTO activities(act_index,at,kind,actor_json,actor_key_json,reach,reply_index,payload_json) VALUES(?,?,?,?,?,?,?,?)', [index, at, kind, encode(actor), key(actor), reach ?? null, reply ?? null, encode(payload)]); },
|
|
775
|
+
insertAddress: (item, address, order) => { run('INSERT INTO landed_audience(act_index,recipient_key_json,recipient_order,route) VALUES(?,?,?,?)', [item, key(address.recipient), order, address.via]); },
|
|
776
|
+
}, { item: { key: index, data: a }, audience: effect.audience.map(r => ({ recipient: r.recipient, via: r.route })) });
|
|
769
777
|
if (effect.participant) {
|
|
770
778
|
const p = effect.participant;
|
|
771
779
|
string(p.name, true);
|
|
@@ -794,7 +802,6 @@ export function createSqliteDriver(db) {
|
|
|
794
802
|
requireFact(t.kind === 'listen' || t.kind === 'ignore');
|
|
795
803
|
run('INSERT INTO attention(listener_key_json,target_key_json,target_json,kind,since_index) VALUES(?,?,?,?,?) ON CONFLICT(listener_key_json,target_key_json) DO UPDATE SET target_json=excluded.target_json,kind=excluded.kind,since_index=excluded.since_index', [key(t.listener), key(t.target), encode(t.target), t.kind, t.sinceIndex]);
|
|
796
804
|
}
|
|
797
|
-
effect.audience.forEach((r, order) => run('INSERT INTO landed_audience(act_index,recipient_key_json,recipient_order,route) VALUES(?,?,?,?)', [index, key(r.recipient), order, r.route]));
|
|
798
805
|
run('UPDATE square_meta SET next_act_index=? WHERE id=1', [index + 1]);
|
|
799
806
|
changed = true;
|
|
800
807
|
},
|
|
@@ -802,11 +809,11 @@ export function createSqliteDriver(db) {
|
|
|
802
809
|
finite(at);
|
|
803
810
|
const next = read.header().nextActIndex;
|
|
804
811
|
indexes.forEach(index => requireFact(integer(index) < next, 'receipt references an unassigned activity index.'));
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
812
|
+
const canonical = owner(name);
|
|
813
|
+
string(canonical, true);
|
|
814
|
+
const count = recordConsumed({
|
|
815
|
+
insertReceipt: (ref, time) => run('INSERT OR IGNORE INTO receipts(owner_json,act_index,at) VALUES(?,?,?)', [encode(ref.recipient), ref.item, time]) > 0,
|
|
816
|
+
}, indexes.map(item => ({ recipient: canonical, item })), at);
|
|
810
817
|
if (count)
|
|
811
818
|
changed = true;
|
|
812
819
|
return count;
|
|
@@ -861,6 +868,40 @@ export function createSqliteDriver(db) {
|
|
|
861
868
|
return count > 0;
|
|
862
869
|
},
|
|
863
870
|
};
|
|
871
|
+
function attempt(row) {
|
|
872
|
+
const data = object(json(row.payload_json)), evidence = deliveryEvidence(row, data);
|
|
873
|
+
return { purpose: evidence.kind === 'wake' ? 'dispatch' : 'presentation', token: evidence.claimToken ?? '',
|
|
874
|
+
ordinal: evidence.attemptN, outcome: evidence.outcome, at: evidence.at, expiresAt: evidence.expiresAt, data };
|
|
875
|
+
}
|
|
876
|
+
function attemptRows(seat, index, kind, known) {
|
|
877
|
+
const scope = [key(seat.participant), encode(seat.generation), index, kind];
|
|
878
|
+
let sources = [];
|
|
879
|
+
return {
|
|
880
|
+
list() {
|
|
881
|
+
sources = all('SELECT * FROM delivery_evidence WHERE participant_key_json=? AND generation_json=? AND act_index=? AND kind=? ORDER BY attempt_n DESC', scope);
|
|
882
|
+
return sources.map(attempt);
|
|
883
|
+
},
|
|
884
|
+
evidence(value) {
|
|
885
|
+
const source = sources.find(row => row.attempt_n === value.ordinal);
|
|
886
|
+
return deliveryEvidence({ ...source, outcome: value.outcome, at: value.at, expires_at: value.expiresAt ?? null }, value.data);
|
|
887
|
+
},
|
|
888
|
+
byToken(token) {
|
|
889
|
+
if (known?.token === token)
|
|
890
|
+
return known;
|
|
891
|
+
const row = one('SELECT * FROM delivery_evidence WHERE participant_key_json=? AND generation_json=? AND act_index=? AND kind=? AND claim_token_json=?', [...scope, encode(token)]);
|
|
892
|
+
return row === undefined ? undefined : attempt(row);
|
|
893
|
+
},
|
|
894
|
+
insert(value) {
|
|
895
|
+
run('INSERT INTO delivery_evidence(participant_key_json,participant_json,generation_json,act_index,kind,attempt_n,outcome,at,expires_at,claim_token_json,payload_json) VALUES(?,?,?,?,?,?,?,?,?,?,?)', [scope[0], encode(seat.participant), scope[1], index, kind, value.ordinal, value.outcome, value.at, value.expiresAt ?? null, encode(value.token), encode(value.data)]);
|
|
896
|
+
deliveryChanged = true;
|
|
897
|
+
},
|
|
898
|
+
replace(value) {
|
|
899
|
+
const count = run('UPDATE delivery_evidence SET outcome=?,at=?,expires_at=?,payload_json=? WHERE participant_key_json=? AND generation_json=? AND act_index=? AND kind=? AND attempt_n=? AND claim_token_json IS ?', [value.outcome, value.at, value.expiresAt ?? null, encode(value.data), ...scope, value.ordinal, value.token === '' ? null : encode(value.token)]);
|
|
900
|
+
if (count)
|
|
901
|
+
deliveryChanged = true;
|
|
902
|
+
},
|
|
903
|
+
};
|
|
904
|
+
}
|
|
864
905
|
const delivery = {
|
|
865
906
|
claimDelivery(input) {
|
|
866
907
|
requireFact(input.kind === 'wake' || input.kind === 'presentation');
|
|
@@ -872,7 +913,7 @@ export function createSqliteDriver(db) {
|
|
|
872
913
|
wakeAddress(input.route);
|
|
873
914
|
const currentSeat = read.seat(input.seat.participant);
|
|
874
915
|
const item = read.activity(index);
|
|
875
|
-
if (currentSeat === undefined || currentSeat.generation !== input.seat.generation ||
|
|
916
|
+
if (currentSeat === undefined || currentSeat.attachment !== 'attached' || currentSeat.generation !== input.seat.generation || currentSeat.owner !== input.seat.owner
|
|
876
917
|
|| item?.kind !== 'say' || read.directedAt(input.seat.participant, index) === undefined)
|
|
877
918
|
return { status: 'stale' };
|
|
878
919
|
if (matchingDeferrals(read.deliveryDeferrals(currentSeat.participant, currentSeat.generation), item.metadata, input.at).length > 0)
|
|
@@ -880,42 +921,24 @@ export function createSqliteDriver(db) {
|
|
|
880
921
|
const cancelledThrough = read.cancelledThrough(input.seat.participant, input.seat.generation);
|
|
881
922
|
if (cancelledThrough !== undefined && index <= cancelledThrough)
|
|
882
923
|
return { status: 'stale' };
|
|
883
|
-
const rows =
|
|
884
|
-
const
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
:
|
|
888
|
-
if (
|
|
889
|
-
return { status: '
|
|
890
|
-
const
|
|
891
|
-
|
|
892
|
-
return { status: 'busy', evidence: dispatching };
|
|
893
|
-
if (dispatching !== undefined) {
|
|
894
|
-
const updated = { ...dispatching, outcome: 'unknown', at: input.at, expiresAt: undefined, diagnostic: 'interrupted dispatch' };
|
|
895
|
-
const source = rows.find((row) => row.attempt_n === dispatching.attemptN);
|
|
896
|
-
run('UPDATE delivery_evidence SET outcome=?,at=?,expires_at=NULL,payload_json=? WHERE participant_key_json=? AND generation_json=? AND act_index=? AND kind=? AND attempt_n=?', ['unknown', input.at, encode({ ...object(json(source.payload_json)), diagnostic: 'interrupted dispatch' }), key(input.seat.participant), encode(input.seat.generation), index, input.kind, dispatching.attemptN]);
|
|
897
|
-
deliveryChanged = true;
|
|
898
|
-
return { status: 'terminal', evidence: updated };
|
|
899
|
-
}
|
|
900
|
-
const attemptN = (decoded[0]?.attemptN ?? -1) + 1;
|
|
901
|
-
const payload = input.route === undefined ? {} : { route: input.route };
|
|
902
|
-
const expiry = finite(input.at + leaseMs);
|
|
903
|
-
run('INSERT INTO delivery_evidence(participant_key_json,participant_json,generation_json,act_index,kind,attempt_n,outcome,at,expires_at,claim_token_json,payload_json) VALUES(?,?,?,?,?,?,?,?,?,?,?)', [key(input.seat.participant), encode(input.seat.participant), encode(input.seat.generation), index, input.kind, attemptN, 'dispatching', input.at, expiry, encode(input.claimToken), encode(payload)]);
|
|
904
|
-
deliveryChanged = true;
|
|
905
|
-
return { status: 'acquired', claimToken: input.claimToken, attemptN };
|
|
924
|
+
const rows = attemptRows(input.seat, index, input.kind);
|
|
925
|
+
const result = claimAttempt({ ...rows, replace(value) {
|
|
926
|
+
rows.replace({ ...value, data: { ...value.data, diagnostic: 'interrupted dispatch' } });
|
|
927
|
+
} }, { purpose: input.kind === 'wake' ? 'dispatch' : 'presentation', token: input.claimToken,
|
|
928
|
+
at: input.at, leaseMs, data: input.route === undefined ? {} : { route: input.route } });
|
|
929
|
+
if (result.status === 'acquired')
|
|
930
|
+
return { status: 'acquired', claimToken: result.token, attemptN: result.ordinal };
|
|
931
|
+
const evidence = result.interrupted ? { ...result.evidence, data: { ...result.evidence.data, diagnostic: 'interrupted dispatch' } } : result.evidence;
|
|
932
|
+
return { status: result.status, evidence: rows.evidence(evidence) };
|
|
906
933
|
},
|
|
907
934
|
prepareDelivery(input) {
|
|
908
935
|
const row = one('SELECT * FROM delivery_evidence WHERE participant_key_json=? AND generation_json=? AND claim_token_json=?', [key(input.seat.participant), encode(input.seat.generation), encode(input.claimToken)]);
|
|
909
936
|
if (row === undefined || row.outcome !== 'dispatching')
|
|
910
937
|
return false;
|
|
911
|
-
const correlation = nativeCorrelation(input.correlation);
|
|
912
|
-
const payload = object(json(row.payload_json));
|
|
938
|
+
const previous = attempt(row), correlation = nativeCorrelation(input.correlation), payload = previous.data;
|
|
913
939
|
if (stableJson(payload.correlation ?? null) === stableJson(correlation))
|
|
914
940
|
return true;
|
|
915
|
-
|
|
916
|
-
if (count)
|
|
917
|
-
deliveryChanged = true;
|
|
918
|
-
return count > 0;
|
|
941
|
+
return prepareAttempt(attemptRows(input.seat, integer(row.act_index), row.kind, previous), { token: input.claimToken, data: { ...payload, correlation } });
|
|
919
942
|
},
|
|
920
943
|
completeDelivery(input) {
|
|
921
944
|
const index = activityIndex(input.activity);
|
|
@@ -925,16 +948,9 @@ export function createSqliteDriver(db) {
|
|
|
925
948
|
const row = one('SELECT * FROM delivery_evidence WHERE participant_key_json=? AND generation_json=? AND act_index=? AND claim_token_json=?', [key(input.seat.participant), encode(input.seat.generation), index, encode(input.claimToken)]);
|
|
926
949
|
if (row === undefined)
|
|
927
950
|
return false;
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
return false;
|
|
932
|
-
const previous = object(json(row.payload_json));
|
|
933
|
-
const payload = { ...previous, ...(input.signature === undefined ? {} : { signature: input.signature }), ...(input.message === undefined ? {} : { message: input.message }), ...(input.diagnostic === undefined ? {} : { diagnostic: input.diagnostic }), ...(input.correlation === undefined ? {} : { correlation: input.correlation }) };
|
|
934
|
-
const count = run('UPDATE delivery_evidence SET outcome=?,at=?,expires_at=NULL,payload_json=? WHERE participant_key_json=? AND generation_json=? AND act_index=? AND claim_token_json=?', [input.outcome, input.at, encode(payload), key(input.seat.participant), encode(input.seat.generation), index, encode(input.claimToken)]);
|
|
935
|
-
if (count)
|
|
936
|
-
deliveryChanged = true;
|
|
937
|
-
return count > 0;
|
|
951
|
+
const previous = attempt(row);
|
|
952
|
+
const payload = { ...previous.data, ...(input.signature === undefined ? {} : { signature: input.signature }), ...(input.message === undefined ? {} : { message: input.message }), ...(input.diagnostic === undefined ? {} : { diagnostic: input.diagnostic }), ...(input.correlation === undefined ? {} : { correlation: input.correlation }) };
|
|
953
|
+
return settleAttempt(attemptRows(input.seat, index, row.kind, previous), { token: input.claimToken, outcome: input.outcome, at: input.at, data: payload });
|
|
938
954
|
},
|
|
939
955
|
observeNativeDelivery(input) {
|
|
940
956
|
const row = one('SELECT * FROM delivery_evidence WHERE participant_key_json=? AND generation_json=? AND claim_token_json=?', [key(input.seat.participant), encode(input.seat.generation), encode(input.claimToken)]);
|
|
@@ -1023,15 +1039,18 @@ export function exportSqliteState(db) {
|
|
|
1023
1039
|
}
|
|
1024
1040
|
/** Full read-only integrity inspection, including maintained-index replay comparison. */
|
|
1025
1041
|
export function inspectSqlite(db) {
|
|
1042
|
+
return inspectRows(db, seat);
|
|
1043
|
+
}
|
|
1044
|
+
function inspectRows(db, inspectSeat) {
|
|
1026
1045
|
const check = db.prepare('PRAGMA integrity_check').all();
|
|
1027
1046
|
requireFact(check.length === 1 && check[0].integrity_check === 'ok', 'SQLite integrity check failed.');
|
|
1028
1047
|
const state = exportSqliteState(db), d = createSqliteDriver(db);
|
|
1029
1048
|
d.roster();
|
|
1030
1049
|
for (const row of db.prepare('SELECT * FROM seats').all())
|
|
1031
|
-
|
|
1050
|
+
inspectSeat(row);
|
|
1032
1051
|
for (const row of db.prepare('SELECT * FROM delivery_evidence').all())
|
|
1033
1052
|
deliveryEvidence(row);
|
|
1034
|
-
if (db.prepare('PRAGMA user_version').get().user_version
|
|
1053
|
+
if (Number(db.prepare('PRAGMA user_version').get().user_version) >= V5_USER_VERSION) {
|
|
1035
1054
|
for (const row of db.prepare('SELECT * FROM delivery_deferrals').all())
|
|
1036
1055
|
deliveryDeferral(row);
|
|
1037
1056
|
}
|
|
@@ -1045,6 +1064,12 @@ export function inspectSqlite(db) {
|
|
|
1045
1064
|
const rebuilt = new MemoryDatabase(':memory:');
|
|
1046
1065
|
try {
|
|
1047
1066
|
initializeSqlite(rebuilt, state, d.header().revision);
|
|
1067
|
+
// A migration may remove the activity that established canonical casing.
|
|
1068
|
+
// Retained participant spelling stays authoritative while replay checks
|
|
1069
|
+
// every derived lifecycle/count fact against surviving activities.
|
|
1070
|
+
const retainName = rebuilt.prepare('UPDATE participants SET name_json=? WHERE name_key_json=?');
|
|
1071
|
+
for (const p of d.roster())
|
|
1072
|
+
retainName.run(encode(p.name), key(p.name));
|
|
1048
1073
|
for (const table of ['participants', 'attention', 'landed_audience']) {
|
|
1049
1074
|
const original = db.prepare(`SELECT * FROM ${table} ORDER BY 1,2`).all();
|
|
1050
1075
|
const expected = rebuilt.prepare(`SELECT * FROM ${table} ORDER BY 1,2`).all();
|
package/dist/square-tools.d.ts
CHANGED
|
@@ -1,20 +1,17 @@
|
|
|
1
1
|
import { z } from 'zod/v4';
|
|
2
2
|
import { type Square } from './square-api.js';
|
|
3
|
-
import type { OperationControl } from './square-facade.js';
|
|
3
|
+
import type { Owner, WakeAddress, OperationControl } from './square-facade.js';
|
|
4
|
+
export interface ToolIdentity {
|
|
5
|
+
readonly owner?: Owner;
|
|
6
|
+
readonly wakeAddress?: WakeAddress;
|
|
7
|
+
}
|
|
4
8
|
type JsonObject = Record<string, unknown>;
|
|
5
|
-
type Outcome = Promise<object>;
|
|
6
|
-
type ToolRender = (result: JsonObject, args: JsonObject) => string | undefined;
|
|
7
9
|
interface ToolDefinition {
|
|
8
10
|
name: string;
|
|
9
11
|
description: string;
|
|
10
12
|
inputSchema: z.ZodObject<z.ZodRawShape>;
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
render: ToolRender;
|
|
14
|
-
}
|
|
15
|
-
/** A transport that shows people the square asks the same operation for its rendering facts. */
|
|
16
|
-
export interface ToolControl extends OperationControl {
|
|
17
|
-
readonly observe?: boolean;
|
|
13
|
+
/** Human text identical to what the CLI prints; domain receipts stay inside the adapter. */
|
|
14
|
+
run(square: Square, args: JsonObject, control: OperationControl, identity: ToolIdentity): Promise<string>;
|
|
18
15
|
}
|
|
19
16
|
export declare const SQUARE_TOOL_INSTRUCTIONS = "Join once. Then express to speak, and catch to take in what reached you. History looks back without taking anything in.";
|
|
20
17
|
export declare const SQUARE_TOOLS: readonly ToolDefinition[];
|