@adonis-agora/authkit-server 1.0.0-rc.6 → 1.0.0-rc.7

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 CHANGED
@@ -1,5 +1,11 @@
1
1
  # @adonis-agora/authkit-server
2
2
 
3
+ ## 1.0.0-rc.7
4
+
5
+ ### Minor Changes
6
+
7
+ - [#465](https://github.com/DavideCarvalho/adonis-agora-authkit/pull/465) [`6bd9575`](https://github.com/DavideCarvalho/adonis-agora-authkit/commit/6bd95759752c0fac14a061875abebb38c0e238b7) Thanks [@DavideCarvalho](https://github.com/DavideCarvalho)! - The active organization is published as the request's tenant in `@adonis-agora/context`: `Context.tenant()` returns `{ id, kind: 'organization', source: 'authkit', slug, role }` (and `tenantId` as before). New client option `tenancy`: `eager` resolves the session at request start (default on when `config/context.ts` enables tenancy and the resolver is `jwt`), `personal` makes the user the tenant when there is no active organization (off by default), and `resolve` maps the session to your own (optionally nested) tenants. A tenant the app sets itself with `Context.setTenant` is never overwritten. authkit-server ships `authkitTenantLabels()`, a label resolver for `config/context.ts` → `tenancy.label` that shows organization names in the consoles, and account stores gain the optional `findOrgsByIds` (implemented by the Lucid store).
8
+
3
9
  ## 1.0.0-rc.6
4
10
 
5
11
  ### Minor Changes
package/build/index.d.ts CHANGED
@@ -161,4 +161,5 @@ export { ensureAuthkitSchema, ensureAuthkitTables } from './src/schema/ensure.js
161
161
  export type { ServiceTenantInfo } from './src/service_tenants/client_metadata.js';
162
162
  export type { ResolvedServiceTenantResource, ResolvedServiceTenantsConfig, ServiceTenantResourceInput, ServiceTenantsConfigInput, } from './src/service_tenants/config.js';
163
163
  export { AuthkitTenantVerifier, type AuthkitTenantVerifierFn, type AuthkitTenantVerifierOptions, authkitTenantVerifier, type TenantTokenIssuer, type TenantVerifierInput, type VerifiedTenant, } from './src/service_tenants/tenant_verifier.js';
164
+ export { type AuthkitTenantLabelsOptions, authkitTenantLabels, type TenantLabelResolver, } from './src/tenancy/tenant_labels.js';
164
165
  export { stubsRoot } from './stubs/main.js';
package/build/index.js CHANGED
@@ -137,4 +137,5 @@ export { checkClientRegistration, classifyRedirect, RegistrationPolicyError, } f
137
137
  export { registerOidcRoutes } from './src/register_routes.js';
138
138
  export { ensureAuthkitSchema, ensureAuthkitTables } from './src/schema/ensure.js';
139
139
  export { AuthkitTenantVerifier, authkitTenantVerifier, } from './src/service_tenants/tenant_verifier.js';
140
+ export { authkitTenantLabels, } from './src/tenancy/tenant_labels.js';
140
141
  export { stubsRoot } from './stubs/main.js';
@@ -605,6 +605,12 @@ export interface OrganizationsCapability {
605
605
  }): Promise<OrgSummary>;
606
606
  findOrgById(orgId: string): Promise<OrgSummary | null>;
607
607
  findOrgBySlug(slug: string): Promise<OrgSummary | null>;
608
+ /**
609
+ * OPTIONAL: the orgs among `orgIds` that exist, in a bounded number of queries
610
+ * (any order; unknown ids are left out). Absent → callers fall back to
611
+ * `findOrgById` per id.
612
+ */
613
+ findOrgsByIds?(orgIds: readonly string[]): Promise<OrgSummary[]>;
608
614
  listOrgsForAccount(accountId: string): Promise<Array<OrgSummary & {
609
615
  role: string;
610
616
  }>>;
@@ -137,6 +137,12 @@ export function buildOrganizations(ctx) {
137
137
  const row = await OrgModel.find(orgId);
138
138
  return row ? toOrgSummary(row) : null;
139
139
  },
