Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion typescript/ts_sdk/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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.
Expand Down
4 changes: 3 additions & 1 deletion typescript/ts_sdk/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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.

Expand Down
4 changes: 2 additions & 2 deletions typescript/ts_sdk/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 5 additions & 4 deletions typescript/ts_sdk/package.json
Original file line number Diff line number Diff line change
@@ -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",
Expand Down Expand Up @@ -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": [
Expand Down
37 changes: 37 additions & 0 deletions typescript/ts_sdk/scripts/check-dist-exports.mjs
Original file line number Diff line number Diff line change
@@ -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.`
);
3 changes: 3 additions & 0 deletions typescript/ts_sdk/scripts/clean.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { rmSync } from 'node:fs';

rmSync(new URL('../dist', import.meta.url), { recursive: true, force: true });
4 changes: 3 additions & 1 deletion typescript/ts_sdk/tests/examples-http.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 3 additions & 1 deletion typescript/ts_sdk/tests/im-client.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
8 changes: 8 additions & 0 deletions typescript/ts_sdk/tests/public-api.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<string, unknown>).buildOriginAuthentication).toBeUndefined();
});
Expand Down