@feltdb/core 0.6.9 → 0.6.11
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/application-lifecycle.js +112 -0
- package/dist/cli/application.js +10 -0
- package/dist/cli/commands.js +407 -119
- package/dist/cli/development-session.js +54 -0
- package/dist/cli/index.js +1 -1
- package/dist/cli/workspace-integration.js +146 -20
- package/dist/collection.d.ts +110 -2
- package/dist/collection.d.ts.map +1 -1
- package/dist/collection.js +228 -3
- package/dist/create/cli.js +4 -2
- package/dist/create/create.js +42 -6
- package/dist/create/frameworks.js +18 -0
- package/dist/create/package-versions.js +1 -1
- package/dist/create/server-source/crates/feltdb/src/bin/feltdb_node.rs +408 -178
- package/dist/create/server-source/crates/feltdb/src/lib.rs +49 -5
- package/dist/create/server-source/crates/feltdb/src/multi_operation_transaction.rs +659 -0
- package/dist/create/server-source/crates/feltdb/src/p1_application_atomicity.rs +285 -0
- package/dist/create/server-source/crates/feltdb/src/p1_atomicity_acceptance.rs +582 -0
- package/dist/create/server-source/crates/feltdb-server/src/main.rs +141 -0
- package/dist/create/workspace-initialization.js +4 -5
- package/dist/db.d.ts +63 -1
- package/dist/db.d.ts.map +1 -1
- package/dist/db.js +145 -4
- package/dist/development-runtime-bridge.d.ts +60 -0
- package/dist/development-runtime-bridge.d.ts.map +1 -0
- package/dist/development-runtime-bridge.js +171 -0
- package/dist/embedded-transaction.d.ts +77 -0
- package/dist/embedded-transaction.d.ts.map +1 -0
- package/dist/embedded-transaction.js +102 -0
- package/dist/feltdb.d.ts +49 -1
- package/dist/feltdb.d.ts.map +1 -1
- package/dist/file-db.d.ts +33 -0
- package/dist/file-db.d.ts.map +1 -1
- package/dist/file-db.js +128 -4
- package/dist/freshness.d.ts +119 -0
- package/dist/freshness.d.ts.map +1 -0
- package/dist/freshness.js +115 -0
- package/dist/http-db.d.ts +48 -0
- package/dist/http-db.d.ts.map +1 -1
- package/dist/http-db.js +77 -1
- package/dist/index-backend.d.ts +8 -0
- package/dist/index-backend.d.ts.map +1 -1
- package/dist/index-backend.js +13 -0
- package/dist/index-core.d.ts +80 -0
- package/dist/index-core.d.ts.map +1 -0
- package/dist/index-core.js +74 -0
- package/dist/index-manager.d.ts +11 -0
- package/dist/index-manager.d.ts.map +1 -1
- package/dist/index-manager.js +30 -13
- package/dist/index-types.d.ts +17 -0
- package/dist/index-types.d.ts.map +1 -1
- package/dist/index.browser.d.ts +14 -0
- package/dist/index.browser.d.ts.map +1 -0
- package/dist/index.browser.js +13 -0
- package/dist/index.d.ts +8 -59
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -54
- package/dist/indexeddb-db.d.ts +32 -0
- package/dist/indexeddb-db.d.ts.map +1 -1
- package/dist/indexeddb-db.js +151 -1
- package/dist/memory-db.d.ts +26 -0
- package/dist/memory-db.d.ts.map +1 -1
- package/dist/memory-db.js +86 -0
- package/dist/runtime-registry.d.ts +32 -0
- package/dist/runtime-registry.d.ts.map +1 -0
- package/dist/runtime-registry.js +38 -0
- package/dist/studio/app.d.ts +2 -1
- package/dist/studio/app.d.ts.map +1 -1
- package/dist/studio/components/StateExplorer.d.ts +2 -1
- package/dist/studio/components/StateExplorer.d.ts.map +1 -1
- package/dist/studio/components/index.js +1 -1
- package/dist/studio/{components-9kDSWiGL.js → components-C5p2TfIU.js} +25 -14
- package/dist/studio/index.js +234 -160
- package/dist/studio-app/assets/{feltdb_wasm-B4wq4mqp.js → feltdb_wasm-CJv3wHzi.js} +1 -1
- package/dist/studio-app/assets/feltdb_wasm_bg-C8TG8r2n.wasm +0 -0
- package/dist/studio-app/assets/index-DospFFYE.js +28 -0
- package/dist/studio-app/index.html +1 -1
- package/dist/transaction.d.ts +98 -0
- package/dist/transaction.d.ts.map +1 -0
- package/dist/transaction.js +86 -0
- package/dist/wasm/feltdb_wasm_bg.wasm +0 -0
- package/dist/workspace/browser.d.ts +22 -0
- package/dist/workspace/browser.d.ts.map +1 -0
- package/dist/workspace/browser.js +17 -0
- package/dist/workspace/development-node.d.ts +16 -0
- package/dist/workspace/development-node.d.ts.map +1 -1
- package/dist/workspace/development-node.js +85 -1
- package/dist/workspace/git-identity.d.ts +35 -0
- package/dist/workspace/git-identity.d.ts.map +1 -0
- package/dist/workspace/git-identity.js +81 -0
- package/dist/workspace/index.d.ts +12 -2
- package/dist/workspace/index.d.ts.map +1 -1
- package/dist/workspace/index.js +7 -1
- package/dist/workspace/investigation-analysis.d.ts +47 -0
- package/dist/workspace/investigation-analysis.d.ts.map +1 -0
- package/dist/workspace/investigation-analysis.js +181 -0
- package/dist/workspace/investigation-lifecycle-manager.d.ts +88 -0
- package/dist/workspace/investigation-lifecycle-manager.d.ts.map +1 -0
- package/dist/workspace/investigation-lifecycle-manager.js +259 -0
- package/dist/workspace/investigation-supervisor.d.ts +100 -0
- package/dist/workspace/investigation-supervisor.d.ts.map +1 -0
- package/dist/workspace/investigation-supervisor.js +238 -0
- package/dist/workspace/runtime-investigation.d.ts +5 -1
- package/dist/workspace/runtime-investigation.d.ts.map +1 -1
- package/dist/workspace/runtime-investigation.js +50 -21
- package/dist/workspace/runtime-observation.d.ts +82 -0
- package/dist/workspace/runtime-observation.d.ts.map +1 -0
- package/dist/workspace/runtime-observation.js +170 -0
- package/dist/workspace/runtime-observer.d.ts +57 -0
- package/dist/workspace/runtime-observer.d.ts.map +1 -0
- package/dist/workspace/runtime-observer.js +272 -0
- package/dist/workspace/workspace-connection.d.ts.map +1 -1
- package/dist/workspace/workspace-connection.js +14 -5
- package/dist/workspace/workspace-identity.d.ts +1 -1
- package/dist/workspace/workspace-identity.d.ts.map +1 -1
- package/dist/workspace/workspace-identity.js +4 -4
- package/dist/workspace/workspace-types.d.ts +208 -0
- package/dist/workspace/workspace-types.d.ts.map +1 -1
- package/package.json +12 -4
- package/dist/create/server-source/crates/feltdb/src/phase_1c_three_node.rs +0 -523
- package/dist/studio-app/assets/feltdb_wasm_bg-Ceyi7l21.wasm +0 -0
- package/dist/studio-app/assets/index-BF45M757.js +0 -28
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
/** Maximum unsent events retained by a runtime. New events are dropped beyond this bound. */
|
|
2
|
+
export const DEVELOPMENT_OBSERVATION_BUFFER_LIMIT = 256;
|
|
3
|
+
let configuredSession;
|
|
4
|
+
/** Supply ephemeral `feltdb dev` identity. This is a no-op when values are absent. */
|
|
5
|
+
export function configureDevelopmentRuntimeBridge(session) {
|
|
6
|
+
if (!session) {
|
|
7
|
+
configuredSession = undefined;
|
|
8
|
+
return;
|
|
9
|
+
}
|
|
10
|
+
if (!session.sessionId || !session.workspaceId || !session.namespace || !session.runtime || !session.authorityUrl || !session.bridgeUrl)
|
|
11
|
+
return;
|
|
12
|
+
configuredSession = session;
|
|
13
|
+
}
|
|
14
|
+
function randomId() {
|
|
15
|
+
const value = globalThis.crypto?.randomUUID?.().replace(/-/g, '')
|
|
16
|
+
?? `${Date.now().toString(36)}${Math.random().toString(36).slice(2)}${Math.random().toString(36).slice(2)}`;
|
|
17
|
+
return `runtime_${value}`;
|
|
18
|
+
}
|
|
19
|
+
function processSession() {
|
|
20
|
+
const environment = globalThis.process?.env;
|
|
21
|
+
if (!environment?.FELTDB_DEV_SESSION_ID)
|
|
22
|
+
return undefined;
|
|
23
|
+
return {
|
|
24
|
+
sessionId: environment.FELTDB_DEV_SESSION_ID,
|
|
25
|
+
workspaceId: environment.FELTDB_WORKSPACE_ID,
|
|
26
|
+
namespace: environment.FELTDB_NAMESPACE,
|
|
27
|
+
runtime: environment.FELTDB_RUNTIME,
|
|
28
|
+
authorityUrl: environment.FELTDB_AUTHORITY_URL || environment.FELTDB_WORKSPACE_ENDPOINT,
|
|
29
|
+
bridgeUrl: environment.FELTDB_DEV_BRIDGE_URL,
|
|
30
|
+
applicationUrl: environment.FELTDB_APPLICATION_URL,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
function safeBridgeUrl(value) {
|
|
34
|
+
try {
|
|
35
|
+
const url = new URL(value);
|
|
36
|
+
if (url.protocol !== 'http:' || !['127.0.0.1', 'localhost', '::1', '[::1]'].includes(url.hostname))
|
|
37
|
+
return undefined;
|
|
38
|
+
return url.origin;
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
return undefined;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
/** Internal, optional registration hook called by Core runtime construction. */
|
|
45
|
+
export function attachDevelopmentRuntimeBridge(input) {
|
|
46
|
+
const runtimeInstanceId = randomId();
|
|
47
|
+
let activeSession;
|
|
48
|
+
let heartbeat;
|
|
49
|
+
let flushTimer;
|
|
50
|
+
let flushing = false;
|
|
51
|
+
let closing = false;
|
|
52
|
+
let dropped = 0;
|
|
53
|
+
const observations = [];
|
|
54
|
+
const applicationId = input.applicationId
|
|
55
|
+
|| globalThis.document?.title
|
|
56
|
+
|| globalThis.process?.env?.npm_package_name
|
|
57
|
+
|| 'application';
|
|
58
|
+
const register = async (candidate) => {
|
|
59
|
+
const session = candidate || configuredSession || processSession();
|
|
60
|
+
const compatibleRuntime = session?.runtime === input.runtime
|
|
61
|
+
|| (input.runtime === 'remote' && ['managed', 'self-hosted', 'remote'].includes(session?.runtime || ''));
|
|
62
|
+
if (!session || session.namespace !== input.namespace || !compatibleRuntime)
|
|
63
|
+
return;
|
|
64
|
+
const bridgeUrl = safeBridgeUrl(session.bridgeUrl);
|
|
65
|
+
if (!bridgeUrl)
|
|
66
|
+
return;
|
|
67
|
+
activeSession = { ...session, bridgeUrl };
|
|
68
|
+
const registration = { ...activeSession, runtimeInstanceId, applicationId };
|
|
69
|
+
try {
|
|
70
|
+
const response = await fetch(`${bridgeUrl}/api/v1/development/runtime/register`, {
|
|
71
|
+
method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify(registration),
|
|
72
|
+
});
|
|
73
|
+
if (!response.ok)
|
|
74
|
+
return;
|
|
75
|
+
if (!heartbeat) {
|
|
76
|
+
heartbeat = setInterval(() => { void register(activeSession); }, 2000);
|
|
77
|
+
heartbeat.unref?.();
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
catch { /* Development tooling is optional. */ }
|
|
81
|
+
};
|
|
82
|
+
const flush = async () => {
|
|
83
|
+
if (flushing || !activeSession || observations.length === 0)
|
|
84
|
+
return;
|
|
85
|
+
flushing = true;
|
|
86
|
+
const batch = observations.splice(0, 32);
|
|
87
|
+
const droppedEvents = dropped;
|
|
88
|
+
dropped = 0;
|
|
89
|
+
try {
|
|
90
|
+
const response = await fetch(`${activeSession.bridgeUrl}/api/v1/development/runtime/${encodeURIComponent(runtimeInstanceId)}/observations`, {
|
|
91
|
+
method: 'POST', headers: { 'content-type': 'application/json' },
|
|
92
|
+
body: JSON.stringify({ sessionId: activeSession.sessionId, observations: batch, dropped: droppedEvents }),
|
|
93
|
+
});
|
|
94
|
+
if (!response.ok)
|
|
95
|
+
throw new Error('observation delivery failed');
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
if (!closing) {
|
|
99
|
+
const available = DEVELOPMENT_OBSERVATION_BUFFER_LIMIT - observations.length;
|
|
100
|
+
observations.unshift(...batch.slice(Math.max(0, batch.length - available)));
|
|
101
|
+
dropped += droppedEvents + Math.max(0, batch.length - available);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
finally {
|
|
105
|
+
flushing = false;
|
|
106
|
+
if (observations.length && !closing) {
|
|
107
|
+
flushTimer = setTimeout(() => { flushTimer = undefined; void flush(); }, 100);
|
|
108
|
+
flushTimer.unref?.();
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
const enqueue = (event) => {
|
|
113
|
+
if (!activeSession || closing)
|
|
114
|
+
return;
|
|
115
|
+
if (observations.length >= DEVELOPMENT_OBSERVATION_BUFFER_LIMIT)
|
|
116
|
+
dropped++;
|
|
117
|
+
else
|
|
118
|
+
observations.push(event);
|
|
119
|
+
if (!flushTimer && !flushing) {
|
|
120
|
+
flushTimer = setTimeout(() => { flushTimer = undefined; void flush(); }, 0);
|
|
121
|
+
flushTimer.unref?.();
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
const observation = {
|
|
125
|
+
start(type, details = {}) {
|
|
126
|
+
const correlationId = `op_${randomId().slice(8)}`;
|
|
127
|
+
const startedAt = Date.now();
|
|
128
|
+
const emit = (status, metadata, error) => enqueue({
|
|
129
|
+
eventId: `evt_${randomId().slice(8)}`, correlationId, timestamp: Date.now(),
|
|
130
|
+
workspaceId: activeSession?.workspaceId, sessionId: activeSession?.sessionId, runtimeInstanceId,
|
|
131
|
+
operation: { type, collection: details.collection, transactionId: details.transactionId }, status,
|
|
132
|
+
durationMs: status === 'started' ? undefined : Date.now() - startedAt,
|
|
133
|
+
metadata: metadata || details.metadata,
|
|
134
|
+
error: status === 'failed' ? {
|
|
135
|
+
code: typeof error === 'object' && error && 'code' in error ? String(error.code) : undefined,
|
|
136
|
+
message: (error instanceof Error ? error.message : String(error)).slice(0, 500),
|
|
137
|
+
} : undefined,
|
|
138
|
+
});
|
|
139
|
+
emit('started');
|
|
140
|
+
return { complete: metadata => emit('completed', metadata), fail: error => emit('failed', undefined, error) };
|
|
141
|
+
},
|
|
142
|
+
};
|
|
143
|
+
const browser = globalThis.window;
|
|
144
|
+
const receive = (event) => {
|
|
145
|
+
if (event.source !== browser?.parent || event.data?.type !== 'feltdb:dev-session')
|
|
146
|
+
return;
|
|
147
|
+
void register(event.data.session);
|
|
148
|
+
};
|
|
149
|
+
browser?.addEventListener?.('message', receive);
|
|
150
|
+
void register();
|
|
151
|
+
const close = async () => {
|
|
152
|
+
closing = true;
|
|
153
|
+
if (heartbeat)
|
|
154
|
+
clearInterval(heartbeat);
|
|
155
|
+
if (flushTimer)
|
|
156
|
+
clearTimeout(flushTimer);
|
|
157
|
+
while (observations.length)
|
|
158
|
+
await flush();
|
|
159
|
+
browser?.removeEventListener?.('message', receive);
|
|
160
|
+
if (!activeSession)
|
|
161
|
+
return;
|
|
162
|
+
try {
|
|
163
|
+
await fetch(`${activeSession.bridgeUrl}/api/v1/development/runtime/${encodeURIComponent(runtimeInstanceId)}?sessionId=${encodeURIComponent(activeSession.sessionId)}`, {
|
|
164
|
+
method: 'DELETE', keepalive: true,
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
catch { /* Lease expiry handles crashes and unavailable tooling. */ }
|
|
168
|
+
};
|
|
169
|
+
browser?.addEventListener?.('pagehide', () => { void close(); }, { once: true });
|
|
170
|
+
return { runtimeInstanceId, observation, close };
|
|
171
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Transaction semantics for embedded runtimes.
|
|
3
|
+
*
|
|
4
|
+
* FeltDB has one transaction contract. The authority-backed runtime satisfies
|
|
5
|
+
* it by handing the staged transaction to the store's own atomic commit path;
|
|
6
|
+
* the embedded runtimes satisfy it here.
|
|
7
|
+
*
|
|
8
|
+
* The semantics live in this module *once*. A runtime does not reimplement
|
|
9
|
+
* them — it supplies only the thing that is genuinely runtime-specific: its
|
|
10
|
+
* atomic durable commit boundary.
|
|
11
|
+
*
|
|
12
|
+
* ```text
|
|
13
|
+
* db.transaction()
|
|
14
|
+
* │
|
|
15
|
+
* staged operations
|
|
16
|
+
* │
|
|
17
|
+
* ┌────────┴────────┐
|
|
18
|
+
* │ │
|
|
19
|
+
* authority embedded
|
|
20
|
+
* (store's atomic (decidePlan here +
|
|
21
|
+
* commit path) runtime commit)
|
|
22
|
+
* │ │
|
|
23
|
+
* └────────┬────────┘
|
|
24
|
+
* │
|
|
25
|
+
* atomic durable
|
|
26
|
+
* commit
|
|
27
|
+
* ```
|
|
28
|
+
*
|
|
29
|
+
* The decision step is pure: it reads current state and produces a plan. It
|
|
30
|
+
* performs no I/O and mutates nothing, so a runtime can evaluate the whole
|
|
31
|
+
* transaction before touching storage and then apply the plan in one atomic
|
|
32
|
+
* step. That ordering is what makes partial application impossible.
|
|
33
|
+
*/
|
|
34
|
+
import type { AtomicTransactionRequest, AtomicTransactionResult } from './transaction.js';
|
|
35
|
+
/** One resolved mutation. An absent `value` means delete. */
|
|
36
|
+
export interface EmbeddedMutation {
|
|
37
|
+
/** Storage key, `collection:id`. */
|
|
38
|
+
key: string;
|
|
39
|
+
collection: string;
|
|
40
|
+
id: string;
|
|
41
|
+
value?: Record<string, unknown>;
|
|
42
|
+
}
|
|
43
|
+
/** What a runtime must be able to tell the decision step. */
|
|
44
|
+
export interface EmbeddedTransactionState {
|
|
45
|
+
/** Whether a record currently exists. */
|
|
46
|
+
exists(key: string): boolean;
|
|
47
|
+
/** Whether this transaction id has already been committed. */
|
|
48
|
+
hasApplied(transactionId: string): boolean;
|
|
49
|
+
}
|
|
50
|
+
export type EmbeddedPlan = {
|
|
51
|
+
kind: 'duplicate';
|
|
52
|
+
} | {
|
|
53
|
+
kind: 'reject';
|
|
54
|
+
reason: string;
|
|
55
|
+
} | {
|
|
56
|
+
kind: 'apply';
|
|
57
|
+
mutations: EmbeddedMutation[];
|
|
58
|
+
};
|
|
59
|
+
/** Storage key for a collection and id. */
|
|
60
|
+
export declare function recordKey(collection: string, id: string): string;
|
|
61
|
+
/**
|
|
62
|
+
* Decide what a transaction should do, without doing any of it.
|
|
63
|
+
*
|
|
64
|
+
* Returns `duplicate` when this transaction id was already committed (so
|
|
65
|
+
* redelivery is a no-op), `reject` when the transaction cannot commit at all,
|
|
66
|
+
* or `apply` with every mutation resolved.
|
|
67
|
+
*
|
|
68
|
+
* A rejection means nothing may be written. There is no partial plan.
|
|
69
|
+
*/
|
|
70
|
+
export declare function decideTransaction(request: AtomicTransactionRequest, state: EmbeddedTransactionState): EmbeddedPlan;
|
|
71
|
+
/** Shape a runtime returns after committing. */
|
|
72
|
+
export declare function embeddedResult(request: AtomicTransactionRequest, duplicate: boolean, stateBefore: number, stateAfter: number): AtomicTransactionResult;
|
|
73
|
+
/** Raised when a transaction is refused. Nothing was written. */
|
|
74
|
+
export declare class EmbeddedTransactionRejected extends Error {
|
|
75
|
+
constructor(reason: string);
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=embedded-transaction.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"embedded-transaction.d.ts","sourceRoot":"","sources":["../src/embedded-transaction.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAEH,OAAO,KAAK,EAAE,wBAAwB,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;AAE1F,6DAA6D;AAC7D,MAAM,WAAW,gBAAgB;IAC/B,oCAAoC;IACpC,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,EAAE,MAAM,CAAC;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC;AAED,6DAA6D;AAC7D,MAAM,WAAW,wBAAwB;IACvC,yCAAyC;IACzC,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;IAC7B,8DAA8D;IAC9D,UAAU,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC;CAC5C;AAED,MAAM,MAAM,YAAY,GACpB;IAAE,IAAI,EAAE,WAAW,CAAA;CAAE,GACrB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAClC;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,SAAS,EAAE,gBAAgB,EAAE,CAAA;CAAE,CAAC;AAErD,2CAA2C;AAC3C,wBAAgB,SAAS,CAAC,UAAU,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAEhE;AAID;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,wBAAwB,EACjC,KAAK,EAAE,wBAAwB,GAC9B,YAAY,CA0Cd;AAED,gDAAgD;AAChD,wBAAgB,cAAc,CAC5B,OAAO,EAAE,wBAAwB,EACjC,SAAS,EAAE,OAAO,EAClB,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,GACjB,uBAAuB,CAQzB;AAED,iEAAiE;AACjE,qBAAa,2BAA4B,SAAQ,KAAK;gBACxC,MAAM,EAAE,MAAM;CAI3B"}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Transaction semantics for embedded runtimes.
|
|
3
|
+
*
|
|
4
|
+
* FeltDB has one transaction contract. The authority-backed runtime satisfies
|
|
5
|
+
* it by handing the staged transaction to the store's own atomic commit path;
|
|
6
|
+
* the embedded runtimes satisfy it here.
|
|
7
|
+
*
|
|
8
|
+
* The semantics live in this module *once*. A runtime does not reimplement
|
|
9
|
+
* them — it supplies only the thing that is genuinely runtime-specific: its
|
|
10
|
+
* atomic durable commit boundary.
|
|
11
|
+
*
|
|
12
|
+
* ```text
|
|
13
|
+
* db.transaction()
|
|
14
|
+
* │
|
|
15
|
+
* staged operations
|
|
16
|
+
* │
|
|
17
|
+
* ┌────────┴────────┐
|
|
18
|
+
* │ │
|
|
19
|
+
* authority embedded
|
|
20
|
+
* (store's atomic (decidePlan here +
|
|
21
|
+
* commit path) runtime commit)
|
|
22
|
+
* │ │
|
|
23
|
+
* └────────┬────────┘
|
|
24
|
+
* │
|
|
25
|
+
* atomic durable
|
|
26
|
+
* commit
|
|
27
|
+
* ```
|
|
28
|
+
*
|
|
29
|
+
* The decision step is pure: it reads current state and produces a plan. It
|
|
30
|
+
* performs no I/O and mutates nothing, so a runtime can evaluate the whole
|
|
31
|
+
* transaction before touching storage and then apply the plan in one atomic
|
|
32
|
+
* step. That ordering is what makes partial application impossible.
|
|
33
|
+
*/
|
|
34
|
+
/** Storage key for a collection and id. */
|
|
35
|
+
export function recordKey(collection, id) {
|
|
36
|
+
return `${collection}:${id}`;
|
|
37
|
+
}
|
|
38
|
+
const SEGMENT = /^[A-Za-z0-9._-]{1,128}$/;
|
|
39
|
+
/**
|
|
40
|
+
* Decide what a transaction should do, without doing any of it.
|
|
41
|
+
*
|
|
42
|
+
* Returns `duplicate` when this transaction id was already committed (so
|
|
43
|
+
* redelivery is a no-op), `reject` when the transaction cannot commit at all,
|
|
44
|
+
* or `apply` with every mutation resolved.
|
|
45
|
+
*
|
|
46
|
+
* A rejection means nothing may be written. There is no partial plan.
|
|
47
|
+
*/
|
|
48
|
+
export function decideTransaction(request, state) {
|
|
49
|
+
if (!request.transactionId || !request.transactionId.trim()) {
|
|
50
|
+
return { kind: 'reject', reason: 'transactionId is required' };
|
|
51
|
+
}
|
|
52
|
+
if (request.operations.length === 0) {
|
|
53
|
+
return { kind: 'reject', reason: 'a transaction requires at least one operation' };
|
|
54
|
+
}
|
|
55
|
+
if (state.hasApplied(request.transactionId)) {
|
|
56
|
+
return { kind: 'duplicate' };
|
|
57
|
+
}
|
|
58
|
+
const mutations = [];
|
|
59
|
+
const seen = new Set();
|
|
60
|
+
for (const operation of request.operations) {
|
|
61
|
+
if (!SEGMENT.test(operation.collection) || !SEGMENT.test(operation.id)) {
|
|
62
|
+
return {
|
|
63
|
+
kind: 'reject',
|
|
64
|
+
reason: `invalid collection or id: ${operation.collection}:${operation.id}`,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
const key = recordKey(operation.collection, operation.id);
|
|
68
|
+
if (seen.has(key)) {
|
|
69
|
+
return { kind: 'reject', reason: `transaction writes ${key} more than once` };
|
|
70
|
+
}
|
|
71
|
+
seen.add(key);
|
|
72
|
+
if (operation.requireAbsent && state.exists(key)) {
|
|
73
|
+
return { kind: 'reject', reason: `PRECONDITION_FAILED:${key}:record already exists` };
|
|
74
|
+
}
|
|
75
|
+
mutations.push({
|
|
76
|
+
key,
|
|
77
|
+
collection: operation.collection,
|
|
78
|
+
id: operation.id,
|
|
79
|
+
value: operation.value === undefined
|
|
80
|
+
? undefined
|
|
81
|
+
: { ...operation.value, id: operation.id },
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
return { kind: 'apply', mutations };
|
|
85
|
+
}
|
|
86
|
+
/** Shape a runtime returns after committing. */
|
|
87
|
+
export function embeddedResult(request, duplicate, stateBefore, stateAfter) {
|
|
88
|
+
return {
|
|
89
|
+
transactionId: request.transactionId,
|
|
90
|
+
duplicate,
|
|
91
|
+
operations: request.operations.length,
|
|
92
|
+
stateBefore,
|
|
93
|
+
stateAfter,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
/** Raised when a transaction is refused. Nothing was written. */
|
|
97
|
+
export class EmbeddedTransactionRejected extends Error {
|
|
98
|
+
constructor(reason) {
|
|
99
|
+
super(reason);
|
|
100
|
+
this.name = 'EmbeddedTransactionRejected';
|
|
101
|
+
}
|
|
102
|
+
}
|
package/dist/feltdb.d.ts
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* This is the FFI interface to the Rust WASM implementation.
|
|
5
5
|
*/
|
|
6
|
+
import type { FreshnessCapability, Revision } from './freshness.js';
|
|
6
7
|
/**
|
|
7
8
|
* WASM database instance
|
|
8
9
|
*/
|
|
@@ -63,9 +64,34 @@ export interface JsDb {
|
|
|
63
64
|
*/
|
|
64
65
|
instance_id(): string;
|
|
65
66
|
/**
|
|
66
|
-
* Get sequence number
|
|
67
|
+
* Get sequence number.
|
|
68
|
+
*
|
|
69
|
+
* **Not a freshness token.** This means something different in every runtime:
|
|
70
|
+
* a hardcoded `0` over HTTP, the number of mutations this handle performed in
|
|
71
|
+
* the memory and browser runtimes, and the loaded snapshot's counter in the
|
|
72
|
+
* file runtime. None of those reflect a write made by another process, tab,
|
|
73
|
+
* or node. Use `freshness()` and `revision()` to decide whether a cached copy
|
|
74
|
+
* is current.
|
|
67
75
|
*/
|
|
68
76
|
get_sequence(): number;
|
|
77
|
+
/**
|
|
78
|
+
* Declare what freshness validation this runtime can honestly support.
|
|
79
|
+
*
|
|
80
|
+
* A runtime implements this only if it has something true to say. Omitting it
|
|
81
|
+
* is read as "explicit refresh only", which is the safe answer.
|
|
82
|
+
*
|
|
83
|
+
* See packages/core/src/freshness.ts for the rule this answer is held to.
|
|
84
|
+
*/
|
|
85
|
+
freshness?(): FreshnessCapability | Promise<FreshnessCapability>;
|
|
86
|
+
/**
|
|
87
|
+
* The current committed-state revision.
|
|
88
|
+
*
|
|
89
|
+
* Defined **only** by runtimes whose `freshness()` advertises
|
|
90
|
+
* `validation: 'revision'`. A runtime that exposes this without advertising
|
|
91
|
+
* it is a contract violation, because an exposed revision will eventually be
|
|
92
|
+
* trusted.
|
|
93
|
+
*/
|
|
94
|
+
revision?(): Promise<Revision>;
|
|
69
95
|
/** Read durable mutation events when the runtime exposes an audit log. */
|
|
70
96
|
audit_events?(): any | Promise<any>;
|
|
71
97
|
/** Export and merge portable embedded-runtime operations. */
|
|
@@ -95,6 +121,28 @@ export interface JsDb {
|
|
|
95
121
|
admitOperation?(input: any): Promise<any>;
|
|
96
122
|
/** Atomic operation lifecycle transition: versioned conditional state changes. */
|
|
97
123
|
transitionOperation?(input: any): Promise<any>;
|
|
124
|
+
/**
|
|
125
|
+
* Commit several operations as one atomic, durable transaction.
|
|
126
|
+
*
|
|
127
|
+
* A runtime implements this only when it is backed by an authority that can
|
|
128
|
+
* provide the guarantee. Runtimes that cannot leave it undefined, so callers
|
|
129
|
+
* get an explicit refusal instead of a silent sequence of separate writes.
|
|
130
|
+
*/
|
|
131
|
+
commit_transaction?(request: {
|
|
132
|
+
transactionId: string;
|
|
133
|
+
operations: Array<{
|
|
134
|
+
collection: string;
|
|
135
|
+
id: string;
|
|
136
|
+
value?: Record<string, unknown>;
|
|
137
|
+
expectedVersion?: number;
|
|
138
|
+
}>;
|
|
139
|
+
}): Promise<{
|
|
140
|
+
transactionId: string;
|
|
141
|
+
duplicate: boolean;
|
|
142
|
+
operations: number;
|
|
143
|
+
stateBefore: number;
|
|
144
|
+
stateAfter: number;
|
|
145
|
+
}>;
|
|
98
146
|
}
|
|
99
147
|
/**
|
|
100
148
|
* A row stored in the database
|
package/dist/feltdb.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"feltdb.d.ts","sourceRoot":"","sources":["../src/feltdb.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;GAEG;AACH,MAAM,WAAW,IAAI;IACnB;;OAEG;IACH,UAAU,CAAC,SAAS,EAAE,GAAG,GAAG,GAAG,CAAC;IAEhC;;OAEG;IACH,SAAS,IAAI,GAAG,CAAC;IAEjB;;OAEG;IACH,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,GAAG,CAAC;IAE/B;;OAEG;IACH,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,GAAG,CAAC;IAEpC;;OAEG;IACH,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,GAAG,CAAC;IAEvC;;OAEG;IACH,oBAAoB,CAAC,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,GAAG,CAAC;IAEnE;;OAEG;IACH,2BAA2B,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,GAAG,CAAC;IAEpE;;OAEG;IACH,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;IAEzC;;OAEG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;IAErC;;OAEG;IACH,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;IAEvD,6DAA6D;IAC7D,MAAM,CAAC,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;IAExD,qDAAqD;IACrD,MAAM,CAAC,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;IAEzC,2EAA2E;IAC3E,iBAAiB,CAAC,CAAC,QAAQ,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,IAAI,CAAC;IAC5F,KAAK,CAAC,IAAI,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE/B;;OAEG;IACH,sBAAsB,CAAC,UAAU,EAAE,MAAM,GAAG,GAAG,CAAC;IAEhD;;OAEG;IACH,WAAW,IAAI,MAAM,CAAC;IAEtB
|
|
1
|
+
{"version":3,"file":"feltdb.d.ts","sourceRoot":"","sources":["../src/feltdb.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAEpE;;GAEG;AACH,MAAM,WAAW,IAAI;IACnB;;OAEG;IACH,UAAU,CAAC,SAAS,EAAE,GAAG,GAAG,GAAG,CAAC;IAEhC;;OAEG;IACH,SAAS,IAAI,GAAG,CAAC;IAEjB;;OAEG;IACH,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,GAAG,CAAC;IAE/B;;OAEG;IACH,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,GAAG,CAAC;IAEpC;;OAEG;IACH,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,GAAG,CAAC;IAEvC;;OAEG;IACH,oBAAoB,CAAC,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,GAAG,CAAC;IAEnE;;OAEG;IACH,2BAA2B,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,GAAG,CAAC;IAEpE;;OAEG;IACH,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;IAEzC;;OAEG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;IAErC;;OAEG;IACH,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;IAEvD,6DAA6D;IAC7D,MAAM,CAAC,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;IAExD,qDAAqD;IACrD,MAAM,CAAC,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;IAEzC,2EAA2E;IAC3E,iBAAiB,CAAC,CAAC,QAAQ,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,IAAI,CAAC;IAC5F,KAAK,CAAC,IAAI,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE/B;;OAEG;IACH,sBAAsB,CAAC,UAAU,EAAE,MAAM,GAAG,GAAG,CAAC;IAEhD;;OAEG;IACH,WAAW,IAAI,MAAM,CAAC;IAEtB;;;;;;;;;OASG;IACH,YAAY,IAAI,MAAM,CAAC;IAEvB;;;;;;;OAOG;IACH,SAAS,CAAC,IAAI,mBAAmB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAC;IAEjE;;;;;;;OAOG;IACH,QAAQ,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,CAAC;IAE/B,0EAA0E;IAC1E,YAAY,CAAC,IAAI,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;IAEpC,6DAA6D;IAC7D,iBAAiB,CAAC,CAAC,cAAc,EAAE,MAAM,GAAG,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;IAC/D,uBAAuB,CAAC,CAAC,UAAU,EAAE,GAAG,EAAE,GAAG,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;IAEhE,oEAAoE;IACpE,WAAW,CAAC,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,QAAQ,EAAE,OAAO,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAExF,0EAA0E;IAC1E,GAAG,CAAC,CAAC,MAAM,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,eAAe,EAAE,MAAM,CAAC;QAAC,aAAa,CAAC,EAAE,MAAM,CAAC;QAAC,eAAe,CAAC,EAAE,MAAM,CAAC;QAAC,gBAAgB,CAAC,EAAE,OAAO,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,cAAc,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,GAAG,CAAA;KAAE,CAAC,CAAC;IAErQ,8EAA8E;IAC9E,cAAc,CAAC,CAAC,KAAK,EAAE,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;IAE1C,kFAAkF;IAClF,mBAAmB,CAAC,CAAC,KAAK,EAAE,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;IAE/C;;;;;;OAMG;IACH,kBAAkB,CAAC,CAAC,OAAO,EAAE;QAC3B,aAAa,EAAE,MAAM,CAAC;QACtB,UAAU,EAAE,KAAK,CAAC;YAChB,UAAU,EAAE,MAAM,CAAC;YACnB,EAAE,EAAE,MAAM,CAAC;YACX,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;YAChC,eAAe,CAAC,EAAE,MAAM,CAAC;SAC1B,CAAC,CAAC;KACJ,GAAG,OAAO,CAAC;QACV,aAAa,EAAE,MAAM,CAAC;QACtB,SAAS,EAAE,OAAO,CAAC;QACnB,UAAU,EAAE,MAAM,CAAC;QACnB,WAAW,EAAE,MAAM,CAAC;QACpB,UAAU,EAAE,MAAM,CAAC;KACpB,CAAC,CAAC;CACJ;AAED;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;IACpB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB"}
|
package/dist/file-db.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { JsDb } from './feltdb.js';
|
|
2
|
+
import type { FreshnessCapability } from './freshness.js';
|
|
2
3
|
import type { OperationAdmissionInput, OperationAdmissionResult, OperationTransitionInput, OperationTransitionResult } from './operation-admission.js';
|
|
4
|
+
import type { AtomicTransactionRequest, AtomicTransactionResult } from './transaction.js';
|
|
3
5
|
interface JsResult {
|
|
4
6
|
success: boolean;
|
|
5
7
|
data?: string;
|
|
@@ -23,6 +25,7 @@ export declare class FileJsDb implements JsDb {
|
|
|
23
25
|
private readonly origin;
|
|
24
26
|
private readonly peers;
|
|
25
27
|
private lockFd;
|
|
28
|
+
private readonly applied;
|
|
26
29
|
constructor(path: string);
|
|
27
30
|
private loadState;
|
|
28
31
|
private initializeState;
|
|
@@ -33,6 +36,18 @@ export declare class FileJsDb implements JsDb {
|
|
|
33
36
|
private releaseLockAsync;
|
|
34
37
|
private saveState;
|
|
35
38
|
private event;
|
|
39
|
+
/**
|
|
40
|
+
* Commit several operations atomically and durably.
|
|
41
|
+
*
|
|
42
|
+
* The snapshot is published by writing a temporary file, fsyncing it, and
|
|
43
|
+
* renaming it over the previous one. The rename is atomic, so a reader sees
|
|
44
|
+
* either the whole transaction or none of it, and a crash at any point
|
|
45
|
+
* leaves one of those two states on disk — never a mixture.
|
|
46
|
+
*
|
|
47
|
+
* Order matters here. The next state is built and persisted *before* it is
|
|
48
|
+
* adopted in memory, so a failed write cannot leave memory ahead of disk.
|
|
49
|
+
*/
|
|
50
|
+
commit_transaction(request: AtomicTransactionRequest): Promise<AtomicTransactionResult>;
|
|
36
51
|
insert(key: string, value: string): JsResult;
|
|
37
52
|
update(key: string, value: string): JsResult;
|
|
38
53
|
get(key: string): JsResult;
|
|
@@ -48,6 +63,24 @@ export declare class FileJsDb implements JsDb {
|
|
|
48
63
|
get_pending_for_peer(): JsResult;
|
|
49
64
|
instance_id(): string;
|
|
50
65
|
get_sequence(): number;
|
|
66
|
+
/**
|
|
67
|
+
* The file runtime declines revision validation, and this is the honest answer
|
|
68
|
+
* rather than a missing feature.
|
|
69
|
+
*
|
|
70
|
+
* A shared directory has no serialization authority over its writers.
|
|
71
|
+
* `insert`, `update`, `delete`, and `commit_transaction` do not take the
|
|
72
|
+
* cross-process lock, and publication is a whole-snapshot rename, so two
|
|
73
|
+
* processes writing the same directory lose data. `state.sequence` therefore
|
|
74
|
+
* cannot distinguish "one writer committed 50" from "two writers committed 50
|
|
75
|
+
* each and one snapshot won" — it produces a plausible but false answer,
|
|
76
|
+
* which is worse than producing none.
|
|
77
|
+
*
|
|
78
|
+
* Measured in tools/cli/test/file-runtime-concurrency.test.mjs and analysed in
|
|
79
|
+
* docs/architecture/freshness-revision-investigation.md. Making this runtime
|
|
80
|
+
* revision-capable requires fixing lock discipline and publication together;
|
|
81
|
+
* advertising `refresh` is correct until then, not a placeholder.
|
|
82
|
+
*/
|
|
83
|
+
freshness(): FreshnessCapability;
|
|
51
84
|
audit_events(): PortableEvent[];
|
|
52
85
|
export_operations(sinceSequence: number): PortableEvent[];
|
|
53
86
|
apply_remote_operations(operations: PortableEvent[]): {
|
package/dist/file-db.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file-db.d.ts","sourceRoot":"","sources":["../src/file-db.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,KAAK,EACV,uBAAuB,EACvB,wBAAwB,EACxB,wBAAwB,EACxB,yBAAyB,EAG1B,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"file-db.d.ts","sourceRoot":"","sources":["../src/file-db.ts"],"names":[],"mappings":"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"}
|