@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
package/dist/activity-feed.js
CHANGED
|
@@ -3,7 +3,7 @@ const CONTEXT_LIMIT = 5;
|
|
|
3
3
|
const PREVIEW_CHARS = 400;
|
|
4
4
|
/** A bounded, nonconsuming glimpse; seen rows beyond a cursor hole must not reappear. */
|
|
5
5
|
export function expressionContext(facts, name) {
|
|
6
|
-
const filter = { afterIndex: facts.participant(name)?.lastJoinIndex ?? -1, unseenOnly: true };
|
|
6
|
+
const filter = { kinds: ['say'], afterIndex: facts.participant(name)?.lastJoinIndex ?? -1, unseenOnly: true };
|
|
7
7
|
const page = facts.directed(name, filter, { edge: 'newest', limit: CONTEXT_LIMIT });
|
|
8
8
|
const activities = facts.activities(page.items.map(head => head.index)).filter(act => act.kind === 'say')
|
|
9
9
|
.sort((a, b) => a.index - b.index).map(act => {
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { DatabaseSync } from 'node:sqlite';
|
|
2
|
+
export interface StoreFormat {
|
|
3
|
+
readonly applicationId: number;
|
|
4
|
+
readonly userVersion: number;
|
|
5
|
+
readonly validate: (db: DatabaseSync, location: string) => void;
|
|
6
|
+
readonly reset: (db: DatabaseSync) => void;
|
|
7
|
+
readonly observerKey: string;
|
|
8
|
+
}
|
|
9
|
+
export type StoreInitializer = (db: DatabaseSync) => void;
|
|
10
|
+
export type StoreChanges = {
|
|
11
|
+
readonly changed: boolean;
|
|
12
|
+
readonly deliveryChanged: boolean;
|
|
13
|
+
};
|
|
14
|
+
export interface StoreTransaction {
|
|
15
|
+
readonly db: DatabaseSync;
|
|
16
|
+
guard<F extends (...args: never[]) => unknown>(fn: F): F;
|
|
17
|
+
track(changes: StoreChanges): void;
|
|
18
|
+
}
|
|
19
|
+
export declare function requireSquareExtension(location: string): void;
|
|
20
|
+
export declare function storageError(error: unknown, location: string): unknown;
|
|
21
|
+
/** Private storage opening; never creates a missing file. */
|
|
22
|
+
export declare function openExistingSquareDatabase(location: string): DatabaseSync;
|
|
23
|
+
export declare function abort(signal?: AbortSignal): void;
|
|
24
|
+
/** One ordered connection and transaction lifetime, shared by Channel and Agora compositions. */
|
|
25
|
+
export declare function createArtifactStore(location: string, format: StoreFormat, initialize?: StoreInitializer, externalSignal?: AbortSignal): {
|
|
26
|
+
run<R>(write: boolean, callback: (tx: StoreTransaction) => R, signal?: AbortSignal, settlement?: boolean): Promise<{
|
|
27
|
+
value: R;
|
|
28
|
+
version: number;
|
|
29
|
+
changed: boolean;
|
|
30
|
+
deliveryChanged: boolean;
|
|
31
|
+
}>;
|
|
32
|
+
revision: (signal?: AbortSignal, delivery?: boolean) => Promise<number>;
|
|
33
|
+
deliveryRevision: (signal?: AbortSignal) => Promise<number>;
|
|
34
|
+
changed(since: number, timeout: number, signal?: AbortSignal): Promise<boolean>;
|
|
35
|
+
close(): Promise<void>;
|
|
36
|
+
};
|
|
37
|
+
export declare function inspectStore<R>(location: string, format: StoreFormat, select: (db: DatabaseSync) => R, signal?: AbortSignal): Promise<R>;
|
|
38
|
+
export declare function observeStoreRevision(location: string, format: StoreFormat, delivery?: boolean): Promise<import("./file-changes.js").VersionObserver<number | null>>;
|
|
39
|
+
/** Atomic publication and explicit replacement share the same closed physical schema. */
|
|
40
|
+
export declare function createStoreFile(location: string, format: StoreFormat, initialize: StoreInitializer, signal?: AbortSignal): Promise<boolean>;
|
|
41
|
+
export declare function replaceStoreFile(location: string, format: StoreFormat, initialize: (db: DatabaseSync, revision: number) => void, signal?: AbortSignal): Promise<void>;
|
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
import { DatabaseSync } from 'node:sqlite';
|
|
2
|
+
import { randomUUID } from 'node:crypto';
|
|
3
|
+
import fs from 'node:fs';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { pathToFileURL } from 'node:url';
|
|
6
|
+
import { setTimeout as sleep } from 'node:timers/promises';
|
|
7
|
+
import { canonicalPath } from './canonical-path.js';
|
|
8
|
+
import { observeFileVersion } from './file-changes.js';
|
|
9
|
+
import { retrySqliteBusy, inSqliteTransaction } from './sqlite-transaction.js';
|
|
10
|
+
import { InternalSquareError, SquareError } from './neutral.js';
|
|
11
|
+
import { readStorageRevision } from './sqlite-framing.js';
|
|
12
|
+
import { invalidArtifact } from './sqlite-values.js';
|
|
13
|
+
export function requireSquareExtension(location) {
|
|
14
|
+
if (!location.endsWith('.square'))
|
|
15
|
+
throw new SquareError('invalid_args', `Square artifacts must use the .square extension: ${location}`);
|
|
16
|
+
}
|
|
17
|
+
export function storageError(error, location) {
|
|
18
|
+
if (!(error instanceof Error) || error instanceof SquareError || error instanceof InternalSquareError)
|
|
19
|
+
return error;
|
|
20
|
+
if (/unable to open database file|no such file|SQLITE_CANTOPEN/i.test(error.message))
|
|
21
|
+
return new InternalSquareError('not_found', `square file not found: ${location}`);
|
|
22
|
+
if (/not a database|SQLITE_NOTADB/i.test(error.message))
|
|
23
|
+
return invalidArtifact('not a SQLite database.');
|
|
24
|
+
return error;
|
|
25
|
+
}
|
|
26
|
+
/** Private storage opening; never creates a missing file. */
|
|
27
|
+
export function openExistingSquareDatabase(location) {
|
|
28
|
+
requireSquareExtension(location);
|
|
29
|
+
const uri = pathToFileURL(path.resolve(location));
|
|
30
|
+
uri.searchParams.set('mode', 'rw');
|
|
31
|
+
try {
|
|
32
|
+
return new DatabaseSync(uri.href);
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
throw storageError(error, location);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
export function abort(signal) {
|
|
39
|
+
if (signal?.aborted)
|
|
40
|
+
throw signal.reason ?? new Error('Square artifact operation aborted');
|
|
41
|
+
}
|
|
42
|
+
function synchronous(value) {
|
|
43
|
+
if (value !== null && (typeof value === 'object' || typeof value === 'function') && typeof value.then === 'function') {
|
|
44
|
+
void Promise.resolve(value).catch(() => undefined);
|
|
45
|
+
throw new TypeError('Square artifact callbacks must be synchronous.');
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
/** One ordered connection and transaction lifetime, shared by Channel and Agora compositions. */
|
|
49
|
+
export function createArtifactStore(location, format, initialize, externalSignal) {
|
|
50
|
+
let database, closed = false, inCallback = false;
|
|
51
|
+
let tail = Promise.resolve();
|
|
52
|
+
const cancel = new AbortController();
|
|
53
|
+
const canonical = initialize === undefined ? canonicalPath(location) : Promise.resolve(location);
|
|
54
|
+
if (initialize) {
|
|
55
|
+
database = new DatabaseSync(':memory:');
|
|
56
|
+
try {
|
|
57
|
+
initialize(database);
|
|
58
|
+
database.exec(`PRAGMA application_id=${format.applicationId}; PRAGMA user_version=${format.userVersion}`);
|
|
59
|
+
}
|
|
60
|
+
catch (error) {
|
|
61
|
+
database.close();
|
|
62
|
+
throw error;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
const combined = (signal) => AbortSignal.any([cancel.signal, ...(externalSignal ? [externalSignal] : []), ...(signal ? [signal] : [])]);
|
|
66
|
+
const validate = (db) => { format.validate(db, initialize ? ':memory:' : location); return readStorageRevision(db); };
|
|
67
|
+
async function connection(signal) {
|
|
68
|
+
if (database)
|
|
69
|
+
return database;
|
|
70
|
+
location = await canonical;
|
|
71
|
+
abort(signal);
|
|
72
|
+
database = openExistingSquareDatabase(location);
|
|
73
|
+
try {
|
|
74
|
+
await retrySqliteBusy(() => validate(database), signal);
|
|
75
|
+
database.exec('PRAGMA busy_timeout=0; PRAGMA synchronous=FULL');
|
|
76
|
+
}
|
|
77
|
+
catch (error) {
|
|
78
|
+
database.close();
|
|
79
|
+
database = undefined;
|
|
80
|
+
throw storageError(error, location);
|
|
81
|
+
}
|
|
82
|
+
return database;
|
|
83
|
+
}
|
|
84
|
+
function queue(operation, signal) {
|
|
85
|
+
if (inCallback)
|
|
86
|
+
throw new TypeError('Square artifact operations cannot nest inside a callback.');
|
|
87
|
+
if (closed)
|
|
88
|
+
return Promise.reject(new Error('Square artifact is closed'));
|
|
89
|
+
const result = tail.then(() => { abort(signal); return operation(signal); });
|
|
90
|
+
tail = result.then(() => undefined, () => undefined);
|
|
91
|
+
return result;
|
|
92
|
+
}
|
|
93
|
+
function transaction(write, callback, signal) {
|
|
94
|
+
return connection(signal).then(db => inSqliteTransaction(db, write, () => validate(db), version => {
|
|
95
|
+
const changes = [];
|
|
96
|
+
let active = true, failed = false, failure;
|
|
97
|
+
const guard = fn => ((...args) => {
|
|
98
|
+
if (!active)
|
|
99
|
+
throw new Error('Square artifact transaction capability expired');
|
|
100
|
+
abort(signal);
|
|
101
|
+
if (failed)
|
|
102
|
+
throw failure;
|
|
103
|
+
try {
|
|
104
|
+
return fn(...args);
|
|
105
|
+
}
|
|
106
|
+
catch (error) {
|
|
107
|
+
failed = true;
|
|
108
|
+
failure = storageError(error, location);
|
|
109
|
+
throw failure;
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
let value;
|
|
113
|
+
inCallback = true;
|
|
114
|
+
try {
|
|
115
|
+
value = callback({ db, guard, track: item => changes.push(item) });
|
|
116
|
+
synchronous(value);
|
|
117
|
+
}
|
|
118
|
+
finally {
|
|
119
|
+
inCallback = false;
|
|
120
|
+
active = false;
|
|
121
|
+
}
|
|
122
|
+
if (failed)
|
|
123
|
+
throw failure;
|
|
124
|
+
const changed = write && changes.some(item => item.changed), deliveryChanged = write && changes.some(item => item.deliveryChanged);
|
|
125
|
+
if (changed || deliveryChanged) {
|
|
126
|
+
if ((changed && version === Number.MAX_SAFE_INTEGER) || (deliveryChanged && readStorageRevision(db, true) === Number.MAX_SAFE_INTEGER))
|
|
127
|
+
throw invalidArtifact('revision cannot advance beyond the safe integer limit.');
|
|
128
|
+
db.prepare('UPDATE storage_meta SET revision=revision+?, delivery_revision=delivery_revision+? WHERE id=1').run(Number(changed), Number(deliveryChanged));
|
|
129
|
+
}
|
|
130
|
+
return { value, version: version + Number(changed), changed, deliveryChanged };
|
|
131
|
+
}, signal));
|
|
132
|
+
}
|
|
133
|
+
const revision = (signal, delivery = false) => queue(async (s) => {
|
|
134
|
+
const db = await connection(s);
|
|
135
|
+
return inSqliteTransaction(db, false, () => validate(db), () => readStorageRevision(db, delivery), s);
|
|
136
|
+
}, combined(signal));
|
|
137
|
+
return {
|
|
138
|
+
run(write, callback, signal, settlement = false) {
|
|
139
|
+
return queue(s => transaction(write, callback, s), settlement
|
|
140
|
+
? AbortSignal.any([cancel.signal, AbortSignal.timeout(5000)]) : combined(signal));
|
|
141
|
+
},
|
|
142
|
+
revision,
|
|
143
|
+
deliveryRevision: (signal) => revision(signal, true),
|
|
144
|
+
async changed(since, timeout, signal) {
|
|
145
|
+
if (inCallback)
|
|
146
|
+
throw new TypeError('Square artifact operations cannot nest inside a callback.');
|
|
147
|
+
if (closed)
|
|
148
|
+
return false;
|
|
149
|
+
const s = combined(signal), deadline = Date.now() + Math.max(0, timeout);
|
|
150
|
+
if (initialize) {
|
|
151
|
+
try {
|
|
152
|
+
do {
|
|
153
|
+
if (await revision(s) > since)
|
|
154
|
+
return true;
|
|
155
|
+
if (Date.now() >= deadline)
|
|
156
|
+
return false;
|
|
157
|
+
await sleep(Math.min(25, deadline - Date.now()), undefined, { signal: s });
|
|
158
|
+
} while (!closed);
|
|
159
|
+
}
|
|
160
|
+
catch (error) {
|
|
161
|
+
if (closed)
|
|
162
|
+
return false;
|
|
163
|
+
abort(s);
|
|
164
|
+
throw error;
|
|
165
|
+
}
|
|
166
|
+
return false;
|
|
167
|
+
}
|
|
168
|
+
const observer = await observeStoreRevision(await canonical, format);
|
|
169
|
+
try {
|
|
170
|
+
return await observer.changed(since, Math.max(0, deadline - Date.now()), s);
|
|
171
|
+
}
|
|
172
|
+
catch (error) {
|
|
173
|
+
if (closed)
|
|
174
|
+
return false;
|
|
175
|
+
abort(s);
|
|
176
|
+
throw error;
|
|
177
|
+
}
|
|
178
|
+
finally {
|
|
179
|
+
observer.close();
|
|
180
|
+
}
|
|
181
|
+
},
|
|
182
|
+
async close() {
|
|
183
|
+
if (inCallback)
|
|
184
|
+
throw new TypeError('Square artifact cannot close inside a callback.');
|
|
185
|
+
if (!closed) {
|
|
186
|
+
closed = true;
|
|
187
|
+
cancel.abort(new Error('Square artifact is closed'));
|
|
188
|
+
}
|
|
189
|
+
await tail;
|
|
190
|
+
database?.close();
|
|
191
|
+
database = undefined;
|
|
192
|
+
},
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
export async function inspectStore(location, format, select, signal) {
|
|
196
|
+
const db = openExistingSquareDatabase(location);
|
|
197
|
+
return inSqliteTransaction(db, false, () => format.validate(db, location), () => select(db), signal)
|
|
198
|
+
.catch(error => { throw storageError(error, location); }).finally(() => db.close());
|
|
199
|
+
}
|
|
200
|
+
export function observeStoreRevision(location, format, delivery = false) {
|
|
201
|
+
return observeFileVersion(location, `${format.observerKey}-${delivery ? 'delivery-revision' : 'revision'}`, async (file, signal) => {
|
|
202
|
+
try {
|
|
203
|
+
return await inspectStore(file, format, db => readStorageRevision(db, delivery), signal);
|
|
204
|
+
}
|
|
205
|
+
catch (error) {
|
|
206
|
+
abort(signal);
|
|
207
|
+
if (error instanceof InternalSquareError && error.code === 'not_found')
|
|
208
|
+
return null;
|
|
209
|
+
throw error;
|
|
210
|
+
}
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
/** Atomic publication and explicit replacement share the same closed physical schema. */
|
|
214
|
+
export async function createStoreFile(location, format, initialize, signal) {
|
|
215
|
+
abort(signal);
|
|
216
|
+
location = await canonicalPath(location);
|
|
217
|
+
requireSquareExtension(location);
|
|
218
|
+
await fs.promises.mkdir(path.dirname(location), { recursive: true });
|
|
219
|
+
const temporary = path.join(path.dirname(location), `.${path.basename(location)}.${process.pid}.${randomUUID()}.tmp`);
|
|
220
|
+
const handle = await fs.promises.open(temporary, 'wx');
|
|
221
|
+
await handle.close();
|
|
222
|
+
try {
|
|
223
|
+
const db = new DatabaseSync(temporary);
|
|
224
|
+
try {
|
|
225
|
+
db.exec('PRAGMA journal_mode=DELETE; PRAGMA synchronous=FULL');
|
|
226
|
+
await inSqliteTransaction(db, true, () => { }, () => { initialize(db); db.exec(`PRAGMA application_id=${format.applicationId}; PRAGMA user_version=${format.userVersion}`); }, signal);
|
|
227
|
+
}
|
|
228
|
+
finally {
|
|
229
|
+
db.close();
|
|
230
|
+
}
|
|
231
|
+
const flush = await fs.promises.open(temporary, 'r+');
|
|
232
|
+
try {
|
|
233
|
+
await flush.sync();
|
|
234
|
+
}
|
|
235
|
+
finally {
|
|
236
|
+
await flush.close();
|
|
237
|
+
}
|
|
238
|
+
abort(signal);
|
|
239
|
+
try {
|
|
240
|
+
await fs.promises.link(temporary, location);
|
|
241
|
+
return true;
|
|
242
|
+
}
|
|
243
|
+
catch (error) {
|
|
244
|
+
if (error.code === 'EEXIST')
|
|
245
|
+
return false;
|
|
246
|
+
throw error;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
finally {
|
|
250
|
+
await fs.promises.unlink(temporary).catch(() => undefined);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
export async function replaceStoreFile(location, format, initialize, signal) {
|
|
254
|
+
if (await createStoreFile(location, format, db => initialize(db, 0), signal))
|
|
255
|
+
return;
|
|
256
|
+
abort(signal);
|
|
257
|
+
const db = openExistingSquareDatabase(await canonicalPath(location));
|
|
258
|
+
try {
|
|
259
|
+
await retrySqliteBusy(() => format.validate(db, location), signal);
|
|
260
|
+
db.exec('PRAGMA busy_timeout=0; PRAGMA synchronous=FULL');
|
|
261
|
+
await inSqliteTransaction(db, true, () => format.validate(db, location), () => {
|
|
262
|
+
const revision = readStorageRevision(db);
|
|
263
|
+
if (revision === Number.MAX_SAFE_INTEGER)
|
|
264
|
+
throw invalidArtifact('revision cannot advance beyond the safe integer limit.');
|
|
265
|
+
format.reset(db);
|
|
266
|
+
initialize(db, revision + 1);
|
|
267
|
+
}, signal);
|
|
268
|
+
}
|
|
269
|
+
finally {
|
|
270
|
+
db.close();
|
|
271
|
+
}
|
|
272
|
+
}
|
package/dist/artifact.d.ts
CHANGED
|
@@ -1,21 +1,22 @@
|
|
|
1
|
-
import { DatabaseSync } from 'node:sqlite';
|
|
2
1
|
import { type BuildOptions } from './model.js';
|
|
3
2
|
import type { SquareResourceOwner, SquareArtifactPort } from './ports.js';
|
|
4
3
|
import { type SquareState } from './square-sqlite.js';
|
|
4
|
+
import type { ChannelArtifact } from './channel-ports.js';
|
|
5
|
+
export { openExistingSquareDatabase } from './artifact-store.js';
|
|
6
|
+
export declare function channelArtifact(port: SquareArtifactPort): ChannelArtifact;
|
|
5
7
|
/** Explicit-lifetime holder of one reused artifact connection. Request cancellation
|
|
6
8
|
* never becomes the shared connection's lifetime; close drains the owner once. */
|
|
7
9
|
export declare function createSquareResourceOwner(): SquareResourceOwner;
|
|
8
10
|
/** All build paths share configuration validation and lazy guide preparation. */
|
|
9
|
-
export declare function prepareSquareBuild(options: Omit<BuildOptions, 'force'>, snippet: string): SquareState;
|
|
11
|
+
export declare function prepareSquareBuild(options: Omit<BuildOptions, 'force'>, snippet: string, includeGuides?: boolean): SquareState;
|
|
10
12
|
/** File build owns publication and CLI conflict semantics, not host resources. */
|
|
11
|
-
export declare function createSquare(location: string, options: BuildOptions, snippet: string, signal?: AbortSignal): Promise<Pick<SquareState, 'hardCap' | 'throttlePerMinute'>>;
|
|
13
|
+
export declare function createSquare(location: string, options: BuildOptions, snippet: string, signal?: AbortSignal, includeGuides?: boolean): Promise<Pick<SquareState, 'hardCap' | 'throttlePerMinute'>>;
|
|
12
14
|
export interface DoctorProblem {
|
|
13
15
|
kind: string;
|
|
14
16
|
message: string;
|
|
15
17
|
}
|
|
16
18
|
export interface DiagnoseResult {
|
|
17
19
|
unfixable?: string;
|
|
18
|
-
migrationRequired?: string;
|
|
19
20
|
problems: DoctorProblem[];
|
|
20
21
|
standingCount?: number;
|
|
21
22
|
}
|
|
@@ -23,18 +24,13 @@ export interface SquareSnapshot {
|
|
|
23
24
|
readonly state: SquareState;
|
|
24
25
|
readonly revision: number;
|
|
25
26
|
}
|
|
26
|
-
/**
|
|
27
|
-
export declare function openExistingSquareDatabase(location: string): DatabaseSync;
|
|
28
|
-
/** One connection, ordered operations, guarded synchronous transaction capabilities. */
|
|
27
|
+
/** Agora composition over the same lower SQL and ordered store used by standalone Channel. */
|
|
29
28
|
export declare function createArtifactPort(location: string, initial?: SquareState, externalSignal?: AbortSignal): SquareArtifactPort;
|
|
30
|
-
/** New-format creation; initial authority is accepted only at this explicit boundary. */
|
|
31
29
|
export declare function createSquareFile(location: string, state: SquareState, signal?: AbortSignal): Promise<boolean>;
|
|
32
|
-
/** Explicit build --force / fixture import, never a runtime state-replacement callback. */
|
|
33
30
|
export declare function writeSquareFile(location: string, state: SquareState, signal?: AbortSignal): Promise<void>;
|
|
34
|
-
/** Explicit test/export projection. Hot callers must use the typed port. */
|
|
35
31
|
export declare function readSquareSnapshot(location: string, signal?: AbortSignal): Promise<SquareSnapshot>;
|
|
36
32
|
export declare function readSquareRevision(location: string, signal?: AbortSignal): Promise<number>;
|
|
37
33
|
export declare function readSquareDeliveryRevision(location: string, signal?: AbortSignal): Promise<number>;
|
|
38
|
-
export declare
|
|
39
|
-
export declare
|
|
34
|
+
export declare const observeSquareRevision: (location: string) => Promise<import("./file-changes.js").VersionObserver<number | null>>;
|
|
35
|
+
export declare const observeSquareDeliveryRevision: (location: string) => Promise<import("./file-changes.js").VersionObserver<number | null>>;
|
|
40
36
|
export declare function diagnoseSquareFile(location: string): Promise<DiagnoseResult>;
|