Skip to content

Transactions

The SDK exposes one typed helper per current NOOSChain transaction type. These helpers use the same payload schemas as the chain executor through src/protocol/public-api.ts.

For bucket concepts, encryption modes, schemas, and permissions, see Data Buckets and Permission Model.

Example transaction REGISTER_ORGANIZATION:

ts
await client.transactions.registerOrganization({
  signer,
  nonce: "auto",
  payload: {
    id: "org-example",
    name: "Example Organization",
    metadata: {},
  },
});

Use build for generic flows. This example builds transaction CREATE_BUCKET:

ts
await client.transactions.build({
  type: DomainTransactionType.CreateBucket,
  signer,
  nonce: 2n,
  payload,
});

nonce: "auto" resolves the next nonce from the node through GET /identity/nonce. The SDK sends the signer public key in x-noos-signer-public-key-base64, not in the URL query string. Use explicit nonces for offline signing, batch coordination, or air-gapped workflows.

Use submit(tx) to post the signed transaction to /transactions. The SDK never writes database rows directly.

Transaction CREATE_BUCKET field indexSchema.indexes[].type supports string, number, integer, float, boolean, date, and datetime. number is the backward-compatible finite JSON number type, integer rejects fractional values, and float accepts any finite JSON number. Use date for calendar-only YYYY-MM-DD values, and datetime for exact ISO-8601 UTC timestamps such as 2026-05-26T14:30:00.000Z.

Use updateBucketIndexSchema for compatible public-index schema evolution. This builds transaction UPDATE_BUCKET_INDEX_SCHEMA:

ts
await client.transactions.updateBucketIndexSchema({
  signer,
  nonce: "auto",
  payload: {
    bucketId: "bucket-project-data",
    mode: "compatible",
    indexSchema: {
      indexes: [
        { key: "projectId", type: "string", required: true },
        { key: "score", type: "float" },
      ],
    },
  },
});

The chain accepts optional fields and widened allowedValues. It rejects removing fields, changing types, adding required fields, changing requiredness, or narrowing allowedValues. Updates affect future record validation and search validation only; historical records are not rewritten.

Encrypted Records From Plaintext

For browser/public API clients, prefer addEncryptedRecordFromPlaintext(...) or submitAddEncryptedRecordFromPlaintext(...) instead of collecting transaction ADD_ENCRYPTED_RECORD low-level JSON from users.

ts
const { transaction, submission } =
  await client.transactions.submitAddEncryptedRecordFromPlaintext({
    signer,
    payload: {
      bucketId: "bucket-project-data",
      plaintextUtf8: JSON.stringify({ private: "payload" }),
    },
    publicQueryData: {
      projectId: "project-a",
      reviewed: true,
    },
    actorPublicKey: signer.publicKey,
  });

The helper performs the frontend work for encrypted records:

  • calls POST /buckets/:id/records/prepare-add-encrypted-record with the actor public key and plaintext;
  • lets the node verify bucket:write, generate a raw UUID record id, encrypt the payload, calculate payloadHash, and derive record envelopes or bucket-key references;
  • receives a short-lived preparedTransactionId and exact unsigned transaction ADD_ENCRYPTED_RECORD envelope;
  • signs that exact envelope;
  • submits the signed transaction to /transactions with the preparedTransactionId.

The node rejects altered, expired, reused, or unprepared transaction ADD_ENCRYPTED_RECORD submissions. The prepare endpoint also rejects client-supplied record ids; deterministic record ids are not supported by this public write flow. For per_record_key, the prepared transaction carries record-level key envelopes for the generated record DEK. For per_bucket_key, record-level key envelopes are normally empty; the prepared transaction references the active bucketKeyId/bucketKeyVersion, and the SDK does not receive bucket-key envelopes during write preparation.

The SDK does not send user private keys to the node. Plaintext does reach the API in this prepared write flow, and the API temporarily sees generated per-record DEKs unless encryption is moved behind KMS/HSM/enclave custody. Choose this helper only when that trust boundary is acceptable for the application.

Tests

Run the SDK transaction tests from the repository root:

powershell
npm run nooschain-ts:test

The prepared encrypted-record regression coverage lives in apps/nooschain-ts/test/sdk.test.ts. It verifies that the plaintext helper:

  • calls POST /buckets/:id/records/prepare-add-encrypted-record;
  • sends the actor public key and plaintext to the prepare endpoint;
  • does not send a client-generated record id;
  • does not call the legacy encrypted-wrap-dek path;
  • signs the exact prepared transaction ADD_ENCRYPTED_RECORD envelope;
  • submits the signed transaction to /transactions with the returned preparedTransactionId.

Run npm run nooschain-ts:build after changing exported SDK types, and npm run typecheck when the change may affect monorepo consumers such as apps/noos-web-gui.

Audience-first NOOSChain documentation.