@agent-network-protocol/dsh-anp-identity 0.1.6 → 0.1.8

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.
Files changed (116) hide show
  1. package/BOUNDARY.md +30 -5
  2. package/PUBLICATION.md +181 -0
  3. package/README.md +73 -1
  4. package/README.zh.md +44 -1
  5. package/V7-MANAGEMENT.md +18 -0
  6. package/cordis.patch.yml +9 -0
  7. package/examples/fresh-bootstrap.cordis.patch.yml +38 -0
  8. package/lib/authorization-types.d.ts +6 -0
  9. package/lib/authorization-types.d.ts.map +1 -1
  10. package/lib/authorization.d.ts.map +1 -1
  11. package/lib/authorization.js +23 -6
  12. package/lib/authorization.js.map +1 -1
  13. package/lib/catalog.d.ts +3 -1
  14. package/lib/catalog.d.ts.map +1 -1
  15. package/lib/catalog.js +15 -3
  16. package/lib/catalog.js.map +1 -1
  17. package/lib/client/controller.d.ts +18 -0
  18. package/lib/client/controller.d.ts.map +1 -1
  19. package/lib/client/controller.js +89 -5
  20. package/lib/client/controller.js.map +1 -1
  21. package/lib/client/views.d.ts.map +1 -1
  22. package/lib/client/views.js +37 -6
  23. package/lib/client/views.js.map +1 -1
  24. package/lib/client-metadata.d.ts +3 -0
  25. package/lib/client-metadata.d.ts.map +1 -0
  26. package/lib/client-metadata.js +11 -0
  27. package/lib/client-metadata.js.map +1 -0
  28. package/lib/client.js +260 -14
  29. package/lib/client.js.map +4 -4
  30. package/lib/host-management-secret.d.ts +41 -0
  31. package/lib/host-management-secret.d.ts.map +1 -0
  32. package/lib/host-management-secret.js +92 -0
  33. package/lib/host-management-secret.js.map +1 -0
  34. package/lib/index.d.ts +73 -3
  35. package/lib/index.d.ts.map +1 -1
  36. package/lib/index.js +331 -22
  37. package/lib/index.js.map +1 -1
  38. package/lib/initial-registration-proof.d.ts +13 -0
  39. package/lib/initial-registration-proof.d.ts.map +1 -0
  40. package/lib/initial-registration-proof.js +48 -0
  41. package/lib/initial-registration-proof.js.map +1 -0
  42. package/lib/installed-consumer.d.ts +25 -0
  43. package/lib/installed-consumer.d.ts.map +1 -0
  44. package/lib/installed-consumer.js +66 -0
  45. package/lib/installed-consumer.js.map +1 -0
  46. package/lib/management-credentials.d.ts +15 -0
  47. package/lib/management-credentials.d.ts.map +1 -0
  48. package/lib/management-credentials.js +126 -0
  49. package/lib/management-credentials.js.map +1 -0
  50. package/lib/management-driver.d.ts +83 -0
  51. package/lib/management-driver.d.ts.map +1 -0
  52. package/lib/management-driver.js +405 -0
  53. package/lib/management-driver.js.map +1 -0
  54. package/lib/management-remote.d.ts +27 -1
  55. package/lib/management-remote.d.ts.map +1 -1
  56. package/lib/management-remote.js +69 -3
  57. package/lib/management-remote.js.map +1 -1
  58. package/lib/management-types.d.ts +7 -0
  59. package/lib/management-types.d.ts.map +1 -1
  60. package/lib/pap-callback.d.ts +110 -0
  61. package/lib/pap-callback.d.ts.map +1 -0
  62. package/lib/pap-callback.js +51 -0
  63. package/lib/pap-callback.js.map +1 -0
  64. package/lib/protocol-bootstrap.d.ts +24 -0
  65. package/lib/protocol-bootstrap.d.ts.map +1 -0
  66. package/lib/protocol-bootstrap.js +34 -0
  67. package/lib/protocol-bootstrap.js.map +1 -0
  68. package/lib/protocol-client.d.ts +137 -0
  69. package/lib/protocol-client.d.ts.map +1 -0
  70. package/lib/protocol-client.js +11 -0
  71. package/lib/protocol-client.js.map +1 -0
  72. package/lib/provider-api.d.ts +6 -2
  73. package/lib/provider-api.d.ts.map +1 -1
  74. package/lib/provider-api.js.map +1 -1
  75. package/lib/publication-http.d.ts +19 -0
  76. package/lib/publication-http.d.ts.map +1 -0
  77. package/lib/publication-http.js +183 -0
  78. package/lib/publication-http.js.map +1 -0
  79. package/lib/publication-types.d.ts +161 -0
  80. package/lib/publication-types.d.ts.map +1 -0
  81. package/lib/publication-types.js +35 -0
  82. package/lib/publication-types.js.map +1 -0
  83. package/lib/publication.d.ts +21 -0
  84. package/lib/publication.d.ts.map +1 -0
  85. package/lib/publication.js +235 -0
  86. package/lib/publication.js.map +1 -0
  87. package/lib/registration-bootstrap.d.ts +56 -0
  88. package/lib/registration-bootstrap.d.ts.map +1 -0
  89. package/lib/registration-bootstrap.js +523 -0
  90. package/lib/registration-bootstrap.js.map +1 -0
  91. package/lib/registration-service-settings.d.ts +12 -0
  92. package/lib/registration-service-settings.d.ts.map +1 -0
  93. package/lib/registration-service-settings.js +124 -0
  94. package/lib/registration-service-settings.js.map +1 -0
  95. package/lib/registration-service-types.d.ts +11 -0
  96. package/lib/registration-service-types.d.ts.map +1 -0
  97. package/lib/registration-service-types.js +3 -0
  98. package/lib/registration-service-types.js.map +1 -0
  99. package/lib/remote.d.ts.map +1 -1
  100. package/lib/remote.js +11 -2
  101. package/lib/remote.js.map +1 -1
  102. package/lib/target-policy.d.ts +35 -0
  103. package/lib/target-policy.d.ts.map +1 -0
  104. package/lib/target-policy.js +319 -0
  105. package/lib/target-policy.js.map +1 -0
  106. package/lib/user-client.d.ts +6 -0
  107. package/lib/user-client.d.ts.map +1 -1
  108. package/lib/user-client.js.map +1 -1
  109. package/lib/user-operation.d.ts.map +1 -1
  110. package/lib/user-operation.js +9 -0
  111. package/lib/user-operation.js.map +1 -1
  112. package/lib/user-service.d.ts +8 -1
  113. package/lib/user-service.d.ts.map +1 -1
  114. package/lib/user-service.js +58 -4
  115. package/lib/user-service.js.map +1 -1
  116. package/package.json +51 -29