140
+ async findOrgsByIds(orgIds) {
141
+ const ids = [...new Set(orgIds)];
142
+ if (ids.length === 0)
143
+ return [];
144
+ return (await findManyChunked(OrgModel, ids)).map(toOrgSummary);
145
+ },
140
146
  async findOrgBySlug(slug) {
141
147
  const row = await OrgModel.query().where('slug', slug).first();
142
148
  return row ? toOrgSummary(row) : null;
@@ -0,0 +1,30 @@
1
+ import type { AccountStore, OrgSummary } from '../accounts/account_store.js';
2
+ /** What `config/context.ts` → `tenancy.label` expects: tenant id → display label. */
3
+ export type TenantLabelResolver = (ids: readonly string[]) => Promise<Record<string, string>>;
4
+ export interface AuthkitTenantLabelsOptions {
5
+ /** Which field labels an organization: `'name'` (default), `'slug'`, or your own function. */
6
+ label?: 'name' | 'slug' | ((org: OrgSummary) => string);
7
+ /**
8
+ * Where the account store comes from. Default: the `authkit.server` binding of the
9
+ * booted app (`config/authkit.ts` → `accountStore`).
10
+ */
11
+ store?: () => AccountStore | Promise<AccountStore>;
12
+ }
13
+ /**
14
+ * A tenant label resolver backed by authkit organizations, for
15
+ * `config/context.ts` → `tenancy.label`. Consoles call it with the tenant ids they
16
+ * are about to show; it returns `{ [orgId]: name }` for the ids that are authkit
17
+ * organizations. Ids it does not know (personal tenants, other kinds) are left
18
+ * out, so the console shows the id. It only reads labels: no membership, role or
19
+ * metadata leaves it.
20
+ *
21
+ * ```ts
22
+ * // config/context.ts
23
+ * import { authkitTenantLabels } from '@adonis-agora/authkit-server'
24
+ *
25
+ * export default defineConfig({
26
+ * tenancy: { enabled: true, kinds: ['organization'], label: authkitTenantLabels() },
27
+ * })
28
+ * ```
29
+ */
30
+ export declare function authkitTenantLabels(options?: AuthkitTenantLabelsOptions): TenantLabelResolver;
@@ -0,0 +1,64 @@
1
+ import { getBootedApp } from '../../services/booted_app.js';
2
+ import { supportsOrganizations } from '../accounts/account_store.js';
3
+ /** Fallback walk without `findOrgsByIds`: one lookup per id, at most this many ids. */
4
+ const FALLBACK_MAX = 200;
5
+ const defaultStore = async () => {
6
+ const service = (await getBootedApp().container.make('authkit.server'));
7
+ return service.config.accountStore;
8
+ };
9
+ /**
10
+ * A tenant label resolver backed by authkit organizations, for
11
+ * `config/context.ts` → `tenancy.label`. Consoles call it with the tenant ids they
12
+ * are about to show; it returns `{ [orgId]: name }` for the ids that are authkit
13
+ * organizations. Ids it does not know (personal tenants, other kinds) are left
14
+ * out, so the console shows the id. It only reads labels: no membership, role or
15
+ * metadata leaves it.
16
+ *
17
+ * ```ts
18
+ * // config/context.ts
19
+ * import { authkitTenantLabels } from '@adonis-agora/authkit-server'
20
+ *
21
+ * export default defineConfig({
22
+ * tenancy: { enabled: true, kinds: ['organization'], label: authkitTenantLabels() },
23
+ * })
24
+ * ```
25
+ */
26
+ export function authkitTenantLabels(options = {}) {
27
+ const pick = typeof options.label === 'function'
28
+ ? options.label
29
+ : options.label === 'slug'
30
+ ? (org) => org.slug
31
+ : (org) => org.name;
32
+ return async (ids) => {
33
+ const wanted = [
34
+ ...new Set((Array.isArray(ids) ? ids : []).filter((id) => typeof id === 'string' && id)),
35
+ ];
36
+ if (wanted.length === 0)
37
+ return {};
38
+ const store = await (options.store ?? defaultStore)();
39
+ if (!store || !supportsOrganizations(store))
40
+ return {};
41
+ let orgs;
42
+ if (typeof store.findOrgsByIds === 'function') {
43
+ orgs = await store.findOrgsByIds(wanted);
44
+ }
45
+ else {
46
+ orgs = [];
47
+ for (const id of wanted.slice(0, FALLBACK_MAX)) {
48
+ const org = await store.findOrgById(id);
49
+ if (org)
50
+ orgs.push(org);
51
+ }
52
+ }
53
+ const asked = new Set(wanted);
54
+ const labels = {};
55
+ for (const org of orgs) {
56
+ if (!asked.has(org.id))
57
+ continue;
58
+ const label = pick(org);
59
+ if (typeof label === 'string' && label !== '')
60
+ labels[org.id] = label;
61
+ }
62
+ return labels;
63
+ };
64
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adonis-agora/authkit-server",
3
- "version": "1.0.0-rc.6",
3
+ "version": "1.0.0-rc.7",
4
4
  "description": "AdonisJS OIDC/OAuth2 provider (Identity Provider) toolkit: ejectable auth server with sessions, rate-limiting, MFA/TOTP, audit log, federated logout and OpenTelemetry metrics.",
5
5
  "license": "MIT",
6
6
  "author": "dudousxd",