@feltdb/core 0.13.0 → 0.15.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/agent-runtime.d.ts +64 -2
- package/dist/agent-runtime.d.ts.map +1 -1
- package/dist/agent-runtime.js +121 -11
- package/dist/agent-state.d.ts +48 -0
- package/dist/agent-state.d.ts.map +1 -1
- package/dist/agent-state.js +174 -12
- package/dist/agent.d.ts +10 -1
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +10 -1
- package/dist/build-identity.json +4 -4
- package/dist/cli/commands.js +27 -6
- package/dist/collection.d.ts +3 -1
- package/dist/collection.d.ts.map +1 -1
- package/dist/collection.js +30 -8
- package/dist/create/build-identity.json +4 -4
- package/dist/create/cli.js +1 -1
- package/dist/create/create.js +4 -6
- package/dist/create/package-versions.js +1 -1
- package/dist/create/server-source/Cargo.lock +6 -6
- package/dist/create/server-source/Cargo.toml +1 -1
- package/dist/create/server-source/crates/feltdb/src/lib.rs +126 -35
- package/dist/create/server-source/crates/feltdb/src/state_contract.rs +162 -53
- package/dist/create/server-source/crates/feltdb/src/worker_mesh.rs +137 -1
- package/dist/create/server-source/crates/feltdb/src/workload.rs +1427 -91
- package/dist/create/server-source/crates/feltdb-client/Cargo.toml +1 -1
- package/dist/create/server-source/crates/feltdb-server/Cargo.toml +1 -1
- package/dist/create/server-source/crates/feltdb-server/README.md +6 -1
- package/dist/create/server-source/crates/feltdb-server/src/app_state.rs +9 -1
- package/dist/create/server-source/crates/feltdb-server/src/auth.rs +85 -25
- package/dist/create/server-source/crates/feltdb-server/src/backup.rs +4 -0
- package/dist/create/server-source/crates/feltdb-server/src/console_accounts.rs +1009 -0
- package/dist/create/server-source/crates/feltdb-server/src/control_authorization.rs +441 -0
- package/dist/create/server-source/crates/feltdb-server/src/identity.rs +68 -6
- package/dist/create/server-source/crates/feltdb-server/src/key_management.rs +355 -23
- package/dist/create/server-source/crates/feltdb-server/src/lib.rs +3 -0
- package/dist/create/server-source/crates/feltdb-server/src/main.rs +879 -84
- package/dist/create/server-source/crates/feltdb-server/src/redaction.rs +208 -0
- package/dist/create/server-source/crates/feltdb-server/src/tenancy.rs +198 -19
- package/dist/create/server-source/crates/feltdb-server/tests/transaction_precondition_contract.rs +403 -0
- package/dist/db.d.ts +64 -9
- package/dist/db.d.ts.map +1 -1
- package/dist/db.js +153 -27
- package/dist/deployment.d.ts +19 -0
- package/dist/deployment.d.ts.map +1 -1
- package/dist/deployment.js +38 -2
- package/dist/embedded-query.d.ts.map +1 -1
- package/dist/embedded-query.js +5 -4
- package/dist/embedded-transaction.d.ts +8 -4
- package/dist/embedded-transaction.d.ts.map +1 -1
- package/dist/embedded-transaction.js +55 -19
- package/dist/error-codes.d.ts +31 -2
- package/dist/error-codes.d.ts.map +1 -1
- package/dist/error-codes.js +41 -2
- package/dist/feltdb.d.ts +7 -0
- package/dist/feltdb.d.ts.map +1 -1
- package/dist/file-db.d.ts +27 -0
- package/dist/file-db.d.ts.map +1 -1
- package/dist/file-db.js +145 -7
- package/dist/http-client.d.ts +11 -3
- package/dist/http-client.d.ts.map +1 -1
- package/dist/http-client.js +27 -14
- package/dist/http-db.d.ts +27 -1
- package/dist/http-db.d.ts.map +1 -1
- package/dist/http-db.js +252 -54
- package/dist/index.js +1 -1
- package/dist/local-state-lock.d.ts +34 -0
- package/dist/local-state-lock.d.ts.map +1 -0
- package/dist/local-state-lock.js +225 -0
- package/dist/reactive-graph.d.ts +0 -3
- package/dist/reactive-graph.d.ts.map +1 -1
- package/dist/reactive-graph.js +11 -1
- package/dist/runtime-registry.d.ts +7 -2
- package/dist/runtime-registry.d.ts.map +1 -1
- package/dist/runtime-registry.js +2 -2
- package/dist/studio/components/index.js +1 -1
- package/dist/studio/{components-BSGmHfif.js → components-CJmzntBi.js} +2 -1
- package/dist/studio/index.js +1 -1
- package/dist/studio-app/assets/{feltdb_wasm-3hDngl1h.js → feltdb_wasm-BjM1ylL3.js} +1 -1
- package/dist/studio-app/assets/feltdb_wasm_bg-TseJn2Ax.wasm +0 -0
- package/dist/studio-app/assets/index-1wd0uKua.js +30 -0
- package/dist/studio-app/index.html +1 -1
- package/dist/transaction.d.ts +27 -11
- package/dist/transaction.d.ts.map +1 -1
- package/dist/transaction.js +20 -14
- package/dist/wasm/feltdb_wasm_bg.wasm +0 -0
- package/dist/wasm/package.json +1 -1
- package/dist/workload.d.ts +31 -3
- package/dist/workload.d.ts.map +1 -1
- package/dist/workload.js +28 -3
- package/package.json +1 -1
- package/dist/studio-app/assets/feltdb_wasm_bg-CFQT4gCy.wasm +0 -0
- package/dist/studio-app/assets/index-Dql1hS5m.js +0 -30
package/dist/agent-state.js
CHANGED
|
@@ -32,6 +32,13 @@ export const FELTDB_AGENT_CHECKPOINT_COLLECTION = '_feltdb.AgentCheckpoint';
|
|
|
32
32
|
export const FELTDB_AGENT_MEMORY_COLLECTION = '_feltdb.AgentMemory';
|
|
33
33
|
export const FELTDB_AGENT_HANDOFF_COLLECTION = '_feltdb.AgentHandoff';
|
|
34
34
|
export const AGENT_CONTEXT_FORMAT = 'feltdb.agent-context@1';
|
|
35
|
+
/**
|
|
36
|
+
* Index keys written beside every task head so `listTasks` can filter by
|
|
37
|
+
* project with an equality prefix. Derived from `scope.project` and `status`
|
|
38
|
+
* on every task write; never returned as part of an `AgentTask`.
|
|
39
|
+
*/
|
|
40
|
+
const TASK_PROJECT_FIELD = 'list_project';
|
|
41
|
+
const TASK_STATUS_PROJECT_FIELD = 'list_status_project';
|
|
35
42
|
/** Compound indexes every agent-state query is planned against. */
|
|
36
43
|
export const AGENT_STATE_INDEXES = [
|
|
37
44
|
{
|
|
@@ -54,9 +61,73 @@ export const AGENT_STATE_INDEXES = [
|
|
|
54
61
|
persistent: true,
|
|
55
62
|
},
|
|
56
63
|
},
|
|
64
|
+
// listTasks: one index per filter shape, each led by a distinct field, so
|
|
65
|
+
// every shape has exactly one compatible plan and none is a residual filter.
|
|
66
|
+
{
|
|
67
|
+
collection: FELTDB_AGENT_TASK_COLLECTION,
|
|
68
|
+
index: {
|
|
69
|
+
name: 'agent_tasks_by_updated',
|
|
70
|
+
type: 'compound',
|
|
71
|
+
fields: ['updated_at', 'id'],
|
|
72
|
+
directions: ['desc', 'asc'],
|
|
73
|
+
persistent: true,
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
collection: FELTDB_AGENT_TASK_COLLECTION,
|
|
78
|
+
index: {
|
|
79
|
+
name: 'agent_tasks_by_status_updated',
|
|
80
|
+
type: 'compound',
|
|
81
|
+
fields: ['status', 'updated_at', 'id'],
|
|
82
|
+
directions: ['asc', 'desc', 'asc'],
|
|
83
|
+
persistent: true,
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
collection: FELTDB_AGENT_TASK_COLLECTION,
|
|
88
|
+
index: {
|
|
89
|
+
name: 'agent_tasks_by_project_updated',
|
|
90
|
+
type: 'compound',
|
|
91
|
+
fields: [TASK_PROJECT_FIELD, 'updated_at', 'id'],
|
|
92
|
+
directions: ['asc', 'desc', 'asc'],
|
|
93
|
+
persistent: true,
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
collection: FELTDB_AGENT_TASK_COLLECTION,
|
|
98
|
+
index: {
|
|
99
|
+
name: 'agent_tasks_by_status_project_updated',
|
|
100
|
+
type: 'compound',
|
|
101
|
+
fields: [TASK_STATUS_PROJECT_FIELD, 'updated_at', 'id'],
|
|
102
|
+
directions: ['asc', 'desc', 'asc'],
|
|
103
|
+
persistent: true,
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
// listHandoffs
|
|
107
|
+
{
|
|
108
|
+
collection: FELTDB_AGENT_HANDOFF_COLLECTION,
|
|
109
|
+
index: {
|
|
110
|
+
name: 'agent_handoffs_by_created',
|
|
111
|
+
type: 'compound',
|
|
112
|
+
fields: ['created_at', 'id'],
|
|
113
|
+
directions: ['desc', 'asc'],
|
|
114
|
+
persistent: true,
|
|
115
|
+
},
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
collection: FELTDB_AGENT_HANDOFF_COLLECTION,
|
|
119
|
+
index: {
|
|
120
|
+
name: 'agent_handoffs_by_status_created',
|
|
121
|
+
type: 'compound',
|
|
122
|
+
fields: ['status', 'created_at', 'id'],
|
|
123
|
+
directions: ['asc', 'desc', 'asc'],
|
|
124
|
+
persistent: true,
|
|
125
|
+
},
|
|
126
|
+
},
|
|
57
127
|
];
|
|
58
128
|
const TASK_STATUSES = ['ready', 'running', 'blocked', 'completed', 'cancelled'];
|
|
59
129
|
const TERMINAL = ['completed', 'cancelled'];
|
|
130
|
+
const HANDOFF_STATUSES = ['open', 'claimed', 'accepted'];
|
|
60
131
|
/** Every refusal. A refused write committed nothing. */
|
|
61
132
|
export class AgentStateError extends Error {
|
|
62
133
|
code;
|
|
@@ -150,6 +221,26 @@ function strip(row) {
|
|
|
150
221
|
const { id: _id, __version, ...rest } = row;
|
|
151
222
|
return { ...rest, revision: typeof __version === 'number' ? __version : 1 };
|
|
152
223
|
}
|
|
224
|
+
/** A task row without its derived index keys. */
|
|
225
|
+
function toTask(row) {
|
|
226
|
+
const { [TASK_PROJECT_FIELD]: _project, [TASK_STATUS_PROJECT_FIELD]: _statusProject, ...task } = strip(row);
|
|
227
|
+
return task;
|
|
228
|
+
}
|
|
229
|
+
/** A task head as written: the task plus the index keys `listTasks` filters on. */
|
|
230
|
+
function taskHead(task) {
|
|
231
|
+
const project = task.scope?.project;
|
|
232
|
+
return {
|
|
233
|
+
...task,
|
|
234
|
+
...(project === undefined ? {} : {
|
|
235
|
+
[TASK_PROJECT_FIELD]: project,
|
|
236
|
+
[TASK_STATUS_PROJECT_FIELD]: statusProjectKey(task.status, project),
|
|
237
|
+
}),
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
function statusProjectKey(status, project) {
|
|
241
|
+
// A status never contains '|', so the first '|' separates the two.
|
|
242
|
+
return `${status}|${project}`;
|
|
243
|
+
}
|
|
153
244
|
function version(row) {
|
|
154
245
|
return typeof row.__version === 'number' ? row.__version : 1;
|
|
155
246
|
}
|
|
@@ -270,7 +361,7 @@ export class AgentStateStore {
|
|
|
270
361
|
};
|
|
271
362
|
try {
|
|
272
363
|
await this.db.transaction(tx => {
|
|
273
|
-
tx.collection(FELTDB_AGENT_TASK_COLLECTION).set(taskId, task, { requireAbsent: true });
|
|
364
|
+
tx.collection(FELTDB_AGENT_TASK_COLLECTION).set(taskId, taskHead(task), { requireAbsent: true });
|
|
274
365
|
tx.collection(FELTDB_AGENT_CHECKPOINT_COLLECTION).set(checkpoint.checkpoint_id, checkpoint, { requireAbsent: true });
|
|
275
366
|
});
|
|
276
367
|
}
|
|
@@ -286,7 +377,7 @@ export class AgentStateStore {
|
|
|
286
377
|
const row = await this.taskRow(identifier(taskId, 'taskId'));
|
|
287
378
|
if (!row)
|
|
288
379
|
return null;
|
|
289
|
-
const task =
|
|
380
|
+
const task = toTask(row);
|
|
290
381
|
const checkpoint = await this.getCheckpoint(task.task_id, task.checkpoint_version);
|
|
291
382
|
if (!checkpoint) {
|
|
292
383
|
throw fail('NOT_FOUND', `task ${taskId} names checkpoint ${task.checkpoint_version}, which is not committed`);
|
|
@@ -300,6 +391,30 @@ export class AgentStateStore {
|
|
|
300
391
|
const { revision: _revision, ...checkpoint } = strip(row);
|
|
301
392
|
return checkpoint;
|
|
302
393
|
}
|
|
394
|
+
/**
|
|
395
|
+
* One bounded page of tasks, most recently updated first (ties by task id),
|
|
396
|
+
* optionally narrowed to a status and/or a project.
|
|
397
|
+
*
|
|
398
|
+
* Every filter shape is answered by one declared compound index with an
|
|
399
|
+
* equality prefix; nothing reads the whole collection. Continue with
|
|
400
|
+
* `cursor: page.nextCursor` and the same filters.
|
|
401
|
+
*/
|
|
402
|
+
async listTasks(input = {}) {
|
|
403
|
+
if (input.status !== undefined && !TASK_STATUSES.includes(input.status)) {
|
|
404
|
+
throw fail('INVALID_REQUEST', `status must be one of ${TASK_STATUSES.join(', ')}`);
|
|
405
|
+
}
|
|
406
|
+
const project = input.project === undefined ? undefined : name(input.project, 'project');
|
|
407
|
+
const where = project === undefined
|
|
408
|
+
? (input.status === undefined ? [] : [{ field: 'status', eq: input.status }])
|
|
409
|
+
: input.status === undefined
|
|
410
|
+
? [{ field: TASK_PROJECT_FIELD, eq: project }]
|
|
411
|
+
: [{ field: TASK_STATUS_PROJECT_FIELD, eq: statusProjectKey(input.status, project) }];
|
|
412
|
+
const page = await this.page(FELTDB_AGENT_TASK_COLLECTION, where, 'updated_at', input.limit, input.cursor);
|
|
413
|
+
return {
|
|
414
|
+
tasks: page.records.map(toTask),
|
|
415
|
+
...(page.nextCursor ? { nextCursor: page.nextCursor } : {}),
|
|
416
|
+
};
|
|
417
|
+
}
|
|
303
418
|
/**
|
|
304
419
|
* Commit checkpoint N+1 atomically with the task head.
|
|
305
420
|
*
|
|
@@ -323,7 +438,7 @@ export class AgentStateStore {
|
|
|
323
438
|
throw fail('INVALID_REQUEST', `evidence must be an array of at most ${LIST_LIMIT} references`);
|
|
324
439
|
}
|
|
325
440
|
const row = await this.requireTask(id);
|
|
326
|
-
const task =
|
|
441
|
+
const task = toTask(row);
|
|
327
442
|
if (input.expectedVersion !== undefined && input.expectedVersion !== task.checkpoint_version) {
|
|
328
443
|
throw fail('VERSION_CONFLICT', `task ${id} is at checkpoint ${task.checkpoint_version}, not ${input.expectedVersion}`, {
|
|
329
444
|
expected: input.expectedVersion, current: task.checkpoint_version,
|
|
@@ -369,7 +484,7 @@ export class AgentStateStore {
|
|
|
369
484
|
};
|
|
370
485
|
try {
|
|
371
486
|
await this.db.transaction(tx => {
|
|
372
|
-
tx.collection(FELTDB_AGENT_TASK_COLLECTION).set(id, head, { ifVersion: version(row) });
|
|
487
|
+
tx.collection(FELTDB_AGENT_TASK_COLLECTION).set(id, taskHead(head), { ifVersion: version(row) });
|
|
373
488
|
tx.collection(FELTDB_AGENT_CHECKPOINT_COLLECTION).set(next.checkpoint_id, next, { requireAbsent: true });
|
|
374
489
|
for (const entry of cited) {
|
|
375
490
|
if (entry.evidence.kind === 'record') {
|
|
@@ -400,7 +515,7 @@ export class AgentStateStore {
|
|
|
400
515
|
*/
|
|
401
516
|
async resume(taskId, input) {
|
|
402
517
|
const row = await this.requireTask(identifier(taskId, 'taskId'));
|
|
403
|
-
this.assertOwner(
|
|
518
|
+
this.assertOwner(toTask(row), name(input.actor, 'actor'));
|
|
404
519
|
return this.assembleContext(taskId, input);
|
|
405
520
|
}
|
|
406
521
|
// --------------------------------------------------------------- memory
|
|
@@ -414,7 +529,7 @@ export class AgentStateStore {
|
|
|
414
529
|
const scopeKey = memoryScopeKey(scope);
|
|
415
530
|
if (taskId || scope.kind === 'task') {
|
|
416
531
|
const owningTask = taskId ?? scope.taskId;
|
|
417
|
-
const task =
|
|
532
|
+
const task = toTask(await this.requireTask(owningTask));
|
|
418
533
|
if (scope.kind === 'task' && scope.taskId !== task.task_id) {
|
|
419
534
|
throw fail('INVALID_REQUEST', `memory for task ${task.task_id} cannot be written to task scope ${scope.taskId}`);
|
|
420
535
|
}
|
|
@@ -481,7 +596,7 @@ export class AgentStateStore {
|
|
|
481
596
|
* its workspace. A memory scoped to another task is never returned.
|
|
482
597
|
*/
|
|
483
598
|
async recallForTask(taskId, input = {}) {
|
|
484
|
-
const task =
|
|
599
|
+
const task = toTask(await this.requireTask(identifier(taskId, 'taskId')));
|
|
485
600
|
const limit = boundedLimit(input.limit, 20, 100);
|
|
486
601
|
const scopes = [
|
|
487
602
|
{ kind: 'task', taskId: task.task_id },
|
|
@@ -572,7 +687,7 @@ export class AgentStateStore {
|
|
|
572
687
|
const actor = name(input.actor, 'actor');
|
|
573
688
|
const to = input.to === undefined ? undefined : name(input.to, 'to');
|
|
574
689
|
const row = await this.requireTask(id);
|
|
575
|
-
const task =
|
|
690
|
+
const task = toTask(row);
|
|
576
691
|
this.assertOwner(task, actor);
|
|
577
692
|
if (TERMINAL.includes(task.status))
|
|
578
693
|
throw fail('INVALID_TRANSITION', `task ${id} is ${task.status}; it cannot be handed off`);
|
|
@@ -633,12 +748,34 @@ export class AgentStateStore {
|
|
|
633
748
|
}
|
|
634
749
|
return resolveHandoff({ ...record, revision: 1 }, task, checkpoint);
|
|
635
750
|
}
|
|
751
|
+
/**
|
|
752
|
+
* One bounded page of handoff records, newest first (ties by handoff id).
|
|
753
|
+
* `open: true` lists the handoffs nobody has claimed yet. Indexed; never a
|
|
754
|
+
* collection scan.
|
|
755
|
+
*/
|
|
756
|
+
async listHandoffs(input = {}) {
|
|
757
|
+
if (input.open === false) {
|
|
758
|
+
throw fail('INVALID_REQUEST', "open: false is ambiguous; pass status: 'claimed' or 'accepted'");
|
|
759
|
+
}
|
|
760
|
+
if (input.status !== undefined && !HANDOFF_STATUSES.includes(input.status)) {
|
|
761
|
+
throw fail('INVALID_REQUEST', `status must be one of ${HANDOFF_STATUSES.join(', ')}`);
|
|
762
|
+
}
|
|
763
|
+
if (input.open && input.status !== undefined && input.status !== 'open') {
|
|
764
|
+
throw fail('INVALID_REQUEST', `open: true contradicts status: '${input.status}'`);
|
|
765
|
+
}
|
|
766
|
+
const status = input.open ? 'open' : input.status;
|
|
767
|
+
const page = await this.page(FELTDB_AGENT_HANDOFF_COLLECTION, status === undefined ? [] : [{ field: 'status', eq: status }], 'created_at', input.limit, input.cursor);
|
|
768
|
+
return {
|
|
769
|
+
handoffs: page.records.map(row => strip(row)),
|
|
770
|
+
...(page.nextCursor ? { nextCursor: page.nextCursor } : {}),
|
|
771
|
+
};
|
|
772
|
+
}
|
|
636
773
|
async getHandoff(handoffId) {
|
|
637
774
|
const row = await this.db.collection(FELTDB_AGENT_HANDOFF_COLLECTION).get(identifier(handoffId, 'handoffId', 128));
|
|
638
775
|
if (!row)
|
|
639
776
|
return null;
|
|
640
777
|
const record = strip(row);
|
|
641
|
-
const task =
|
|
778
|
+
const task = toTask(await this.requireTask(record.task_id));
|
|
642
779
|
const checkpoint = await this.getCheckpoint(record.task_id, record.checkpoint_version);
|
|
643
780
|
if (!checkpoint)
|
|
644
781
|
throw fail('NOT_FOUND', `handoff ${handoffId} references checkpoint ${record.checkpoint_version}, which is not committed`);
|
|
@@ -664,7 +801,7 @@ export class AgentStateStore {
|
|
|
664
801
|
const first = await handoffs.get(id);
|
|
665
802
|
if (!first)
|
|
666
803
|
throw fail('NOT_FOUND', `handoff ${id} does not exist`);
|
|
667
|
-
const task =
|
|
804
|
+
const task = toTask(await this.requireTask(strip(first).task_id));
|
|
668
805
|
// Decide on a handoff read taken after the task read. A claim commits both
|
|
669
806
|
// records together, so this pair can never show a claimed task beside an
|
|
670
807
|
// open handoff, which would misreport a lost race as a stale handoff.
|
|
@@ -710,7 +847,7 @@ export class AgentStateStore {
|
|
|
710
847
|
try {
|
|
711
848
|
await this.db.transaction(tx => {
|
|
712
849
|
tx.collection(FELTDB_AGENT_HANDOFF_COLLECTION).set(id, claimed, { ifVersion: handoff.revision });
|
|
713
|
-
tx.collection(FELTDB_AGENT_TASK_COLLECTION).set(task.task_id, head, { ifVersion: task.revision });
|
|
850
|
+
tx.collection(FELTDB_AGENT_TASK_COLLECTION).set(task.task_id, taskHead(head), { ifVersion: task.revision });
|
|
714
851
|
});
|
|
715
852
|
}
|
|
716
853
|
catch (error) {
|
|
@@ -760,7 +897,7 @@ export class AgentStateStore {
|
|
|
760
897
|
}
|
|
761
898
|
throw error;
|
|
762
899
|
}
|
|
763
|
-
const task =
|
|
900
|
+
const task = toTask(await this.requireTask(handoff.task_id));
|
|
764
901
|
return this.resolveRecord({ ...accepted, revision: handoff.revision + 1 }, task);
|
|
765
902
|
}
|
|
766
903
|
// -------------------------------------------------------------- context
|
|
@@ -894,6 +1031,31 @@ export class AgentStateStore {
|
|
|
894
1031
|
return bundle;
|
|
895
1032
|
}
|
|
896
1033
|
// ------------------------------------------------------------- internal
|
|
1034
|
+
async page(collection, where, newestFirst, limit, cursor) {
|
|
1035
|
+
if (cursor !== undefined && (typeof cursor !== 'string' || !cursor)) {
|
|
1036
|
+
throw fail('INVALID_REQUEST', 'cursor must be the nextCursor of a previous page');
|
|
1037
|
+
}
|
|
1038
|
+
let page;
|
|
1039
|
+
try {
|
|
1040
|
+
page = await this.db.query({
|
|
1041
|
+
collection,
|
|
1042
|
+
...(where.length ? { where } : {}),
|
|
1043
|
+
orderBy: [{ field: newestFirst, direction: 'desc' }],
|
|
1044
|
+
limit: boundedLimit(limit, 50, 1_000),
|
|
1045
|
+
...(cursor ? { cursor } : {}),
|
|
1046
|
+
});
|
|
1047
|
+
}
|
|
1048
|
+
catch (error) {
|
|
1049
|
+
if (/INVALID_CURSOR/.test(error instanceof Error ? error.message : String(error))) {
|
|
1050
|
+
throw fail('INVALID_REQUEST', 'cursor does not belong to this query; pass the nextCursor of a page with the same filters');
|
|
1051
|
+
}
|
|
1052
|
+
throw error;
|
|
1053
|
+
}
|
|
1054
|
+
return {
|
|
1055
|
+
records: page.records,
|
|
1056
|
+
...(page.nextCursor && !page.exhausted ? { nextCursor: page.nextCursor } : {}),
|
|
1057
|
+
};
|
|
1058
|
+
}
|
|
897
1059
|
async taskRow(taskId) {
|
|
898
1060
|
return this.db.collection(FELTDB_AGENT_TASK_COLLECTION).get(taskId);
|
|
899
1061
|
}
|
package/dist/agent.d.ts
CHANGED
|
@@ -19,7 +19,11 @@ export interface AgentRef {
|
|
|
19
19
|
toString(): string;
|
|
20
20
|
}
|
|
21
21
|
/**
|
|
22
|
-
* Lifecycle states for agent execution
|
|
22
|
+
* Lifecycle states for agent execution.
|
|
23
|
+
*
|
|
24
|
+
* `Completed`, `Failed` and `Cancelled` are terminal. `Cancelled` is reachable
|
|
25
|
+
* from every non-terminal state, through `AgentRuntime.cancel` or
|
|
26
|
+
* `transition(execution, Cancelled)`.
|
|
23
27
|
*/
|
|
24
28
|
export declare enum AgentExecutionStatus {
|
|
25
29
|
Created = "Created",
|
|
@@ -113,6 +117,10 @@ export interface AgentExecution {
|
|
|
113
117
|
completedMs?: number;
|
|
114
118
|
/** Optional error message if execution failed */
|
|
115
119
|
error?: string;
|
|
120
|
+
/** The agent-state task this execution works on, when it was created for one. */
|
|
121
|
+
taskId?: string;
|
|
122
|
+
/** Why the execution was cancelled (status `Cancelled`). */
|
|
123
|
+
cancelReason?: string;
|
|
116
124
|
/** Metadata about the execution */
|
|
117
125
|
metadata?: Record<string, any>;
|
|
118
126
|
}
|
|
@@ -120,6 +128,7 @@ export interface AgentExecution {
|
|
|
120
128
|
* Parse an agent reference from its canonical form
|
|
121
129
|
* @example parseAgentRef("flow://agent/researcher@1")
|
|
122
130
|
*/
|
|
131
|
+
export declare const AGENT_EXECUTION_TERMINAL_STATUSES: readonly AgentExecutionStatus[];
|
|
123
132
|
export declare function parseAgentRef(ref: string): AgentRef;
|
|
124
133
|
/**
|
|
125
134
|
* Create an agent reference
|
package/dist/agent.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;;;GAIG;AACH,MAAM,WAAW,QAAQ;IACvB,iBAAiB;IACjB,IAAI,EAAE,MAAM,CAAC;IAEb,oBAAoB;IACpB,OAAO,EAAE,MAAM,CAAC;IAEhB,0BAA0B;IAC1B,QAAQ,IAAI,MAAM,CAAC;CACpB;AAED
|
|
1
|
+
{"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"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"}
|
package/dist/agent.js
CHANGED
|
@@ -6,7 +6,11 @@
|
|
|
6
6
|
* of the same causal graph.
|
|
7
7
|
*/
|
|
8
8
|
/**
|
|
9
|
-
* Lifecycle states for agent execution
|
|
9
|
+
* Lifecycle states for agent execution.
|
|
10
|
+
*
|
|
11
|
+
* `Completed`, `Failed` and `Cancelled` are terminal. `Cancelled` is reachable
|
|
12
|
+
* from every non-terminal state, through `AgentRuntime.cancel` or
|
|
13
|
+
* `transition(execution, Cancelled)`.
|
|
10
14
|
*/
|
|
11
15
|
export var AgentExecutionStatus;
|
|
12
16
|
(function (AgentExecutionStatus) {
|
|
@@ -25,6 +29,11 @@ export var AgentExecutionStatus;
|
|
|
25
29
|
* Parse an agent reference from its canonical form
|
|
26
30
|
* @example parseAgentRef("flow://agent/researcher@1")
|
|
27
31
|
*/
|
|
32
|
+
export const AGENT_EXECUTION_TERMINAL_STATUSES = [
|
|
33
|
+
AgentExecutionStatus.Completed,
|
|
34
|
+
AgentExecutionStatus.Failed,
|
|
35
|
+
AgentExecutionStatus.Cancelled,
|
|
36
|
+
];
|
|
28
37
|
export function parseAgentRef(ref) {
|
|
29
38
|
const match = ref.match(/^flow:\/\/agent\/([^@]+)@(\d+)$/);
|
|
30
39
|
if (!match) {
|
package/dist/build-identity.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schema": "feltdb.build-identity.v2",
|
|
3
3
|
"package": "@feltdb/core",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.15.0",
|
|
5
5
|
"git": {
|
|
6
|
-
"sha1": "
|
|
6
|
+
"sha1": "5ad54972a9e31a5459cadbb471428111624ec9c6",
|
|
7
7
|
"dirty": false
|
|
8
8
|
},
|
|
9
9
|
"path_in_vcs": "packages/core",
|
|
10
|
-
"source_digest": "sha256:
|
|
10
|
+
"source_digest": "sha256:01efc5737aae1fef37c976e5841df3bb9b615d034f31d27b038f7fd4ca202428",
|
|
11
11
|
"inputs": [
|
|
12
12
|
"Cargo.lock",
|
|
13
13
|
"Cargo.toml",
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"tools/cli",
|
|
21
21
|
"tools/create-feltdb"
|
|
22
22
|
],
|
|
23
|
-
"files":
|
|
23
|
+
"files": 789,
|
|
24
24
|
"build": {
|
|
25
25
|
"command": "npm run build",
|
|
26
26
|
"node": "v24.9.0"
|
package/dist/cli/commands.js
CHANGED
|
@@ -40,6 +40,27 @@ function loadProjectEnvironment(file = path.resolve('.env.local')) {
|
|
|
40
40
|
if (!(key in process.env))
|
|
41
41
|
process.env[key] = value;
|
|
42
42
|
}
|
|
43
|
+
warnBrowserExposedCredentials();
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Credentials under a `VITE_` name are inlined into the application's browser
|
|
47
|
+
* bundle by Vite, so they are no longer read as credentials anywhere. Say so,
|
|
48
|
+
* rather than silently dropping authentication a project used to have.
|
|
49
|
+
*/
|
|
50
|
+
function warnBrowserExposedCredentials() {
|
|
51
|
+
for (const name of Object.keys(process.env)) {
|
|
52
|
+
if (/^VITE_[A-Z0-9_]*(?:TOKEN|API_KEY|SECRET)$/.test(name) && process.env[name]) {
|
|
53
|
+
console.warn(`⚠ ${name} is ignored: VITE_* variables are inlined into browser bundles. Move the credential to FELTDB_TOKEN (server-side only).`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* The local `feltdb dev` Studio is an operator console on localhost. It
|
|
59
|
+
* receives the developer's server-side key at runtime (no-store), never from a
|
|
60
|
+
* bundled VITE_* value.
|
|
61
|
+
*/
|
|
62
|
+
function studioOperatorToken() {
|
|
63
|
+
return process.env.FELTDB_TOKEN || '';
|
|
43
64
|
}
|
|
44
65
|
async function availablePort(preferred, host = '127.0.0.1') {
|
|
45
66
|
for (let port = preferred; port < preferred + 100; port += 1) {
|
|
@@ -831,8 +852,8 @@ async function handleConnect(args) {
|
|
|
831
852
|
let health;
|
|
832
853
|
try {
|
|
833
854
|
const response = await fetch(`${url}/health`, {
|
|
834
|
-
headers: process.env.FELTDB_TOKEN
|
|
835
|
-
? { Authorization: `Bearer ${process.env.FELTDB_TOKEN
|
|
855
|
+
headers: process.env.FELTDB_TOKEN
|
|
856
|
+
? { Authorization: `Bearer ${process.env.FELTDB_TOKEN}` }
|
|
836
857
|
: {},
|
|
837
858
|
signal: controller.signal,
|
|
838
859
|
});
|
|
@@ -855,14 +876,14 @@ async function handleConnect(args) {
|
|
|
855
876
|
fs.writeFileSync(connFile, JSON.stringify({
|
|
856
877
|
url,
|
|
857
878
|
connected: new Date().toISOString(),
|
|
858
|
-
authenticated: Boolean(process.env.FELTDB_TOKEN
|
|
879
|
+
authenticated: Boolean(process.env.FELTDB_TOKEN),
|
|
859
880
|
namespace: managed.namespace || project.namespace || 'default',
|
|
860
881
|
runtime: project.runtime || 'self-hosted',
|
|
861
882
|
}, null, 2));
|
|
862
883
|
console.log('✅ Connected to FeltDB\n');
|
|
863
884
|
console.log('Endpoint: ' + url);
|
|
864
885
|
console.log(`Namespace: ${managed.namespace || project.namespace || 'default'}`);
|
|
865
|
-
console.log(`Authenticated: ${process.env.FELTDB_TOKEN
|
|
886
|
+
console.log(`Authenticated: ${process.env.FELTDB_TOKEN ? 'yes' : 'no'}`);
|
|
866
887
|
console.log(`Runtime: ${project.runtime || 'self-hosted'}`);
|
|
867
888
|
console.log(`Health: ${health.status || 'healthy'}\n`);
|
|
868
889
|
console.log('Use: feltdb status (to check connection)\n');
|
|
@@ -1894,7 +1915,7 @@ async function handleStudio(args, onReady) {
|
|
|
1894
1915
|
environment: managedProject.environment || 'production',
|
|
1895
1916
|
publishEndpoint: '/_feltdb/publish',
|
|
1896
1917
|
} : undefined;
|
|
1897
|
-
response.end(JSON.stringify({ token: connectUrl ?
|
|
1918
|
+
response.end(JSON.stringify({ token: connectUrl ? studioOperatorToken() : '', managedPublish, session, studioQuery, sourceSync: { enabled: true, webllmEnabled, previewOnly, token: studioMutationToken, aiModel: publicAiModelConfiguration() } }));
|
|
1898
1919
|
return;
|
|
1899
1920
|
}
|
|
1900
1921
|
if (pathname === '/_feltdb/contract') {
|
|
@@ -1913,7 +1934,7 @@ async function handleStudio(args, onReady) {
|
|
|
1913
1934
|
endpoint.searchParams.set('application_id', applicationId);
|
|
1914
1935
|
endpoint.searchParams.set('environment', managedProject.environment || lastPublished?.environment || 'production');
|
|
1915
1936
|
const headers = {};
|
|
1916
|
-
const credential = process.env.FELTDB_MANAGED_CONTROL_API_KEY || process.env.
|
|
1937
|
+
const credential = process.env.FELTDB_MANAGED_CONTROL_API_KEY || process.env.FELTDB_TOKEN;
|
|
1917
1938
|
if (credential)
|
|
1918
1939
|
headers.authorization = `Bearer ${credential}`;
|
|
1919
1940
|
const discovered = await fetch(endpoint, { headers });
|
package/dist/collection.d.ts
CHANGED
|
@@ -359,7 +359,9 @@ export declare class Collection<T> {
|
|
|
359
359
|
/**
|
|
360
360
|
* Refresh data from the database and notify subscribers.
|
|
361
361
|
*/
|
|
362
|
-
refresh(
|
|
362
|
+
refresh(options?: {
|
|
363
|
+
strict?: boolean;
|
|
364
|
+
}): Promise<void>;
|
|
363
365
|
}
|
|
364
366
|
/**
|
|
365
367
|
* Relationship helper for loading related data.
|
package/dist/collection.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"collection.d.ts","sourceRoot":"","sources":["../src/collection.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"collection.d.ts","sourceRoot":"","sources":["../src/collection.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAIL,KAAK,mBAAmB,EACxB,KAAK,QAAQ,EACd,MAAM,gBAAgB,CAAC;AAMxB,OAAO,KAAK,EAAE,WAAW,EAAc,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAErF,6CAA6C;AAC7C,MAAM,WAAW,aAAa;IAC5B;;;;;OAKG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAKD,MAAM,MAAM,SAAS,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC;AAChD,MAAM,MAAM,UAAU,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,EAAE,KAAK,IAAI,CAAC;AAEjD,MAAM,WAAW,qBAAqB;IACpC,OAAO,CAAC,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,KAAK,GAAG,MAAM,CAAA;KAAE,CAAC,CAAC;IAC9D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAqCD;;;;;;GAMG;AACH,MAAM,WAAW,cAAc;IAC7B,gGAAgG;IAChG,UAAU,EAAE,UAAU,GAAG,SAAS,CAAC;IACnC,4EAA4E;IAC5E,eAAe,EAAE,OAAO,CAAC;IACzB,oEAAoE;IACpE,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,mCAAmC;IACnC,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;GAGG;AACH,MAAM,WAAW,qBAAqB,CAAC,CAAC;IACtC,mCAAmC;IACnC,OAAO,EAAE,OAAO,CAAC;IACjB,iEAAiE;IACjE,IAAI,CAAC,EAAE,CAAC,GAAG;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IACjC,+DAA+D;IAC/D,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,wDAAwD;IACxD,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;;;GAKG;AACH,qBAAa,UAAU,CAAC,CAAC;IACvB,OAAO,CAAC,EAAE,CAAO;IACjB,OAAO,CAAC,IAAI,CAAS;IACrB,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,SAAS,CAA6B;IAC9C,OAAO,CAAC,KAAK,CAAW;IACxB,OAAO,CAAC,WAAW,CAAiC;IACpD,OAAO,CAAC,MAAM,CAA8B;IAC5C,OAAO,CAAC,QAAQ,CAAuB;IACvC,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,oBAAoB,CAA8B;IAC1D,OAAO,CAAC,gBAAgB,CAA6B;IACrD,OAAO,CAAC,kBAAkB,CAA6B;IACvD,OAAO,CAAC,YAAY,CAAoC;IACxD,iGAAiG;IACjG,OAAO,CAAC,eAAe,CAAkC;IACzD,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,aAAa,CAAS;IAC9B,mFAAmF;IACnF,OAAO,CAAC,eAAe,CAAK;IAC5B,gFAAgF;IAChF,OAAO,CAAC,iBAAiB,CAAM;IAC/B,OAAO,CAAC,QAAQ,CAAoC;IACpD,oEAAoE;IACpE,OAAO,CAAC,WAAW,CAA+B;IAClD,kFAAkF;IAClF,OAAO,CAAC,eAAe,CAAuB;IAC9C;;;;;;;OAOG;IACH,OAAO,CAAC,cAAc,CAAyB;IAC/C,yEAAyE;IACzE,OAAO,CAAC,aAAa,CAA+B;gBAExC,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC,EAAE,WAAW,UAAO;IAoBxG;;OAEG;YACW,oBAAoB;IAelC;;;OAGG;IACG,GAAG,IAAI,OAAO,CAAC,CAAC,EAAE,CAAC;IAOzB,qEAAqE;IAC/D,IAAI,IAAI,OAAO,CAAC,CAAC,EAAE,CAAC;IAI1B;;;;;;;;;;;;;OAaG;IACG,IAAI,CAAC,KAAK,GAAE,OAAO,CAAC,CAAC,CAAM,EAAE,OAAO,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC;IAuFjF,6EAA6E;IACvE,KAAK,CAAC,KAAK,GAAE,OAAO,CAAC,CAAC,CAAM,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC;IAIjD;;;;;OAKG;IACH,aAAa,IAAI,mBAAmB,GAAG,IAAI;IAI3C,wEAAwE;IACxE,OAAO,CAAC,QAAQ;IAWhB;;;;;;OAMG;IACH,OAAO,CAAC,eAAe;IAiBvB;;;;;;OAMG;IACH,OAAO,CAAC,wBAAwB;IA0BhC;;;;;OAKG;IACH,WAAW,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI;IAatC;;OAEG;IACH,WAAW,IAAI,WAAW,EAAE;IAI5B;;;OAGG;IACG,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;IAgBrC;;OAEG;IACG,eAAe,IAAI,OAAO,CAAC,OAAO,CAAC;IAazC;;OAEG;IACG,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC;IAYjD;;;OAGG;IACH,KAAK,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC;IAO7C;;;;;;;;;;;;;;;OAeG;IACG,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,OAAO,CAAC,MAAM,CAAC;IAmDlG,qEAAqE;IAC/D,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAIlE;;;;;;;;;;;OAWG;IACG,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAsBrE,8EAA8E;YAChE,cAAc;IAc5B,wGAAwG;IACxG,OAAO,CAAC,gBAAgB;IAMxB,4EAA4E;YAC9D,OAAO;IAYrB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAgCG;IACG,eAAe,CACnB,EAAE,EAAE,MAAM,GAAG,MAAM,EACnB,eAAe,EAAE,MAAM,EACvB,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,EACnB,aAAa,CAAC,EAAE,MAAM,EACtB,eAAe,CAAC,EAAE,MAAM,EACxB,gBAAgB,CAAC,EAAE,OAAO,EAC1B,YAAY,CAAC,EAAE,CAAC,GACf,OAAO,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC;IA6EpC;;OAEG;IACG,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAgChD;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC;IAK9B;;OAEG;IACG,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAKnD;;;;;;OAMG;IACH,OAAO,CAAC,SAAS;IAKjB;;;;;;;;OAQG;YACW,6BAA6B;IAkC3C;;;;;OAKG;YACW,iCAAiC;IAyE/C;;;;;;;;;;;;;OAaG;IACG,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC;QAAE,QAAQ,EAAE,OAAO,CAAC;QAAC,KAAK,EAAE,CAAC,CAAA;KAAE,CAAC;IAsClG;;;OAGG;IACH,SAAS,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC,CAAC,EAAE,aAAa,CAAC,EAAE,MAAM,GAAG,MAAM,IAAI;IA6CxE,mEAAmE;IACnE,KAAK,IAAI,IAAI;IASb;;;;;;;;;;;OAWG;IACH,SAAS,IAAI,OAAO,CAAC,mBAAmB,CAAC;IAIzC;;;;;;OAMG;IACH,kBAAkB,IAAI,cAAc,GAAG,IAAI;IAI3C;;;;;;;;;OASG;YACW,eAAe;IAQ7B;;OAEG;IACG,OAAO,CAAC,OAAO,GAAE;QAAE,MAAM,CAAC,EAAE,OAAO,CAAA;KAAO,GAAG,OAAO,CAAC,IAAI,CAAC;CA6EjE;AAgBD;;GAEG;AACH,qBAAa,YAAY,CAAC,MAAM,EAAE,KAAK;IACrC,OAAO,CAAC,QAAQ,CAAO;IACvB,OAAO,CAAC,OAAO,CAAO;IACtB,OAAO,CAAC,eAAe,CAAS;IAChC,OAAO,CAAC,UAAU,CAAoC;gBAGpD,QAAQ,EAAE,IAAI,EACd,OAAO,EAAE,IAAI,EACb,eAAe,EAAE,MAAM,EACvB,UAAU,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,MAAM,GAAG,MAAM;IAQ/C;;OAEG;IACG,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,KAAK,EAAE,CAAC;CAoBxD"}
|
package/dist/collection.js
CHANGED
|
@@ -129,7 +129,9 @@ export class Collection {
|
|
|
129
129
|
* Returns cached results (live-updated).
|
|
130
130
|
*/
|
|
131
131
|
async all() {
|
|
132
|
-
|
|
132
|
+
// A read the authority refused, or could not answer, is raised typed --
|
|
133
|
+
// never answered from whatever this handle last cached.
|
|
134
|
+
await this.refresh({ strict: true });
|
|
133
135
|
return [...this.cache];
|
|
134
136
|
}
|
|
135
137
|
/** List records through the canonical application collection API. */
|
|
@@ -375,7 +377,7 @@ export class Collection {
|
|
|
375
377
|
const key = `${this.name}:${id}`;
|
|
376
378
|
const result = await this.db.get(key);
|
|
377
379
|
if (!result.success) {
|
|
378
|
-
throw
|
|
380
|
+
throw runtimeFailure(result, result.error || `Failed to read record ${id}`);
|
|
379
381
|
}
|
|
380
382
|
if (result.data) {
|
|
381
383
|
return JSON.parse(result.data);
|
|
@@ -421,7 +423,7 @@ export class Collection {
|
|
|
421
423
|
const stored = { ...data, id: recordId, __version: 1 };
|
|
422
424
|
const result = await this.db.insert(key, JSON.stringify(stored));
|
|
423
425
|
if (!result.success) {
|
|
424
|
-
throw
|
|
426
|
+
throw runtimeFailure(result, `Insert failed: ${result.error}`);
|
|
425
427
|
}
|
|
426
428
|
await this.publish('insert', key, String(recordId), null, stored);
|
|
427
429
|
return String(recordId);
|
|
@@ -614,9 +616,11 @@ export class Collection {
|
|
|
614
616
|
const result = await this.db.delete(key);
|
|
615
617
|
if (!result.success) {
|
|
616
618
|
const message = `Delete failed: ${result.error}`;
|
|
617
|
-
throw
|
|
618
|
-
?
|
|
619
|
-
:
|
|
619
|
+
throw result.cause
|
|
620
|
+
? runtimeFailure(result, message)
|
|
621
|
+
: /not found/i.test(String(result.error))
|
|
622
|
+
? new FeltDBServiceError(message, FeltDBErrorCode.NOT_FOUND)
|
|
623
|
+
: new Error(message);
|
|
620
624
|
}
|
|
621
625
|
// Update indexes - find and remove the deleted record
|
|
622
626
|
const deleted = await this.get(id);
|
|
@@ -686,7 +690,7 @@ export class Collection {
|
|
|
686
690
|
throw error;
|
|
687
691
|
const existing = await this.db.get(key);
|
|
688
692
|
if (!existing.success) {
|
|
689
|
-
throw
|
|
693
|
+
throw runtimeFailure(existing, existing.error || `could not read the record that won ${key}`);
|
|
690
694
|
}
|
|
691
695
|
if (!existing.data) {
|
|
692
696
|
throw new Error(`${key} was created and then removed while resolving a conditional create`);
|
|
@@ -914,7 +918,7 @@ export class Collection {
|
|
|
914
918
|
/**
|
|
915
919
|
* Refresh data from the database and notify subscribers.
|
|
916
920
|
*/
|
|
917
|
-
async refresh() {
|
|
921
|
+
async refresh(options = {}) {
|
|
918
922
|
try {
|
|
919
923
|
// The revision is read *before* the query, so it can only ever be older
|
|
920
924
|
// than the data it ends up labelling. The reverse ordering would let a
|
|
@@ -980,14 +984,32 @@ export class Collection {
|
|
|
980
984
|
}
|
|
981
985
|
}
|
|
982
986
|
else if (!result.success) {
|
|
987
|
+
if (options.strict)
|
|
988
|
+
throw runtimeFailure(result, result.error || `Failed to read ${this.name}`);
|
|
983
989
|
console.error('Query failed:', result.error);
|
|
984
990
|
}
|
|
985
991
|
}
|
|
986
992
|
catch (err) {
|
|
993
|
+
if (options.strict)
|
|
994
|
+
throw err;
|
|
987
995
|
console.error('Refresh error:', err);
|
|
988
996
|
}
|
|
989
997
|
}
|
|
990
998
|
}
|
|
999
|
+
/**
|
|
1000
|
+
* The error a failed runtime result is raised as. A remote runtime attaches
|
|
1001
|
+
* the authority's typed refusal (`cause`): its stable code, status, request id
|
|
1002
|
+
* and body travel on, so an unauthenticated, cross-application or interrupted
|
|
1003
|
+
* operation is never a bare `Error` with the code only in its message.
|
|
1004
|
+
*/
|
|
1005
|
+
function runtimeFailure(result, message) {
|
|
1006
|
+
const cause = result.cause;
|
|
1007
|
+
if (!(cause instanceof FeltDBServiceError))
|
|
1008
|
+
return new Error(message);
|
|
1009
|
+
const error = new FeltDBServiceError(message, cause.code, cause.requestId, cause.status, cause.body);
|
|
1010
|
+
error.cause = cause;
|
|
1011
|
+
return error;
|
|
1012
|
+
}
|
|
991
1013
|
/**
|
|
992
1014
|
* Relationship helper for loading related data.
|
|
993
1015
|
*/
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schema": "feltdb.build-identity.v2",
|
|
3
3
|
"package": "create-feltdb",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.15.0",
|
|
5
5
|
"git": {
|
|
6
|
-
"sha1": "
|
|
6
|
+
"sha1": "5ad54972a9e31a5459cadbb471428111624ec9c6",
|
|
7
7
|
"dirty": false
|
|
8
8
|
},
|
|
9
9
|
"path_in_vcs": "tools/create-feltdb",
|
|
10
|
-
"source_digest": "sha256:
|
|
10
|
+
"source_digest": "sha256:01efc5737aae1fef37c976e5841df3bb9b615d034f31d27b038f7fd4ca202428",
|
|
11
11
|
"inputs": [
|
|
12
12
|
"Cargo.lock",
|
|
13
13
|
"Cargo.toml",
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"tools/cli",
|
|
21
21
|
"tools/create-feltdb"
|
|
22
22
|
],
|
|
23
|
-
"files":
|
|
23
|
+
"files": 789,
|
|
24
24
|
"build": {
|
|
25
25
|
"command": "npm run build",
|
|
26
26
|
"node": "v24.9.0"
|
package/dist/create/cli.js
CHANGED
|
@@ -226,7 +226,7 @@ Deployment Target (Explicit):
|
|
|
226
226
|
|
|
227
227
|
--managed Managed FeltDB runtime
|
|
228
228
|
Best for: Production without operating servers
|
|
229
|
-
Requires VITE_FELTDB_URL
|
|
229
|
+
Requires VITE_FELTDB_URL; server-side FELTDB_TOKEN only
|
|
230
230
|
|
|
231
231
|
Options:
|
|
232
232
|
--browser Explicit: Browser runtime with IndexedDB
|