@4xeoz/re-entry 0.2.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/README.md +337 -0
- package/node_modules/@webmcp-challenge/reentry-core/README.md +112 -0
- package/node_modules/@webmcp-challenge/reentry-core/package.json +38 -0
- package/node_modules/@webmcp-challenge/reentry-core/protocol/test-vectors/v0.1.json +47 -0
- package/node_modules/@webmcp-challenge/reentry-core/src/agent-adapter.mjs +438 -0
- package/node_modules/@webmcp-challenge/reentry-core/src/cloud-receiver-http.mjs +268 -0
- package/node_modules/@webmcp-challenge/reentry-core/src/host-sdk.mjs +278 -0
- package/node_modules/@webmcp-challenge/reentry-core/src/index.mjs +3 -0
- package/node_modules/@webmcp-challenge/reentry-core/src/local-connector-client.mjs +530 -0
- package/node_modules/@webmcp-challenge/reentry-core/src/managed-context-adapter.mjs +275 -0
- package/node_modules/@webmcp-challenge/reentry-core/src/protocol.mjs +845 -0
- package/node_modules/@webmcp-challenge/reentry-core/src/receiver-core.mjs +867 -0
- package/node_modules/@webmcp-challenge/reentry-core/src/receiver-delivery.mjs +613 -0
- package/node_modules/@webmcp-challenge/reentry-core/src/receiver-http-contract.mjs +24 -0
- package/node_modules/@webmcp-challenge/reentry-core/src/receiver-support.mjs +151 -0
- package/node_modules/@webmcp-challenge/reentry-core/src/sqlite-receiver-schema.mjs +184 -0
- package/node_modules/@webmcp-challenge/reentry-core/src/sqlite-receiver-store.mjs +573 -0
- package/package.json +44 -0
- package/src/browser-prompt.mjs +18 -0
- package/src/codex-discovery.mjs +246 -0
- package/src/codex-exec-adapter.mjs +197 -0
- package/src/codex-queue-adapter.mjs +214 -0
- package/src/credentials.mjs +87 -0
- package/src/index.mjs +6 -0
- package/src/local-connector.mjs +82 -0
- package/src/macos-service.mjs +184 -0
- package/src/main.mjs +733 -0
- package/src/pairing-client.mjs +545 -0
- package/src/terminal-ui.mjs +99 -0
|
@@ -0,0 +1,573 @@
|
|
|
1
|
+
import { DatabaseSync } from "node:sqlite";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
DELIVERY_DETAIL_SELECT,
|
|
5
|
+
DELIVERY_STATE_SCHEMA_SQL,
|
|
6
|
+
SCHEMA_SQL,
|
|
7
|
+
SCHEMA_VERSION,
|
|
8
|
+
} from "./sqlite-receiver-schema.mjs";
|
|
9
|
+
|
|
10
|
+
const STORE_OPTION_FIELDS = Object.freeze(["filename"]);
|
|
11
|
+
|
|
12
|
+
export class SqliteReceiverStore {
|
|
13
|
+
#database;
|
|
14
|
+
#statements;
|
|
15
|
+
#closed = false;
|
|
16
|
+
#inTransaction = false;
|
|
17
|
+
|
|
18
|
+
constructor(options) {
|
|
19
|
+
requireStoreOptions(options);
|
|
20
|
+
const filename = requireFilename(options.filename);
|
|
21
|
+
this.#database = new DatabaseSync(filename);
|
|
22
|
+
try {
|
|
23
|
+
this.#configure(filename === ":memory:");
|
|
24
|
+
this.#initializeSchema();
|
|
25
|
+
this.#statements = this.#prepareStatements();
|
|
26
|
+
} catch (error) {
|
|
27
|
+
this.#database.close();
|
|
28
|
+
this.#closed = true;
|
|
29
|
+
throw error;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
transaction(callback) {
|
|
34
|
+
this.#assertOpen();
|
|
35
|
+
if (typeof callback !== "function") {
|
|
36
|
+
throw new TypeError("SQLite Receiver transaction callback must be a function");
|
|
37
|
+
}
|
|
38
|
+
if (this.#inTransaction) {
|
|
39
|
+
throw new Error("Nested SQLite Receiver transactions are not supported");
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
this.#database.exec("BEGIN IMMEDIATE");
|
|
43
|
+
this.#inTransaction = true;
|
|
44
|
+
try {
|
|
45
|
+
const result = callback(this);
|
|
46
|
+
if (result && typeof result.then === "function") {
|
|
47
|
+
throw new TypeError("SQLite Receiver transaction callback must be synchronous");
|
|
48
|
+
}
|
|
49
|
+
this.#database.exec("COMMIT");
|
|
50
|
+
return result;
|
|
51
|
+
} catch (error) {
|
|
52
|
+
try {
|
|
53
|
+
this.#database.exec("ROLLBACK");
|
|
54
|
+
} catch (rollbackError) {
|
|
55
|
+
throw new AggregateError(
|
|
56
|
+
[error, rollbackError],
|
|
57
|
+
"SQLite Receiver transaction and rollback both failed",
|
|
58
|
+
{ cause: error },
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
throw error;
|
|
62
|
+
} finally {
|
|
63
|
+
this.#inTransaction = false;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
getChallengeByManifestId(manifestId) {
|
|
68
|
+
this.#assertOpen();
|
|
69
|
+
return plainRow(this.#statements.challengeByManifestId.get(manifestId));
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
getChallengeById(challengeId) {
|
|
73
|
+
this.#assertOpen();
|
|
74
|
+
return plainRow(this.#statements.challengeById.get(challengeId));
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
insertChallenge(challenge) {
|
|
78
|
+
this.#assertWriteTransaction();
|
|
79
|
+
const result = this.#statements.insertChallenge.run(
|
|
80
|
+
challenge.challenge_id,
|
|
81
|
+
challenge.manifest_id,
|
|
82
|
+
challenge.manifest_json,
|
|
83
|
+
challenge.expected_origin,
|
|
84
|
+
challenge.effective_expires_at,
|
|
85
|
+
challenge.status,
|
|
86
|
+
challenge.decision_id,
|
|
87
|
+
challenge.decision_action,
|
|
88
|
+
challenge.subject_id,
|
|
89
|
+
challenge.created_at,
|
|
90
|
+
challenge.decided_at,
|
|
91
|
+
);
|
|
92
|
+
assertSingleChange(result, "insert challenge");
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
setChallengeDecision(decision) {
|
|
96
|
+
this.#assertWriteTransaction();
|
|
97
|
+
const result = this.#statements.setChallengeDecision.run(
|
|
98
|
+
decision.status,
|
|
99
|
+
decision.decision_id,
|
|
100
|
+
decision.decision_action,
|
|
101
|
+
decision.subject_id,
|
|
102
|
+
decision.decided_at,
|
|
103
|
+
decision.challenge_id,
|
|
104
|
+
);
|
|
105
|
+
return result.changes === 1;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
getGrantByChallengeId(challengeId) {
|
|
109
|
+
this.#assertOpen();
|
|
110
|
+
return plainRow(this.#statements.grantByChallengeId.get(challengeId));
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
getGrantByBindingId(bindingId) {
|
|
114
|
+
this.#assertOpen();
|
|
115
|
+
return plainRow(this.#statements.grantByBindingId.get(bindingId));
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
insertGrant(grant) {
|
|
119
|
+
this.#assertWriteTransaction();
|
|
120
|
+
const result = this.#statements.insertGrant.run(
|
|
121
|
+
grant.grant_id,
|
|
122
|
+
grant.challenge_id,
|
|
123
|
+
grant.manifest_id,
|
|
124
|
+
grant.binding_id,
|
|
125
|
+
grant.subject_id,
|
|
126
|
+
grant.delivery_target_id,
|
|
127
|
+
grant.correlation_id,
|
|
128
|
+
grant.issuer_origin,
|
|
129
|
+
grant.workflow_type,
|
|
130
|
+
grant.workflow_id,
|
|
131
|
+
grant.event_type,
|
|
132
|
+
grant.canonical_url,
|
|
133
|
+
grant.expires_at,
|
|
134
|
+
grant.human_boundary,
|
|
135
|
+
grant.runs_remaining,
|
|
136
|
+
grant.revoked_at,
|
|
137
|
+
grant.receipt_json,
|
|
138
|
+
grant.created_at,
|
|
139
|
+
);
|
|
140
|
+
assertSingleChange(result, "insert Grant");
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
revokeGrant(grantId, revokedAt) {
|
|
144
|
+
this.#assertWriteTransaction();
|
|
145
|
+
const result = this.#statements.revokeGrant.run(revokedAt, grantId);
|
|
146
|
+
return result.changes === 1;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
consumeGrantRun(grantId) {
|
|
150
|
+
this.#assertWriteTransaction();
|
|
151
|
+
const result = this.#statements.consumeGrantRun.run(grantId);
|
|
152
|
+
return result.changes === 1;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
getEventById(eventId) {
|
|
156
|
+
this.#assertOpen();
|
|
157
|
+
return plainRow(this.#statements.eventById.get(eventId));
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
insertEvent(event) {
|
|
161
|
+
this.#assertWriteTransaction();
|
|
162
|
+
const result = this.#statements.insertEvent.run(
|
|
163
|
+
event.event_id,
|
|
164
|
+
event.grant_id,
|
|
165
|
+
event.canonical_body,
|
|
166
|
+
event.acceptance_json,
|
|
167
|
+
event.received_at,
|
|
168
|
+
);
|
|
169
|
+
assertSingleChange(result, "insert event");
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
insertDelivery(delivery) {
|
|
173
|
+
this.#assertWriteTransaction();
|
|
174
|
+
const result = this.#statements.insertDelivery.run(
|
|
175
|
+
delivery.delivery_id,
|
|
176
|
+
delivery.event_id,
|
|
177
|
+
delivery.grant_id,
|
|
178
|
+
delivery.delivery_target_id,
|
|
179
|
+
delivery.status,
|
|
180
|
+
delivery.created_at,
|
|
181
|
+
);
|
|
182
|
+
assertSingleChange(result, "insert delivery");
|
|
183
|
+
const state = this.#statements.insertDeliveryState.run(
|
|
184
|
+
delivery.delivery_id,
|
|
185
|
+
delivery.status,
|
|
186
|
+
delivery.maximum_attempts,
|
|
187
|
+
delivery.created_at,
|
|
188
|
+
);
|
|
189
|
+
assertSingleChange(state, "insert delivery state");
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
getDeliveryByEventId(eventId) {
|
|
193
|
+
this.#assertOpen();
|
|
194
|
+
return plainRow(this.#statements.deliveryByEventId.get(eventId));
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
getDeliveryById(deliveryId) {
|
|
198
|
+
this.#assertOpen();
|
|
199
|
+
return plainRow(this.#statements.deliveryById.get(deliveryId));
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
getDeliveryByEffectId(effectId) {
|
|
203
|
+
this.#assertOpen();
|
|
204
|
+
return plainRow(this.#statements.deliveryByEffectId.get(effectId));
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
getDeliveryByCurrentLeaseTokenDigest(leaseTokenDigest) {
|
|
208
|
+
this.#assertOpen();
|
|
209
|
+
return plainRow(this.#statements.deliveryByCurrentLeaseTokenDigest.get(leaseTokenDigest));
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
hasDeliveryAttemptTokenDigest(leaseTokenDigest) {
|
|
213
|
+
this.#assertOpen();
|
|
214
|
+
return this.#statements.hasDeliveryAttemptTokenDigest.get(leaseTokenDigest) !== undefined;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
getActiveDeliveryByTarget(deliveryTargetId, now) {
|
|
218
|
+
this.#assertOpen();
|
|
219
|
+
return plainRow(this.#statements.activeDeliveryByTarget.get(deliveryTargetId, now));
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
getNextDeliveryByTarget(deliveryTargetId, now) {
|
|
223
|
+
this.#assertOpen();
|
|
224
|
+
return plainRow(this.#statements.nextDeliveryByTarget.get(deliveryTargetId, now));
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
claimDelivery(claim) {
|
|
228
|
+
this.#assertWriteTransaction();
|
|
229
|
+
const result = this.#statements.claimDelivery.run(
|
|
230
|
+
claim.attempt,
|
|
231
|
+
claim.connector_id,
|
|
232
|
+
claim.lease_token_digest,
|
|
233
|
+
claim.leased_at,
|
|
234
|
+
claim.lease_expires_at,
|
|
235
|
+
claim.updated_at,
|
|
236
|
+
claim.delivery_id,
|
|
237
|
+
claim.expected_status,
|
|
238
|
+
claim.expected_attempt,
|
|
239
|
+
claim.expected_connector_id,
|
|
240
|
+
claim.expected_lease_token_digest,
|
|
241
|
+
claim.expected_lease_expires_at,
|
|
242
|
+
);
|
|
243
|
+
if (result.changes !== 1) return false;
|
|
244
|
+
const attempt = this.#statements.insertDeliveryAttempt.run(
|
|
245
|
+
claim.delivery_id,
|
|
246
|
+
claim.attempt,
|
|
247
|
+
claim.connector_id,
|
|
248
|
+
claim.lease_token_digest,
|
|
249
|
+
claim.leased_at,
|
|
250
|
+
claim.lease_expires_at,
|
|
251
|
+
);
|
|
252
|
+
assertSingleChange(attempt, "insert delivery attempt");
|
|
253
|
+
return true;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
cancelDelivery(transition) {
|
|
257
|
+
this.#assertWriteTransaction();
|
|
258
|
+
const result = this.#statements.cancelDelivery.run(
|
|
259
|
+
transition.reason,
|
|
260
|
+
transition.updated_at,
|
|
261
|
+
transition.delivery_id,
|
|
262
|
+
);
|
|
263
|
+
return result.changes === 1;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
exhaustDelivery(transition) {
|
|
267
|
+
this.#assertWriteTransaction();
|
|
268
|
+
const result = this.#statements.exhaustDelivery.run(
|
|
269
|
+
transition.reason,
|
|
270
|
+
transition.updated_at,
|
|
271
|
+
transition.delivery_id,
|
|
272
|
+
transition.expected_attempt,
|
|
273
|
+
transition.expected_connector_id,
|
|
274
|
+
transition.expected_lease_token_digest,
|
|
275
|
+
transition.expected_lease_expires_at,
|
|
276
|
+
);
|
|
277
|
+
return result.changes === 1;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
acknowledgeDelivery(acknowledgement) {
|
|
281
|
+
this.#assertWriteTransaction();
|
|
282
|
+
const result = this.#statements.acknowledgeDelivery.run(
|
|
283
|
+
acknowledgement.effect_id,
|
|
284
|
+
acknowledgement.effect_attestation_json,
|
|
285
|
+
acknowledgement.acknowledged_at,
|
|
286
|
+
acknowledgement.updated_at,
|
|
287
|
+
acknowledgement.delivery_id,
|
|
288
|
+
acknowledgement.expected_status,
|
|
289
|
+
acknowledgement.expected_attempt,
|
|
290
|
+
acknowledgement.expected_connector_id,
|
|
291
|
+
acknowledgement.expected_lease_token_digest,
|
|
292
|
+
acknowledgement.expected_lease_expires_at,
|
|
293
|
+
);
|
|
294
|
+
return result.changes === 1;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
close() {
|
|
298
|
+
if (this.#closed) return;
|
|
299
|
+
if (this.#inTransaction) {
|
|
300
|
+
throw new Error("Cannot close SQLite Receiver store during a transaction");
|
|
301
|
+
}
|
|
302
|
+
this.#database.close();
|
|
303
|
+
this.#closed = true;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
#configure(inMemory) {
|
|
307
|
+
this.#database.exec("PRAGMA foreign_keys = ON");
|
|
308
|
+
this.#database.exec("PRAGMA busy_timeout = 5000");
|
|
309
|
+
if (!inMemory) {
|
|
310
|
+
const row = this.#database.prepare("PRAGMA journal_mode = WAL").get();
|
|
311
|
+
if (String(row?.journal_mode).toLowerCase() !== "wal") {
|
|
312
|
+
throw new Error("SQLite Receiver store could not enable WAL journal mode");
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
this.#database.exec("PRAGMA synchronous = FULL");
|
|
316
|
+
if (this.#database.prepare("PRAGMA foreign_keys").get()?.foreign_keys !== 1) {
|
|
317
|
+
throw new Error("SQLite Receiver store could not enable foreign keys");
|
|
318
|
+
}
|
|
319
|
+
if (this.#database.prepare("PRAGMA synchronous").get()?.synchronous !== 2) {
|
|
320
|
+
throw new Error("SQLite Receiver store could not enable full synchronous durability");
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
#initializeSchema() {
|
|
325
|
+
const version = this.#database.prepare("PRAGMA user_version").get()?.user_version;
|
|
326
|
+
if (version === SCHEMA_VERSION) return;
|
|
327
|
+
if (version === 1) {
|
|
328
|
+
this.#schemaTransaction("migration", () => {
|
|
329
|
+
this.#database.exec(DELIVERY_STATE_SCHEMA_SQL);
|
|
330
|
+
this.#database.exec(`
|
|
331
|
+
INSERT INTO receiver_delivery_states (
|
|
332
|
+
delivery_id, status, maximum_attempts, current_attempt, current_connector_id,
|
|
333
|
+
current_lease_token_digest, leased_at, lease_expires_at, effect_id,
|
|
334
|
+
effect_attestation_json, acknowledged_at, terminal_reason, updated_at
|
|
335
|
+
)
|
|
336
|
+
SELECT
|
|
337
|
+
delivery_id, 'pending', 1, 0, NULL, NULL, NULL, NULL, NULL,
|
|
338
|
+
NULL, NULL, NULL, created_at
|
|
339
|
+
FROM receiver_deliveries
|
|
340
|
+
`);
|
|
341
|
+
});
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
344
|
+
if (version !== 0) {
|
|
345
|
+
throw new Error(`Unsupported SQLite Receiver schema version: ${version}`);
|
|
346
|
+
}
|
|
347
|
+
const existingTable = this.#database.prepare(
|
|
348
|
+
"SELECT name FROM sqlite_schema WHERE type = 'table' AND name NOT LIKE 'sqlite_%' LIMIT 1",
|
|
349
|
+
).get();
|
|
350
|
+
if (existingTable) {
|
|
351
|
+
throw new Error("Unversioned SQLite Receiver database is not empty");
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
this.#schemaTransaction("initialization", () => this.#database.exec(SCHEMA_SQL));
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
#schemaTransaction(operation, callback) {
|
|
358
|
+
this.#database.exec("BEGIN IMMEDIATE");
|
|
359
|
+
try {
|
|
360
|
+
callback();
|
|
361
|
+
this.#database.exec(`PRAGMA user_version = ${SCHEMA_VERSION}`);
|
|
362
|
+
this.#database.exec("COMMIT");
|
|
363
|
+
} catch (error) {
|
|
364
|
+
try {
|
|
365
|
+
this.#database.exec("ROLLBACK");
|
|
366
|
+
} catch (rollbackError) {
|
|
367
|
+
throw new AggregateError(
|
|
368
|
+
[error, rollbackError],
|
|
369
|
+
`SQLite Receiver schema ${operation} and rollback both failed`,
|
|
370
|
+
{ cause: error },
|
|
371
|
+
);
|
|
372
|
+
}
|
|
373
|
+
throw error;
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
#prepareStatements() {
|
|
378
|
+
return {
|
|
379
|
+
challengeByManifestId: this.#database.prepare(
|
|
380
|
+
"SELECT * FROM receiver_challenges WHERE manifest_id = ?",
|
|
381
|
+
),
|
|
382
|
+
challengeById: this.#database.prepare(
|
|
383
|
+
"SELECT * FROM receiver_challenges WHERE challenge_id = ?",
|
|
384
|
+
),
|
|
385
|
+
insertChallenge: this.#database.prepare(`
|
|
386
|
+
INSERT INTO receiver_challenges (
|
|
387
|
+
challenge_id, manifest_id, manifest_json, expected_origin, effective_expires_at,
|
|
388
|
+
status, decision_id, decision_action, subject_id, created_at, decided_at
|
|
389
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
390
|
+
`),
|
|
391
|
+
setChallengeDecision: this.#database.prepare(`
|
|
392
|
+
UPDATE receiver_challenges
|
|
393
|
+
SET status = ?, decision_id = ?, decision_action = ?, subject_id = ?, decided_at = ?
|
|
394
|
+
WHERE challenge_id = ? AND status = 'pending'
|
|
395
|
+
`),
|
|
396
|
+
grantByChallengeId: this.#database.prepare(
|
|
397
|
+
"SELECT * FROM receiver_grants WHERE challenge_id = ?",
|
|
398
|
+
),
|
|
399
|
+
grantByBindingId: this.#database.prepare(
|
|
400
|
+
"SELECT * FROM receiver_grants WHERE binding_id = ?",
|
|
401
|
+
),
|
|
402
|
+
insertGrant: this.#database.prepare(`
|
|
403
|
+
INSERT INTO receiver_grants (
|
|
404
|
+
grant_id, challenge_id, manifest_id, binding_id, subject_id, delivery_target_id,
|
|
405
|
+
correlation_id, issuer_origin, workflow_type, workflow_id, event_type, canonical_url,
|
|
406
|
+
expires_at, human_boundary, runs_remaining, revoked_at, receipt_json, created_at
|
|
407
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
408
|
+
`),
|
|
409
|
+
revokeGrant: this.#database.prepare(`
|
|
410
|
+
UPDATE receiver_grants
|
|
411
|
+
SET revoked_at = ?
|
|
412
|
+
WHERE grant_id = ? AND revoked_at IS NULL
|
|
413
|
+
`),
|
|
414
|
+
consumeGrantRun: this.#database.prepare(`
|
|
415
|
+
UPDATE receiver_grants
|
|
416
|
+
SET runs_remaining = 0
|
|
417
|
+
WHERE grant_id = ? AND runs_remaining = 1 AND revoked_at IS NULL
|
|
418
|
+
`),
|
|
419
|
+
eventById: this.#database.prepare(
|
|
420
|
+
"SELECT * FROM receiver_events WHERE event_id = ?",
|
|
421
|
+
),
|
|
422
|
+
insertEvent: this.#database.prepare(`
|
|
423
|
+
INSERT INTO receiver_events (
|
|
424
|
+
event_id, grant_id, canonical_body, acceptance_json, received_at
|
|
425
|
+
) VALUES (?, ?, ?, ?, ?)
|
|
426
|
+
`),
|
|
427
|
+
insertDelivery: this.#database.prepare(`
|
|
428
|
+
INSERT INTO receiver_deliveries (
|
|
429
|
+
delivery_id, event_id, grant_id, delivery_target_id, status, created_at
|
|
430
|
+
) VALUES (?, ?, ?, ?, ?, ?)
|
|
431
|
+
`),
|
|
432
|
+
insertDeliveryState: this.#database.prepare(`
|
|
433
|
+
INSERT INTO receiver_delivery_states (
|
|
434
|
+
delivery_id, status, maximum_attempts, current_attempt, current_connector_id,
|
|
435
|
+
current_lease_token_digest, leased_at, lease_expires_at, effect_id,
|
|
436
|
+
effect_attestation_json, acknowledged_at, terminal_reason, updated_at
|
|
437
|
+
) VALUES (?, ?, ?, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ?)
|
|
438
|
+
`),
|
|
439
|
+
deliveryByEventId: this.#database.prepare(`
|
|
440
|
+
${DELIVERY_DETAIL_SELECT}
|
|
441
|
+
WHERE d.event_id = ?
|
|
442
|
+
`),
|
|
443
|
+
deliveryById: this.#database.prepare(`
|
|
444
|
+
${DELIVERY_DETAIL_SELECT}
|
|
445
|
+
WHERE d.delivery_id = ?
|
|
446
|
+
`),
|
|
447
|
+
deliveryByEffectId: this.#database.prepare(`
|
|
448
|
+
SELECT delivery_id
|
|
449
|
+
FROM receiver_delivery_states
|
|
450
|
+
WHERE effect_id = ?
|
|
451
|
+
`),
|
|
452
|
+
deliveryByCurrentLeaseTokenDigest: this.#database.prepare(`
|
|
453
|
+
${DELIVERY_DETAIL_SELECT}
|
|
454
|
+
WHERE s.current_lease_token_digest = ?
|
|
455
|
+
`),
|
|
456
|
+
hasDeliveryAttemptTokenDigest: this.#database.prepare(`
|
|
457
|
+
SELECT 1
|
|
458
|
+
FROM receiver_delivery_attempts
|
|
459
|
+
WHERE lease_token_digest = ?
|
|
460
|
+
`),
|
|
461
|
+
activeDeliveryByTarget: this.#database.prepare(`
|
|
462
|
+
${DELIVERY_DETAIL_SELECT}
|
|
463
|
+
WHERE d.delivery_target_id = ?
|
|
464
|
+
AND s.status = 'leased'
|
|
465
|
+
AND s.lease_expires_at > ?
|
|
466
|
+
ORDER BY d.created_at, d.delivery_id
|
|
467
|
+
LIMIT 1
|
|
468
|
+
`),
|
|
469
|
+
nextDeliveryByTarget: this.#database.prepare(`
|
|
470
|
+
${DELIVERY_DETAIL_SELECT}
|
|
471
|
+
WHERE d.delivery_target_id = ?
|
|
472
|
+
AND (
|
|
473
|
+
s.status = 'pending'
|
|
474
|
+
OR (s.status = 'leased' AND s.lease_expires_at <= ?)
|
|
475
|
+
)
|
|
476
|
+
ORDER BY d.created_at, d.delivery_id
|
|
477
|
+
LIMIT 1
|
|
478
|
+
`),
|
|
479
|
+
claimDelivery: this.#database.prepare(`
|
|
480
|
+
UPDATE receiver_delivery_states
|
|
481
|
+
SET status = 'leased', current_attempt = ?, current_connector_id = ?,
|
|
482
|
+
current_lease_token_digest = ?, leased_at = ?, lease_expires_at = ?,
|
|
483
|
+
effect_id = NULL, effect_attestation_json = NULL, acknowledged_at = NULL,
|
|
484
|
+
terminal_reason = NULL, updated_at = ?
|
|
485
|
+
WHERE delivery_id = ? AND status = ? AND current_attempt = ?
|
|
486
|
+
AND current_connector_id IS ?
|
|
487
|
+
AND current_lease_token_digest IS ?
|
|
488
|
+
AND lease_expires_at IS ?
|
|
489
|
+
`),
|
|
490
|
+
insertDeliveryAttempt: this.#database.prepare(`
|
|
491
|
+
INSERT INTO receiver_delivery_attempts (
|
|
492
|
+
delivery_id, attempt, connector_id, lease_token_digest, leased_at, lease_expires_at
|
|
493
|
+
) VALUES (?, ?, ?, ?, ?, ?)
|
|
494
|
+
`),
|
|
495
|
+
cancelDelivery: this.#database.prepare(`
|
|
496
|
+
UPDATE receiver_delivery_states
|
|
497
|
+
SET status = 'cancelled', terminal_reason = ?, updated_at = ?
|
|
498
|
+
WHERE delivery_id = ? AND status = 'pending' AND current_attempt = 0
|
|
499
|
+
`),
|
|
500
|
+
exhaustDelivery: this.#database.prepare(`
|
|
501
|
+
UPDATE receiver_delivery_states
|
|
502
|
+
SET status = 'retry_exhausted', terminal_reason = ?, updated_at = ?
|
|
503
|
+
WHERE delivery_id = ? AND status = 'leased' AND current_attempt = ?
|
|
504
|
+
AND current_connector_id = ?
|
|
505
|
+
AND current_lease_token_digest = ?
|
|
506
|
+
AND lease_expires_at = ?
|
|
507
|
+
`),
|
|
508
|
+
acknowledgeDelivery: this.#database.prepare(`
|
|
509
|
+
UPDATE receiver_delivery_states
|
|
510
|
+
SET status = 'acknowledged', effect_id = ?, effect_attestation_json = ?,
|
|
511
|
+
acknowledged_at = ?, terminal_reason = NULL, updated_at = ?
|
|
512
|
+
WHERE delivery_id = ? AND status = ? AND current_attempt = ?
|
|
513
|
+
AND current_connector_id = ?
|
|
514
|
+
AND current_lease_token_digest = ?
|
|
515
|
+
AND lease_expires_at = ?
|
|
516
|
+
`),
|
|
517
|
+
};
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
#assertOpen() {
|
|
521
|
+
if (this.#closed) throw new Error("SQLite Receiver store is closed");
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
#assertWriteTransaction() {
|
|
525
|
+
this.#assertOpen();
|
|
526
|
+
if (!this.#inTransaction) {
|
|
527
|
+
throw new Error("SQLite Receiver writes require an active transaction");
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
function requireStoreOptions(options) {
|
|
533
|
+
if (!options || typeof options !== "object" || Array.isArray(options)) {
|
|
534
|
+
throw new TypeError("SQLite Receiver store options must be an object");
|
|
535
|
+
}
|
|
536
|
+
const prototype = Object.getPrototypeOf(options);
|
|
537
|
+
if (prototype !== Object.prototype && prototype !== null) {
|
|
538
|
+
throw new TypeError("SQLite Receiver store options must be a plain object");
|
|
539
|
+
}
|
|
540
|
+
const fields = Reflect.ownKeys(options);
|
|
541
|
+
if (
|
|
542
|
+
fields.length !== STORE_OPTION_FIELDS.length ||
|
|
543
|
+
fields.some((field) => typeof field !== "string" || !STORE_OPTION_FIELDS.includes(field))
|
|
544
|
+
) {
|
|
545
|
+
throw new TypeError("SQLite Receiver store options must contain only filename");
|
|
546
|
+
}
|
|
547
|
+
const descriptor = Object.getOwnPropertyDescriptor(options, "filename");
|
|
548
|
+
if (!descriptor?.enumerable || !("value" in descriptor)) {
|
|
549
|
+
throw new TypeError("SQLite Receiver store filename must be an enumerable data property");
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
function requireFilename(value) {
|
|
554
|
+
if (
|
|
555
|
+
typeof value !== "string" ||
|
|
556
|
+
value.length === 0 ||
|
|
557
|
+
Buffer.byteLength(value, "utf8") > 4_096 ||
|
|
558
|
+
value.includes("\0")
|
|
559
|
+
) {
|
|
560
|
+
throw new TypeError("SQLite Receiver store filename is invalid");
|
|
561
|
+
}
|
|
562
|
+
return value;
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
function plainRow(row) {
|
|
566
|
+
return row === undefined ? undefined : { ...row };
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
function assertSingleChange(result, operation) {
|
|
570
|
+
if (result.changes !== 1) {
|
|
571
|
+
throw new Error(`SQLite Receiver store failed to ${operation}`);
|
|
572
|
+
}
|
|
573
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@4xeoz/re-entry",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Outbound Local Connector process for the Re-entry Core local preview.",
|
|
6
|
+
"publishConfig": {
|
|
7
|
+
"access": "public"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"README.md",
|
|
11
|
+
"src"
|
|
12
|
+
],
|
|
13
|
+
"bin": {
|
|
14
|
+
"re-entry": "./src/main.mjs"
|
|
15
|
+
},
|
|
16
|
+
"exports": {
|
|
17
|
+
".": "./src/index.mjs",
|
|
18
|
+
"./connector": "./src/local-connector.mjs",
|
|
19
|
+
"./codex-discovery": "./src/codex-discovery.mjs",
|
|
20
|
+
"./codex-exec-adapter": "./src/codex-exec-adapter.mjs",
|
|
21
|
+
"./pairing": "./src/pairing-client.mjs",
|
|
22
|
+
"./credentials": "./src/credentials.mjs",
|
|
23
|
+
"./macos-service": "./src/macos-service.mjs"
|
|
24
|
+
},
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"@webmcp-challenge/reentry-core": "file:../../reentry-core"
|
|
27
|
+
},
|
|
28
|
+
"bundleDependencies": [
|
|
29
|
+
"@webmcp-challenge/reentry-core"
|
|
30
|
+
],
|
|
31
|
+
"scripts": {
|
|
32
|
+
"start": "node src/main.mjs",
|
|
33
|
+
"connect": "node src/main.mjs connect",
|
|
34
|
+
"status": "node src/main.mjs status",
|
|
35
|
+
"doctor": "node src/main.mjs doctor",
|
|
36
|
+
"check:syntax": "node scripts/check-syntax.mjs",
|
|
37
|
+
"test:codex": "node --test test/codex-exec-adapter.test.mjs",
|
|
38
|
+
"test": "node --test test/*.test.mjs",
|
|
39
|
+
"verify": "npm run check:syntax && npm test"
|
|
40
|
+
},
|
|
41
|
+
"engines": {
|
|
42
|
+
"node": ">=24"
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { createInterface } from "node:readline/promises";
|
|
2
|
+
import process from "node:process";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Pause an interactive CLI until the user is ready for the browser to open.
|
|
6
|
+
* Non-interactive callers should skip this function and open the URL directly.
|
|
7
|
+
*/
|
|
8
|
+
export async function waitForEnterToOpenBrowser(options = {}) {
|
|
9
|
+
const input = options.input ?? process.stdin;
|
|
10
|
+
const output = options.output ?? process.stdout;
|
|
11
|
+
const prompt = options.prompt ?? " Press Enter to open Re-entry in your browser: ";
|
|
12
|
+
const readline = createInterface({ input, output });
|
|
13
|
+
try {
|
|
14
|
+
await readline.question(prompt);
|
|
15
|
+
} finally {
|
|
16
|
+
readline.close();
|
|
17
|
+
}
|
|
18
|
+
}
|