@claw-network/node 0.2.0
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/README.md +49 -0
- package/dist/api/api-key-store.d.ts +74 -0
- package/dist/api/api-key-store.d.ts.map +1 -0
- package/dist/api/api-key-store.js +170 -0
- package/dist/api/api-key-store.js.map +1 -0
- package/dist/api/auth.d.ts +30 -0
- package/dist/api/auth.d.ts.map +1 -0
- package/dist/api/auth.js +115 -0
- package/dist/api/auth.js.map +1 -0
- package/dist/api/legacy.d.ts +26 -0
- package/dist/api/legacy.d.ts.map +1 -0
- package/dist/api/legacy.js +281 -0
- package/dist/api/legacy.js.map +1 -0
- package/dist/api/middleware.d.ts +35 -0
- package/dist/api/middleware.d.ts.map +1 -0
- package/dist/api/middleware.js +75 -0
- package/dist/api/middleware.js.map +1 -0
- package/dist/api/response.d.ts +85 -0
- package/dist/api/response.d.ts.map +1 -0
- package/dist/api/response.js +185 -0
- package/dist/api/response.js.map +1 -0
- package/dist/api/router.d.ts +45 -0
- package/dist/api/router.d.ts.map +1 -0
- package/dist/api/router.js +183 -0
- package/dist/api/router.js.map +1 -0
- package/dist/api/routes/admin.d.ts +11 -0
- package/dist/api/routes/admin.d.ts.map +1 -0
- package/dist/api/routes/admin.js +124 -0
- package/dist/api/routes/admin.js.map +1 -0
- package/dist/api/routes/contracts.d.ts +7 -0
- package/dist/api/routes/contracts.d.ts.map +1 -0
- package/dist/api/routes/contracts.js +665 -0
- package/dist/api/routes/contracts.js.map +1 -0
- package/dist/api/routes/dao.d.ts +7 -0
- package/dist/api/routes/dao.d.ts.map +1 -0
- package/dist/api/routes/dao.js +549 -0
- package/dist/api/routes/dao.js.map +1 -0
- package/dist/api/routes/dev.d.ts +9 -0
- package/dist/api/routes/dev.d.ts.map +1 -0
- package/dist/api/routes/dev.js +273 -0
- package/dist/api/routes/dev.js.map +1 -0
- package/dist/api/routes/escrows.d.ts +7 -0
- package/dist/api/routes/escrows.d.ts.map +1 -0
- package/dist/api/routes/escrows.js +454 -0
- package/dist/api/routes/escrows.js.map +1 -0
- package/dist/api/routes/identities.d.ts +7 -0
- package/dist/api/routes/identities.d.ts.map +1 -0
- package/dist/api/routes/identities.js +245 -0
- package/dist/api/routes/identities.js.map +1 -0
- package/dist/api/routes/markets-capabilities.d.ts +7 -0
- package/dist/api/routes/markets-capabilities.d.ts.map +1 -0
- package/dist/api/routes/markets-capabilities.js +477 -0
- package/dist/api/routes/markets-capabilities.js.map +1 -0
- package/dist/api/routes/markets-disputes.d.ts +7 -0
- package/dist/api/routes/markets-disputes.d.ts.map +1 -0
- package/dist/api/routes/markets-disputes.js +102 -0
- package/dist/api/routes/markets-disputes.js.map +1 -0
- package/dist/api/routes/markets-info.d.ts +7 -0
- package/dist/api/routes/markets-info.d.ts.map +1 -0
- package/dist/api/routes/markets-info.js +523 -0
- package/dist/api/routes/markets-info.js.map +1 -0
- package/dist/api/routes/markets-search.d.ts +7 -0
- package/dist/api/routes/markets-search.d.ts.map +1 -0
- package/dist/api/routes/markets-search.js +38 -0
- package/dist/api/routes/markets-search.js.map +1 -0
- package/dist/api/routes/markets-tasks.d.ts +7 -0
- package/dist/api/routes/markets-tasks.d.ts.map +1 -0
- package/dist/api/routes/markets-tasks.js +539 -0
- package/dist/api/routes/markets-tasks.js.map +1 -0
- package/dist/api/routes/node.d.ts +7 -0
- package/dist/api/routes/node.d.ts.map +1 -0
- package/dist/api/routes/node.js +53 -0
- package/dist/api/routes/node.js.map +1 -0
- package/dist/api/routes/nonce.d.ts +10 -0
- package/dist/api/routes/nonce.d.ts.map +1 -0
- package/dist/api/routes/nonce.js +65 -0
- package/dist/api/routes/nonce.js.map +1 -0
- package/dist/api/routes/reputations.d.ts +7 -0
- package/dist/api/routes/reputations.d.ts.map +1 -0
- package/dist/api/routes/reputations.js +243 -0
- package/dist/api/routes/reputations.js.map +1 -0
- package/dist/api/routes/transfers.d.ts +7 -0
- package/dist/api/routes/transfers.d.ts.map +1 -0
- package/dist/api/routes/transfers.js +88 -0
- package/dist/api/routes/transfers.js.map +1 -0
- package/dist/api/routes/wallets.d.ts +7 -0
- package/dist/api/routes/wallets.d.ts.map +1 -0
- package/dist/api/routes/wallets.js +132 -0
- package/dist/api/routes/wallets.js.map +1 -0
- package/dist/api/schemas/common.d.ts +45 -0
- package/dist/api/schemas/common.d.ts.map +1 -0
- package/dist/api/schemas/common.js +30 -0
- package/dist/api/schemas/common.js.map +1 -0
- package/dist/api/schemas/contracts.d.ts +284 -0
- package/dist/api/schemas/contracts.d.ts.map +1 -0
- package/dist/api/schemas/contracts.js +79 -0
- package/dist/api/schemas/contracts.js.map +1 -0
- package/dist/api/schemas/dao.d.ts +271 -0
- package/dist/api/schemas/dao.d.ts.map +1 -0
- package/dist/api/schemas/dao.js +78 -0
- package/dist/api/schemas/dao.js.map +1 -0
- package/dist/api/schemas/identity.d.ts +75 -0
- package/dist/api/schemas/identity.d.ts.map +1 -0
- package/dist/api/schemas/identity.js +32 -0
- package/dist/api/schemas/identity.js.map +1 -0
- package/dist/api/schemas/markets.d.ts +822 -0
- package/dist/api/schemas/markets.d.ts.map +1 -0
- package/dist/api/schemas/markets.js +246 -0
- package/dist/api/schemas/markets.js.map +1 -0
- package/dist/api/schemas/wallet.d.ts +163 -0
- package/dist/api/schemas/wallet.d.ts.map +1 -0
- package/dist/api/schemas/wallet.js +54 -0
- package/dist/api/schemas/wallet.js.map +1 -0
- package/dist/api/server.d.ts +45 -0
- package/dist/api/server.d.ts.map +1 -0
- package/dist/api/server.js +131 -0
- package/dist/api/server.js.map +1 -0
- package/dist/api/types.d.ts +69 -0
- package/dist/api/types.d.ts.map +1 -0
- package/dist/api/types.js +196 -0
- package/dist/api/types.js.map +1 -0
- package/dist/daemon.d.ts +11 -0
- package/dist/daemon.d.ts.map +1 -0
- package/dist/daemon.js +248 -0
- package/dist/daemon.js.map +1 -0
- package/dist/index.d.ts +137 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +795 -0
- package/dist/index.js.map +1 -0
- package/dist/indexer/index.d.ts +10 -0
- package/dist/indexer/index.d.ts.map +1 -0
- package/dist/indexer/index.js +7 -0
- package/dist/indexer/index.js.map +1 -0
- package/dist/indexer/indexer.d.ts +60 -0
- package/dist/indexer/indexer.d.ts.map +1 -0
- package/dist/indexer/indexer.js +408 -0
- package/dist/indexer/indexer.js.map +1 -0
- package/dist/indexer/query.d.ts +141 -0
- package/dist/indexer/query.d.ts.map +1 -0
- package/dist/indexer/query.js +244 -0
- package/dist/indexer/query.js.map +1 -0
- package/dist/indexer/store.d.ts +95 -0
- package/dist/indexer/store.d.ts.map +1 -0
- package/dist/indexer/store.js +250 -0
- package/dist/indexer/store.js.map +1 -0
- package/dist/logger.d.ts +13 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +37 -0
- package/dist/logger.js.map +1 -0
- package/dist/p2p/sync.d.ts +105 -0
- package/dist/p2p/sync.d.ts.map +1 -0
- package/dist/p2p/sync.js +875 -0
- package/dist/p2p/sync.js.map +1 -0
- package/dist/policy/liquidity-policy.d.ts +17 -0
- package/dist/policy/liquidity-policy.d.ts.map +1 -0
- package/dist/policy/liquidity-policy.js +112 -0
- package/dist/policy/liquidity-policy.js.map +1 -0
- package/dist/services/chain-config.d.ts +226 -0
- package/dist/services/chain-config.d.ts.map +1 -0
- package/dist/services/chain-config.js +105 -0
- package/dist/services/chain-config.js.map +1 -0
- package/dist/services/contract-provider.d.ts +44 -0
- package/dist/services/contract-provider.d.ts.map +1 -0
- package/dist/services/contract-provider.js +167 -0
- package/dist/services/contract-provider.js.map +1 -0
- package/dist/services/contracts-service.d.ts +192 -0
- package/dist/services/contracts-service.d.ts.map +1 -0
- package/dist/services/contracts-service.js +336 -0
- package/dist/services/contracts-service.js.map +1 -0
- package/dist/services/dao-service.d.ts +245 -0
- package/dist/services/dao-service.d.ts.map +1 -0
- package/dist/services/dao-service.js +389 -0
- package/dist/services/dao-service.js.map +1 -0
- package/dist/services/identity-service.d.ts +150 -0
- package/dist/services/identity-service.d.ts.map +1 -0
- package/dist/services/identity-service.js +286 -0
- package/dist/services/identity-service.js.map +1 -0
- package/dist/services/index.d.ts +20 -0
- package/dist/services/index.d.ts.map +1 -0
- package/dist/services/index.js +15 -0
- package/dist/services/index.js.map +1 -0
- package/dist/services/reputation-service.d.ts +128 -0
- package/dist/services/reputation-service.d.ts.map +1 -0
- package/dist/services/reputation-service.js +204 -0
- package/dist/services/reputation-service.js.map +1 -0
- package/dist/services/wallet-service.d.ts +201 -0
- package/dist/services/wallet-service.d.ts.map +1 -0
- package/dist/services/wallet-service.js +402 -0
- package/dist/services/wallet-service.js.map +1 -0
- package/package.json +66 -0
package/README.md
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# @claw-network/node
|
|
2
|
+
|
|
3
|
+
> ClawNet node daemon — HTTP API and P2P networking for the AI agent economy.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @claw-network/node
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
### Start as daemon
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npx clawnetd
|
|
17
|
+
# API available at http://127.0.0.1:9528
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
### Options
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
clawnetd [options]
|
|
24
|
+
|
|
25
|
+
--data-dir <path> Override storage root
|
|
26
|
+
--api-host <host> API host (default: 127.0.0.1)
|
|
27
|
+
--api-port <port> API port (default: 9528)
|
|
28
|
+
--no-api Disable local API server
|
|
29
|
+
--listen <multiaddr> libp2p listen address (repeatable)
|
|
30
|
+
--bootstrap <multiaddr> Bootstrap peer (repeatable)
|
|
31
|
+
-h, --help Show help
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Programmatic
|
|
35
|
+
|
|
36
|
+
```typescript
|
|
37
|
+
import { startDaemon } from '@claw-network/node';
|
|
38
|
+
|
|
39
|
+
await startDaemon(['--api-port', '9528']);
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Documentation
|
|
43
|
+
|
|
44
|
+
- [Deployment Guide](https://github.com/claw-network/clawnet/blob/main/docs/DEPLOYMENT.md)
|
|
45
|
+
- [API Reference](https://github.com/claw-network/clawnet/blob/main/docs/API_REFERENCE.md)
|
|
46
|
+
|
|
47
|
+
## License
|
|
48
|
+
|
|
49
|
+
MIT
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* API Key Store — SQLite-backed multi-key management.
|
|
3
|
+
*
|
|
4
|
+
* Each key has:
|
|
5
|
+
* - id: auto-increment primary key
|
|
6
|
+
* - key: 64-char hex token (crypto-random)
|
|
7
|
+
* - label: human-readable tag (e.g. "alice-agent", "bot-prod")
|
|
8
|
+
* - status: 'active' | 'revoked'
|
|
9
|
+
* - createdAt: ISO-8601 timestamp
|
|
10
|
+
* - revokedAt: ISO-8601 timestamp (nullable)
|
|
11
|
+
* - lastUsedAt: ISO-8601 timestamp (nullable)
|
|
12
|
+
*
|
|
13
|
+
* Uses the same `better-sqlite3` that IndexerStore already depends on.
|
|
14
|
+
*/
|
|
15
|
+
export interface ApiKeyRecord {
|
|
16
|
+
id: number;
|
|
17
|
+
key: string;
|
|
18
|
+
label: string;
|
|
19
|
+
status: 'active' | 'revoked';
|
|
20
|
+
createdAt: string;
|
|
21
|
+
revokedAt: string | null;
|
|
22
|
+
lastUsedAt: string | null;
|
|
23
|
+
}
|
|
24
|
+
/** Public-facing record (omits the full key, shows only prefix). */
|
|
25
|
+
export interface ApiKeySummary {
|
|
26
|
+
id: number;
|
|
27
|
+
keyPrefix: string;
|
|
28
|
+
label: string;
|
|
29
|
+
status: 'active' | 'revoked';
|
|
30
|
+
createdAt: string;
|
|
31
|
+
revokedAt: string | null;
|
|
32
|
+
lastUsedAt: string | null;
|
|
33
|
+
}
|
|
34
|
+
export declare class ApiKeyStore {
|
|
35
|
+
private readonly db;
|
|
36
|
+
private stmtInsert;
|
|
37
|
+
private stmtLookup;
|
|
38
|
+
private stmtListAll;
|
|
39
|
+
private stmtListActive;
|
|
40
|
+
private stmtRevoke;
|
|
41
|
+
private stmtTouch;
|
|
42
|
+
private stmtGetById;
|
|
43
|
+
private stmtDelete;
|
|
44
|
+
constructor(dbPath: string);
|
|
45
|
+
/**
|
|
46
|
+
* Add the `key_prefix` column if it doesn't exist yet (schema upgrade).
|
|
47
|
+
* SQLite has no `ADD COLUMN IF NOT EXISTS`, so check PRAGMA table_info.
|
|
48
|
+
*/
|
|
49
|
+
private migrateAddKeyPrefix;
|
|
50
|
+
/**
|
|
51
|
+
* One-time migration: if the `key_prefix` column was just added to an
|
|
52
|
+
* existing database, hash any plaintext keys that are still stored.
|
|
53
|
+
* Plaintext keys are 64-char hex; hashed keys are also 64-char hex but
|
|
54
|
+
* we detect the old schema by checking whether `key_prefix` is empty.
|
|
55
|
+
*/
|
|
56
|
+
private migrateHashKeys;
|
|
57
|
+
private prepareStatements;
|
|
58
|
+
/** Generate a new API key. Returns the full plaintext key (only shown once). */
|
|
59
|
+
create(label: string): ApiKeyRecord;
|
|
60
|
+
/** Validate an API key. Returns the record if active, null otherwise. */
|
|
61
|
+
validate(key: string): ApiKeyRecord | null;
|
|
62
|
+
/** List all keys (with truncated key values for safety). */
|
|
63
|
+
list(includeRevoked?: boolean): ApiKeySummary[];
|
|
64
|
+
/** Get a key by ID (returns null if not found). */
|
|
65
|
+
getById(id: number): ApiKeyRecord | null;
|
|
66
|
+
/** Revoke a key. Returns true if revoked, false if already revoked or not found. */
|
|
67
|
+
revoke(id: number): boolean;
|
|
68
|
+
/** Permanently delete a key. */
|
|
69
|
+
delete(id: number): boolean;
|
|
70
|
+
/** Total active key count. */
|
|
71
|
+
activeCount(): number;
|
|
72
|
+
close(): void;
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=api-key-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-key-store.d.ts","sourceRoot":"","sources":["../../src/api/api-key-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAiBH,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,QAAQ,GAAG,SAAS,CAAC;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,oEAAoE;AACpE,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,QAAQ,GAAG,SAAS,CAAC;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAyBD,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAoB;IAGvC,OAAO,CAAC,UAAU,CAAsB;IACxC,OAAO,CAAC,UAAU,CAAsB;IACxC,OAAO,CAAC,WAAW,CAAsB;IACzC,OAAO,CAAC,cAAc,CAAsB;IAC5C,OAAO,CAAC,UAAU,CAAsB;IACxC,OAAO,CAAC,SAAS,CAAsB;IACvC,OAAO,CAAC,WAAW,CAAsB;IACzC,OAAO,CAAC,UAAU,CAAsB;gBAE5B,MAAM,EAAE,MAAM;IAS1B;;;OAGG;IACH,OAAO,CAAC,mBAAmB;IAQ3B;;;;;OAKG;IACH,OAAO,CAAC,eAAe;IAiBvB,OAAO,CAAC,iBAAiB;IA6BzB,gFAAgF;IAChF,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,YAAY;IAWnC,yEAAyE;IACzE,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI;IAS1C,4DAA4D;IAC5D,IAAI,CAAC,cAAc,UAAQ,GAAG,aAAa,EAAE;IAO7C,mDAAmD;IACnD,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI;IAIxC,oFAAoF;IACpF,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IAM3B,gCAAgC;IAChC,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IAK3B,8BAA8B;IAC9B,WAAW,IAAI,MAAM;IAKrB,KAAK,IAAI,IAAI;CAGd"}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* API Key Store — SQLite-backed multi-key management.
|
|
3
|
+
*
|
|
4
|
+
* Each key has:
|
|
5
|
+
* - id: auto-increment primary key
|
|
6
|
+
* - key: 64-char hex token (crypto-random)
|
|
7
|
+
* - label: human-readable tag (e.g. "alice-agent", "bot-prod")
|
|
8
|
+
* - status: 'active' | 'revoked'
|
|
9
|
+
* - createdAt: ISO-8601 timestamp
|
|
10
|
+
* - revokedAt: ISO-8601 timestamp (nullable)
|
|
11
|
+
* - lastUsedAt: ISO-8601 timestamp (nullable)
|
|
12
|
+
*
|
|
13
|
+
* Uses the same `better-sqlite3` that IndexerStore already depends on.
|
|
14
|
+
*/
|
|
15
|
+
import Database from 'better-sqlite3';
|
|
16
|
+
import crypto from 'node:crypto';
|
|
17
|
+
// ---------------------------------------------------------------------------
|
|
18
|
+
// Key hashing — SHA-256 is sufficient because API keys are 256-bit random.
|
|
19
|
+
// ---------------------------------------------------------------------------
|
|
20
|
+
function hashKey(raw) {
|
|
21
|
+
return crypto.createHash('sha256').update(raw, 'utf8').digest('hex');
|
|
22
|
+
}
|
|
23
|
+
// ---------------------------------------------------------------------------
|
|
24
|
+
// Schema
|
|
25
|
+
// ---------------------------------------------------------------------------
|
|
26
|
+
const SCHEMA_SQL = `
|
|
27
|
+
CREATE TABLE IF NOT EXISTS api_keys (
|
|
28
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
29
|
+
key TEXT NOT NULL UNIQUE,
|
|
30
|
+
key_prefix TEXT NOT NULL DEFAULT '',
|
|
31
|
+
label TEXT NOT NULL,
|
|
32
|
+
status TEXT NOT NULL DEFAULT 'active',
|
|
33
|
+
created_at TEXT NOT NULL,
|
|
34
|
+
revoked_at TEXT,
|
|
35
|
+
last_used_at TEXT
|
|
36
|
+
);
|
|
37
|
+
CREATE INDEX IF NOT EXISTS idx_api_keys_key ON api_keys(key);
|
|
38
|
+
CREATE INDEX IF NOT EXISTS idx_api_keys_status ON api_keys(status);
|
|
39
|
+
`;
|
|
40
|
+
// ---------------------------------------------------------------------------
|
|
41
|
+
// Store
|
|
42
|
+
// ---------------------------------------------------------------------------
|
|
43
|
+
export class ApiKeyStore {
|
|
44
|
+
db;
|
|
45
|
+
// Prepared statements (lazy-init)
|
|
46
|
+
stmtInsert;
|
|
47
|
+
stmtLookup;
|
|
48
|
+
stmtListAll;
|
|
49
|
+
stmtListActive;
|
|
50
|
+
stmtRevoke;
|
|
51
|
+
stmtTouch;
|
|
52
|
+
stmtGetById;
|
|
53
|
+
stmtDelete;
|
|
54
|
+
constructor(dbPath) {
|
|
55
|
+
this.db = new Database(dbPath);
|
|
56
|
+
this.db.pragma('journal_mode = WAL');
|
|
57
|
+
this.db.exec(SCHEMA_SQL);
|
|
58
|
+
this.migrateAddKeyPrefix();
|
|
59
|
+
this.migrateHashKeys();
|
|
60
|
+
this.prepareStatements();
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Add the `key_prefix` column if it doesn't exist yet (schema upgrade).
|
|
64
|
+
* SQLite has no `ADD COLUMN IF NOT EXISTS`, so check PRAGMA table_info.
|
|
65
|
+
*/
|
|
66
|
+
migrateAddKeyPrefix() {
|
|
67
|
+
const columns = this.db.pragma('table_info(api_keys)');
|
|
68
|
+
const hasColumn = columns.some((c) => c.name === 'key_prefix');
|
|
69
|
+
if (!hasColumn) {
|
|
70
|
+
this.db.exec("ALTER TABLE api_keys ADD COLUMN key_prefix TEXT NOT NULL DEFAULT ''");
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* One-time migration: if the `key_prefix` column was just added to an
|
|
75
|
+
* existing database, hash any plaintext keys that are still stored.
|
|
76
|
+
* Plaintext keys are 64-char hex; hashed keys are also 64-char hex but
|
|
77
|
+
* we detect the old schema by checking whether `key_prefix` is empty.
|
|
78
|
+
*/
|
|
79
|
+
migrateHashKeys() {
|
|
80
|
+
const rows = this.db
|
|
81
|
+
.prepare("SELECT id, key FROM api_keys WHERE key_prefix = ''")
|
|
82
|
+
.all();
|
|
83
|
+
if (rows.length === 0)
|
|
84
|
+
return;
|
|
85
|
+
const update = this.db.prepare('UPDATE api_keys SET key = ?, key_prefix = ? WHERE id = ?');
|
|
86
|
+
const migrate = this.db.transaction(() => {
|
|
87
|
+
for (const row of rows) {
|
|
88
|
+
update.run(hashKey(row.key), row.key.slice(0, 8) + '…', row.id);
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
migrate();
|
|
92
|
+
}
|
|
93
|
+
prepareStatements() {
|
|
94
|
+
this.stmtInsert = this.db.prepare(`INSERT INTO api_keys (key, key_prefix, label, status, created_at) VALUES (?, ?, ?, 'active', ?)`);
|
|
95
|
+
this.stmtLookup = this.db.prepare(`SELECT id, key, key_prefix AS keyPrefix, label, status, created_at AS createdAt, revoked_at AS revokedAt, last_used_at AS lastUsedAt
|
|
96
|
+
FROM api_keys WHERE key = ?`);
|
|
97
|
+
this.stmtListAll = this.db.prepare(`SELECT id, key, key_prefix AS keyPrefix, label, status, created_at AS createdAt, revoked_at AS revokedAt, last_used_at AS lastUsedAt
|
|
98
|
+
FROM api_keys ORDER BY id`);
|
|
99
|
+
this.stmtListActive = this.db.prepare(`SELECT id, key, key_prefix AS keyPrefix, label, status, created_at AS createdAt, revoked_at AS revokedAt, last_used_at AS lastUsedAt
|
|
100
|
+
FROM api_keys WHERE status = 'active' ORDER BY id`);
|
|
101
|
+
this.stmtRevoke = this.db.prepare(`UPDATE api_keys SET status = 'revoked', revoked_at = ? WHERE id = ? AND status = 'active'`);
|
|
102
|
+
this.stmtTouch = this.db.prepare(`UPDATE api_keys SET last_used_at = ? WHERE id = ?`);
|
|
103
|
+
this.stmtGetById = this.db.prepare(`SELECT id, key, key_prefix AS keyPrefix, label, status, created_at AS createdAt, revoked_at AS revokedAt, last_used_at AS lastUsedAt
|
|
104
|
+
FROM api_keys WHERE id = ?`);
|
|
105
|
+
this.stmtDelete = this.db.prepare(`DELETE FROM api_keys WHERE id = ?`);
|
|
106
|
+
}
|
|
107
|
+
/** Generate a new API key. Returns the full plaintext key (only shown once). */
|
|
108
|
+
create(label) {
|
|
109
|
+
const rawKey = crypto.randomBytes(32).toString('hex'); // 64-char hex
|
|
110
|
+
const keyHash = hashKey(rawKey);
|
|
111
|
+
const prefix = rawKey.slice(0, 8) + '…';
|
|
112
|
+
const now = new Date().toISOString();
|
|
113
|
+
this.stmtInsert.run(keyHash, prefix, label, now);
|
|
114
|
+
// Return the record with the PLAINTEXT key — this is the only time it's visible
|
|
115
|
+
const row = this.stmtLookup.get(keyHash);
|
|
116
|
+
return { ...row, key: rawKey };
|
|
117
|
+
}
|
|
118
|
+
/** Validate an API key. Returns the record if active, null otherwise. */
|
|
119
|
+
validate(key) {
|
|
120
|
+
const keyHash = hashKey(key);
|
|
121
|
+
const record = this.stmtLookup.get(keyHash);
|
|
122
|
+
if (!record || record.status !== 'active')
|
|
123
|
+
return null;
|
|
124
|
+
// Touch last_used_at asynchronously (non-blocking for perf)
|
|
125
|
+
this.stmtTouch.run(new Date().toISOString(), record.id);
|
|
126
|
+
return record;
|
|
127
|
+
}
|
|
128
|
+
/** List all keys (with truncated key values for safety). */
|
|
129
|
+
list(includeRevoked = false) {
|
|
130
|
+
const rows = includeRevoked
|
|
131
|
+
? this.stmtListAll.all()
|
|
132
|
+
: this.stmtListActive.all();
|
|
133
|
+
return rows.map(toSummary);
|
|
134
|
+
}
|
|
135
|
+
/** Get a key by ID (returns null if not found). */
|
|
136
|
+
getById(id) {
|
|
137
|
+
return this.stmtGetById.get(id) ?? null;
|
|
138
|
+
}
|
|
139
|
+
/** Revoke a key. Returns true if revoked, false if already revoked or not found. */
|
|
140
|
+
revoke(id) {
|
|
141
|
+
const now = new Date().toISOString();
|
|
142
|
+
const result = this.stmtRevoke.run(now, id);
|
|
143
|
+
return result.changes > 0;
|
|
144
|
+
}
|
|
145
|
+
/** Permanently delete a key. */
|
|
146
|
+
delete(id) {
|
|
147
|
+
const result = this.stmtDelete.run(id);
|
|
148
|
+
return result.changes > 0;
|
|
149
|
+
}
|
|
150
|
+
/** Total active key count. */
|
|
151
|
+
activeCount() {
|
|
152
|
+
const row = this.db.prepare('SELECT COUNT(*) AS cnt FROM api_keys WHERE status = ?').get('active');
|
|
153
|
+
return row.cnt;
|
|
154
|
+
}
|
|
155
|
+
close() {
|
|
156
|
+
this.db.close();
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
function toSummary(record) {
|
|
160
|
+
return {
|
|
161
|
+
id: record.id,
|
|
162
|
+
keyPrefix: record.keyPrefix || record.key.slice(0, 8) + '…',
|
|
163
|
+
label: record.label,
|
|
164
|
+
status: record.status,
|
|
165
|
+
createdAt: record.createdAt,
|
|
166
|
+
revokedAt: record.revokedAt,
|
|
167
|
+
lastUsedAt: record.lastUsedAt,
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
//# sourceMappingURL=api-key-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-key-store.js","sourceRoot":"","sources":["../../src/api/api-key-store.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* API Key authentication middleware.
|
|
3
|
+
*
|
|
4
|
+
* Strategy:
|
|
5
|
+
* 1. If no ApiKeyStore is configured → skip auth (backwards-compatible).
|
|
6
|
+
* 2. If the store has 0 active keys → skip auth (fresh node, not yet configured).
|
|
7
|
+
* 3. Otherwise, require a valid `X-Api-Key` header (or `Authorization: Bearer <key>`).
|
|
8
|
+
* 4. GET requests to /api/v1/node (status endpoint) are always open.
|
|
9
|
+
*
|
|
10
|
+
* When auth is enforced, the middleware rejects with 401 Unauthorized.
|
|
11
|
+
* The validated key metadata is attached to the request for downstream use.
|
|
12
|
+
*/
|
|
13
|
+
import type { IncomingMessage } from 'node:http';
|
|
14
|
+
import type { Middleware } from './router.js';
|
|
15
|
+
import type { ApiKeyStore } from './api-key-store.js';
|
|
16
|
+
import type { NetworkType } from './types.js';
|
|
17
|
+
export interface ApiKeyAuth {
|
|
18
|
+
keyId: number;
|
|
19
|
+
label: string;
|
|
20
|
+
}
|
|
21
|
+
/** Retrieve the authenticated key from a request (or undefined). */
|
|
22
|
+
export declare function getApiKeyAuth(req: IncomingMessage): ApiKeyAuth | undefined;
|
|
23
|
+
/**
|
|
24
|
+
* Create the API key auth middleware.
|
|
25
|
+
*
|
|
26
|
+
* @param store - optional ApiKeyStore. If undefined or has 0 keys, auth is skipped.
|
|
27
|
+
* @param network - network type. On mainnet, 0-key still enforces 401.
|
|
28
|
+
*/
|
|
29
|
+
export declare function apiKeyAuth(store: ApiKeyStore | undefined, network?: NetworkType): Middleware;
|
|
30
|
+
//# sourceMappingURL=auth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/api/auth.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAkB,MAAM,WAAW,CAAC;AACjE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,KAAK,EAAE,WAAW,EAAgB,MAAM,oBAAoB,CAAC;AACpE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAS9C,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf;AAED,oEAAoE;AACpE,wBAAgB,aAAa,CAAC,GAAG,EAAE,eAAe,GAAG,UAAU,GAAG,SAAS,CAE1E;AAsBD;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,WAAW,GAAG,SAAS,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,UAAU,CAoD5F"}
|
package/dist/api/auth.js
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* API Key authentication middleware.
|
|
3
|
+
*
|
|
4
|
+
* Strategy:
|
|
5
|
+
* 1. If no ApiKeyStore is configured → skip auth (backwards-compatible).
|
|
6
|
+
* 2. If the store has 0 active keys → skip auth (fresh node, not yet configured).
|
|
7
|
+
* 3. Otherwise, require a valid `X-Api-Key` header (or `Authorization: Bearer <key>`).
|
|
8
|
+
* 4. GET requests to /api/v1/node (status endpoint) are always open.
|
|
9
|
+
*
|
|
10
|
+
* When auth is enforced, the middleware rejects with 401 Unauthorized.
|
|
11
|
+
* The validated key metadata is attached to the request for downstream use.
|
|
12
|
+
*/
|
|
13
|
+
import { unauthorized } from './response.js';
|
|
14
|
+
// ---------------------------------------------------------------------------
|
|
15
|
+
// Augment request to carry auth context
|
|
16
|
+
// ---------------------------------------------------------------------------
|
|
17
|
+
const AUTH_SYMBOL = Symbol('apiKeyAuth');
|
|
18
|
+
/** Retrieve the authenticated key from a request (or undefined). */
|
|
19
|
+
export function getApiKeyAuth(req) {
|
|
20
|
+
return req[AUTH_SYMBOL];
|
|
21
|
+
}
|
|
22
|
+
// ---------------------------------------------------------------------------
|
|
23
|
+
// Public route patterns (no auth required)
|
|
24
|
+
// ---------------------------------------------------------------------------
|
|
25
|
+
/** Routes that are always accessible without an API key. */
|
|
26
|
+
const PUBLIC_ROUTES = [
|
|
27
|
+
// Node status — needed by health checks and SDK connection probing
|
|
28
|
+
(url) => url === '/api/v1/node' || url === '/api/v1/node/',
|
|
29
|
+
// OPTIONS (CORS preflight)
|
|
30
|
+
(_url, method) => method === 'OPTIONS',
|
|
31
|
+
];
|
|
32
|
+
function isPublicRoute(url, method) {
|
|
33
|
+
return PUBLIC_ROUTES.some((check) => check(url, method));
|
|
34
|
+
}
|
|
35
|
+
// ---------------------------------------------------------------------------
|
|
36
|
+
// Middleware factory
|
|
37
|
+
// ---------------------------------------------------------------------------
|
|
38
|
+
/**
|
|
39
|
+
* Create the API key auth middleware.
|
|
40
|
+
*
|
|
41
|
+
* @param store - optional ApiKeyStore. If undefined or has 0 keys, auth is skipped.
|
|
42
|
+
* @param network - network type. On mainnet, 0-key still enforces 401.
|
|
43
|
+
*/
|
|
44
|
+
export function apiKeyAuth(store, network) {
|
|
45
|
+
return async (req, res, next) => {
|
|
46
|
+
// No store configured → open access (backward-compatible)
|
|
47
|
+
if (!store) {
|
|
48
|
+
await next();
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
// Parse the URL pathname
|
|
52
|
+
const pathname = new URL(req.url ?? '/', `http://${req.headers.host ?? 'localhost'}`).pathname;
|
|
53
|
+
const method = (req.method ?? 'GET').toUpperCase();
|
|
54
|
+
// Public routes are always accessible
|
|
55
|
+
if (isPublicRoute(pathname, method)) {
|
|
56
|
+
await next();
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
// If no keys have been created yet:
|
|
60
|
+
// - mainnet: still enforce 401 (must create keys before API is usable)
|
|
61
|
+
// - testnet/devnet: open access (fresh node, backwards-compatible)
|
|
62
|
+
if (store.activeCount() === 0) {
|
|
63
|
+
if (network === 'mainnet') {
|
|
64
|
+
unauthorized(res, 'No API keys configured. Create a key with `clawnet api-key create <label>` before using mainnet API.', pathname);
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
await next();
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
// Extract key from header
|
|
71
|
+
const key = extractApiKey(req);
|
|
72
|
+
if (!key) {
|
|
73
|
+
unauthorized(res, 'API key required. Provide via X-Api-Key header or Authorization: Bearer <key>', pathname);
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
// Validate against store
|
|
77
|
+
const record = store.validate(key);
|
|
78
|
+
if (!record) {
|
|
79
|
+
unauthorized(res, 'Invalid or revoked API key', pathname);
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
// Attach auth context to request
|
|
83
|
+
req[AUTH_SYMBOL] = {
|
|
84
|
+
keyId: record.id,
|
|
85
|
+
label: record.label,
|
|
86
|
+
};
|
|
87
|
+
await next();
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
// ---------------------------------------------------------------------------
|
|
91
|
+
// Helpers
|
|
92
|
+
// ---------------------------------------------------------------------------
|
|
93
|
+
function extractApiKey(req) {
|
|
94
|
+
// Try X-Api-Key header first
|
|
95
|
+
const xApiKey = firstHeaderValue(req.headers['x-api-key']);
|
|
96
|
+
if (xApiKey)
|
|
97
|
+
return xApiKey.trim();
|
|
98
|
+
// Fall back to Authorization: Bearer <key>
|
|
99
|
+
const auth = firstHeaderValue(req.headers.authorization);
|
|
100
|
+
if (!auth)
|
|
101
|
+
return undefined;
|
|
102
|
+
const normalized = auth.trim();
|
|
103
|
+
if (!normalized.toLowerCase().startsWith('bearer '))
|
|
104
|
+
return undefined;
|
|
105
|
+
const token = normalized.slice(7).trim();
|
|
106
|
+
return token || undefined;
|
|
107
|
+
}
|
|
108
|
+
function firstHeaderValue(value) {
|
|
109
|
+
if (typeof value === 'string')
|
|
110
|
+
return value;
|
|
111
|
+
if (Array.isArray(value) && value.length > 0)
|
|
112
|
+
return value[0];
|
|
113
|
+
return undefined;
|
|
114
|
+
}
|
|
115
|
+
//# sourceMappingURL=auth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/api/auth.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Legacy event-sourced helper functions.
|
|
3
|
+
*
|
|
4
|
+
* These power the fallback path when on-chain services are unavailable.
|
|
5
|
+
* Extracted from the original server.ts monolith.
|
|
6
|
+
*/
|
|
7
|
+
import type { EventStore, EventEnvelope } from '@claw-network/core';
|
|
8
|
+
import { type WalletState, type SearchQuery } from '@claw-network/protocol';
|
|
9
|
+
export declare function parseEvent(bytes: unknown): EventEnvelope | null;
|
|
10
|
+
export interface IdentityView {
|
|
11
|
+
did: string;
|
|
12
|
+
publicKey: string;
|
|
13
|
+
created: number;
|
|
14
|
+
updated: number;
|
|
15
|
+
displayName?: string;
|
|
16
|
+
avatar?: string;
|
|
17
|
+
bio?: string;
|
|
18
|
+
platformLinks: Array<Record<string, unknown>>;
|
|
19
|
+
capabilities: Array<Record<string, unknown>>;
|
|
20
|
+
}
|
|
21
|
+
export declare function resolveLocalIdentity(dataDir?: string): Promise<IdentityView | null>;
|
|
22
|
+
export declare function buildIdentityView(eventStore: EventStore, did: string): Promise<IdentityView | null>;
|
|
23
|
+
export declare function buildIdentityCapabilities(eventStore: EventStore, did?: string): Promise<Array<Record<string, unknown>>>;
|
|
24
|
+
export declare function buildWalletState(eventStore: EventStore): Promise<WalletState>;
|
|
25
|
+
export declare function parseMarketSearchQuery(params: URLSearchParams): SearchQuery;
|
|
26
|
+
//# sourceMappingURL=legacy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"legacy.d.ts","sourceRoot":"","sources":["../../src/api/legacy.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAOpE,OAAO,EAGL,KAAK,WAAW,EAChB,KAAK,WAAW,EASjB,MAAM,wBAAwB,CAAC;AAKhC,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,aAAa,GAAG,IAAI,CAW/D;AAID,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAC9C,YAAY,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CAC9C;AAED,wBAAsB,oBAAoB,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CA6BzF;AAED,wBAAsB,iBAAiB,CACrC,UAAU,EAAE,UAAU,EACtB,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAqD9B;AAED,wBAAsB,yBAAyB,CAC7C,UAAU,EAAE,UAAU,EACtB,GAAG,CAAC,EAAE,MAAM,GACX,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CA2BzC;AAID,wBAAsB,gBAAgB,CAAC,UAAU,EAAE,UAAU,GAAG,OAAO,CAAC,WAAW,CAAC,CAoBnF;AAyBD,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,eAAe,GAAG,WAAW,CA6E3E"}
|