@hasna/todos 0.15.47 → 0.15.49
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/cli/commands/query-commands.d.ts.map +1 -1
- package/dist/cli/index.js +296 -81
- package/dist/contracts.js +56 -5
- package/dist/db/task-crud.d.ts +6 -0
- package/dist/db/task-crud.d.ts.map +1 -1
- package/dist/db/tasks.d.ts +1 -1
- package/dist/db/tasks.d.ts.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +187 -70
- package/dist/lib/dedupe-projection.d.ts +48 -0
- package/dist/lib/dedupe-projection.d.ts.map +1 -0
- package/dist/lib/redaction.d.ts.map +1 -1
- package/dist/lib/task-dedupe.d.ts +5 -9
- package/dist/lib/task-dedupe.d.ts.map +1 -1
- package/dist/mcp/index.js +246 -80
- package/dist/mcp/tools/task-crud.d.ts.map +1 -1
- package/dist/mcp.js +3 -2
- package/dist/project-registration.js +128 -68
- package/dist/registry.js +56 -5
- package/dist/release-provenance.json +5 -5
- package/dist/server/cloud.d.ts.map +1 -1
- package/dist/server/index.js +248 -82
- package/dist/server/routes.d.ts.map +1 -1
- package/dist/server/v1.d.ts.map +1 -1
- package/dist/storage/postgres-adapter.d.ts.map +1 -1
- package/dist/storage/postgres-errors.d.ts +15 -0
- package/dist/storage/postgres-errors.d.ts.map +1 -0
- package/dist/storage/postgres-sync.d.ts +7 -0
- package/dist/storage/postgres-sync.d.ts.map +1 -1
- package/dist/storage/shadow-outbox.d.ts.map +1 -1
- package/dist/storage/shadow.d.ts.map +1 -1
- package/dist/storage.js +139 -66
- package/dist/task-manifest.js +118 -47
- package/dist/task-subtree-transfer.js +326 -44
- package/dist/types/index.d.ts +2 -2
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +3 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"postgres-sync.d.ts","sourceRoot":"","sources":["../../src/storage/postgres-sync.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"postgres-sync.d.ts","sourceRoot":"","sources":["../../src/storage/postgres-sync.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,mBAAmB,EACnB,oBAAoB,EACrB,MAAM,iBAAiB,CAAC;AAWzB,MAAM,MAAM,2BAA2B,GACnC,OAAO,GACP,UAAU,GACV,uBAAuB,GACvB,OAAO,GACP,QAAQ,GACR,YAAY,GACZ,WAAW,GACX,gBAAgB,GAChB,eAAe,CAAC;AAEpB,MAAM,WAAW,wBAAwB,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IACnE,IAAI,EAAE,CAAC,EAAE,CAAC;CACX;AAED,MAAM,WAAW,wBAAwB;IACvC,KAAK,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,GAAG,EAAE,MAAM,EACX,MAAM,CAAC,EAAE,SAAS,OAAO,EAAE,GAC1B,OAAO,CAAC,wBAAwB,CAAC,CAAC,CAAC,CAAC,CAAC;IACxC;;;;;;OAMG;IACH,WAAW,CAAC,CAAC,CAAC,EACZ,EAAE,EAAE,CAAC,MAAM,EAAE,wBAAwB,KAAK,OAAO,CAAC,CAAC,CAAC,GACnD,OAAO,CAAC,CAAC,CAAC,CAAC;CACf;AAED,MAAM,WAAW,mCAAmC;IAClD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,gCAAgC;IAC/C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,2BAA2B,EAAE,CAAC;CAC7C;AAED,MAAM,WAAW,2BAA2B;IAC1C,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,OAAO,CAAC,MAAM,CAAC,2BAA2B,EAAE,MAAM,CAAC,CAAC,CAAC;CACnE;AAED,MAAM,WAAW,0BAA0B;IACzC,WAAW,EAAE,2BAA2B,CAAC;IACzC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAAC;IAClC,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB;AAED,eAAO,MAAM,iCAAiC,uBAAuB,CAAC;AACtE,eAAO,MAAM,mCAAmC,uBAAuB,CAAC;AAExE,wBAAgB,0BAA0B,CACxC,SAAS,SAAoC,EAC7C,eAAe,SAAsC,GACpD,MAAM,EAAE,CA6HV;AAED,MAAM,WAAW,0BAA0B;IACzC,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,UAAU,GAAG,YAAY,CAAC;IACvC,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;IACxB,KAAK,EAAE,WAAW,GAAG,SAAS,CAAC;CAChC;AAED,MAAM,WAAW,6BAA6B;IAC5C,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,qBAAa,wCAAyC,SAAQ,KAAK;aACrC,SAAS,EAAE,0BAA0B,EAAE;gBAAvC,SAAS,EAAE,0BAA0B,EAAE;CAUpE;AAED,qBAAa,iCAAkC,SAAQ,KAAK;aAC9B,UAAU,EAAE,MAAM;gBAAlB,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO;CAQ/D;AAED,kFAAkF;AAClF,wBAAgB,mCAAmC,CACjD,SAAS,SAAoC,GAC5C,MAAM,CAqCR;AAED,kFAAkF;AAClF,wBAAgB,qCAAqC,CACnD,SAAS,SAAoC,GAC5C,MAAM,EAAE,CAUV;AAED,kGAAkG;AAClG,wBAAgB,qCAAqC,CACnD,SAAS,SAAoC,GAC5C,MAAM,CAWR;AAED,4FAA4F;AAC5F,wBAAsB,qCAAqC,CACzD,MAAM,EAAE,wBAAwB,EAChC,SAAS,SAAoC,GAC5C,OAAO,CAAC,IAAI,CAAC,CAsBf;AAED;;;;GAIG;AACH,wBAAgB,kCAAkC,CAChD,SAAS,SAAoC,GAC5C,MAAM,CAKR;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,gCAAgC,CAC9C,SAAS,SAAoC,GAC5C,MAAM,CAKR;AAED;;;;;;;;GAQG;AACH,wBAAgB,iCAAiC,CAC/C,SAAS,SAAoC,GAC5C,MAAM,CAKR;AAED,qBAAa,sBAAsB;IAO/B,OAAO,CAAC,QAAQ,CAAC,MAAM;IANzB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAS;IAC1C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;gBAGtB,MAAM,EAAE,wBAAwB,EACjD,OAAO,GAAE,mCAAwC;IAU7C,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;IAM7B,YAAY,CAChB,QAAQ,EAAE,oBAAoB,EAC9B,OAAO,GAAE,mBAAwB,GAChC,OAAO,CAAC,2BAA2B,CAAC;IAgGvC;;;;;OAKG;YACW,0BAA0B;IAmDlC,YAAY,CAAC,OAAO,GAAE,gCAAqC,GAAG,OAAO,CAAC,oBAAoB,CAAC;IAsB3F,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAQ/C,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAU5D;AAED,wBAAgB,4BAA4B,CAC1C,MAAM,EAAE,wBAAwB,EAChC,OAAO,GAAE,mCAAwC,GAChD,sBAAsB,CAExB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shadow-outbox.d.ts","sourceRoot":"","sources":["../../src/storage/shadow-outbox.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"shadow-outbox.d.ts","sourceRoot":"","sources":["../../src/storage/shadow-outbox.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shadow.d.ts","sourceRoot":"","sources":["../../src/storage/shadow.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,KAAK,EACL,IAAI,EACJ,OAAO,EACP,IAAI,EACJ,WAAW,EACX,QAAQ,EACR,YAAY,EACb,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"shadow.d.ts","sourceRoot":"","sources":["../../src/storage/shadow.ts"],"names":[],"mappings":"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"}
|
package/dist/storage.js
CHANGED
|
@@ -5531,13 +5531,15 @@ function upsertSecretSafetyConfig(input) {
|
|
|
5531
5531
|
saveConfig({ ...config, secret_safety: next });
|
|
5532
5532
|
return next;
|
|
5533
5533
|
}
|
|
5534
|
-
var DEFAULT_SECRET_PATTERNS, DEFAULT_SECRET_KEY_PATTERN, NON_SECRET_USAGE_KEYS, REDACTION_PLACEHOLDER;
|
|
5534
|
+
var XAI_PREFIX, DEFAULT_SECRET_PATTERNS, DEFAULT_SECRET_KEY_PATTERN, NON_SECRET_USAGE_KEYS, REDACTION_PLACEHOLDER;
|
|
5535
5535
|
var init_redaction = __esm(() => {
|
|
5536
5536
|
init_config2();
|
|
5537
|
+
XAI_PREFIX = ["x", "ai", "-"].join("");
|
|
5537
5538
|
DEFAULT_SECRET_PATTERNS = [
|
|
5538
5539
|
{ name: "aws-access-key", regex: /\b(AKIA|ASIA)[0-9A-Z]{16}\b/g, replacement: "[REDACTED_AWS_KEY]" },
|
|
5539
5540
|
{ name: "private-key", regex: /-----BEGIN (?:RSA |EC |OPENSSH |)PRIVATE KEY-----[\s\S]*?-----END (?:RSA |EC |OPENSSH |)PRIVATE KEY-----/g, replacement: "[REDACTED_PRIVATE_KEY]" },
|
|
5540
5541
|
{ name: "openai-token", regex: /\bsk-[A-Za-z0-9_-]{12,}\b/g, replacement: "[REDACTED_TOKEN]" },
|
|
5542
|
+
{ name: `${XAI_PREFIX}token`, regex: /\bxai[-][A-Za-z0-9]{20,80}\b/g, replacement: "[REDACTED_TOKEN]" },
|
|
5541
5543
|
{ name: "npm-token", regex: /\bnpm_[A-Za-z0-9]{20,}\b/g, replacement: "[REDACTED_NPM_TOKEN]" },
|
|
5542
5544
|
{ name: "github-fine-grained-token", regex: /\bgithub_pat_[A-Za-z0-9_]{20,}\b/g, replacement: "[REDACTED_GITHUB_TOKEN]" },
|
|
5543
5545
|
{ name: "github-token", regex: /\bgh[opsu]_[A-Za-z0-9]{20,}\b/g, replacement: "[REDACTED_GITHUB_TOKEN]" },
|
|
@@ -9933,6 +9935,12 @@ function listTasks(filter = {}, db) {
|
|
|
9933
9935
|
const d = db || getDatabase();
|
|
9934
9936
|
const { clearExpiredLocks: clearExpiredLocks2 } = (init_database(), __toCommonJS(exports_database));
|
|
9935
9937
|
clearExpiredLocks2(d);
|
|
9938
|
+
if (filter.limit !== undefined) {
|
|
9939
|
+
const limit = filter.limit;
|
|
9940
|
+
if (!Number.isSafeInteger(limit) || limit <= 0 || limit > MAX_TASK_LIST_LIMIT) {
|
|
9941
|
+
throw new TypeError(`listTasks limit must be a positive integer between 1 and ${MAX_TASK_LIST_LIMIT}; got ${String(limit)}`);
|
|
9942
|
+
}
|
|
9943
|
+
}
|
|
9936
9944
|
const conditions = [];
|
|
9937
9945
|
const params = [];
|
|
9938
9946
|
if (filter.project_id) {
|
|
@@ -10466,6 +10474,7 @@ function deleteTask(id, db) {
|
|
|
10466
10474
|
}
|
|
10467
10475
|
return result.changes > 0;
|
|
10468
10476
|
}
|
|
10477
|
+
var MAX_TASK_LIST_LIMIT = 1e5;
|
|
10469
10478
|
var init_task_crud = __esm(() => {
|
|
10470
10479
|
init_types();
|
|
10471
10480
|
init_database();
|
|
@@ -15177,6 +15186,30 @@ function changedSinceStampNewer(stamp, since) {
|
|
|
15177
15186
|
// src/storage/postgres-adapter.ts
|
|
15178
15187
|
init_stale_lock_handoff();
|
|
15179
15188
|
|
|
15189
|
+
// src/storage/postgres-sync.ts
|
|
15190
|
+
init_types();
|
|
15191
|
+
|
|
15192
|
+
// src/storage/postgres-errors.ts
|
|
15193
|
+
function isPostgresUniqueViolation(error) {
|
|
15194
|
+
if (typeof error !== "object" || error === null)
|
|
15195
|
+
return false;
|
|
15196
|
+
const candidate = error;
|
|
15197
|
+
const states = [candidate.code, candidate.errno, candidate.sqlState, candidate.sqlstate];
|
|
15198
|
+
if (typeof candidate.cause === "object" && candidate.cause !== null) {
|
|
15199
|
+
const cause = candidate.cause;
|
|
15200
|
+
states.push(cause.code, cause.errno, cause.sqlState, cause.sqlstate);
|
|
15201
|
+
}
|
|
15202
|
+
return states.some((state) => String(state) === "23505");
|
|
15203
|
+
}
|
|
15204
|
+
function postgresConstraintName(error) {
|
|
15205
|
+
if (typeof error !== "object" || error === null)
|
|
15206
|
+
return "";
|
|
15207
|
+
const candidate = error;
|
|
15208
|
+
const cause = typeof candidate.cause === "object" && candidate.cause !== null ? candidate.cause : undefined;
|
|
15209
|
+
const constraint = candidate.constraint ?? candidate.constraint_name ?? cause?.constraint ?? cause?.constraint_name;
|
|
15210
|
+
return typeof constraint === "string" ? constraint : "";
|
|
15211
|
+
}
|
|
15212
|
+
|
|
15180
15213
|
// src/storage/postgres-sync.ts
|
|
15181
15214
|
var DEFAULT_TODOS_POSTGRES_SYNC_TABLE = "todos_sync_records";
|
|
15182
15215
|
var DEFAULT_TODOS_POSTGRES_CURSOR_TABLE = "todos_sync_cursors";
|
|
@@ -15379,53 +15412,98 @@ class PostgresTodosSyncStore {
|
|
|
15379
15412
|
if (routingErrors.length > 0) {
|
|
15380
15413
|
throw new Error(`Invalid snapshot routing metadata: ${routingErrors.join("; ")}`);
|
|
15381
15414
|
}
|
|
15382
|
-
const
|
|
15383
|
-
|
|
15384
|
-
|
|
15385
|
-
|
|
15386
|
-
|
|
15387
|
-
|
|
15388
|
-
const
|
|
15389
|
-
|
|
15390
|
-
|
|
15391
|
-
|
|
15392
|
-
|
|
15393
|
-
|
|
15394
|
-
|
|
15395
|
-
|
|
15396
|
-
|
|
15397
|
-
|
|
15398
|
-
|
|
15399
|
-
|
|
15400
|
-
|
|
15401
|
-
|
|
15402
|
-
|
|
15403
|
-
|
|
15404
|
-
|
|
15405
|
-
|
|
15406
|
-
|
|
15407
|
-
|
|
15408
|
-
|
|
15409
|
-
|
|
15410
|
-
|
|
15411
|
-
|
|
15412
|
-
|
|
15413
|
-
|
|
15414
|
-
|
|
15415
|
-
|
|
15416
|
-
|
|
15417
|
-
|
|
15418
|
-
|
|
15419
|
-
|
|
15420
|
-
|
|
15421
|
-
|
|
15422
|
-
|
|
15423
|
-
|
|
15424
|
-
|
|
15425
|
-
|
|
15426
|
-
|
|
15415
|
+
const push = async (client) => {
|
|
15416
|
+
const existing = await client.query(`SELECT object_type, object_id, payload, updated_at, deleted_at, source_machine_id, version
|
|
15417
|
+
FROM ${this.tableName}
|
|
15418
|
+
WHERE service = $1 AND object_type IN ($2, $3) AND deleted_at IS NULL`, [this.service, "projects", "task_lists"]);
|
|
15419
|
+
const existingProjects = [];
|
|
15420
|
+
const existingTaskLists = [];
|
|
15421
|
+
for (const row of existing.rows) {
|
|
15422
|
+
const payload = payloadRecord(row.payload);
|
|
15423
|
+
if (row.object_type === "projects")
|
|
15424
|
+
existingProjects.push(payload);
|
|
15425
|
+
if (row.object_type === "task_lists")
|
|
15426
|
+
existingTaskLists.push(payload);
|
|
15427
|
+
}
|
|
15428
|
+
const destinationErrors = validateSnapshotRoutingDestinationConflicts(snapshot.projects, snapshot.taskLists, existingProjects, existingTaskLists);
|
|
15429
|
+
if (destinationErrors.length > 0) {
|
|
15430
|
+
throw new ResourceConflictError("SNAPSHOT_DESTINATION_CONFLICT", `Snapshot routing conflicts with destination: ${destinationErrors.join("; ")}`);
|
|
15431
|
+
}
|
|
15432
|
+
const result = { records: 0, objectTypes: {} };
|
|
15433
|
+
const sourceMachineId = context.requestId ?? this.sourceMachineId ?? null;
|
|
15434
|
+
for (const entry of snapshotEntries(snapshot)) {
|
|
15435
|
+
if (entry.deletedAt === null)
|
|
15436
|
+
assertCanonicalScopedSlugEntry(entry);
|
|
15437
|
+
try {
|
|
15438
|
+
await client.query(`INSERT INTO ${this.tableName} (
|
|
15439
|
+
service, object_type, object_id, payload, updated_at,
|
|
15440
|
+
deleted_at, source_machine_id, version
|
|
15441
|
+
) VALUES ($1, $2, $3, $4::jsonb, $5::timestamptz, $6::timestamptz, $7, $8)
|
|
15442
|
+
ON CONFLICT (service, object_type, object_id) DO UPDATE SET
|
|
15443
|
+
payload = EXCLUDED.payload,
|
|
15444
|
+
updated_at = EXCLUDED.updated_at,
|
|
15445
|
+
deleted_at = EXCLUDED.deleted_at,
|
|
15446
|
+
source_machine_id = EXCLUDED.source_machine_id,
|
|
15447
|
+
version = EXCLUDED.version
|
|
15448
|
+
WHERE ${this.tableName}.updated_at < EXCLUDED.updated_at
|
|
15449
|
+
OR (${this.tableName}.updated_at = EXCLUDED.updated_at
|
|
15450
|
+
AND COALESCE(${this.tableName}.version, 0) <= COALESCE(EXCLUDED.version, 0))`, [
|
|
15451
|
+
this.service,
|
|
15452
|
+
entry.type,
|
|
15453
|
+
entry.id,
|
|
15454
|
+
entry.payload,
|
|
15455
|
+
entry.updatedAt,
|
|
15456
|
+
entry.deletedAt,
|
|
15457
|
+
sourceMachineId,
|
|
15458
|
+
entry.version
|
|
15459
|
+
]);
|
|
15460
|
+
} catch (error) {
|
|
15461
|
+
await this.classifySyncInsertConflict(error, entry);
|
|
15462
|
+
}
|
|
15463
|
+
result.records += 1;
|
|
15464
|
+
result.objectTypes[entry.type] = (result.objectTypes[entry.type] ?? 0) + 1;
|
|
15465
|
+
}
|
|
15466
|
+
return result;
|
|
15467
|
+
};
|
|
15468
|
+
if (typeof this.client.transaction === "function") {
|
|
15469
|
+
return this.client.transaction((client) => push(client));
|
|
15427
15470
|
}
|
|
15428
|
-
return
|
|
15471
|
+
return push(this.client);
|
|
15472
|
+
}
|
|
15473
|
+
async classifySyncInsertConflict(error, entry) {
|
|
15474
|
+
if (!isPostgresUniqueViolation(error))
|
|
15475
|
+
throw error;
|
|
15476
|
+
const payload = entry.payload;
|
|
15477
|
+
const taskListSlug = String(payload["slug"] ?? "");
|
|
15478
|
+
const projectSlug = String(payload["task_list_id"] ?? "");
|
|
15479
|
+
const constraintName = postgresConstraintName(error);
|
|
15480
|
+
if (entry.type === "projects" && constraintName.includes("project_task_list_slug_uidx")) {
|
|
15481
|
+
throw new ResourceConflictError("PROJECT_SLUG_CONFLICT", `Project slug "${projectSlug}" already exists`);
|
|
15482
|
+
}
|
|
15483
|
+
if (entry.type === "task_lists" && constraintName.includes("task_list_scope_slug_uidx")) {
|
|
15484
|
+
throw new ResourceConflictError("TASK_LIST_SLUG_CONFLICT", `Task list with slug "${taskListSlug}" already exists in this scope`);
|
|
15485
|
+
}
|
|
15486
|
+
if (entry.type === "task_lists") {
|
|
15487
|
+
const scope = typeof payload["project_id"] === "string" ? payload["project_id"] : "";
|
|
15488
|
+
const conflict = await this.client.query(`/* todos:classify-sync-task-list-conflict */ SELECT EXISTS (
|
|
15489
|
+
SELECT 1 FROM ${this.tableName}
|
|
15490
|
+
WHERE service = $1 AND object_type = 'task_lists' AND object_id <> $2
|
|
15491
|
+
AND deleted_at IS NULL AND COALESCE(payload->>'project_id','') = $3 AND payload->>'slug' = $4
|
|
15492
|
+
) AS conflict`, [this.service, entry.id, scope, taskListSlug]);
|
|
15493
|
+
if (conflict.rows[0]?.conflict) {
|
|
15494
|
+
throw new ResourceConflictError("TASK_LIST_SLUG_CONFLICT", `Task list with slug "${taskListSlug}" already exists in this scope`);
|
|
15495
|
+
}
|
|
15496
|
+
} else if (entry.type === "projects") {
|
|
15497
|
+
const conflict = await this.client.query(`/* todos:classify-sync-project-conflict */ SELECT EXISTS (
|
|
15498
|
+
SELECT 1 FROM ${this.tableName}
|
|
15499
|
+
WHERE service = $1 AND object_type = 'projects' AND object_id <> $2
|
|
15500
|
+
AND deleted_at IS NULL AND payload->>'task_list_id' = $3
|
|
15501
|
+
) AS conflict`, [this.service, entry.id, projectSlug]);
|
|
15502
|
+
if (conflict.rows[0]?.conflict) {
|
|
15503
|
+
throw new ResourceConflictError("PROJECT_SLUG_CONFLICT", `Project slug "${projectSlug}" already exists`);
|
|
15504
|
+
}
|
|
15505
|
+
}
|
|
15506
|
+
throw error;
|
|
15429
15507
|
}
|
|
15430
15508
|
async pullSnapshot(options = {}) {
|
|
15431
15509
|
const params = [this.service];
|
|
@@ -18137,27 +18215,9 @@ async function retryOnTransientPostgresError(fn, attempts = 2, delayMs = 150) {
|
|
|
18137
18215
|
}
|
|
18138
18216
|
throw lastError;
|
|
18139
18217
|
}
|
|
18140
|
-
function isPostgresUniqueViolation(error) {
|
|
18141
|
-
if (typeof error !== "object" || error === null)
|
|
18142
|
-
return false;
|
|
18143
|
-
const candidate = error;
|
|
18144
|
-
const states = [candidate.code, candidate.errno, candidate.sqlState, candidate.sqlstate];
|
|
18145
|
-
if (typeof candidate.cause === "object" && candidate.cause !== null) {
|
|
18146
|
-
const cause = candidate.cause;
|
|
18147
|
-
states.push(cause.code, cause.errno, cause.sqlState, cause.sqlstate);
|
|
18148
|
-
}
|
|
18149
|
-
return states.some((state) => String(state) === "23505");
|
|
18150
|
-
}
|
|
18151
|
-
function postgresConstraintName(error) {
|
|
18152
|
-
if (typeof error !== "object" || error === null)
|
|
18153
|
-
return "";
|
|
18154
|
-
const candidate = error;
|
|
18155
|
-
const cause = typeof candidate.cause === "object" && candidate.cause !== null ? candidate.cause : undefined;
|
|
18156
|
-
const constraint = candidate.constraint ?? candidate.constraint_name ?? cause?.constraint ?? cause?.constraint_name;
|
|
18157
|
-
return typeof constraint === "string" ? constraint : "";
|
|
18158
|
-
}
|
|
18159
18218
|
|
|
18160
18219
|
// src/storage/shadow.ts
|
|
18220
|
+
init_types();
|
|
18161
18221
|
var SNAPSHOT_TO_OBJECT_TYPE = {
|
|
18162
18222
|
tasks: "tasks",
|
|
18163
18223
|
projects: "projects",
|
|
@@ -18299,6 +18359,12 @@ class TodosShadowMirror {
|
|
|
18299
18359
|
const message = error instanceof Error ? error.message : String(error);
|
|
18300
18360
|
const objectType = op.kind === "upsert" ? SNAPSHOT_TO_OBJECT_TYPE[op.key] : op.objectType;
|
|
18301
18361
|
const id = op.kind === "upsert" ? String(op.record["id"]) : op.id;
|
|
18362
|
+
if (error instanceof ResourceConflictError) {
|
|
18363
|
+
this.metrics.failed += 1;
|
|
18364
|
+
this.metrics.lastError = message;
|
|
18365
|
+
this.onEvent?.({ type: "dropped", objectType, id, error: message });
|
|
18366
|
+
return;
|
|
18367
|
+
}
|
|
18302
18368
|
this.metrics.retries += 1;
|
|
18303
18369
|
this.metrics.lastError = message;
|
|
18304
18370
|
op.attempts += 1;
|
|
@@ -18649,6 +18715,7 @@ function assertPostgresAdapterCapabilities(adapter) {
|
|
|
18649
18715
|
}
|
|
18650
18716
|
}
|
|
18651
18717
|
// src/storage/shadow-outbox.ts
|
|
18718
|
+
init_types();
|
|
18652
18719
|
init_shadow_outbox_schema();
|
|
18653
18720
|
init_shadow_outbox_schema();
|
|
18654
18721
|
var MAX_BACKOFF_MS = 5 * 60000;
|
|
@@ -18778,6 +18845,12 @@ class TodosShadowOutbox {
|
|
|
18778
18845
|
this.onEvent?.({ type: "mirrored", objectType: row.object_type, id: row.object_id, lagMs });
|
|
18779
18846
|
} catch (error) {
|
|
18780
18847
|
const message = error instanceof Error ? error.message : String(error);
|
|
18848
|
+
if (error instanceof ResourceConflictError) {
|
|
18849
|
+
this.metrics.lastError = message;
|
|
18850
|
+
this.db.run(`UPDATE shadow_outbox SET attempts=?, last_error=?, status='failed' WHERE seq=? AND revision=?`, [row.attempts + 1, message, row.seq, row.revision]);
|
|
18851
|
+
this.onEvent?.({ type: "parked", objectType: row.object_type, id: row.object_id, error: message });
|
|
18852
|
+
return;
|
|
18853
|
+
}
|
|
18781
18854
|
this.metrics.retries += 1;
|
|
18782
18855
|
this.metrics.lastError = message;
|
|
18783
18856
|
const attempts = row.attempts + 1;
|
package/dist/task-manifest.js
CHANGED
|
@@ -615,13 +615,15 @@ function upsertSecretSafetyConfig(input) {
|
|
|
615
615
|
saveConfig({ ...config, secret_safety: next });
|
|
616
616
|
return next;
|
|
617
617
|
}
|
|
618
|
-
var DEFAULT_SECRET_PATTERNS, DEFAULT_SECRET_KEY_PATTERN, NON_SECRET_USAGE_KEYS, REDACTION_PLACEHOLDER;
|
|
618
|
+
var XAI_PREFIX, DEFAULT_SECRET_PATTERNS, DEFAULT_SECRET_KEY_PATTERN, NON_SECRET_USAGE_KEYS, REDACTION_PLACEHOLDER;
|
|
619
619
|
var init_redaction = __esm(() => {
|
|
620
620
|
init_config();
|
|
621
|
+
XAI_PREFIX = ["x", "ai", "-"].join("");
|
|
621
622
|
DEFAULT_SECRET_PATTERNS = [
|
|
622
623
|
{ name: "aws-access-key", regex: /\b(AKIA|ASIA)[0-9A-Z]{16}\b/g, replacement: "[REDACTED_AWS_KEY]" },
|
|
623
624
|
{ name: "private-key", regex: /-----BEGIN (?:RSA |EC |OPENSSH |)PRIVATE KEY-----[\s\S]*?-----END (?:RSA |EC |OPENSSH |)PRIVATE KEY-----/g, replacement: "[REDACTED_PRIVATE_KEY]" },
|
|
624
625
|
{ name: "openai-token", regex: /\bsk-[A-Za-z0-9_-]{12,}\b/g, replacement: "[REDACTED_TOKEN]" },
|
|
626
|
+
{ name: `${XAI_PREFIX}token`, regex: /\bxai[-][A-Za-z0-9]{20,80}\b/g, replacement: "[REDACTED_TOKEN]" },
|
|
625
627
|
{ name: "npm-token", regex: /\bnpm_[A-Za-z0-9]{20,}\b/g, replacement: "[REDACTED_NPM_TOKEN]" },
|
|
626
628
|
{ name: "github-fine-grained-token", regex: /\bgithub_pat_[A-Za-z0-9_]{20,}\b/g, replacement: "[REDACTED_GITHUB_TOKEN]" },
|
|
627
629
|
{ name: "github-token", regex: /\bgh[opsu]_[A-Za-z0-9]{20,}\b/g, replacement: "[REDACTED_GITHUB_TOKEN]" },
|
|
@@ -6010,6 +6012,30 @@ class SqliteTodosTaskManifestBackend {
|
|
|
6010
6012
|
}
|
|
6011
6013
|
}
|
|
6012
6014
|
|
|
6015
|
+
// src/storage/postgres-sync.ts
|
|
6016
|
+
init_types();
|
|
6017
|
+
|
|
6018
|
+
// src/storage/postgres-errors.ts
|
|
6019
|
+
function isPostgresUniqueViolation(error) {
|
|
6020
|
+
if (typeof error !== "object" || error === null)
|
|
6021
|
+
return false;
|
|
6022
|
+
const candidate = error;
|
|
6023
|
+
const states = [candidate.code, candidate.errno, candidate.sqlState, candidate.sqlstate];
|
|
6024
|
+
if (typeof candidate.cause === "object" && candidate.cause !== null) {
|
|
6025
|
+
const cause = candidate.cause;
|
|
6026
|
+
states.push(cause.code, cause.errno, cause.sqlState, cause.sqlstate);
|
|
6027
|
+
}
|
|
6028
|
+
return states.some((state) => String(state) === "23505");
|
|
6029
|
+
}
|
|
6030
|
+
function postgresConstraintName(error) {
|
|
6031
|
+
if (typeof error !== "object" || error === null)
|
|
6032
|
+
return "";
|
|
6033
|
+
const candidate = error;
|
|
6034
|
+
const cause = typeof candidate.cause === "object" && candidate.cause !== null ? candidate.cause : undefined;
|
|
6035
|
+
const constraint = candidate.constraint ?? candidate.constraint_name ?? cause?.constraint ?? cause?.constraint_name;
|
|
6036
|
+
return typeof constraint === "string" ? constraint : "";
|
|
6037
|
+
}
|
|
6038
|
+
|
|
6013
6039
|
// src/storage/postgres-sync.ts
|
|
6014
6040
|
var DEFAULT_TODOS_POSTGRES_SYNC_TABLE = "todos_sync_records";
|
|
6015
6041
|
var DEFAULT_TODOS_POSTGRES_CURSOR_TABLE = "todos_sync_cursors";
|
|
@@ -6212,53 +6238,98 @@ class PostgresTodosSyncStore {
|
|
|
6212
6238
|
if (routingErrors.length > 0) {
|
|
6213
6239
|
throw new Error(`Invalid snapshot routing metadata: ${routingErrors.join("; ")}`);
|
|
6214
6240
|
}
|
|
6215
|
-
const
|
|
6216
|
-
|
|
6217
|
-
|
|
6218
|
-
|
|
6219
|
-
|
|
6220
|
-
|
|
6221
|
-
const
|
|
6222
|
-
|
|
6223
|
-
|
|
6224
|
-
|
|
6225
|
-
|
|
6226
|
-
|
|
6227
|
-
|
|
6228
|
-
|
|
6229
|
-
|
|
6230
|
-
|
|
6231
|
-
|
|
6232
|
-
|
|
6233
|
-
|
|
6234
|
-
|
|
6235
|
-
|
|
6236
|
-
|
|
6237
|
-
|
|
6238
|
-
|
|
6239
|
-
|
|
6240
|
-
|
|
6241
|
-
|
|
6242
|
-
|
|
6243
|
-
|
|
6244
|
-
|
|
6245
|
-
|
|
6246
|
-
|
|
6247
|
-
|
|
6248
|
-
|
|
6249
|
-
|
|
6250
|
-
|
|
6251
|
-
|
|
6252
|
-
|
|
6253
|
-
|
|
6254
|
-
|
|
6255
|
-
|
|
6256
|
-
|
|
6257
|
-
|
|
6258
|
-
|
|
6259
|
-
|
|
6241
|
+
const push = async (client) => {
|
|
6242
|
+
const existing = await client.query(`SELECT object_type, object_id, payload, updated_at, deleted_at, source_machine_id, version
|
|
6243
|
+
FROM ${this.tableName}
|
|
6244
|
+
WHERE service = $1 AND object_type IN ($2, $3) AND deleted_at IS NULL`, [this.service, "projects", "task_lists"]);
|
|
6245
|
+
const existingProjects = [];
|
|
6246
|
+
const existingTaskLists = [];
|
|
6247
|
+
for (const row of existing.rows) {
|
|
6248
|
+
const payload = payloadRecord(row.payload);
|
|
6249
|
+
if (row.object_type === "projects")
|
|
6250
|
+
existingProjects.push(payload);
|
|
6251
|
+
if (row.object_type === "task_lists")
|
|
6252
|
+
existingTaskLists.push(payload);
|
|
6253
|
+
}
|
|
6254
|
+
const destinationErrors = validateSnapshotRoutingDestinationConflicts(snapshot.projects, snapshot.taskLists, existingProjects, existingTaskLists);
|
|
6255
|
+
if (destinationErrors.length > 0) {
|
|
6256
|
+
throw new ResourceConflictError("SNAPSHOT_DESTINATION_CONFLICT", `Snapshot routing conflicts with destination: ${destinationErrors.join("; ")}`);
|
|
6257
|
+
}
|
|
6258
|
+
const result = { records: 0, objectTypes: {} };
|
|
6259
|
+
const sourceMachineId = context.requestId ?? this.sourceMachineId ?? null;
|
|
6260
|
+
for (const entry of snapshotEntries(snapshot)) {
|
|
6261
|
+
if (entry.deletedAt === null)
|
|
6262
|
+
assertCanonicalScopedSlugEntry(entry);
|
|
6263
|
+
try {
|
|
6264
|
+
await client.query(`INSERT INTO ${this.tableName} (
|
|
6265
|
+
service, object_type, object_id, payload, updated_at,
|
|
6266
|
+
deleted_at, source_machine_id, version
|
|
6267
|
+
) VALUES ($1, $2, $3, $4::jsonb, $5::timestamptz, $6::timestamptz, $7, $8)
|
|
6268
|
+
ON CONFLICT (service, object_type, object_id) DO UPDATE SET
|
|
6269
|
+
payload = EXCLUDED.payload,
|
|
6270
|
+
updated_at = EXCLUDED.updated_at,
|
|
6271
|
+
deleted_at = EXCLUDED.deleted_at,
|
|
6272
|
+
source_machine_id = EXCLUDED.source_machine_id,
|
|
6273
|
+
version = EXCLUDED.version
|
|
6274
|
+
WHERE ${this.tableName}.updated_at < EXCLUDED.updated_at
|
|
6275
|
+
OR (${this.tableName}.updated_at = EXCLUDED.updated_at
|
|
6276
|
+
AND COALESCE(${this.tableName}.version, 0) <= COALESCE(EXCLUDED.version, 0))`, [
|
|
6277
|
+
this.service,
|
|
6278
|
+
entry.type,
|
|
6279
|
+
entry.id,
|
|
6280
|
+
entry.payload,
|
|
6281
|
+
entry.updatedAt,
|
|
6282
|
+
entry.deletedAt,
|
|
6283
|
+
sourceMachineId,
|
|
6284
|
+
entry.version
|
|
6285
|
+
]);
|
|
6286
|
+
} catch (error) {
|
|
6287
|
+
await this.classifySyncInsertConflict(error, entry);
|
|
6288
|
+
}
|
|
6289
|
+
result.records += 1;
|
|
6290
|
+
result.objectTypes[entry.type] = (result.objectTypes[entry.type] ?? 0) + 1;
|
|
6291
|
+
}
|
|
6292
|
+
return result;
|
|
6293
|
+
};
|
|
6294
|
+
if (typeof this.client.transaction === "function") {
|
|
6295
|
+
return this.client.transaction((client) => push(client));
|
|
6296
|
+
}
|
|
6297
|
+
return push(this.client);
|
|
6298
|
+
}
|
|
6299
|
+
async classifySyncInsertConflict(error, entry) {
|
|
6300
|
+
if (!isPostgresUniqueViolation(error))
|
|
6301
|
+
throw error;
|
|
6302
|
+
const payload = entry.payload;
|
|
6303
|
+
const taskListSlug = String(payload["slug"] ?? "");
|
|
6304
|
+
const projectSlug = String(payload["task_list_id"] ?? "");
|
|
6305
|
+
const constraintName = postgresConstraintName(error);
|
|
6306
|
+
if (entry.type === "projects" && constraintName.includes("project_task_list_slug_uidx")) {
|
|
6307
|
+
throw new ResourceConflictError("PROJECT_SLUG_CONFLICT", `Project slug "${projectSlug}" already exists`);
|
|
6308
|
+
}
|
|
6309
|
+
if (entry.type === "task_lists" && constraintName.includes("task_list_scope_slug_uidx")) {
|
|
6310
|
+
throw new ResourceConflictError("TASK_LIST_SLUG_CONFLICT", `Task list with slug "${taskListSlug}" already exists in this scope`);
|
|
6311
|
+
}
|
|
6312
|
+
if (entry.type === "task_lists") {
|
|
6313
|
+
const scope = typeof payload["project_id"] === "string" ? payload["project_id"] : "";
|
|
6314
|
+
const conflict = await this.client.query(`/* todos:classify-sync-task-list-conflict */ SELECT EXISTS (
|
|
6315
|
+
SELECT 1 FROM ${this.tableName}
|
|
6316
|
+
WHERE service = $1 AND object_type = 'task_lists' AND object_id <> $2
|
|
6317
|
+
AND deleted_at IS NULL AND COALESCE(payload->>'project_id','') = $3 AND payload->>'slug' = $4
|
|
6318
|
+
) AS conflict`, [this.service, entry.id, scope, taskListSlug]);
|
|
6319
|
+
if (conflict.rows[0]?.conflict) {
|
|
6320
|
+
throw new ResourceConflictError("TASK_LIST_SLUG_CONFLICT", `Task list with slug "${taskListSlug}" already exists in this scope`);
|
|
6321
|
+
}
|
|
6322
|
+
} else if (entry.type === "projects") {
|
|
6323
|
+
const conflict = await this.client.query(`/* todos:classify-sync-project-conflict */ SELECT EXISTS (
|
|
6324
|
+
SELECT 1 FROM ${this.tableName}
|
|
6325
|
+
WHERE service = $1 AND object_type = 'projects' AND object_id <> $2
|
|
6326
|
+
AND deleted_at IS NULL AND payload->>'task_list_id' = $3
|
|
6327
|
+
) AS conflict`, [this.service, entry.id, projectSlug]);
|
|
6328
|
+
if (conflict.rows[0]?.conflict) {
|
|
6329
|
+
throw new ResourceConflictError("PROJECT_SLUG_CONFLICT", `Project slug "${projectSlug}" already exists`);
|
|
6330
|
+
}
|
|
6260
6331
|
}
|
|
6261
|
-
|
|
6332
|
+
throw error;
|
|
6262
6333
|
}
|
|
6263
6334
|
async pullSnapshot(options = {}) {
|
|
6264
6335
|
const params = [this.service];
|