@kehto/runtime 0.12.0 → 0.14.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 +5 -5
- package/dist/index.d.ts +31 -48
- package/dist/index.js +103 -136
- package/dist/index.js.map +1 -1
- package/package.json +8 -8
package/README.md
CHANGED
|
@@ -16,10 +16,10 @@ pnpm add @kehto/runtime
|
|
|
16
16
|
|
|
17
17
|
`@kehto/runtime` is Kehto's NIP-5D protocol engine. It owns every incoming napplet message, gates it through the ACL enforcement layer, routes it to the correct NAP handler, and emits the corresponding reply envelope.
|
|
18
18
|
|
|
19
|
-
The runtime is built around the current draft dispatch contract from `@napplet/core` — `createDispatch()` + `
|
|
19
|
+
The runtime is built around the current draft dispatch contract from `@napplet/core` — `createDispatch()` + `registerNap()` — so routing is declarative, not a hand-rolled switch. It covers the NIP-5D domains currently supported by Kehto:
|
|
20
20
|
|
|
21
21
|
- **identity** — `identity.getProfile`, `identity.getFollows`, `identity.getPublicKey`, …
|
|
22
|
-
- **
|
|
22
|
+
- **inc** — `inc.channel.*`, `inc.emit`, cross-napplet pub/sub
|
|
23
23
|
- **keys** — `keys.forward`, `keys.action`, `keys.bind`
|
|
24
24
|
- **media** — `media.*` playback & transport control
|
|
25
25
|
- **notify** — `notify.send`, `notify.channel.register`, badge/permission flows
|
|
@@ -59,8 +59,8 @@ runtime.handleMessage('window-1', {
|
|
|
59
59
|
|
|
60
60
|
### Enforcement gate
|
|
61
61
|
- `createEnforceGate` — legacy pubkey-keyed ACL gate
|
|
62
|
-
- `
|
|
63
|
-
- `
|
|
62
|
+
- `createNapEnforceGate` — NIP-5D windowId-keyed ACL gate
|
|
63
|
+
- `resolveCapabilitiesNap` — map a NIP-5D envelope to required capabilities (re-exported from `@kehto/acl`)
|
|
64
64
|
- `formatDenialReason` — `denied: <capability>` canonical string
|
|
65
65
|
|
|
66
66
|
### Session registry
|
|
@@ -82,7 +82,7 @@ runtime.handleMessage('window-1', {
|
|
|
82
82
|
- `RING_BUFFER_SIZE` — default ring buffer capacity constant
|
|
83
83
|
|
|
84
84
|
### State handler
|
|
85
|
-
- `
|
|
85
|
+
- `handleStorageNap` — canonical `storage.*` NIP-5D handler
|
|
86
86
|
- `cleanupNappState` — remove persisted state when a napplet window closes
|
|
87
87
|
|
|
88
88
|
### Service dispatch
|
package/dist/index.d.ts
CHANGED
|
@@ -3,8 +3,8 @@ export { NappletMessage } from '@napplet/core';
|
|
|
3
3
|
import { Capability } from '@kehto/acl/capabilities';
|
|
4
4
|
export { ALL_CAPABILITIES, Capability } from '@kehto/acl/capabilities';
|
|
5
5
|
import { Decision, Action, Observation, EvaluateResult, NappletPolicy, RateLimit, ContentMatcher, FirewallConfig } from '@kehto/firewall';
|
|
6
|
-
import {
|
|
7
|
-
export {
|
|
6
|
+
import { NapMessage } from '@kehto/acl';
|
|
7
|
+
export { NapMessage, resolveCapabilitiesNap } from '@kehto/acl';
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* Runtime persistence + cache data types.
|
|
@@ -143,13 +143,6 @@ interface VerificationCacheEntry {
|
|
|
143
143
|
* to host napplets. No DOM types, no browser APIs.
|
|
144
144
|
*/
|
|
145
145
|
|
|
146
|
-
/**
|
|
147
|
-
* A napplet class identifier. `null` is the permissive default (no class).
|
|
148
|
-
* provisional — mirrors packages/shell/src/types/internal-class.ts::NappletClass;
|
|
149
|
-
* converges on @napplet/nap/class@^0.3.0 publish. Runtime MUST NOT import
|
|
150
|
-
* from shell (module-boundary), so this duplicate lives here.
|
|
151
|
-
*/
|
|
152
|
-
type NappletClass = string | null;
|
|
153
146
|
/**
|
|
154
147
|
* Event emitted on every ACL enforcement check.
|
|
155
148
|
*
|
|
@@ -178,13 +171,12 @@ interface AclCheckEvent {
|
|
|
178
171
|
/** The triggering message, if available. Accepts NIP-01 arrays or NIP-5D NappletMessage envelopes. */
|
|
179
172
|
message?: unknown[] | NappletMessage;
|
|
180
173
|
/**
|
|
181
|
-
* Why the decision was reached
|
|
182
|
-
*
|
|
174
|
+
* Why the decision was reached. Optional for backwards compatibility with
|
|
175
|
+
* pre-v1.7 audit consumers.
|
|
183
176
|
* 'allowed' -> decision === 'allow'
|
|
184
177
|
* 'capability-missing' -> decision === 'deny' (capability lookup failed)
|
|
185
|
-
* 'class-forbidden' -> decision === 'deny' (class pre-filter refused)
|
|
186
178
|
*/
|
|
187
|
-
reason?: 'allowed' | 'capability-missing'
|
|
179
|
+
reason?: 'allowed' | 'capability-missing';
|
|
188
180
|
}
|
|
189
181
|
/**
|
|
190
182
|
* Abstract message sender — the runtime calls this to send messages
|
|
@@ -501,12 +493,6 @@ interface SessionEntry {
|
|
|
501
493
|
* Renamed from `identitySource: 'auth' | 'source'` in v1.8; see .changeset/v1-8-rename-01-session-provenance.md.
|
|
502
494
|
*/
|
|
503
495
|
provenance: 'nip-5d' | 'legacy-auth';
|
|
504
|
-
/**
|
|
505
|
-
* Class posture resolved synchronously at iframe creation (CLASS-02).
|
|
506
|
-
* `null` is the permissive default (D2). Class tokens like 'class-1' /
|
|
507
|
-
* 'class-2' are NUB-defined. See packages/shell/src/types/internal-class.ts.
|
|
508
|
-
*/
|
|
509
|
-
class: NappletClass;
|
|
510
496
|
}
|
|
511
497
|
/** @deprecated Use SessionEntry. Will be removed in v0.9.0. */
|
|
512
498
|
type NappKeyEntry = SessionEntry;
|
|
@@ -533,16 +519,16 @@ interface AclEntryExternal {
|
|
|
533
519
|
/**
|
|
534
520
|
* Handler for service-specific messages from napplets.
|
|
535
521
|
* Services receive NIP-5D NappletMessage envelopes and respond via the `send` callback.
|
|
536
|
-
* The same interface is used for all services regardless of what
|
|
522
|
+
* The same interface is used for all services regardless of what NAP domain they handle.
|
|
537
523
|
*
|
|
538
524
|
* @example
|
|
539
525
|
* ```ts
|
|
540
526
|
* const audioHandler: ServiceHandler = {
|
|
541
527
|
* descriptor: { name: 'audio', version: '1.0.0' },
|
|
542
528
|
* handleMessage(windowId, message, send) {
|
|
543
|
-
* if (message.type === '
|
|
544
|
-
* // process audio
|
|
545
|
-
* send({ type: '
|
|
529
|
+
* if (message.type === 'inc.emit') {
|
|
530
|
+
* // process audio inc event...
|
|
531
|
+
* send({ type: 'inc.emit.result', id: (message as any).id });
|
|
546
532
|
* }
|
|
547
533
|
* },
|
|
548
534
|
* };
|
|
@@ -764,11 +750,10 @@ interface EnforceResult {
|
|
|
764
750
|
allowed: boolean;
|
|
765
751
|
capability: Capability;
|
|
766
752
|
/**
|
|
767
|
-
* Why the decision was reached
|
|
768
|
-
*
|
|
769
|
-
* backwards compat on the audit surface).
|
|
753
|
+
* Why the decision was reached. Always set on the return path.
|
|
754
|
+
* Distinct from AclCheckEvent.reason (which is optional for backwards compat).
|
|
770
755
|
*/
|
|
771
|
-
reason: 'allowed' | 'capability-missing'
|
|
756
|
+
reason: 'allowed' | 'capability-missing';
|
|
772
757
|
}
|
|
773
758
|
/**
|
|
774
759
|
* Identity lookup function type — resolves a pubkey to its full identity.
|
|
@@ -818,36 +803,34 @@ interface EnforceConfig {
|
|
|
818
803
|
*/
|
|
819
804
|
declare function createEnforceGate(config: EnforceConfig): (pubkey: string, capability: Capability, message?: unknown[]) => EnforceResult;
|
|
820
805
|
/**
|
|
821
|
-
* Enforcement gate configuration for NIP-5D
|
|
806
|
+
* Enforcement gate configuration for NIP-5D NAP handlers.
|
|
822
807
|
* Uses windowId for identity resolution instead of pubkey (which is '' in NIP-5D sessions).
|
|
823
808
|
*
|
|
824
809
|
* @param checkAcl - The ACL check function
|
|
825
|
-
* @param resolveIdentityByWindowId - Maps windowId to identity (dTag, aggregateHash
|
|
826
|
-
*
|
|
827
|
-
* before consulting the ACL check. null class = permissive default (D2).
|
|
828
|
-
* @param onAclCheck - Optional audit callback, called on every enforceNub() check
|
|
810
|
+
* @param resolveIdentityByWindowId - Maps windowId to identity (dTag, aggregateHash).
|
|
811
|
+
* @param onAclCheck - Optional audit callback, called on every enforceNap() check
|
|
829
812
|
*/
|
|
830
|
-
interface
|
|
813
|
+
interface NapEnforceConfig {
|
|
831
814
|
checkAcl: AclChecker;
|
|
832
815
|
resolveIdentityByWindowId: (windowId: string) => {
|
|
833
816
|
dTag: string;
|
|
834
817
|
aggregateHash: string;
|
|
835
|
-
class: NappletClass;
|
|
836
818
|
} | undefined;
|
|
837
819
|
onAclCheck?: (event: AclCheckEvent) => void;
|
|
838
820
|
}
|
|
839
821
|
/**
|
|
840
|
-
* Create an enforcement gate for NIP-5D
|
|
822
|
+
* Create an enforcement gate for NIP-5D NAP message handlers.
|
|
841
823
|
*
|
|
842
824
|
* Unlike createEnforceGate (which resolves identity by pubkey), this factory
|
|
843
825
|
* resolves identity by windowId — necessary for NIP-5D sessions where pubkey is ''.
|
|
844
826
|
*
|
|
845
|
-
* @param config -
|
|
846
|
-
* @returns An
|
|
827
|
+
* @param config - NAP enforcement configuration
|
|
828
|
+
* @returns An enforceNap function that resolves identity by windowId and
|
|
829
|
+
* delegates to the ACL check.
|
|
847
830
|
*
|
|
848
831
|
* @example
|
|
849
832
|
* ```ts
|
|
850
|
-
* const gate =
|
|
833
|
+
* const gate = createNapEnforceGate({
|
|
851
834
|
* checkAcl: aclStore.check,
|
|
852
835
|
* resolveIdentityByWindowId: (wid) => sessionRegistry.getEntryByWindowId(wid),
|
|
853
836
|
* onAclCheck: hooks.onAclCheck,
|
|
@@ -856,7 +839,7 @@ interface NubEnforceConfig {
|
|
|
856
839
|
* // result.allowed === true | false
|
|
857
840
|
* ```
|
|
858
841
|
*/
|
|
859
|
-
declare function
|
|
842
|
+
declare function createNapEnforceGate(config: NapEnforceConfig): (windowId: string, capability: Capability, message?: NapMessage) => EnforceResult;
|
|
860
843
|
/**
|
|
861
844
|
* Format a denial reason string with the standard 'denied:' prefix.
|
|
862
845
|
*
|
|
@@ -1271,7 +1254,7 @@ interface EventBuffer {
|
|
|
1271
1254
|
declare function createEventBuffer(sendToNapplet: SendToNapplet, sessionRegistry: SessionRegistry, enforce: (pubkey: string, capability: Capability, message?: unknown[]) => EnforceResult, subscriptions: Map<string, SubscriptionEntry>, getBufferSize?: () => number): EventBuffer;
|
|
1272
1255
|
|
|
1273
1256
|
/**
|
|
1274
|
-
* The napplet protocol engine — handles NIP-5D
|
|
1257
|
+
* The napplet protocol engine — handles NIP-5D NAP domain dispatch,
|
|
1275
1258
|
* ACL enforcement, subscription lifecycle.
|
|
1276
1259
|
*
|
|
1277
1260
|
* @example
|
|
@@ -1349,7 +1332,7 @@ interface Runtime {
|
|
|
1349
1332
|
declare function createRuntime(hooks: RuntimeAdapter): Runtime;
|
|
1350
1333
|
|
|
1351
1334
|
/**
|
|
1352
|
-
* state-handler.ts — Storage
|
|
1335
|
+
* state-handler.ts — Storage NAP request handler using persistence hooks.
|
|
1353
1336
|
*
|
|
1354
1337
|
* Handles napplet storage operations (get, set, remove, keys) via the
|
|
1355
1338
|
* canonical `@napplet/nap/storage` NIP-5D envelope surface. Delegates
|
|
@@ -1367,7 +1350,7 @@ declare function createRuntime(hooks: RuntimeAdapter): Runtime;
|
|
|
1367
1350
|
*/
|
|
1368
1351
|
|
|
1369
1352
|
/**
|
|
1370
|
-
* Handle a NIP-5D
|
|
1353
|
+
* Handle a NIP-5D NAP storage message from a napplet.
|
|
1371
1354
|
* Routes to the canonical four `@napplet/nap/storage` actions:
|
|
1372
1355
|
* - `storage.get` → `storage.get.result` `{ value: string | null }`
|
|
1373
1356
|
* - `storage.set` → `storage.set.result` `{ ok: boolean }` (canonical only checks `error`)
|
|
@@ -1401,13 +1384,13 @@ declare function createRuntime(hooks: RuntimeAdapter): Runtime;
|
|
|
1401
1384
|
*
|
|
1402
1385
|
* @example
|
|
1403
1386
|
* ```ts
|
|
1404
|
-
* import {
|
|
1387
|
+
* import { handleStorageNap } from '@kehto/runtime';
|
|
1405
1388
|
*
|
|
1406
|
-
*
|
|
1389
|
+
* handleStorageNap(windowId, { type: 'storage.get', id: 'q1', key: 'draft' },
|
|
1407
1390
|
* sendToNapplet, sessionRegistry, aclState, statePersistence);
|
|
1408
1391
|
* ```
|
|
1409
1392
|
*/
|
|
1410
|
-
declare function
|
|
1393
|
+
declare function handleStorageNap(windowId: string, msg: NappletMessage, sendToNapplet: SendToNapplet, sessionRegistry: SessionRegistry, aclState: AclStateContainer, statePersistence: StatePersistence): void;
|
|
1411
1394
|
/**
|
|
1412
1395
|
* Remove all state entries for a napplet identity.
|
|
1413
1396
|
* Clears both new-format and legacy-format keys for completeness.
|
|
@@ -1430,10 +1413,10 @@ declare function cleanupNappState(pubkey: string, dTag: string, aggregateHash: s
|
|
|
1430
1413
|
/**
|
|
1431
1414
|
* Route a NappletMessage envelope to the matching service handler.
|
|
1432
1415
|
*
|
|
1433
|
-
*
|
|
1416
|
+
* NAP-domain services are routed by the domain prefix of message.type
|
|
1434
1417
|
* (e.g., 'signer.signEvent' -> 'signer' service).
|
|
1435
1418
|
*
|
|
1436
|
-
*
|
|
1419
|
+
* INC-routed services receive inc.emit messages and are routed by the
|
|
1437
1420
|
* topic prefix before ':' (e.g., topic 'audio:play' -> 'audio' service).
|
|
1438
1421
|
*
|
|
1439
1422
|
* Returns true if a service handled the message, false otherwise.
|
|
@@ -1467,4 +1450,4 @@ declare function routeServiceMessage(windowId: string, message: NappletMessage,
|
|
|
1467
1450
|
*/
|
|
1468
1451
|
declare function notifyServiceWindowDestroyed(windowId: string, services: ServiceRegistry): void;
|
|
1469
1452
|
|
|
1470
|
-
export { type AclCheckEvent, type AclChecker, type AclEntryExternal, type AclPersistence, type AclStateContainer, type AuthAdapter, type CacheAdapter, type CompatibilityReport, type ConfigAdapter, type ConsentHandler, type ConsentRequest, type CryptoAdapter, type DmAdapter, type EnforceConfig, type EnforceResult, type EventBuffer, type FirewallEvent, type FirewallPersistence, type FirewallStateContainer, type GuidPersistence, type HashVerifierAdapter, type HotkeyAdapter, type IdentityResolver, type ManifestCache, type ManifestCacheEntry, type ManifestPersistence, type
|
|
1453
|
+
export { type AclCheckEvent, type AclChecker, type AclEntryExternal, type AclPersistence, type AclStateContainer, type AuthAdapter, type CacheAdapter, type CompatibilityReport, type ConfigAdapter, type ConsentHandler, type ConsentRequest, type CryptoAdapter, type DmAdapter, type EnforceConfig, type EnforceResult, type EventBuffer, type FirewallEvent, type FirewallPersistence, type FirewallStateContainer, type GuidPersistence, type HashVerifierAdapter, type HotkeyAdapter, type IdentityResolver, type ManifestCache, type ManifestCacheEntry, type ManifestPersistence, type NapEnforceConfig, type NappKeyEntry, type NappKeyRegistry, type PendingUpdate, type PendingUpdateNotifier, RING_BUFFER_SIZE, type RelayConfigAdapter, type RelayPoolAdapter, type RelaySubscriptionHandle, type ReplayDetector, type Runtime, type RuntimeAdapter, type RuntimeConfigOverrides, type SendToNapplet, type ServiceDescriptor, type ServiceHandler, type ServiceInfo, type ServiceRegistry, type SessionEntry, type SessionRegistry, type ShellSecretPersistence, type Signer, type StatePersistence, type SubscriptionEntry, type VerificationCacheEntry, type WindowManagerAdapter, cleanupNappState, createAclState, createEnforceGate, createEventBuffer, createFirewallState, createManifestCache, createNapEnforceGate, createNappKeyRegistry, createReplayDetector, createRuntime, createSessionRegistry, formatDenialReason, handleStorageNap, matchesAnyFilter, matchesFilter, notifyServiceWindowDestroyed, routeServiceMessage };
|