sos-sdk-node-ts 0.1.13 → 0.1.14
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/CHANGELOG.md +19 -0
- package/README.md +9 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/secure-organization-registration.d.ts +58 -0
- package/dist/secure-organization-registration.js +128 -0
- package/dist/server-passkey-profile.d.ts +8 -0
- package/dist/server-passkey-profile.js +24 -1
- package/docs/ORGANIZATION_REGISTRATION_SOURCE_EVALUATION.md +27 -0
- package/package.json +7 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## Unreleased
|
|
4
|
+
|
|
5
|
+
## 0.1.14 - 2026-10-21
|
|
6
|
+
|
|
7
|
+
- Add a product-neutral server-profile owner assertion for personal passkey
|
|
8
|
+
registration. It binds the selected profile to the authenticated Firebase
|
|
9
|
+
principal without misinterpreting an individual-member actor DID as a
|
|
10
|
+
professional employee identifier; mandatory passkey enrollment after PIN
|
|
11
|
+
verification remains unchanged.
|
|
12
|
+
- Accept the browser WebAuthn secure-context exception for local loopback
|
|
13
|
+
origins while continuing to reject plain HTTP origins on remote hosts.
|
|
14
|
+
|
|
15
|
+
- Adopt the product-neutral secure organization registration runtime previously
|
|
16
|
+
specialized in the clinical Node SDK: reviewed controller bootstrap-wallet
|
|
17
|
+
reconstruction, encrypted verification/reissuance transport, Offer-to-Order
|
|
18
|
+
confirmation and terminal OperationOutcome rejection. Portal forms, sector
|
|
19
|
+
admission policy, profile persistence and deployment values remain outside
|
|
20
|
+
this package.
|
|
21
|
+
|
|
3
22
|
## 0.1.13 - 2026-10-21
|
|
4
23
|
|
|
5
24
|
- Add the trusted-BFF host organization directory client. It submits and polls
|
package/README.md
CHANGED
|
@@ -24,6 +24,15 @@ begins only after exact registry packages are installed and verified.
|
|
|
24
24
|
|
|
25
25
|
Product-neutral Node adapters for trusted SOSCHAIN runtimes.
|
|
26
26
|
|
|
27
|
+
`secure-organization-registration` owns the trusted Node transport used after
|
|
28
|
+
an application has been reviewed: deterministic reconstruction of the exact
|
|
29
|
+
controller bootstrap wallet, encrypted organization verification or credential
|
|
30
|
+
reissuance, and confirmation of the exact accepted Offer through Order. It
|
|
31
|
+
does not own portal forms, admission policy, user authentication, application
|
|
32
|
+
storage, payment policy or professional operations.
|
|
33
|
+
The capability-by-capability source decision is recorded in
|
|
34
|
+
[`docs/ORGANIZATION_REGISTRATION_SOURCE_EVALUATION.md`](docs/ORGANIZATION_REGISTRATION_SOURCE_EVALUATION.md).
|
|
35
|
+
|
|
27
36
|
```text
|
|
28
37
|
gdc-* frozen
|
|
29
38
|
↓
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { resolveDidWebKeyAgreementJwk, type AppInfo, type HostRouteContext, type LegalOrganizationOrderInput, type NodeLegalOrganizationVerificationTransactionInput, type PollOptions, type RouteContext, type SubmitAndPollResult } from 'gdc-sdk-node-ts';
|
|
2
|
+
type PublicJwk = Readonly<Record<string, unknown>>;
|
|
3
|
+
export type HostScopedDidWebResolverOptions = Readonly<{
|
|
4
|
+
gatewayBaseUrl: string;
|
|
5
|
+
hostCoverageScope: string;
|
|
6
|
+
version: string;
|
|
7
|
+
hostNetwork: string;
|
|
8
|
+
fetchImpl?: typeof fetch;
|
|
9
|
+
}>;
|
|
10
|
+
export declare function buildHostScopedDidDocumentUrl(options: Omit<HostScopedDidWebResolverOptions, 'fetchImpl'>): string;
|
|
11
|
+
export declare function createHostScopedDidWebKeyAgreementResolver(options: HostScopedDidWebResolverOptions): (recipientDid: string) => ReturnType<typeof resolveDidWebKeyAgreementJwk>;
|
|
12
|
+
export type SecureOrganizationRegistrationRuntimeOptions = Readonly<{
|
|
13
|
+
gatewayBaseUrl: string;
|
|
14
|
+
appInfo?: AppInfo;
|
|
15
|
+
resolveRecipientJwk(recipientDid: string): Promise<PublicJwk>;
|
|
16
|
+
fetchImpl?: typeof fetch;
|
|
17
|
+
requestTimeoutMs?: number;
|
|
18
|
+
}>;
|
|
19
|
+
type SecureOrganizationBootstrapInput = Readonly<{
|
|
20
|
+
walletSeed: string;
|
|
21
|
+
walletKeyDerivationId: string;
|
|
22
|
+
bearerToken: string;
|
|
23
|
+
providerDid: string;
|
|
24
|
+
routeContext: RouteContext;
|
|
25
|
+
hostContext: HostRouteContext;
|
|
26
|
+
pollOptions?: PollOptions;
|
|
27
|
+
}>;
|
|
28
|
+
export type SecureOrganizationRegistrationInput = SecureOrganizationBootstrapInput & Readonly<{
|
|
29
|
+
verificationInput: NodeLegalOrganizationVerificationTransactionInput;
|
|
30
|
+
}>;
|
|
31
|
+
export type SecureOrganizationOrderInput = SecureOrganizationBootstrapInput & Readonly<{
|
|
32
|
+
orderInput: LegalOrganizationOrderInput;
|
|
33
|
+
}>;
|
|
34
|
+
export declare function buildOrganizationRegistrationWalletContext(walletKeyDerivationId: string): {
|
|
35
|
+
readonly profile: {
|
|
36
|
+
readonly profileId: string;
|
|
37
|
+
};
|
|
38
|
+
readonly runtime: {
|
|
39
|
+
readonly runtimeId: `${string}:server-runtime`;
|
|
40
|
+
readonly runtimeType: "backend-service";
|
|
41
|
+
};
|
|
42
|
+
};
|
|
43
|
+
/** Trusted-server facade for encrypted verification, reissuance and Offer-to-Order confirmation. */
|
|
44
|
+
export declare class SecureOrganizationRegistrationRuntime {
|
|
45
|
+
private readonly options;
|
|
46
|
+
constructor(options: SecureOrganizationRegistrationRuntimeOptions);
|
|
47
|
+
submitVerificationWithBootstrapWallet(input: SecureOrganizationRegistrationInput): Promise<SubmitAndPollResult>;
|
|
48
|
+
submitCredentialReissuanceWithBootstrapWallet(input: SecureOrganizationRegistrationInput): Promise<SubmitAndPollResult>;
|
|
49
|
+
confirmOrderWithBootstrapWallet(input: SecureOrganizationOrderInput): Promise<SubmitAndPollResult>;
|
|
50
|
+
private createEncryptedClient;
|
|
51
|
+
}
|
|
52
|
+
export declare function assertSuccessfulOrganizationRegistrationResult<T extends Readonly<{
|
|
53
|
+
poll: Readonly<{
|
|
54
|
+
status: number;
|
|
55
|
+
body: unknown;
|
|
56
|
+
}>;
|
|
57
|
+
}>>(result: T): T;
|
|
58
|
+
export {};
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
// Copyright 2026 Connecting Solution & Applications Ltd under the Apache License, Version 2.0.
|
|
2
|
+
import { NodeHttpClient, NodeManagedWallet, TransportProfiles, resolveDidWebKeyAgreementJwk, } from 'gdc-sdk-node-ts';
|
|
3
|
+
import { buildAuthorityDidWeb } from 'gdc-common-utils-ts/utils/authority-resolution';
|
|
4
|
+
export function buildHostScopedDidDocumentUrl(options) {
|
|
5
|
+
const gatewayOrigin = secureOrigin(options.gatewayBaseUrl, 'host_did_gateway_url_required');
|
|
6
|
+
const coverage = routeSegment(options.hostCoverageScope, 'host_did_coverage_scope_required').toUpperCase();
|
|
7
|
+
const version = routeSegment(options.version, 'host_did_version_required');
|
|
8
|
+
const network = routeSegment(options.hostNetwork, 'host_did_network_required');
|
|
9
|
+
return `${gatewayOrigin}/host/cds-${coverage}/${version}/${network}/.well-known/did.json`;
|
|
10
|
+
}
|
|
11
|
+
export function createHostScopedDidWebKeyAgreementResolver(options) {
|
|
12
|
+
const gatewayOrigin = secureOrigin(options.gatewayBaseUrl, 'host_did_gateway_url_required');
|
|
13
|
+
const hostDid = buildAuthorityDidWeb({ authority: gatewayOrigin }).toLowerCase();
|
|
14
|
+
const didDocumentUrl = buildHostScopedDidDocumentUrl(options);
|
|
15
|
+
return recipientDid => resolveDidWebKeyAgreementJwk(recipientDid, {
|
|
16
|
+
fetchImpl: options.fetchImpl,
|
|
17
|
+
...(String(recipientDid || '').trim().toLowerCase() === hostDid ? { didDocumentUrl } : {}),
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
export function buildOrganizationRegistrationWalletContext(walletKeyDerivationId) {
|
|
21
|
+
const id = required(walletKeyDerivationId, 'organization_registration_wallet_context_required');
|
|
22
|
+
return { profile: { profileId: id }, runtime: { runtimeId: `${id}:server-runtime`, runtimeType: 'backend-service' } };
|
|
23
|
+
}
|
|
24
|
+
/** Trusted-server facade for encrypted verification, reissuance and Offer-to-Order confirmation. */
|
|
25
|
+
export class SecureOrganizationRegistrationRuntime {
|
|
26
|
+
options;
|
|
27
|
+
constructor(options) {
|
|
28
|
+
this.options = options;
|
|
29
|
+
secureOrigin(options.gatewayBaseUrl, 'organization_registration_gateway_url_required');
|
|
30
|
+
}
|
|
31
|
+
async submitVerificationWithBootstrapWallet(input) {
|
|
32
|
+
const client = await this.createEncryptedClient(input);
|
|
33
|
+
return assertSuccessfulOrganizationRegistrationResult(await client.submitLegalOrganizationVerificationTransaction(input.hostContext, input.verificationInput, input.pollOptions));
|
|
34
|
+
}
|
|
35
|
+
async submitCredentialReissuanceWithBootstrapWallet(input) {
|
|
36
|
+
const client = await this.createEncryptedClient(input);
|
|
37
|
+
return assertSuccessfulOrganizationRegistrationResult(await client.submitLegalOrganizationCredentialReissuance(input.hostContext, input.verificationInput, input.pollOptions));
|
|
38
|
+
}
|
|
39
|
+
async confirmOrderWithBootstrapWallet(input) {
|
|
40
|
+
const client = await this.createEncryptedClient(input);
|
|
41
|
+
return assertSuccessfulOrganizationRegistrationResult(await client.confirmLegalOrganizationOrder(input.hostContext, input.orderInput, input.pollOptions));
|
|
42
|
+
}
|
|
43
|
+
async createEncryptedClient(input) {
|
|
44
|
+
const walletKeyDerivationId = required(input.walletKeyDerivationId, 'organization_registration_wallet_context_required');
|
|
45
|
+
const walletSeed = required(input.walletSeed, 'organization_registration_wallet_seed_required');
|
|
46
|
+
const providerDid = required(input.providerDid, 'organization_registration_provider_did_required');
|
|
47
|
+
const bearerToken = required(input.bearerToken, 'organization_registration_bearer_required');
|
|
48
|
+
const wallet = new NodeManagedWallet({ resolveRecipientJwk: this.options.resolveRecipientJwk });
|
|
49
|
+
const context = buildOrganizationRegistrationWalletContext(walletKeyDerivationId);
|
|
50
|
+
await wallet.provisionManagedKeys(context, { ownerScope: 'profile', purposes: ['actor-signing', 'document-at-rest'], mode: 'deterministic', seedMaterial: walletSeed });
|
|
51
|
+
await wallet.provisionManagedKeys(context, { ownerScope: 'runtime', purposes: ['openid-id-token-signing', 'vp-token-signing', 'comm-signing', 'comm-encryption'], mode: 'deterministic', seedMaterial: walletSeed });
|
|
52
|
+
return new NodeHttpClient({
|
|
53
|
+
baseUrl: this.options.gatewayBaseUrl, bearerToken, ctx: input.routeContext,
|
|
54
|
+
appInfo: this.options.appInfo, fetchImpl: this.options.fetchImpl, requestTimeoutMs: this.options.requestTimeoutMs,
|
|
55
|
+
transportProfile: TransportProfiles.DidcommEncryptedForm,
|
|
56
|
+
secureTransportAdapter: {
|
|
57
|
+
pack: message => wallet.packForRecipientWithContext(message, providerDid, { context }),
|
|
58
|
+
unpack: async (jwe) => (await wallet.unpackWithContext(jwe, { context })).content,
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
export function assertSuccessfulOrganizationRegistrationResult(result) {
|
|
64
|
+
const failure = findFailedOperationOutcome(result.poll.body);
|
|
65
|
+
if (result.poll.status >= 400 || failure) {
|
|
66
|
+
const code = String(failure?.issue.code || 'operation-outcome').trim() || 'operation-outcome';
|
|
67
|
+
const status = failure?.status || result.poll.status;
|
|
68
|
+
throw new Error(`organization_registration_gateway_failed:${status}:${code}`);
|
|
69
|
+
}
|
|
70
|
+
return result;
|
|
71
|
+
}
|
|
72
|
+
function findFailedOperationOutcome(value) {
|
|
73
|
+
const seen = new WeakSet();
|
|
74
|
+
const visit = (candidate, inheritedStatus) => {
|
|
75
|
+
if (!candidate || typeof candidate !== 'object' || seen.has(candidate))
|
|
76
|
+
return undefined;
|
|
77
|
+
seen.add(candidate);
|
|
78
|
+
if (Array.isArray(candidate)) {
|
|
79
|
+
for (const item of candidate) {
|
|
80
|
+
const failure = visit(item, inheritedStatus);
|
|
81
|
+
if (failure)
|
|
82
|
+
return failure;
|
|
83
|
+
}
|
|
84
|
+
return undefined;
|
|
85
|
+
}
|
|
86
|
+
const record = asRecord(candidate);
|
|
87
|
+
const responseStatus = parseHttpStatus(asRecord(record.response).status) || inheritedStatus;
|
|
88
|
+
if (record.resourceType === 'OperationOutcome') {
|
|
89
|
+
const issues = Array.isArray(record.issue) ? record.issue.map(asRecord) : [];
|
|
90
|
+
const issue = issues.find(item => ['error', 'fatal'].includes(String(item.severity || '').toLowerCase()));
|
|
91
|
+
if (issue)
|
|
92
|
+
return { issue, status: parseHttpStatus(issue.responseStatus) || responseStatus };
|
|
93
|
+
}
|
|
94
|
+
for (const nested of Object.values(record)) {
|
|
95
|
+
const failure = visit(nested, responseStatus);
|
|
96
|
+
if (failure)
|
|
97
|
+
return failure;
|
|
98
|
+
}
|
|
99
|
+
return undefined;
|
|
100
|
+
};
|
|
101
|
+
return visit(value);
|
|
102
|
+
}
|
|
103
|
+
function parseHttpStatus(value) {
|
|
104
|
+
const status = Number.parseInt(String(value ?? ''), 10);
|
|
105
|
+
return Number.isInteger(status) && status >= 100 && status <= 599 ? status : undefined;
|
|
106
|
+
}
|
|
107
|
+
function asRecord(value) {
|
|
108
|
+
return value && typeof value === 'object' && !Array.isArray(value) ? value : {};
|
|
109
|
+
}
|
|
110
|
+
function required(value, error) {
|
|
111
|
+
const normalized = String(value ?? '').trim();
|
|
112
|
+
if (!normalized)
|
|
113
|
+
throw new TypeError(error);
|
|
114
|
+
return normalized;
|
|
115
|
+
}
|
|
116
|
+
function routeSegment(value, error) {
|
|
117
|
+
const normalized = required(value, error);
|
|
118
|
+
if (!/^[A-Za-z0-9-]+$/u.test(normalized))
|
|
119
|
+
throw new TypeError(error);
|
|
120
|
+
return normalized;
|
|
121
|
+
}
|
|
122
|
+
function secureOrigin(value, error) {
|
|
123
|
+
const url = new URL(required(value, error));
|
|
124
|
+
if (url.protocol !== 'https:' && !(url.protocol === 'http:' && ['localhost', '127.0.0.1', '::1'].includes(url.hostname))) {
|
|
125
|
+
throw new TypeError('organization_registration_gateway_https_required');
|
|
126
|
+
}
|
|
127
|
+
return url.origin;
|
|
128
|
+
}
|
|
@@ -102,6 +102,14 @@ export type ServerPasskeyProfileServiceOptions = Readonly<{
|
|
|
102
102
|
ceremonyTtlMs?: number;
|
|
103
103
|
accessTtlMs?: number;
|
|
104
104
|
}>;
|
|
105
|
+
/**
|
|
106
|
+
* Confirms that an authenticated Firebase principal owns the selected server
|
|
107
|
+
* profile. Personal actor DIDs describe the subject relationship and are not
|
|
108
|
+
* professional employee identifiers, so they must not be parsed as one.
|
|
109
|
+
*/
|
|
110
|
+
export declare function assertServerProfileOwner<T extends Readonly<{
|
|
111
|
+
ownerId: string;
|
|
112
|
+
}>>(profile: T | undefined, ownerId: string): asserts profile is T;
|
|
105
113
|
/** Product-neutral passkey state machine for SOS, health and animal portal BFFs. */
|
|
106
114
|
export declare class ServerPasskeyProfileService {
|
|
107
115
|
private readonly options;
|
|
@@ -2,6 +2,17 @@ import { createHash, randomBytes, randomUUID } from 'node:crypto';
|
|
|
2
2
|
import { generateAuthenticationOptions, generateRegistrationOptions, verifyAuthenticationResponse, verifyRegistrationResponse, } from '@simplewebauthn/server';
|
|
3
3
|
const CEREMONY_TTL_MS = 5 * 60 * 1000;
|
|
4
4
|
const ACCESS_TTL_MS = 15 * 60 * 1000;
|
|
5
|
+
/**
|
|
6
|
+
* Confirms that an authenticated Firebase principal owns the selected server
|
|
7
|
+
* profile. Personal actor DIDs describe the subject relationship and are not
|
|
8
|
+
* professional employee identifiers, so they must not be parsed as one.
|
|
9
|
+
*/
|
|
10
|
+
export function assertServerProfileOwner(profile, ownerId) {
|
|
11
|
+
const expectedOwnerId = ownerId.trim();
|
|
12
|
+
if (!profile || !expectedOwnerId || profile.ownerId !== expectedOwnerId) {
|
|
13
|
+
throw new Error('profile_not_found');
|
|
14
|
+
}
|
|
15
|
+
}
|
|
5
16
|
/** Product-neutral passkey state machine for SOS, health and animal portal BFFs. */
|
|
6
17
|
export class ServerPasskeyProfileService {
|
|
7
18
|
options;
|
|
@@ -140,7 +151,7 @@ export function createSimpleWebAuthnCeremonyAdapter(input) {
|
|
|
140
151
|
const rpName = String(input.rpName || '').trim();
|
|
141
152
|
const rpId = String(input.rpId || '').trim();
|
|
142
153
|
const origins = input.origins.map(value => String(value || '').trim()).filter(Boolean);
|
|
143
|
-
if (!rpName || !rpId || !origins.length || origins.some(origin => !origin
|
|
154
|
+
if (!rpName || !rpId || !origins.length || origins.some(origin => !isSecureWebAuthnOrigin(origin))) {
|
|
144
155
|
throw new Error('passkey_relying_party_not_configured');
|
|
145
156
|
}
|
|
146
157
|
return {
|
|
@@ -204,3 +215,15 @@ export function createSimpleWebAuthnCeremonyAdapter(input) {
|
|
|
204
215
|
},
|
|
205
216
|
};
|
|
206
217
|
}
|
|
218
|
+
function isSecureWebAuthnOrigin(origin) {
|
|
219
|
+
try {
|
|
220
|
+
const parsed = new URL(origin);
|
|
221
|
+
if (parsed.protocol === 'https:')
|
|
222
|
+
return true;
|
|
223
|
+
return parsed.protocol === 'http:'
|
|
224
|
+
&& (parsed.hostname === 'localhost' || parsed.hostname === '127.0.0.1' || parsed.hostname === '[::1]');
|
|
225
|
+
}
|
|
226
|
+
catch {
|
|
227
|
+
return false;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Organization registration source evaluation
|
|
2
|
+
|
|
3
|
+
The shared SOS Node SDK evaluated the existing clinical organization
|
|
4
|
+
registration runtime capability-by-capability. It did not copy a portal,
|
|
5
|
+
product policy or deployment configuration.
|
|
6
|
+
|
|
7
|
+
| Capability | Decision | Shared boundary |
|
|
8
|
+
| --- | --- | --- |
|
|
9
|
+
| deterministic controller bootstrap-wallet reconstruction | adopted | trusted Node SDK |
|
|
10
|
+
| encrypted DIDComm form transport to SOS Gateway | adopted | trusted Node SDK |
|
|
11
|
+
| organization verification and credential reissuance submission | adopted | trusted Node SDK |
|
|
12
|
+
| exact accepted Offer continuation through Order | adopted | trusted Node SDK |
|
|
13
|
+
| terminal nested `OperationOutcome` rejection | adopted | trusted Node SDK |
|
|
14
|
+
| host DID document route and recipient key resolution | adopted | trusted Node SDK |
|
|
15
|
+
| host organization search and lifecycle | already equivalent | existing host-directory client |
|
|
16
|
+
| application form, localization and product branding | rejected | hosting/controller presentation |
|
|
17
|
+
| sector and jurisdiction admission policy | rejected | trusted portal BFF and ICA |
|
|
18
|
+
| application, PIN and controller-profile persistence | rejected | trusted portal BFF |
|
|
19
|
+
| user authentication and account recovery | rejected | portal identity boundary |
|
|
20
|
+
| payment adapter and commercial policy | rejected | marketplace and billing boundary |
|
|
21
|
+
| professional groups, subjects, services, studies and scheduling | rejected | delegated professional workflows |
|
|
22
|
+
| tenant, host, network, credentials and deployment values | rejected | private deployment configuration |
|
|
23
|
+
|
|
24
|
+
This extraction is a transport prerequisite, not proof of an organization
|
|
25
|
+
onboarding journey. A consumer still has to prove application submission,
|
|
26
|
+
review, verification, Offer, Order, activation, device registration and
|
|
27
|
+
authoritative readback through its real BFF and Gateway environment.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sos-sdk-node-ts",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.14",
|
|
4
4
|
"description": "Product-neutral Node adapters shared by SOSChain, Vet and UHC runtimes",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "Connecting Solution & Applications Ltd",
|
|
@@ -51,6 +51,10 @@
|
|
|
51
51
|
"./host-organization-directory-client": {
|
|
52
52
|
"types": "./dist/host-organization-directory-client.d.ts",
|
|
53
53
|
"default": "./dist/host-organization-directory-client.js"
|
|
54
|
+
},
|
|
55
|
+
"./secure-organization-registration": {
|
|
56
|
+
"types": "./dist/secure-organization-registration.d.ts",
|
|
57
|
+
"default": "./dist/secure-organization-registration.js"
|
|
54
58
|
}
|
|
55
59
|
},
|
|
56
60
|
"files": [
|
|
@@ -70,6 +74,8 @@
|
|
|
70
74
|
},
|
|
71
75
|
"dependencies": {
|
|
72
76
|
"@simplewebauthn/server": "13.3.2",
|
|
77
|
+
"gdc-common-utils-ts": "2.9.30",
|
|
78
|
+
"gdc-sdk-node-ts": "2.9.32",
|
|
73
79
|
"sos-data-utils-ts": "0.6.13",
|
|
74
80
|
"sos-sdk-core-ts": "0.5.2"
|
|
75
81
|
},
|