@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 CHANGED
@@ -419,16 +419,14 @@ class DataClientImpl {
419
419
  schema = liteFromPublishedSchema(published);
420
420
  }
421
421
  catch {
422
- // network / not-found — surface the friendly error below
422
+ // network / not-found — leave `schema` undefined (reads still work)
423
423
  }
424
424
  }
425
- if (!schema) {
426
- throw new Error(`sdk.data: schema "${meta.schema}" not known to the SDK and not published ` +
427
- `on the PDS for ${this.#did}. Pass it via createDataClient({ schemas: [...] }) ` +
428
- `if it's an app-defined (vendor) schema, register it via registerSchema, ` +
429
- `or upgrade the SDK if it's a core schema added in a later release.`);
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.schema);
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.schema);
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.schema);
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 = {};
@@ -1,4 +1,4 @@
1
- export declare const VERSION = "0.1.0-alpha.55";
1
+ export declare const VERSION = "0.1.0-alpha.56";
2
2
  export { AithosSDK } from "./sdk.js";
3
3
  export type { AithosSDKConfig } from "./types.js";
4
4
  export { AithosSDKError } from "./types.js";
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.55";
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("a reader still fails cleanly when the schema is neither bundled nor published", async () => {
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 WITHOUT registering the schema on the PDS.
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: "x", body: "y" });
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
- await assert.rejects(() => reader.collection("memos").get("anything"), /not known to the SDK and not published/);
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.55",
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",