package/lib/index.js CHANGED
@@ -1,5 +1,12 @@
1
+ import { RegistrationServiceSettingsStore } from './registration-service-settings.js';
2
+ import { createManagedPublicationDriver, registerLocalIdentity } from './management-driver.js';
3
+ import { installedConsumerEntries, resolveInstalledConsumer } from './installed-consumer.js';
4
+ import { ProtocolIdentityAuthority } from './target-policy.js';
5
+ import { PapCallbackManagementError } from './pap-callback.js';
6
+ import { PublicationCoordinator } from './publication.js';
7
+ import { exactHttps } from './publication-http.js';
1
8
  /** Host-only ANP Identity service for DeepSeek Harness. */
2
- import { randomUUID } from 'node:crypto';
9
+ import { randomUUID, createHash } from 'node:crypto';
3
10
  import { homedir } from 'node:os';
4
11
  import { isAbsolute, join } from 'node:path';
5
12
  import { Service } from '@deepseek-ai/cordis';
@@ -7,18 +14,21 @@ import z from '@deepseek-ai/schemastery';
7
14
  import { CatalogStore, CATALOG_SCHEMA, CREATE_INTENT_SCHEMA, emptyCatalog, entryReference, findEntry, normalizeHandle, } from './catalog.js';
8
15
  import { pluginError, AnpIdentityPluginError } from './errors.js';
9
16
  import { createAuthenticatedHttp } from './http-auth.js';
10
- import { UserIdentityService, requestSigningKid } from './user-service.js';
17
+ import { UserIdentityService, httpSigningKey } from './user-service.js';
11
18
  import { ANP_IDENTITY_NATIVE_PROVIDER_PROTOCOL, ANP_IDENTITY_PROVIDER_PROTOCOL, ANP_IDENTITY_SERVICE_PROTOCOL, } from './provider-api.js';
12
19
  export { AnpIdentityPluginError } from './errors.js';
13
20
  export { ANP_IDENTITY_HTTP_MAX_BODY_BYTES, } from './http-auth.js';
14
21
  export { ANP_IDENTITY_PROVIDER_PROTOCOL, ANP_IDENTITY_SERVICE_PROTOCOL, } from './provider-api.js';
15
22
  export const Config = z.object({
23
+ signerMode: z.const('local').default('local'),
24
+ protocolPolicies: z.array(z.any()).default([]),
16
25
  stateRoot: z.string(),
17
26
  allowConsumers: z.array(z.string()).default([]),
18
27
  allowProviderConsumers: z.array(z.string()).default([]),
19
28
  httpAllowedOrigins: z.dict(z.array(z.string())).default({}),
20
29
  recoveryOnOpen: z.boolean().default(true),
21
30
  userConsumers: z.array(z.string()).default([]),
31
+ oauthAllowedAudiences: z.dict(z.array(z.string())).default({}),
22
32
  });
23
33
  /** The Loader retains Registry.plugin's awaitable wrapper, not its raw fiber. */
