@aithos/sdk 0.1.0-alpha.55 → 0.1.0-alpha.56
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/src/data.js +25 -12
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.js +1 -1
- package/dist/test/schema-autoresolve.test.js +14 -4
- package/package.json +1 -1
package/dist/src/data.js
CHANGED
|
@@ -419,16 +419,14 @@ class DataClientImpl {
|
|
|
419
419
|
schema = liteFromPublishedSchema(published);
|
|
420
420
|
}
|
|
421
421
|
catch {
|
|
422
|
-
// network / not-found —
|
|
422
|
+
// network / not-found — leave `schema` undefined (reads still work)
|
|
423
423
|
}
|
|
424
424
|
}
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
}
|
|
431
|
-
const state = { name, urn: meta.urn, schema };
|
|
425
|
+
// Do NOT throw when the schema is unknown: reads decrypt from the CMK +
|
|
426
|
+
// metadata/payload alone (the schema is only needed to SPLIT on write).
|
|
427
|
+
// Leaving `schema` undefined keeps the collection fully readable; an
|
|
428
|
+
// insert/update will surface a precise "schema required to write" error.
|
|
429
|
+
const state = { name, urn: meta.urn, ...(schema ? { schema } : {}), schemaId: meta.schema };
|
|
432
430
|
this.#colCache.set(name, state);
|
|
433
431
|
return state;
|
|
434
432
|
}
|
|
@@ -437,7 +435,7 @@ class DataClientImpl {
|
|
|
437
435
|
const cmk = this.#cmkCache.get(state.name);
|
|
438
436
|
if (!cmk)
|
|
439
437
|
throw new Error("CMK not loaded");
|
|
440
|
-
const { metadata, payload } = splitRecord(record, state
|
|
438
|
+
const { metadata, payload } = splitRecord(record, requireSchema(state));
|
|
441
439
|
const recordId = `record_${makeUlid()}`;
|
|
442
440
|
const encrypted = this.#encryptPayload({
|
|
443
441
|
collectionName: state.name,
|
|
@@ -506,7 +504,7 @@ class DataClientImpl {
|
|
|
506
504
|
const cmk = this.#cmkCache.get(state.name);
|
|
507
505
|
if (!cmk)
|
|
508
506
|
throw new Error("CMK not loaded");
|
|
509
|
-
const { metadata, payload } = splitRecord(record, state
|
|
507
|
+
const { metadata, payload } = splitRecord(record, requireSchema(state));
|
|
510
508
|
const encrypted = this.#encryptPayload({
|
|
511
509
|
collectionName: state.name,
|
|
512
510
|
recordId,
|
|
@@ -757,7 +755,7 @@ class DataClientImpl {
|
|
|
757
755
|
if (!this.#deposit) {
|
|
758
756
|
throw new Error("sdk.data: _insertDeposit called without a deposit session");
|
|
759
757
|
}
|
|
760
|
-
const { metadata, payload } = splitRecord(record, state
|
|
758
|
+
const { metadata, payload } = splitRecord(record, requireSchema(state));
|
|
761
759
|
const recordId = `record_${makeUlid()}`;
|
|
762
760
|
const encrypted = this.#encryptPayloadForOwner({
|
|
763
761
|
collectionName: state.name,
|
|
@@ -777,7 +775,7 @@ class DataClientImpl {
|
|
|
777
775
|
/** Build a local collection state for the deposit path (no server fetch:
|
|
778
776
|
* append clients are not authorized to read collection metadata). */
|
|
779
777
|
_depositCollectionState(name, schema) {
|
|
780
|
-
return { name, urn: this.#collectionUrn(name), schema };
|
|
778
|
+
return { name, urn: this.#collectionUrn(name), schema, schemaId: schema.schema };
|
|
781
779
|
}
|
|
782
780
|
}
|
|
783
781
|
class DataCollectionImpl {
|
|
@@ -848,6 +846,21 @@ export function liteFromPublishedSchema(doc) {
|
|
|
848
846
|
defaults: {},
|
|
849
847
|
};
|
|
850
848
|
}
|
|
849
|
+
/**
|
|
850
|
+
* Return the collection's write schema or throw a precise error. Writes need
|
|
851
|
+
* the schema to split a record into indexable metadata vs encrypted payload (and
|
|
852
|
+
* so the PDS can validate); reads never call this.
|
|
853
|
+
*/
|
|
854
|
+
function requireSchema(state) {
|
|
855
|
+
if (!state.schema) {
|
|
856
|
+
const e = new Error(`sdk.data: writing to "${state.name}" needs its schema "${state.schemaId}", which is ` +
|
|
857
|
+
`neither bundled in this client (createDataClient({ schemas: [...] })) nor published on ` +
|
|
858
|
+
`the PDS (registerSchema). Reads work without it — only inserts/updates require it.`);
|
|
859
|
+
e.code = -32602;
|
|
860
|
+
throw e;
|
|
861
|
+
}
|
|
862
|
+
return state.schema;
|
|
863
|
+
}
|
|
851
864
|
function splitRecord(record, schema) {
|
|
852
865
|
const metadata = {};
|
|
853
866
|
const payload = {};
|
package/dist/src/index.d.ts
CHANGED
package/dist/src/index.js
CHANGED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
// Public types specific to the SDK (`AithosSDKConfig`, `AithosSDKError`)
|
|
18
18
|
// are exported from here. Endpoint config (`AithosSdkEndpoints`,
|
|
19
19
|
// `DEFAULT_SDK_ENDPOINTS`) likewise.
|
|
20
|
-
export const VERSION = "0.1.0-alpha.
|
|
20
|
+
export const VERSION = "0.1.0-alpha.56";
|
|
21
21
|
export { AithosSDK } from "./sdk.js";
|
|
22
22
|
export { AithosSDKError } from "./types.js";
|
|
23
23
|
// Re-export protocol-client's JSON-RPC error type so consumers can
|
|
@@ -109,7 +109,7 @@ test("a reader without the bundled vendor lite decodes via the published schema"
|
|
|
109
109
|
assert.equal(got.title, "Hello", "indexable field present");
|
|
110
110
|
assert.equal(got.body, "top secret body", "encrypted field decoded via auto-resolved schema");
|
|
111
111
|
});
|
|
112
|
-
test("
|
|
112
|
+
test("schema-less READ still works (decrypts); only WRITE requires the schema", async () => {
|
|
113
113
|
const seed = new Uint8Array(randomBytes(32));
|
|
114
114
|
const pub = ed.getPublicKey(seed);
|
|
115
115
|
let n = 0n;
|
|
@@ -126,11 +126,21 @@ test("a reader still fails cleanly when the schema is neither bundled nor publis
|
|
|
126
126
|
const did = `did:key:z${mb}`;
|
|
127
127
|
const vm = `${did}#z${mb}`;
|
|
128
128
|
const pds = makePds();
|
|
129
|
-
// Writer creates the collection
|
|
129
|
+
// Writer bundles the lite, creates the collection + a record, but does NOT
|
|
130
|
+
// register the schema on the PDS (simulates an app like delie that keeps its
|
|
131
|
+
// schema local). So no client can auto-resolve it.
|
|
130
132
|
const writer = createDataClient({ pdsUrl: "https://pds.test", did, sphereSeed: seed, verificationMethod: vm, schemas: [memoLite], fetch: pds.fetchImpl });
|
|
131
133
|
await writer.createCollection({ name: "memos", schema: MEMO_ID });
|
|
132
|
-
await writer.collection("memos").insert({ title: "
|
|
134
|
+
const recId = await writer.collection("memos").insert({ title: "Hi", body: "encrypted secret" });
|
|
135
|
+
// Reader has NEITHER the bundled lite NOR a published schema to fetch.
|
|
133
136
|
const reader = createDataClient({ pdsUrl: "https://pds.test", did, sphereSeed: seed, verificationMethod: vm, fetch: pds.fetchImpl });
|
|
134
|
-
|
|
137
|
+
// READ still works — records decrypt from the CMK + metadata/payload; the
|
|
138
|
+
// schema is only needed to SPLIT on write. This is what makes a migrated
|
|
139
|
+
// collection directly usable under #data by any client.
|
|
140
|
+
const got = await reader.collection("memos").get(recId);
|
|
141
|
+
assert.equal(got.title, "Hi", "indexable field (plaintext metadata) present");
|
|
142
|
+
assert.equal(got.body, "encrypted secret", "encrypted field decrypted WITHOUT the schema");
|
|
143
|
+
// WRITE fails cleanly (can't split/validate without the schema).
|
|
144
|
+
await assert.rejects(() => reader.collection("memos").insert({ title: "no", body: "go" }), /needs its schema/);
|
|
135
145
|
});
|
|
136
146
|
//# sourceMappingURL=schema-autoresolve.test.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aithos/sdk",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.56",
|
|
4
4
|
"description": "Aithos SDK — high-level TypeScript developer kit for building agentic apps on the Aithos protocol. Wraps @aithos/protocol-client and exposes the Aithos compute proxy and wallet (Stripe top-up) endpoints.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"aithos",
|