From 882605867ec97054f7e2f0275566d3cdbce85e57 Mon Sep 17 00:00:00 2001 From: YifanZhang Date: Tue, 18 Aug 2026 12:48:42 +0100 Subject: [PATCH] build(ts-sdk): prepare 0.2.1 release --- typescript/ts_sdk/CHANGELOG.md | 9 ++++- typescript/ts_sdk/README.md | 4 +- typescript/ts_sdk/package-lock.json | 4 +- typescript/ts_sdk/package.json | 9 +++-- .../ts_sdk/scripts/check-dist-exports.mjs | 37 +++++++++++++++++++ typescript/ts_sdk/scripts/clean.mjs | 3 ++ typescript/ts_sdk/tests/examples-http.test.ts | 4 +- typescript/ts_sdk/tests/im-client.test.ts | 4 +- typescript/ts_sdk/tests/public-api.test.ts | 8 ++++ 9 files changed, 72 insertions(+), 10 deletions(-) create mode 100644 typescript/ts_sdk/scripts/check-dist-exports.mjs create mode 100644 typescript/ts_sdk/scripts/clean.mjs diff --git a/typescript/ts_sdk/CHANGELOG.md b/typescript/ts_sdk/CHANGELOG.md index 178b0a3..6ba236a 100644 --- a/typescript/ts_sdk/CHANGELOG.md +++ b/typescript/ts_sdk/CHANGELOG.md @@ -1,6 +1,13 @@ # Changelog -## 0.2.0 +## 0.2.1 - 2026-08-18 + +- Export the vNext device-manifest profiles, data model, builder, and validator. +- Export RFC 9421 origin-proof generation and verification helpers. +- Verify the compiled package exposes the APIs required by AWiki Lite before packing. +- Document POSIX mode and Windows ACL requirements for plaintext identity state. + +## 0.2.0 - 2026-08-16 - Add the high-level AWiki IM client for Legacy single-device registration, direct and existing-group messaging, history, and P7 attachments. - Add durable, restart-safe idempotency state for text and attachment sends. diff --git a/typescript/ts_sdk/README.md b/typescript/ts_sdk/README.md index 83baed3..d2ea98f 100644 --- a/typescript/ts_sdk/README.md +++ b/typescript/ts_sdk/README.md @@ -125,6 +125,7 @@ Low-level Rust-aligned names are still exported for compatibility. ### authentication - Create DID-WBA documents for `e1`, `k1`, and `plain_legacy` +- Build and validate vNext device manifests and their capability profiles - Resolve DID documents - Generate and verify legacy `DIDWba` authorization headers - Generate and verify HTTP Message Signatures @@ -133,6 +134,7 @@ Low-level Rust-aligned names are still exported for compatibility. ### proof - Generate W3C Data Integrity / legacy secp256k1 proofs +- Generate and verify RFC 9421 origin proofs for AWiki RPC requests - Verify proofs with domain / challenge / purpose constraints ### wns @@ -150,7 +152,7 @@ Low-level Rust-aligned names are still exported for compatibility. The first IM version intentionally uses the Legacy single-device identity profile. The legacy `send_otp` wire request contains only the phone number; the SDK retains the handle locally and requires the same handle and phone when registration is completed. Manifest registration, multiple identities, multiple devices, end-to-end encryption, real-time subscriptions, and group creation are not included. -The SDK stores private identity material and access tokens as plaintext JSON at `statePath` and writes the state file with mode `0600`. This prevents access by other OS accounts under normal permission enforcement, but the same OS account and anyone who can read backups can recover the private key and token. Production deployments should use disk encryption and encrypted, access-controlled backups. Integration with a credential vault is deferred. Production service URLs must use HTTPS. HTTP loopback is available only with `allowInsecureLoopbackForTesting: true`. +The SDK stores private identity material and access tokens as plaintext JSON at `statePath`. On POSIX systems, it writes the state file with mode `0600`. On Windows, Node.js mode bits do not configure owner-only ACLs, so the state directory must already be protected by a per-user ACL. The same OS account and anyone who can read backups can recover the private key and token. Production deployments should use disk encryption and encrypted, access-controlled backups. Integration with a credential vault is deferred. Production service URLs must use HTTPS. HTTP loopback is available only with `allowInsecureLoopbackForTesting: true`. `userServiceDomain`, `messageServicePublicUrl`, and the bare-domain `did:wba` `messageServiceDid` are explicit because an internal API origin does not necessarily equal the public identity domain or advertised Message Service. `allowedAttachmentOrigins` is an exact origin allowlist for untrusted sender DID resolution, advertised attachment endpoints, upload URLs, and object URLs. Add every trusted cross-Home and object-store origin needed by the deployment; the SDK rejects other origins instead of following them. diff --git a/typescript/ts_sdk/package-lock.json b/typescript/ts_sdk/package-lock.json index 6d2e3a3..b18fc35 100644 --- a/typescript/ts_sdk/package-lock.json +++ b/typescript/ts_sdk/package-lock.json @@ -1,12 +1,12 @@ { "name": "@awiki/anp-typescript-sdk", - "version": "0.2.0", + "version": "0.2.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@awiki/anp-typescript-sdk", - "version": "0.2.0", + "version": "0.2.1", "license": "Apache-2.0", "dependencies": { "@noble/curves": "^1.8.2", diff --git a/typescript/ts_sdk/package.json b/typescript/ts_sdk/package.json index 241cbd2..445178c 100644 --- a/typescript/ts_sdk/package.json +++ b/typescript/ts_sdk/package.json @@ -1,6 +1,6 @@ { "name": "@awiki/anp-typescript-sdk", - "version": "0.2.0", + "version": "0.2.1", "description": "TypeScript SDK for Agent Network Protocol (ANP)", "type": "module", "main": "./dist/index.cjs", @@ -29,10 +29,11 @@ "format": "prettier --write \"src/**/*.ts\" \"tests/**/*.ts\"", "format:check": "prettier --check \"src/**/*.ts\" \"tests/**/*.ts\"", "typecheck": "tsc --noEmit", - "prepublishOnly": "npm run build && npm run test", + "check:dist": "node ./scripts/check-dist-exports.mjs", + "prepublishOnly": "npm run typecheck && npm run test", "dev": "tsup --watch", - "clean": "rm -rf dist", - "prepack": "npm run clean && npm run build", + "clean": "node ./scripts/clean.mjs", + "prepack": "npm run clean && npm run build && npm run check:dist", "publish:dry-run": "npm publish --dry-run" }, "keywords": [ diff --git a/typescript/ts_sdk/scripts/check-dist-exports.mjs b/typescript/ts_sdk/scripts/check-dist-exports.mjs new file mode 100644 index 0000000..aadf87f --- /dev/null +++ b/typescript/ts_sdk/scripts/check-dist-exports.mjs @@ -0,0 +1,37 @@ +import * as sdk from '../dist/index.js'; + +const expectedFunctions = [ + 'DeviceManifestEntry', + 'buildVnextDidDocument', + 'generateRfc9421OriginProof', + 'validateDeviceManifest', +]; + +const expectedConstants = { + PROFILE_CORE_BINDING_V1: 'anp.core.binding.v1', + PROFILE_DIRECT_BASE_V1: 'anp.direct.base.v1', + PROFILE_DIRECT_E2EE_V2: 'anp.direct.e2ee.v2', + PROFILE_GROUP_BASE_V1: 'anp.group.base.v1', + PROFILE_GROUP_E2EE_V2: 'anp.group.e2ee.v2', + PROFILE_IDENTITY_DISCOVERY_V1: 'anp.identity.discovery.v1', +}; + +const failures = []; +for (const name of expectedFunctions) { + if (typeof sdk[name] !== 'function') { + failures.push(`${name} must be a function`); + } +} +for (const [name, expected] of Object.entries(expectedConstants)) { + if (sdk[name] !== expected) { + failures.push(`${name} must equal ${JSON.stringify(expected)}`); + } +} + +if (failures.length > 0) { + throw new Error(`built package export check failed:\n${failures.join('\n')}`); +} + +console.log( + `Verified ${expectedFunctions.length + Object.keys(expectedConstants).length} Lite SDK exports.` +); diff --git a/typescript/ts_sdk/scripts/clean.mjs b/typescript/ts_sdk/scripts/clean.mjs new file mode 100644 index 0000000..b40ab62 --- /dev/null +++ b/typescript/ts_sdk/scripts/clean.mjs @@ -0,0 +1,3 @@ +import { rmSync } from 'node:fs'; + +rmSync(new URL('../dist', import.meta.url), { recursive: true, force: true }); diff --git a/typescript/ts_sdk/tests/examples-http.test.ts b/typescript/ts_sdk/tests/examples-http.test.ts index d570c01..5d802a4 100644 --- a/typescript/ts_sdk/tests/examples-http.test.ts +++ b/typescript/ts_sdk/tests/examples-http.test.ts @@ -43,8 +43,10 @@ describe('DID-WBA HTTP examples', () => { ...env, PYTHONPATH: repoRoot, }; + const pythonCommand = + process.env.ANP_PYTHON ?? (process.platform === 'win32' ? 'python' : 'python3'); const pythonClient = await runCommand( - 'python3', + pythonCommand, [join('typescript', 'ts_sdk', 'examples', 'python_to_ts_did_wba_client.py')], repoRoot, pythonEnv diff --git a/typescript/ts_sdk/tests/im-client.test.ts b/typescript/ts_sdk/tests/im-client.test.ts index af99ec1..57b3610 100644 --- a/typescript/ts_sdk/tests/im-client.test.ts +++ b/typescript/ts_sdk/tests/im-client.test.ts @@ -76,7 +76,9 @@ describe('AWiki IM client', () => { expect(persisted).toContain('test-access-token'); expect(JSON.stringify(identity)).not.toContain('PRIVATE KEY'); expect(JSON.stringify(identity)).not.toContain('token'); - expect((await stat(statePath)).mode & 0o777).toBe(0o600); + if (process.platform !== 'win32') { + expect((await stat(statePath)).mode & 0o777).toBe(0o600); + } await client.dispose(); const restored = createClient(service, statePath); diff --git a/typescript/ts_sdk/tests/public-api.test.ts b/typescript/ts_sdk/tests/public-api.test.ts index ab446c4..252f79d 100644 --- a/typescript/ts_sdk/tests/public-api.test.ts +++ b/typescript/ts_sdk/tests/public-api.test.ts @@ -59,6 +59,14 @@ describe('public API aliases', () => { expect(buildVnextDidDocument).toBeTypeOf('function'); expect(validateDeviceManifest).toBeTypeOf('function'); expect(authentication.deviceManifest.buildVnextDidDocument).toBeTypeOf('function'); + expect(sdk).toMatchObject({ + PROFILE_CORE_BINDING_V1: 'anp.core.binding.v1', + PROFILE_DIRECT_BASE_V1: 'anp.direct.base.v1', + PROFILE_DIRECT_E2EE_V2: 'anp.direct.e2ee.v2', + PROFILE_GROUP_BASE_V1: 'anp.group.base.v1', + PROFILE_GROUP_E2EE_V2: 'anp.group.e2ee.v2', + PROFILE_IDENTITY_DISCOVERY_V1: 'anp.identity.discovery.v1', + }); expect('buildOriginAuthentication' in sdk).toBe(false); expect((sdk as Record).buildOriginAuthentication).toBeUndefined(); });