24
34
  function sameFiber(left, right) {
@@ -54,8 +64,13 @@ const HOST_LEASE_RENEWAL_SKEW_MS = 60_000;
54
64
  export class AnpIdentityService extends Service {
55
65
  static Config = Config;
56
66
  resolvedConfig;
67
+ registrationSettings;
57
68
  catalogStore;
58
69
  providerSlot;
70
+ publications;
71
+ publicationBackends = new Map();
72
+ papCallbackAuthorities = new Map();
73
+ protocols;
59
74
  users;
60
75
  hostContext;
61
76
  disabledFences = new Set();
@@ -63,8 +78,10 @@ export class AnpIdentityService extends Service {
63
78
  constructor(ctx, config) {
64
79
  super(ctx, 'anpIdentity');
65
80
  this.resolvedConfig = resolveConfig(config);
81
+ this.registrationSettings = new RegistrationServiceSettingsStore(this.resolvedConfig.stateRoot);
66
82
  this.catalogStore = new CatalogStore(this.resolvedConfig.stateRoot);
67
83
  this.hostContext = ctx;
84
+ this.publications = new PublicationCoordinator(this.catalogStore, { withNative: operation => this.withPublicationNative(operation) });
68
85
  this.users = new UserIdentityService(this.resolvedConfig.stateRoot, {
69
86
  ensureReady: async () => { await this.awaitProvider(this.requireSlot()); },
70
87
  resolveCaller: context => this.resolveInstalledCaller(context),
@@ -73,7 +90,11 @@ export class AnpIdentityService extends Service {
73
90
  createIdentity: (id, caller, parameters) => this.createConfirmed(id, caller, parameters),
74
91
  reconcileCreation: (id, caller, parameters) => this.reconcileConfirmed(id, caller, parameters),
75
92
  withNative: operation => this.withUserNative(operation),
76
- });
93
+ }, this.publications);
94
+ this.protocols = new ProtocolIdentityAuthority(structuredClone(config.protocolPolicies ?? []), {
95
+ resolveCaller: context => this.resolveInstalledCaller(context), assertCaller: caller => this.assertInstalledCaller(caller),
96
+ providerGeneration: () => this.requireSlot().id, withNative: operation => this.withProtocolNative(operation),
97
+ }, this.publications);
77
98
  const observe = ctx.on.bind(ctx);
78
99
  observe('loader/partial-dispose', (rawEntry, rawPrevious, active) => {
79
100
  if (ctx.fiber.state > 2)
@@ -83,7 +104,7 @@ export class AnpIdentityService extends Service {
83
104
  if (active === false || entry?.disabled)
84
105
  this.cancelDisabledRequests(previous?.name ?? entry?.options?.name);
85
106
  try {
86
- for (const candidate of this.installedEntries()) {
107
+ for (const candidate of installedConsumerEntries(this.hostContext)) {
87
108
  if (candidate.disabled)
88
109
  this.cancelDisabledRequests(candidate.options.name);
89
110
  }
@@ -94,7 +115,7 @@ export class AnpIdentityService extends Service {
94
115
  if (ctx.fiber.state > 2)
95
116
  return;
96
117
  try {
97
- for (const entry of this.installedEntries()) {
118
+ for (const entry of installedConsumerEntries(this.hostContext)) {
98
119
  if (sameFiber(entry.fiber, fiber) && entry.disabled)
99
120
  this.cancelDisabledRequests(entry.options.name);
100
121
  }
@@ -111,7 +132,7 @@ export class AnpIdentityService extends Service {
111
132
  }
112
133
  async health() {
113
134
  const slot = this.providerSlot;
114
- if (slot === undefined || slot.disposed) {
135
+ if (slot === undefined || slot.disposed || this.hostContext.fiber.state > 2) {
115
136
  return {
116
137
  status: 'unavailable',
117
138
  protocol: ANP_IDENTITY_SERVICE_PROTOCOL,
@@ -119,7 +140,25 @@ export class AnpIdentityService extends Service {
119
140
  };
120
141
  }
121
142
  try {
122
- await slot.ready;
143
+ const assertCurrent = () => {
144
+ this.assertSlot(slot);
145
+ if (this.hostContext.fiber.state > 2)
146
+ throw pluginError('provider_disposed');
147
+ };
148
+ const provider = await slot.ready;
149
+ assertCurrent();
150
+ const native = provider.acquireLease({ consumer: '@agent-network-protocol/dsh-anp-identity',
151
+ capabilities: ['IDENTITY_READ'], ttlSeconds: 15 });
152
+ try {
153
+ const info = await native.info();
154
+ assertCurrent();
155
+ // Legacy general health remains compatible; protocol leases require the availability handshake.
156
+ if (info.backendAvailable === false || !info.schemaCompatible || info.health !== 'ready')
157
+ throw pluginError('provider_unavailable');
158
+ }
159
+ finally {
160
+ native.dispose();
161
+ }
123
162
  }
124
163
  catch {
125
164
  return {
@@ -631,13 +670,202 @@ export class AnpIdentityService extends Service {
631
670
  bindUserConsumer(context) {
632
671
  return this.users.bind(context);
633
672
  }
673
+ bindProtocolConsumer(context) { return this.protocols.bind(context); }
674
+ /** Bind the actual installed PAP Host. Private callback access additionally requires its current opaque target.
675
+ * @param context - Original Loader-installed PAP plugin Context.
676
+ * @returns Public identity selection and target-bound, closed callback operations.
677
+ */
678
+ bindPapHostConsumer(context) {
679
+ return this.protocols.bindPapHost(context, async (reference, backend) => {
680
+ const entry = this.papCallbackAuthorities.get(backend);
681
+ if (!entry || entry.reference.storeId !== reference.storeId || entry.reference.identityId !== reference.identityId
682
+ || entry.reference.did !== reference.did)
683
+ throw new PapCallbackManagementError('management_auth_required');
684
+ await entry.authority.assertActive();
685
+ return entry.authority;
686
+ });
687
+ }
688
+ /** Install a real device-authorized backend; the document id comes from authenticated resolve. */
689
+ async configureManagedPublicationBackend(context, name, input) {
690
+ this.assertManagementContext(context);
691
+ const slot = this.requireSlot();
692
+ let disposed = false;
693
+ const assertCurrent = () => {
694
+ if (disposed)
695
+ throw pluginError('provider_disposed');
696
+ // Preserve the original installed manager Context even when a different service consumer invokes a capability.
697
+ const managerService = context.get('anpIdentity');
698
+ managerService.assertManagementContext(context);
699
+ managerService.assertSlot(slot);
700
+ };
701
+ const assertActive = async () => { assertCurrent(); };
702
+ const driver = await createManagedPublicationDriver({ ...input,
703
+ withNative: async (operation) => {
704
+ assertCurrent();
705
+ const result = await context.get('anpIdentity').withPublicationNative(async (native) => {
706
+ assertCurrent();
707
+ const value = await operation(native);
708
+ assertCurrent();
709
+ return value;
710
+ });
711
+ assertCurrent();
712
+ return result;
713
+ }, assertActive, assertCurrent });
714
+ this.assertManagementContext(context);
715
+ const dispose = this.registerPublicationBackend(context, name, driver.backend);
716
+ const generation = Symbol('pap-callback-manager');
717
+ const reference = Object.freeze(structuredClone(input.reference));
718
+ const origin = input.origin;
719
+ const prefix = 'pap-host-target:';
720
+ const assertAuthority = async () => {
721
+ await assertActive();
722
+ const managerService = context.get('anpIdentity');
723
+ if (managerService.publicationBackends.get(name) !== driver.backend
724
+ || managerService.papCallbackAuthorities.get(name)?.generation !== generation)
725
+ throw pluginError('provider_disposed');
726
+ assertCurrent();
727
+ };
728
+ const authority = {
729
+ assertActive: assertAuthority,
730
+ operations: Object.freeze({ execute: driver.execute }),
731
+ reserve: async (transactionId, binding) => {
732
+ await assertAuthority();
733
+ const result = await input.credentials.reserveOperation(reference, origin, prefix + transactionId, binding);
734
+ await assertAuthority();
735
+ return result;
736
+ },
737
+ read: async (transactionId) => {
738
+ await assertAuthority();
739
+ const credential = await input.credentials.get(reference, origin);
740
+ await assertAuthority();
741
+ return credential?.operationBindings?.[prefix + transactionId];
742
+ },
743
+ };
744
+ this.papCallbackAuthorities.set(name, { reference, generation, authority });
745
+ return { backend: name, documentId: driver.documentId, callbackManagement: Object.freeze({ execute: driver.execute }),
746
+ dispose: () => {
747
+ disposed = true;
748
+ dispose();
749
+ if (this.papCallbackAuthorities.get(name)?.generation === generation)
750
+ this.papCallbackAuthorities.delete(name);
751
+ } };
752
+ }
753
+ /** Register the public local Manifest through User Service and persist its verified management credential. */
754
+ async registerLocalIdentity(context, input) {
755
+ const assertActive = await this.pinManagementContext(context, input.reference, input.assertActive);
756
+ const result = await registerLocalIdentity({ ...input, assertActive, withNative: async (operation) => {
757
+ assertActive();
758
+ const value = await context.get('anpIdentity').withPublicationNative(async (native) => {
759
+ assertActive();
760
+ const output = await operation(native);
761
+ assertActive();
762
+ return output;
763
+ }, true);
764
+ assertActive();
765
+ return value;
766
+ } });
767
+ assertActive();
768
+ return result;
769
+ }
770
+ /** Manager-only registration preferences; ordinary consumer capabilities never expose these methods. */
771
+ registrationServiceSettings(context) {
772
+ return this.registrationSettings.read(() => this.assertManagementContext(context));
773
+ }
774
+ configureRegistrationService(context, input) {
775
+ return this.registrationSettings.update(input, () => this.assertManagementContext(context));
776
+ }
777
+ resolveRegistrationServiceOrigin(context, key, fingerprint) {
778
+ return this.registrationSettings.pin(key, fingerprint, () => this.assertManagementContext(context));
779
+ }
780
+ /** Pin the actual ready provider for an approved local identity and the original manager Context.
781
+ * @param context - Original root-installed manager Context.
782
+ * @param reference - Local identity whose current provider is being pinned.
783
+ * @param additionalCheck - Optional stricter Host lifecycle check.
784
+ * @returns A synchronous fence that never switches to a replacement provider.
785
+ */
786
+ async pinManagementContext(context, reference, additionalCheck) {
787
+ additionalCheck?.();
788
+ this.assertManagementContext(context);
789
+ const slot = this.requireSlot();
790
+ const assertActive = () => {
791
+ additionalCheck?.();
792
+ const manager = context.get('anpIdentity');
793
+ manager.assertManagementContext(context);
794
+ manager.assertSlot(slot);
795
+ };
796
+ await this.awaitProvider(slot);
797
+ assertActive();
798
+ await context.get('anpIdentity').withPublicationNative(async (native) => {
799
+ assertActive();
800
+ await native.publicIdentity(reference);
801
+ assertActive();
802
+ });
803
+ assertActive();
804
+ return assertActive;
805
+ }
634
806
  /** Host-only manager; the ordinary consumer facade never exposes this object. */
635
- acquireManagement() {
636
- if (!sameFiber(this.ctx.fiber, this.hostContext.fiber) && !sameFiber(this.ctx.fiber, this.hostContext.root.fiber)) {
807
+ registerPublicationBackend(context, name, backend) {
808
+ this.assertManagementContext(context);
809
+ if (!/^[A-Za-z0-9_-]{1,128}$/u.test(name) || this.publicationBackends.has(name))
810
+ throw pluginError('invalid_request');
811
+ exactHttps(backend.origin);
812
+ this.publicationBackends.set(name, backend);
813
+ return () => { if (this.publicationBackends.get(name) === backend)
814
+ this.publicationBackends.delete(name); };
815
+ }
816
+ assertManagementContext(context) {
817
+ if (!context || !sameFiber(this.ctx.fiber, context.fiber))
637
818
  throw pluginError('consumer_forbidden');
638
- }
639
- const ready = async () => { await this.users.ready; await this.awaitProvider(this.requireSlot()); };
819
+ const manager = this.installedEntries().find(entry => sameFiber(entry.fiber, context.fiber));
820
+ if (!manager || manager.options.name !== '@agent-network-protocol/dsh-anp-identity/management-remote'
821
+ || manager.disabled || !manager.fiber || ![1, 2].includes(manager.fiber.state))
822
+ throw pluginError('consumer_forbidden');
823
+ }
824
+ acquireManagement(context, additionalCheck) {
825
+ additionalCheck?.();
826
+ this.assertManagementContext(context);
827
+ const ready = async () => {
828
+ additionalCheck?.();
829
+ this.assertManagementContext(context);
830
+ await this.users.ready;
831
+ additionalCheck?.();
832
+ this.assertManagementContext(context);
833
+ const slot = this.requireSlot();
834
+ await this.awaitProvider(slot);
835
+ additionalCheck?.();
836
+ this.assertManagementContext(context);
837
+ this.assertSlot(slot);
838
+ };
640
839
  return Object.freeze({
840
+ retryPublication: async (reference) => {
841
+ await ready();
842
+ const entry = findEntry(await this.loadCatalog(this.requireSlot()), reference);
843
+ if (!entry?.publication)
844
+ throw pluginError('provider_unavailable');
845
+ return this.acquireManagement(context, additionalCheck).publishIdentity({ reference, config: entry.publication.config });
846
+ },
847
+ publicationStatus: async (reference) => { await ready(); return this.publications.status(reference); },
848
+ publishIdentity: async (input) => {
849
+ await ready();
850
+ const backend = this.publicationBackends.get(input.config.backend);
851
+ if (!backend)
852
+ throw pluginError('provider_unavailable');
853
+ try {
854
+ return await this.publications.publish(input.reference, input.config, backend, async () => {
855
+ await ready();
856
+ if (this.publicationBackends.get(input.config.backend) !== backend)
857
+ throw pluginError('provider_unavailable');
858
+ const entry = findEntry(await this.loadCatalog(this.requireSlot()), input.reference);
859
+ if (!entry || entry.state !== 'active')
860
+ throw pluginError('identity_not_found');
861
+ });
862
+ }
863
+ catch (error) {
864
+ if (error instanceof AnpIdentityPluginError)
865
+ throw error;
866
+ throw pluginError('provider_unavailable');
867
+ }
868
+ },
641
869
  listIdentities: async () => { await ready(); return this.managementIdentities(); },
642
870
  listRequests: async (history = false) => {
643
871
  await ready();
@@ -770,7 +998,7 @@ export class AnpIdentityService extends Service {
770
998
  return [...loader.entries()];
771
999
  }
772
1000
  resolveInstalledCaller(context) {
773
- const entry = this.installedEntries().find(value => sameFiber(value.fiber, context.fiber));
1001
+ const entry = resolveInstalledConsumer(this.hostContext, context);
774
1002
  if (!entry || entry.disabled || !this.resolvedConfig.userConsumers.has(entry.options.name)
775
1003
  || ![1, 2].includes(entry.fiber.state))
776
1004
  throw pluginError('consumer_forbidden');
@@ -779,7 +1007,7 @@ export class AnpIdentityService extends Service {
779
1007
  assertInstalledCaller(caller) {
780
1008
  if (this.disabledFences.has(caller.consumer))
781
1009
  throw pluginError('consumer_forbidden');
782
- const entry = this.installedEntries().find(value => value.options.name === caller.consumer
1010
+ const entry = installedConsumerEntries(this.hostContext).find(value => value.options.name === caller.consumer
783
1011
  && !value.disabled && value.fiber !== undefined && [1, 2].includes(value.fiber.state));
784
1012
  if (!entry || !this.resolvedConfig.userConsumers.has(caller.consumer))
785
1013
  throw pluginError('consumer_forbidden');
@@ -802,11 +1030,12 @@ export class AnpIdentityService extends Service {
802
1030
  throw pluginError('capability_forbidden');
803
1031
  }
804
1032
  assertLegacyCallerContext(consumer) {
805
- if (this.resolvedConfig.userConsumers.size === 0
806
- || sameFiber(this.ctx.fiber, this.hostContext.fiber) || sameFiber(this.ctx.fiber, this.hostContext.root.fiber))
1033
+ if (this.resolvedConfig.userConsumers.size === 0)
807
1034
  return;
808
1035
  const installed = this.installedEntries().find(entry => sameFiber(entry.fiber, this.ctx.fiber));
809
- if (!installed || installed.disabled || installed.options.name !== consumer
1036
+ if (!installed || installed.disabled
1037
+ || (installed.options.name !== consumer
1038
+ && !(this.resolvedConfig.allowProviderConsumers.has(consumer) && installed.options.name === consumer + '/provider'))
810
1039
  || !installed.fiber || ![1, 2].includes(installed.fiber.state)
811
1040
  || this.resolvedConfig.userConsumers.has(installed.options.name))
812
1041
  throw pluginError('consumer_forbidden');
@@ -824,6 +1053,42 @@ export class AnpIdentityService extends Service {
824
1053
  native.dispose();
825
1054
  }
826
1055
  }
1056
+ async withProtocolNative(operation) {
1057
+ const slot = this.requireSlot();
1058
+ const provider = await this.awaitProvider(slot);
1059
+ const native = provider.acquireLease({ consumer: '@agent-network-protocol/dsh-anp-identity',
1060
+ capabilities: ['IDENTITY_READ', 'IDENTITY_SIGN', 'IDENTITY_PAP_SESSION', 'IDENTITY_PAP_DPOP', 'IDENTITY_KEY_LIFECYCLE'], ttlSeconds: 300 });
1061
+ try {
1062
+ this.assertSlot(slot);
1063
+ const capability = native.providerCapabilities;
1064
+ if (typeof capability !== 'function')
1065
+ throw pluginError('provider_incompatible');
1066
+ const supported = await capability.call(native);
1067
+ if (supported.api_version !== 2 || !supported.algorithms.includes('ES256'))
1068
+ throw pluginError('provider_incompatible');
1069
+ const result = await operation(native);
1070
+ this.assertSlot(slot);
1071
+ return result;
1072
+ }
1073
+ finally {
1074
+ native.dispose();
1075
+ }
1076
+ }
1077
+ async withPublicationNative(operation, registrationSigning = false) {
1078
+ const slot = this.requireSlot();
1079
+ const provider = await this.awaitProvider(slot);
1080
+ const native = provider.acquireLease({ consumer: '@agent-network-protocol/dsh-anp-identity',
1081
+ capabilities: ['IDENTITY_READ', 'IDENTITY_DOCUMENT_UPDATE', 'IDENTITY_HTTP_SIGNATURE', ...(registrationSigning ? ['IDENTITY_SIGN'] : [])], ttlSeconds: 300 });
1082
+ try {
1083
+ this.assertSlot(slot);
1084
+ if (typeof native.oauthPublicJwk !== 'function')
1085
+ throw pluginError('provider_incompatible');
1086
+ return await operation(native);
1087
+ }
1088
+ finally {
1089
+ native.dispose();
1090
+ }
1091
+ }
827
1092
  async userSnapshot(caller, reference) {
828
1093
  this.assertInstalledCaller(caller);
829
1094
  const catalog = await this.loadCatalog(this.requireSlot());
@@ -836,14 +1101,22 @@ export class AnpIdentityService extends Service {
836
1101
  const identity = await this.withUserNative(native => native.publicIdentity(reference));
837
1102
  if (identity.state !== 'active' || !identity.capabilities.didWba)
838
1103
  throw pluginError('provider_incompatible');
839
- requestSigningKid(identity);
1104
+ const http = httpSigningKey(identity);
1105
+ if (http.httpOnly)
1106
+ return { version: 'ordinary-http/1', capabilities: ['identity:read', 'identity:http-auth'],
1107
+ signingPurposes: [], httpOrigins: [...(this.resolvedConfig.httpAllowedOrigins.get(caller.consumer) ?? [])].sort() };
840
1108
  return { version: 'ordinary-use/1', capabilities: ['identity:read', 'identity:sign', 'identity:http-auth'],
841
- signingPurposes: ['authentication', 'application_assertion'],
1109
+ signingPurposes: this.resolvedConfig.oauthAllowedAudiences.has(caller.consumer)
1110
+ ? ['application_assertion', 'oauth_client_assertion'] : ['authentication', 'application_assertion'],
1111
+ ...(this.resolvedConfig.oauthAllowedAudiences.has(caller.consumer)
1112
+ ? { oauthAudiences: [...this.resolvedConfig.oauthAllowedAudiences.get(caller.consumer)].sort() } : {}),
842
1113
  httpOrigins: [...(this.resolvedConfig.httpAllowedOrigins.get(caller.consumer) ?? [])].sort() };
843
1114
  }
844
1115
  async createConfirmed(operationId, caller, parameters) {
845
1116
  this.assertInstalledCaller(caller);
846
1117
  return this.catalogStore.withNativeCreateLock(async () => this.withUserNative(async (native) => {
1118
+ // Refresh the namespace generation after document/key operations performed through identity handles.
1119
+ await native.recover();
847
1120
  const catalog = await this.loadCatalog(this.requireSlot());
848
1121
  const existing = catalog.entries.find(entry => entry.creationOperationId === operationId);
849
1122
  if (existing)
@@ -863,9 +1136,21 @@ export class AnpIdentityService extends Service {
863
1136
  consumer: caller.consumer, label: parameters.label, createdAt: new Date().toISOString(),
864
1137
  ...(parameters.handle === undefined ? {} : { handle: parameters.handle }),
865
1138
  authorizationMode: 'user', baselineIdentityIds: baseline.map(item => item.reference.identityId) });
866
- const identity = await native.create({ profile: 'e1', domain: parameters.domain,
1139
+ const profile = parameters.profile ?? 'e1';
1140
+ const protocol = parameters.usage === 'protocol';
1141
+ const identity = await native.create({ profile, domain: parameters.domain,
867
1142
  pathSegments: parameters.path.split('/').filter(Boolean), capabilities: { didWba: true },
868
- managedKeys: [{ fragment: 'root', role: 'root_control' }, { fragment: 'request', role: 'request_signing' }] });
1143
+ managedKeys: protocol ? [
1144
+ ...(profile === 'e1' ? [{ fragment: 'root', role: 'root_control' }] : []),
1145
+ { fragment: 'device', role: 'device_signing' }, { fragment: 'agreement', role: 'e2ee_agreement' },
1146
+ ] : [{ fragment: 'root', role: 'root_control' }, { fragment: 'request', role: 'request_signing' }],
1147
+ ...(protocol ? { extensions: [{ type: 'device_manifest', value: { devices: [{ deviceId: 'dsh-' + createHash('sha256').update(operationId).digest('hex').slice(0, 24),
1148
+ signingKeyId: '#device', e2eeKeyId: '#agreement', profiles: parameters.identityOnly ? [
1149
+ 'anp.core.binding.v1', 'anp.identity.discovery.v1',
1150
+ ] : [
1151
+ 'anp.core.binding.v1', 'anp.identity.discovery.v1', 'anp.direct.base.v1',
1152
+ 'anp.direct.e2ee.v2', 'anp.group.base.v2', 'anp.group.e2ee.v2',
1153
+ ] }] } }] } : {}) });
869
1154
  await this.catalogStore.updateIntent(operationId, intent => ({ ...intent, reference: identity.reference }));
870
1155
  const entry = await this.catalogStore.commitIntent(operationId);
871
1156
  await this.catalogStore.deleteIntent(operationId);
@@ -1108,7 +1393,13 @@ class HostLease {
1108
1393
  this.#retired.clear();
1109
1394
  this.service.removeLease(this.slot, this);
1110
1395
  }
1111
- info = () => this.call('IDENTITY_READ', () => this.native.info());
1396
+ info = () => this.call('IDENTITY_READ', async () => {
1397
+ const info = await this.native.info();
1398
+ if (info.backendAvailable === false)
1399
+ throw pluginError('provider_unavailable');
1400
+ return { storeId: info.storeId, schemaCompatible: info.schemaCompatible,
1401
+ identityCount: info.identityCount, health: info.health };
1402
+ });
1112
1403
  recover = () => this.call('IDENTITY_READ', () => this.native.recover());
1113
1404
  list = () => this.call('IDENTITY_READ', () => this.native.list());
1114
1405
  publicIdentity = (reference) => this.call('IDENTITY_READ', () => this.native.publicIdentity(reference));
@@ -1116,6 +1407,8 @@ class HostLease {
1116
1407
  recoverIdentity = (reference) => this.call('IDENTITY_READ', () => this.native.recoverIdentity(reference));
1117
1408
  create = (request) => this.call('IDENTITY_CREATE', () => this.service.createForHost(this.slot, this.native, this.consumer, request));
1118
1409
  delete = (reference) => this.call('IDENTITY_DELETE', () => this.service.deleteForHost(this.slot, this.native, this.consumer, reference));
1410
+ oauthPublicJwk = (reference, kid) => this.call('IDENTITY_READ', () => this.native.oauthPublicJwk(reference, kid));
1411
+ signOAuthClientAssertion = (reference, request) => this.call('IDENTITY_SIGN', () => this.native.signOAuthClientAssertion(reference, request));
1119
1412
  sign = (reference, request) => this.call('IDENTITY_SIGN', () => this.native.sign(reference, request));
1120
1413
  verify = (reference, request) => this.call('IDENTITY_READ', () => this.native.verify(reference, request));
1121
1414
  signOriginProof = (reference, request) => this.call('IDENTITY_SIGN', () => this.native.signOriginProof(reference, request));
@@ -1225,6 +1518,8 @@ function renewalAt(issuedAt, ttlSeconds) {
1225
1518
  }
1226
1519
  export default AnpIdentityService;
1227
1520
  function resolveConfig(config) {
1521
+ if (config.signerMode !== undefined && config.signerMode !== 'local')
1522
+ throw new TypeError('Remote signers are unsupported');
1228
1523
  const configured = config.stateRoot?.trim();
1229
1524
  const dshHome = process.env.DSH_HOME?.trim() || join(homedir(), '.dsh');
1230
1525
  const stateRoot = configured === undefined || configured.length === 0
@@ -1250,14 +1545,24 @@ function resolveConfig(config) {
1250
1545
  validateConsumer(consumer);
1251
1546
  if (!allowConsumers.has(consumer))
1252
1547
  throw new TypeError('anp-identity: HTTP consumer must be allowed');
1253
- const normalized = origins.map(normalizeHttpsOrigin);
1548
+ if (origins.includes('*') && !userConsumers.has(consumer)) {
1549
+ throw new TypeError('anp-identity: wildcard HTTP origins require an explicit User consumer');
1550
+ }
1551
+ const normalized = origins.map(value => value === '*' ? value : normalizeHttpsOrigin(value));
1254
1552
  if (new Set(normalized).size !== normalized.length) {
1255
1553
  throw new TypeError('anp-identity: HTTP origins must be unique');
1256
1554
  }
1257
1555
  httpAllowedOrigins.set(consumer, new Set(normalized));
1258
1556
  }
1557
+ const oauthAllowedAudiences = new Map();
1558
+ for (const [consumer, audiences] of Object.entries(config.oauthAllowedAudiences ?? {})) {
1559
+ if (!userConsumers.has(consumer) || !audiences.length)
1560
+ throw new TypeError('OAuth consumers must be approved User consumers');
1561
+ oauthAllowedAudiences.set(consumer, new Set(audiences.map(value => exactHttps(value))));
1562
+ }
1259
1563
  return {
1260
1564
  stateRoot,
1565
+ oauthAllowedAudiences,
1261
1566
  allowConsumers,
1262
1567
  allowProviderConsumers,
1263
1568
  httpAllowedOrigins,
@@ -1469,4 +1774,8 @@ function readErrorCode(error) {
1469
1774
  function isPluginCode(error, code) {
1470
1775
  return error instanceof AnpIdentityPluginError && error.code === code;
1471
1776
  }
1777
+ export { createPublicationBackend } from './publication-http.js';
1778
+ export { EncryptedManagementCredentialBroker } from './management-credentials.js';
1779
+ export { createManagedPublicationDriver, registerLocalIdentity } from './management-driver.js';
1780
+ export { PapCallbackManagementError } from './pap-callback.js';
1472
1781
  //# sourceMappingURL=index.js.map