@authyon/server 0.2.0-beta.12 → 0.2.0-beta.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/dist/index.js CHANGED
@@ -7,7 +7,7 @@ import {
7
7
  JsonHttpClient,
8
8
  LoggingHttpAdapter,
9
9
  createSharedTransport
10
- } from "./chunk-56H66KLG.js";
10
+ } from "./chunk-TWUVXZOT.js";
11
11
  import {
12
12
  AuthorizationError,
13
13
  AuthyonAbility,
@@ -102,9 +102,9 @@ function credentialDetail(value) {
102
102
  accessTokenLifetimeSeconds: value.accessTokenLifetimeSeconds
103
103
  };
104
104
  }
105
- async function credentialPage(request, path, options = {}) {
105
+ async function credentialPage(request, path2, options = {}) {
106
106
  const query = credentialQuery(options);
107
- const page = await request(path, { query });
107
+ const page = await request(path2, { query });
108
108
  if (!page || !Array.isArray(page.data))
109
109
  throw new TypeError("Authyon: expected a paginated credential response.");
110
110
  return {
@@ -117,13 +117,13 @@ async function credentialPage(request, path, options = {}) {
117
117
  hasPrev: page.hasPrev
118
118
  };
119
119
  }
120
- async function allCredentials(request, path) {
120
+ async function allCredentials(request, path2) {
121
121
  const result = [];
122
122
  const seen = /* @__PURE__ */ new Set();
123
123
  let skip = 0;
124
124
  for (let iteration = 0; iteration < 1e3; iteration++) {
125
125
  const page = await request(
126
- path,
126
+ path2,
127
127
  iteration === 0 ? {} : { query: { skip, take: 100 } }
128
128
  );
129
129
  if (Array.isArray(page)) {
@@ -146,134 +146,67 @@ async function allCredentials(request, path) {
146
146
  throw new Error("Authyon: use listPage for more than 1000 credential pages.");
147
147
  }
148
148
 
149
+ // ../../internal/core/financial/subjectFinancialAuthorizations.ts
150
+ function path(id, suffix = "") {
151
+ if (typeof id !== "string" || !id.trim())
152
+ throw new TypeError("Authyon: a financial authorization id is required.");
153
+ return `/auth/authorizations/${encodeURIComponent(id)}${suffix}`;
154
+ }
155
+ function subjectFinancialAuthorizations(request) {
156
+ return {
157
+ /** GET /auth/authorizations/{id} — the pending transaction, to show before asking for the code. */
158
+ get: (id) => request(path(id)),
159
+ /** POST /auth/authorizations/{id}/webauthn/options — passkey options for approving this authorization. */
160
+ webauthnOptions: (id) => request(path(id, "/webauthn/options"), { method: "POST" }),
161
+ /**
162
+ * POST /auth/authorizations/{id}/confirm — approves the transaction.
163
+ *
164
+ * Pass the authenticator code or passkey assertion to verify the second
165
+ * factor inline (recommended). Without `input`, the session itself must
166
+ * have used a passkey or authenticator code within the last 5 minutes,
167
+ * otherwise the API answers `step_up_required`.
168
+ */
169
+ confirm: (id, input) => request(path(id, "/confirm"), { method: "POST", body: input }),
170
+ /** POST /auth/authorizations/{id}/reject — the customer declines the transaction. */
171
+ reject: (id) => request(path(id, "/reject"), { method: "POST" })
172
+ };
173
+ }
174
+
149
175
  // src/client/scopedManagementClient.ts
150
176
  function scopedRequest(request, source) {
151
- return async (path, options = {}) => {
177
+ return async (path2, options = {}) => {
152
178
  const token = typeof source === "function" ? await source() : source;
153
179
  if (typeof token !== "string" || !token.trim() || /\s/u.test(token))
154
180
  throw new TypeError("Authyon: a valid access token is required.");
155
- return request(path, {
181
+ return request(path2, {
156
182
  ...options,
157
183
  headers: { ...options.headers, Authorization: `Bearer ${token}` }
158
184
  });
159
185
  };
160
186
  }
161
- function environmentPath(scope) {
162
- return `/platform/workspaces/${segment(scope.workspaceId)}/environments/${segment(scope.environmentId)}`;
163
- }
164
- function tenantPath(scope) {
165
- return `${environmentPath(scope)}/tenants/${segment(scope.tenantId)}`;
166
- }
167
- function credentialPath(scope) {
168
- return `${scope.tenantId === void 0 ? environmentPath(scope) : tenantPath(scope)}/credentials`;
169
- }
170
- function workspacePath(id) {
171
- return `/platform/workspaces/${segment(id)}`;
172
- }
173
- function workspaceRole(role) {
174
- if (role !== "admin" && role !== "auditor")
175
- throw new TypeError("Authyon: workspace role must be admin or auditor.");
176
- return role;
177
- }
178
187
  var _request;
179
- var PlatformScopedClient = class {
180
- /** @hidden */
181
- constructor(request, token) {
182
- __privateAdd(this, _request);
183
- this.credentials = {
184
- list: (scope, options = {}) => credentialPage(__privateGet(this, _request), credentialPath(scope), options),
185
- get: async (scope, credentialId) => credentialDetail(await __privateGet(this, _request).call(this, `${credentialPath(scope)}/${segment(credentialId)}`)),
186
- create: (scope, input) => __privateGet(this, _request).call(this, credentialPath(scope), {
187
- method: "POST",
188
- body: { description: input.description, ...lifetimeBody(input), ...permissionsBody(input) }
189
- }),
190
- updatePermissions: (scope, credentialId, input) => __privateGet(this, _request).call(this, `${credentialPath(scope)}/${segment(credentialId)}/permissions`, {
191
- method: "PUT",
192
- body: permissionsBody(input)
193
- }),
194
- updateScopes: (scope, credentialId, scopes) => this.credentials.updatePermissions(scope, credentialId, { scopes }),
195
- /** Returns a new secret once. API may require an explicit step-up first. */
196
- rotate: (scope, credentialId) => __privateGet(this, _request).call(this, `${credentialPath(scope)}/${segment(credentialId)}/rotate`, { method: "POST" }),
197
- revoke: (scope, credentialId) => __privateGet(this, _request).call(this, `${credentialPath(scope)}/${segment(credentialId)}`, { method: "DELETE" })
198
- };
199
- this.workspaces = {
200
- team: (workspaceId) => __privateGet(this, _request).call(this, `${workspacePath(workspaceId)}/team`),
201
- members: {
202
- invite: (workspaceId, input) => __privateGet(this, _request).call(this, `${workspacePath(workspaceId)}/invites`, {
203
- method: "POST",
204
- body: { email: input.email, role: workspaceRole(input.role) }
205
- }),
206
- /** memberId comes from team.members; it is not the platform userId. */
207
- remove: (workspaceId, memberId) => __privateGet(this, _request).call(this, `${workspacePath(workspaceId)}/members/${segment(memberId)}`, {
208
- method: "DELETE"
209
- }),
210
- changeRole: (workspaceId, memberId, role) => __privateGet(this, _request).call(this, `${workspacePath(workspaceId)}/members/${segment(memberId)}`, {
211
- method: "PATCH",
212
- body: { role: workspaceRole(role) }
213
- })
214
- },
215
- invites: {
216
- create: (workspaceId, input) => this.workspaces.members.invite(workspaceId, input),
217
- revoke: (workspaceId, inviteId) => __privateGet(this, _request).call(this, `${workspacePath(workspaceId)}/invites/${segment(inviteId)}`, {
218
- method: "DELETE"
219
- })
220
- }
221
- };
222
- this.tenants = {
223
- members: {
224
- list: (scope, options = {}) => __privateGet(this, _request).call(this, `${tenantPath(scope)}/members`, { query: options }),
225
- add: (scope, userId, roles) => __privateGet(this, _request).call(this, `${tenantPath(scope)}/members`, { method: "POST", body: { userId, roles } }),
226
- remove: (scope, userId) => __privateGet(this, _request).call(this, `${tenantPath(scope)}/members/${segment(userId)}`, { method: "DELETE" })
227
- }
228
- };
229
- this.auth = {
230
- /** Explicitly confirms the current platform session; passwords are not retained. */
231
- stepUp: (currentPassword) => __privateGet(this, _request).call(this, "/platform/auth/step-up", { method: "POST", body: { currentPassword } })
232
- };
233
- __privateSet(this, _request, scopedRequest(request, token));
234
- }
235
- };
236
- _request = new WeakMap();
237
- var _request2;
238
188
  var UserScopedClient = class {
239
189
  /** @hidden */
240
190
  constructor(request, token) {
241
- __privateAdd(this, _request2);
191
+ __privateAdd(this, _request);
242
192
  this.tenants = {
243
193
  members: {
244
- list: (tenantId, options = {}) => __privateGet(this, _request2).call(this, `/auth/tenants/${segment(tenantId)}/members`, { query: options }),
194
+ list: (tenantId, options = {}) => __privateGet(this, _request).call(this, `/auth/tenants/${segment(tenantId)}/members`, { query: options }),
245
195
  /** Adds an existing environment user by email; does not send an invitation email. */
246
- invite: (tenantId, input) => __privateGet(this, _request2).call(this, `/auth/tenants/${segment(tenantId)}/members`, {
196
+ invite: (tenantId, input) => __privateGet(this, _request).call(this, `/auth/tenants/${segment(tenantId)}/members`, {
247
197
  method: "POST",
248
198
  body: { email: input.email, roles: input.roles }
249
199
  }),
250
- remove: (tenantId, userId) => __privateGet(this, _request2).call(this, `/auth/tenants/${segment(tenantId)}/members/${segment(userId)}`, {
200
+ remove: (tenantId, userId) => __privateGet(this, _request).call(this, `/auth/tenants/${segment(tenantId)}/members/${segment(userId)}`, {
251
201
  method: "DELETE"
252
202
  })
253
203
  }
254
204
  };
255
- __privateSet(this, _request2, scopedRequest(request, token));
256
- }
257
- };
258
- _request2 = new WeakMap();
259
- var _request3;
260
- var WorkspaceInvitesClient = class {
261
- /** @hidden */
262
- constructor(request) {
263
- __privateAdd(this, _request3);
264
- __privateSet(this, _request3, request);
265
- }
266
- preview(token) {
267
- return __privateGet(this, _request3).call(this, `/platform/workspace-invites/${segment(token)}`);
268
- }
269
- accept(token, input = {}) {
270
- return __privateGet(this, _request3).call(this, `/platform/workspace-invites/${segment(token)}/accept`, {
271
- method: "POST",
272
- body: { name: input.name, password: input.password }
273
- });
205
+ __privateSet(this, _request, scopedRequest(request, token));
206
+ this.financialAuthorizations = subjectFinancialAuthorizations(__privateGet(this, _request));
274
207
  }
275
208
  };
276
- _request3 = new WeakMap();
209
+ _request = new WeakMap();
277
210
 
278
211
  // ../../internal/core/auth/expiringTokenProvider.ts
279
212
  var _token, _inFlight;
@@ -352,9 +285,6 @@ var AuthyonServerClient = class {
352
285
  }
353
286
  })
354
287
  };
355
- this.workspaceInvites = new WorkspaceInvitesClient(
356
- (path, options) => this.http.request(path, options)
357
- );
358
288
  // ── Environment management (users, tenants, roles, permissions, audit) ───
359
289
  this.environment = {
360
290
  users: {
@@ -449,12 +379,12 @@ var AuthyonServerClient = class {
449
379
  credentials: {
450
380
  /** GET /env/tenants/{tenantId}/credentials. Returns metadata only, including revoked credentials. */
451
381
  list: (tenantId) => allCredentials(
452
- (path, options) => this.request(path, { ...options, envBearer: true }),
382
+ (path2, options) => this.request(path2, { ...options, envBearer: true }),
453
383
  `/env/tenants/${segment(tenantId)}/credentials`
454
384
  ),
455
385
  /** Paginated searchable listing. Prefer this over loading every credential. */
456
386
  listPage: (tenantId, options = {}) => credentialPage(
457
- (path, requestOptions) => this.request(path, { ...requestOptions, envBearer: true }),
387
+ (path2, requestOptions) => this.request(path2, { ...requestOptions, envBearer: true }),
458
388
  `/env/tenants/${segment(tenantId)}/credentials`,
459
389
  options
460
390
  ),
@@ -625,6 +555,41 @@ var AuthyonServerClient = class {
625
555
  /** GET /permissions/reserved — reserved permission names you can't redefine. */
626
556
  reserved: () => this.request("/permissions/reserved", { envBearer: true })
627
557
  },
558
+ /**
559
+ * Transaction-bound step-up for financial operations. The environment
560
+ * credential needs the `authyon:financial:authorize` scope.
561
+ *
562
+ * 1. `create()` the authorization for the transaction and the customer.
563
+ * 2. The customer approves it with their authenticator code or passkey
564
+ * (`@authyon/auth` → `financialAuthorizations.confirm`).
565
+ * 3. `consume()` it with the same transaction right before executing it.
566
+ */
567
+ financialAuthorizations: {
568
+ /** POST /env/authorizations — registers a transaction awaiting the customer's approval. */
569
+ create: (input) => {
570
+ const { idempotencyKey, ...body } = input;
571
+ if (typeof idempotencyKey !== "string" || !idempotencyKey.trim())
572
+ throw new TypeError("Authyon: `idempotencyKey` is required.");
573
+ return this.request("/env/authorizations", {
574
+ method: "POST",
575
+ envBearer: true,
576
+ headers: { "Idempotency-Key": idempotencyKey },
577
+ body
578
+ });
579
+ },
580
+ /** GET /env/authorizations/{id} — current status and, once approved, the assurance evidence. */
581
+ get: (id) => this.request(`/env/authorizations/${segment(id)}`, { envBearer: true }),
582
+ /**
583
+ * POST /env/authorizations/{id}/consume — redeems an approved
584
+ * authorization exactly once. Resend the same transaction given to
585
+ * `create()`; any difference fails with `transaction_mismatch`.
586
+ */
587
+ consume: (id, transaction) => this.request(`/env/authorizations/${segment(id)}/consume`, {
588
+ method: "POST",
589
+ envBearer: true,
590
+ body: transaction
591
+ })
592
+ },
628
593
  audit: {
629
594
  /** GET /env/audit — paginated list of the environment's audit events. */
630
595
  list: (params = {}) => this.request("/env/audit", { envBearer: true, query: params }),
@@ -675,7 +640,7 @@ var AuthyonServerClient = class {
675
640
  };
676
641
  });
677
642
  }
678
- async request(path, options = {}) {
643
+ async request(path2, options = {}) {
679
644
  const headers = {
680
645
  ...clientIpHeaders({ clientIp: this.clientIp }),
681
646
  ...options.headers
@@ -684,7 +649,7 @@ var AuthyonServerClient = class {
684
649
  headers.Authorization = `Bearer ${await this.getEnvironmentAccessToken()}`;
685
650
  }
686
651
  if (this.envKey) headers["X-Authyon-Environment"] = this.envKey;
687
- return this.http.request(path, { ...options, headers });
652
+ return this.http.request(path2, { ...options, headers });
688
653
  }
689
654
  /** Mints (and caches) an environment access token from `clientId`/`clientSecret`. */
690
655
  async getEnvironmentAccessToken() {
@@ -739,17 +704,13 @@ var AuthyonServerClient = class {
739
704
  tenant(credentials) {
740
705
  return new TenantScopedClient(this, credentials);
741
706
  }
742
- /** Uses only the supplied platform-user access token. */
743
- platform(token) {
744
- return new PlatformScopedClient((path, options) => this.http.request(path, options), token);
745
- }
746
707
  /** Uses an end-user token; the configured environment key selects the environment. */
747
708
  user(token) {
748
- return new UserScopedClient((path, options) => this.request(path, options), token);
709
+ return new UserScopedClient((path2, options) => this.request(path2, options), token);
749
710
  }
750
711
  /** @internal used by {@link TenantScopedClient} to share the base URL/fetch/error handling. */
751
- _requestAsTenant(accessToken, path, options = {}) {
752
- return this.request(path, {
712
+ _requestAsTenant(accessToken, path2, options = {}) {
713
+ return this.request(path2, {
753
714
  ...options,
754
715
  headers: { ...options.headers, Authorization: `Bearer ${accessToken}` },
755
716
  envBearer: false
@@ -826,8 +787,8 @@ var TenantScopedClient = class {
826
787
  async getAccessToken() {
827
788
  return this.tokenProvider.getAccessToken();
828
789
  }
829
- async request(path, options = {}) {
830
- return this.server._requestAsTenant(await this.getAccessToken(), path, options);
790
+ async request(path2, options = {}) {
791
+ return this.server._requestAsTenant(await this.getAccessToken(), path2, options);
831
792
  }
832
793
  /** POST /tenant/auth/validate — validates this tenant client's current bearer token. */
833
794
  async validate(context) {
@@ -890,11 +851,9 @@ export {
890
851
  FetchHttpAdapter,
891
852
  JwksTokenVerifier,
892
853
  LoggingHttpAdapter,
893
- PlatformScopedClient,
894
854
  TenantScopedClient,
895
855
  TokenVerificationError,
896
856
  UserScopedClient,
897
- WorkspaceInvitesClient,
898
857
  authorizeRequest,
899
858
  authorizeToken,
900
859
  createAuthorizationErrorResponse,
package/dist/next.d.cts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { ReactNode } from 'react';
2
- import { R as RequestAuthorizationOptions, A as AbilitySubject, a as AuthorizationError } from './authorization-DWlLfYQJ.cjs';
3
- import { A as AuthyonServerClient } from './authyonServerClient-t82mwTws.cjs';
2
+ import { R as RequestAuthorizationOptions, A as AbilitySubject, a as AuthorizationError } from './authorization-B7ynKAud.cjs';
3
+ import { A as AuthyonServerClient } from './authyonServerClient-DmNnjw4z.cjs';
4
4
  import 'jose';
5
5
 
6
6
  interface ServerPermissionGuardFallbackContext {
package/dist/next.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { ReactNode } from 'react';
2
- import { R as RequestAuthorizationOptions, A as AbilitySubject, a as AuthorizationError } from './authorization-wrZ5ull7.js';
3
- import { A as AuthyonServerClient } from './authyonServerClient-t82mwTws.js';
2
+ import { R as RequestAuthorizationOptions, A as AbilitySubject, a as AuthorizationError } from './authorization-BF015NDJ.js';
3
+ import { A as AuthyonServerClient } from './authyonServerClient-DmNnjw4z.js';
4
4
  import 'jose';
5
5
 
6
6
  interface ServerPermissionGuardFallbackContext {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@authyon/server",
3
- "version": "0.2.0-beta.12",
3
+ "version": "0.2.0-beta.14",
4
4
  "description": "Authyon SDK for backends — server-to-server organization/member management and access-token verification.",
5
5
  "license": "MIT",
6
6
  "type": "module",