@ai-matrx/auth 0.1.4 → 0.2.1
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 +37 -0
- package/README.md +11 -0
- package/dist/claims-DXdbe3cW.d.cts +138 -0
- package/dist/claims-DXdbe3cW.d.ts +138 -0
- package/dist/index.cjs +135 -1
- package/dist/index.d.cts +4 -51
- package/dist/index.d.ts +4 -51
- package/dist/index.js +138 -1
- package/dist/matrx-oauth.cjs +458 -0
- package/dist/matrx-oauth.d.cts +181 -0
- package/dist/matrx-oauth.d.ts +181 -0
- package/dist/matrx-oauth.js +437 -0
- package/dist/next.cjs +133 -1
- package/dist/next.d.cts +77 -1
- package/dist/next.d.ts +77 -1
- package/dist/next.js +136 -1
- package/dist/node.cjs +139 -2
- package/dist/node.d.cts +117 -1
- package/dist/node.d.ts +117 -1
- package/dist/node.js +136 -1
- package/dist/organizations.cjs +358 -10
- package/dist/organizations.d.cts +359 -3
- package/dist/organizations.d.ts +359 -3
- package/dist/organizations.js +358 -10
- package/dist/react.d.cts +1 -1
- package/dist/react.d.ts +1 -1
- package/dist/storage-Dqnye4KF.d.cts +51 -0
- package/dist/storage-Dqnye4KF.d.ts +51 -0
- package/package.json +12 -2
package/dist/organizations.d.ts
CHANGED
|
@@ -143,6 +143,230 @@ declare function setOrganizationFavourite(db: OrganizationsDb, organizationId: s
|
|
|
143
143
|
type OrganizationRefusal = "lapsed" | "retry" | null;
|
|
144
144
|
declare function classifyOrganizationRefusal(status: number, body: unknown): OrganizationRefusal;
|
|
145
145
|
|
|
146
|
+
/**
|
|
147
|
+
* Organization-question plumbing that is LOGIC, not store binding (moved from the website's
|
|
148
|
+
* `orgBootstrapGate`, `organizationRefusal`, `childOrganization`, `adminOrganization`).
|
|
149
|
+
* Pure: every host input is injected; no Redux, no Next, no window.
|
|
150
|
+
*/
|
|
151
|
+
/** How long a write may wait for the first answer before it is refused anyway. */
|
|
152
|
+
declare const ORGANIZATION_RESOLUTION_TIMEOUT_MS = 10000;
|
|
153
|
+
interface OrganizationBootstrapGate {
|
|
154
|
+
isResolved(): boolean;
|
|
155
|
+
/** The organization question has been answered (with an organization or without). Idempotent. */
|
|
156
|
+
markResolved(): void;
|
|
157
|
+
/** Wait for the answer or the timeout, whichever first. Always resolves; never rejects. */
|
|
158
|
+
whenResolved(timeoutMs?: number): Promise<void>;
|
|
159
|
+
/** Tests and in-place identity swaps only. */
|
|
160
|
+
reset(): void;
|
|
161
|
+
}
|
|
162
|
+
/** "Nobody has looked yet" is a race, not a fact: a held write waits on this, bounded. */
|
|
163
|
+
declare function createOrganizationBootstrapGate(defaultTimeoutMs?: number): OrganizationBootstrapGate;
|
|
164
|
+
/** True when an error body is the server's "you are not a member of the organization you carried". */
|
|
165
|
+
declare function isNotAMemberRefusal(body: unknown): boolean;
|
|
166
|
+
declare const NOT_A_MEMBER_RECHECK_GAP_MS = 30000;
|
|
167
|
+
interface NotAMemberRefusalNotice {
|
|
168
|
+
/** True when a recheck was started (at most one per gap, so a burst reads memberships once). */
|
|
169
|
+
notice(body: unknown, now?: number): boolean;
|
|
170
|
+
reset(): void;
|
|
171
|
+
}
|
|
172
|
+
declare function createNotAMemberRefusalNotice(recheck: () => void, gapMs?: number): NotAMemberRefusalNotice;
|
|
173
|
+
type ParentOrganization = string | {
|
|
174
|
+
organization_id?: string | null;
|
|
175
|
+
} | null | undefined;
|
|
176
|
+
/**
|
|
177
|
+
* A record created as part of an existing parent lives in the PARENT's organization; the explicit
|
|
178
|
+
* one applies only when the parent names none. A disagreement is announced (`onDisagree`,
|
|
179
|
+
* default console.warn), never obeyed.
|
|
180
|
+
*/
|
|
181
|
+
declare function resolveChildOrganizationId(parent: ParentOrganization, explicit?: string | null, label?: string, onDisagree?: (message: string) => void): string | null;
|
|
182
|
+
/** What the host knows about the admin lane. */
|
|
183
|
+
interface AdminSeatInput {
|
|
184
|
+
readonly laneOpen: boolean;
|
|
185
|
+
readonly organizationId?: string | null;
|
|
186
|
+
readonly organizationName?: string | null;
|
|
187
|
+
}
|
|
188
|
+
interface AdminSeat {
|
|
189
|
+
readonly id: string;
|
|
190
|
+
readonly name: string | null;
|
|
191
|
+
}
|
|
192
|
+
/** The admin organization in force right now, or null (off the lane, or none set). */
|
|
193
|
+
declare function resolveAdminSeat(input: AdminSeatInput | null | undefined): AdminSeat | null;
|
|
194
|
+
/** True when the admin seat differs from the person's own active organization (scope/project/task never ride across). */
|
|
195
|
+
declare function adminSeatReplacesUserContext(input: AdminSeatInput | null | undefined, personOrganizationId: string | null | undefined): boolean;
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* The query key, platform-wide. The server stamps this on every deep link it
|
|
199
|
+
* emits; `features/admin/users/components/OrganizationsAdminClient.tsx` has
|
|
200
|
+
* read it since before this module existed. One spelling, in one place.
|
|
201
|
+
*/
|
|
202
|
+
declare const LINK_ORGANIZATION_QUERY_KEY = "org";
|
|
203
|
+
type LinkOrganizationParam =
|
|
204
|
+
/** No link said anything about an organization. The ladder is untouched. */
|
|
205
|
+
{
|
|
206
|
+
kind: "absent";
|
|
207
|
+
}
|
|
208
|
+
/** Something was said and it is neither a uuid nor an address. Refused in words, never used. */
|
|
209
|
+
| {
|
|
210
|
+
kind: "malformed";
|
|
211
|
+
raw: string;
|
|
212
|
+
}
|
|
213
|
+
/** A well-formed organization id. Still has to survive the membership check. */
|
|
214
|
+
| {
|
|
215
|
+
kind: "named";
|
|
216
|
+
organizationId: string;
|
|
217
|
+
}
|
|
218
|
+
/** An organization's address (slug). Survives only by matching a membership's slug. */
|
|
219
|
+
| {
|
|
220
|
+
kind: "addressed";
|
|
221
|
+
slug: string;
|
|
222
|
+
};
|
|
223
|
+
/**
|
|
224
|
+
* Classify one bare `org=` value. The ONE rule for what a value may be, shared
|
|
225
|
+
* by the URL reader below and the boot resolver's bare-value path.
|
|
226
|
+
*/
|
|
227
|
+
declare function classifyLinkOrganizationValue(raw: string): LinkOrganizationParam;
|
|
228
|
+
/**
|
|
229
|
+
* Read the key out of a query string, a `URLSearchParams`, or a full URL.
|
|
230
|
+
* Never throws: a URL this cannot parse is `absent`, because a crash on
|
|
231
|
+
* arrival is a worse answer than the ladder's own.
|
|
232
|
+
*/
|
|
233
|
+
declare function readLinkOrganizationParam(source: string | URLSearchParams | null | undefined): LinkOrganizationParam;
|
|
234
|
+
interface LinkOrganizationMembership {
|
|
235
|
+
id: string;
|
|
236
|
+
name: string;
|
|
237
|
+
/** The organization's address, so an `addressed` link can be matched. */
|
|
238
|
+
slug?: string | null;
|
|
239
|
+
}
|
|
240
|
+
interface LinkOrganizationDecisionInput {
|
|
241
|
+
param: LinkOrganizationParam;
|
|
242
|
+
/** The person's LIVE memberships. The only authority on what they may open. */
|
|
243
|
+
memberships: ReadonlyArray<LinkOrganizationMembership>;
|
|
244
|
+
/** The organization they are working in right now, or null. */
|
|
245
|
+
currentOrganizationId: string | null;
|
|
246
|
+
currentOrganizationName?: string | null;
|
|
247
|
+
/**
|
|
248
|
+
* The knob `userPreferences.organization.switchOnLinkPrompt` — "switch
|
|
249
|
+
* organization when a link asks". DEFAULT ON, so an omitted value is `true`.
|
|
250
|
+
*/
|
|
251
|
+
switchWhenALinkAsks?: boolean;
|
|
252
|
+
/** The account they are signed in as, for the refusal sentence. */
|
|
253
|
+
signedInAs?: string | null;
|
|
254
|
+
/**
|
|
255
|
+
* The link's organization is one this person is not a member of but IS let into
|
|
256
|
+
* by a share they accepted (`lib/organizations/linkOrganizationAdmission.ts`).
|
|
257
|
+
* A share admits and never makes a member, so the answer is `admitted`: nobody
|
|
258
|
+
* is moved, nothing is refused, and the page opens it as that organization's
|
|
259
|
+
* guest. Omitted, the answer is exactly what it was before (VERIFIER-15 H4).
|
|
260
|
+
*/
|
|
261
|
+
admittedByAShare?: boolean;
|
|
262
|
+
/** Replace any of the default English sentences (a localising host). */
|
|
263
|
+
messages?: Partial<LinkOrganizationMessages>;
|
|
264
|
+
}
|
|
265
|
+
interface LinkOrganizationMessages {
|
|
266
|
+
notAMember(signedInAs?: string | null): string;
|
|
267
|
+
malformed(raw: string): string;
|
|
268
|
+
switched(toName: string, fromName: string | null): string;
|
|
269
|
+
offer(toName: string, fromName: string | null): string;
|
|
270
|
+
offerAction(toName: string): string;
|
|
271
|
+
}
|
|
272
|
+
type LinkOrganizationDecision =
|
|
273
|
+
/** Nothing to do. No toast, no change. */
|
|
274
|
+
{
|
|
275
|
+
kind: "no-link";
|
|
276
|
+
}
|
|
277
|
+
/** The link names the organization they are already in. Silent no-op. */
|
|
278
|
+
| {
|
|
279
|
+
kind: "already-current";
|
|
280
|
+
organizationId: string;
|
|
281
|
+
}
|
|
282
|
+
/** Use this organization for this session. `announcement` non-null = they moved. */
|
|
283
|
+
| {
|
|
284
|
+
kind: "honoured";
|
|
285
|
+
organizationId: string;
|
|
286
|
+
organizationName: string;
|
|
287
|
+
announcement: string | null;
|
|
288
|
+
}
|
|
289
|
+
/** The knob is off and this would be a real switch. Offer it as a click. */
|
|
290
|
+
| {
|
|
291
|
+
kind: "offered";
|
|
292
|
+
organizationId: string;
|
|
293
|
+
organizationName: string;
|
|
294
|
+
message: string;
|
|
295
|
+
actionLabel: string;
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* Not a member, but let in by a share they accepted. Silent: nobody is moved
|
|
299
|
+
* (a share never makes a member) and nothing was refused (the page opens it).
|
|
300
|
+
*/
|
|
301
|
+
| {
|
|
302
|
+
kind: "admitted";
|
|
303
|
+
organizationId: string;
|
|
304
|
+
}
|
|
305
|
+
/** Malformed, or not theirs. Changes nothing; says so. */
|
|
306
|
+
| {
|
|
307
|
+
kind: "refused";
|
|
308
|
+
reason: "malformed" | "not-a-member";
|
|
309
|
+
message: string;
|
|
310
|
+
};
|
|
311
|
+
/** What a person reads when the link's organization is not theirs to open. */
|
|
312
|
+
declare function linkOrganizationNotAMemberMessage(signedInAs?: string | null): string;
|
|
313
|
+
/** What a person reads when `org=` is not an organization id at all. */
|
|
314
|
+
declare function linkOrganizationMalformedMessage(raw: string): string;
|
|
315
|
+
/** What a person reads when a link actually moved them. Law 4: never silent. */
|
|
316
|
+
declare function linkOrganizationSwitchAnnouncement(toName: string, fromName: string | null): string;
|
|
317
|
+
/** What a person reads with the knob turned off and a link asking to move them. */
|
|
318
|
+
declare function linkOrganizationOfferMessage(toName: string, fromName: string | null): string;
|
|
319
|
+
/**
|
|
320
|
+
* The decision. One function, every branch, no side effects.
|
|
321
|
+
*
|
|
322
|
+
* 🚨 WHY THE KNOB GOVERNS ONLY A REAL SWITCH. The knob protects the
|
|
323
|
+
* organization a person is WORKING IN from being yanked out from under them by
|
|
324
|
+
* a link someone else composed. With `currentOrganizationId === null` there is
|
|
325
|
+
* nothing to protect and nothing to switch away from: the alternative to
|
|
326
|
+
* honouring the link is the picker, which is the very dead end this module was
|
|
327
|
+
* built to end. So the knob turns a SWITCH into an offer; it never turns an
|
|
328
|
+
* arrival into a refusal. This is deliberate and it is not a hidden default —
|
|
329
|
+
* with no link present, a null selection stays null exactly as before.
|
|
330
|
+
*/
|
|
331
|
+
declare function decideLinkOrganization(input: LinkOrganizationDecisionInput): LinkOrganizationDecision;
|
|
332
|
+
interface ResolveWithLinkInput<T extends {
|
|
333
|
+
id: string;
|
|
334
|
+
name: string;
|
|
335
|
+
slug?: string | null;
|
|
336
|
+
joinedAt?: string;
|
|
337
|
+
}> {
|
|
338
|
+
readonly memberships: readonly T[];
|
|
339
|
+
/** This tab's held organization (rung 1; a refresh keeps it). */
|
|
340
|
+
readonly held?: string | null;
|
|
341
|
+
readonly readAccount: () => Promise<AccountOrganizationChoices>;
|
|
342
|
+
readonly first?: () => Promise<T | null>;
|
|
343
|
+
/** The raw `?org=` value, a query string, a URL or URLSearchParams. Omitted = no link. */
|
|
344
|
+
readonly link?: string | URLSearchParams | null;
|
|
345
|
+
readonly switchWhenALinkAsks?: boolean | undefined;
|
|
346
|
+
readonly signedInAs?: string | null | undefined;
|
|
347
|
+
readonly messages?: Partial<LinkOrganizationMessages> | undefined;
|
|
348
|
+
/** Asked only when the link already failed the membership check (a share admits, never joins). */
|
|
349
|
+
readonly admittedByAShare?: ((organizationId: string) => Promise<boolean>) | undefined;
|
|
350
|
+
}
|
|
351
|
+
interface ResolvedWithLink<T> {
|
|
352
|
+
readonly organization: T;
|
|
353
|
+
readonly rung: OrganizationRung | "link";
|
|
354
|
+
/** What the link meant, when it said anything — the host SAYS it (refused / announced / offered). */
|
|
355
|
+
readonly link: LinkOrganizationDecision;
|
|
356
|
+
}
|
|
357
|
+
/**
|
|
358
|
+
* The ONE load ladder with the link folded in: held → last active → start-up → first, then the
|
|
359
|
+
* link's own organization wins ONLY when it is a current membership. Every other link outcome
|
|
360
|
+
* (refused, offered, already-current, admitted) leaves the ladder's answer standing. Null when
|
|
361
|
+
* the person has no memberships. A failed read throws through.
|
|
362
|
+
*/
|
|
363
|
+
declare function resolveOrganizationWithLink<T extends {
|
|
364
|
+
id: string;
|
|
365
|
+
name: string;
|
|
366
|
+
slug?: string | null;
|
|
367
|
+
joinedAt?: string;
|
|
368
|
+
}>(input: ResolveWithLinkInput<T>): Promise<ResolvedWithLink<T> | null>;
|
|
369
|
+
|
|
146
370
|
/**
|
|
147
371
|
* THE ACTIVE ORGANIZATION — one per tab / running app, set once when the app loads, never none
|
|
148
372
|
* while the person has a membership (Arman, 2026-10-07; organizations STATE rules 10–15).
|
|
@@ -181,7 +405,7 @@ interface ActiveOrganizationSnapshot {
|
|
|
181
405
|
readonly organization: OrganizationMembership | null;
|
|
182
406
|
readonly memberships: readonly OrganizationMembership[];
|
|
183
407
|
/** Which ladder rung answered (or "switched" after a person's click). */
|
|
184
|
-
readonly rung: OrganizationRung | "switched" | null;
|
|
408
|
+
readonly rung: OrganizationRung | "switched" | "link" | null;
|
|
185
409
|
readonly error: string | null;
|
|
186
410
|
}
|
|
187
411
|
declare class NoActiveOrganizationError extends Error {
|
|
@@ -214,13 +438,145 @@ interface CreateActiveOrganizationOptions {
|
|
|
214
438
|
readonly held?: HeldOrganizationStore | undefined;
|
|
215
439
|
/** An extra first rung (the web's `?org=` link). Kept only if it is a current membership. */
|
|
216
440
|
readonly linked?: (() => string | null | undefined) | undefined;
|
|
441
|
+
/**
|
|
442
|
+
* The link's own organization (`?org=` uuid or address) as a first-class rung: honoured only when
|
|
443
|
+
* it is a current membership, otherwise the ladder stands and `onDecision` receives the refusal /
|
|
444
|
+
* offer / announcement for the host to SAY. Supersedes `linked` when both are given.
|
|
445
|
+
*/
|
|
446
|
+
readonly link?: {
|
|
447
|
+
readonly source: () => string | URLSearchParams | null | undefined;
|
|
448
|
+
readonly switchWhenALinkAsks?: (() => boolean | undefined) | undefined;
|
|
449
|
+
readonly signedInAs?: (() => string | null | undefined) | undefined;
|
|
450
|
+
readonly messages?: Partial<LinkOrganizationMessages> | undefined;
|
|
451
|
+
/** A share admits without making a member (asked only after a not-a-member verdict). */
|
|
452
|
+
readonly admittedByAShare?: ((organizationId: string) => Promise<boolean>) | undefined;
|
|
453
|
+
readonly onDecision?: ((decision: LinkOrganizationDecision) => void) | undefined;
|
|
454
|
+
} | undefined;
|
|
455
|
+
/**
|
|
456
|
+
* THE ADMIN SEAT: while the host's admin lane is open, the admin's own organization IS the active
|
|
457
|
+
* one for every reader (`current()`, `ensureOrgId()`); off the lane the person's own is untouched.
|
|
458
|
+
* Ignored unless the seat is a current membership. The snapshot always keeps the person's own.
|
|
459
|
+
*/
|
|
460
|
+
readonly adminSeat?: (() => AdminSeatInput | null | undefined) | undefined;
|
|
461
|
+
/** Marked resolved whenever the ladder settles (organization or none). */
|
|
462
|
+
readonly bootstrapGate?: OrganizationBootstrapGate | undefined;
|
|
463
|
+
/** Minimum gap between ladder re-runs caused by a not-a-member refusal. Default 30 s. */
|
|
464
|
+
readonly refusalRecheckGapMs?: number | undefined;
|
|
217
465
|
/** Load as soon as it is created (default true). */
|
|
218
466
|
readonly autoLoad?: boolean | undefined;
|
|
219
467
|
}
|
|
220
468
|
/** A held store over a `Storage` (browser `sessionStorage` = per tab), identity-keyed. */
|
|
221
|
-
declare function storageHeldOrganization(storage: Pick<Storage, "getItem" | "setItem" | "removeItem">, key?: string): HeldOrganizationStore
|
|
469
|
+
declare function storageHeldOrganization(storage: Pick<Storage, "getItem" | "setItem" | "removeItem">, key?: string): HeldOrganizationStore & {
|
|
470
|
+
read(userId: string): string | null;
|
|
471
|
+
};
|
|
222
472
|
/** Held in memory: the running app's own choice (desktop, scripts, tests). */
|
|
223
473
|
declare function memoryHeldOrganization(): HeldOrganizationStore;
|
|
224
474
|
declare function createActiveOrganization(options: CreateActiveOrganizationOptions): ActiveOrganization;
|
|
225
475
|
|
|
226
|
-
|
|
476
|
+
/**
|
|
477
|
+
* "This request needs an organization and names none" — the ONE recogniser, the server's throwable
|
|
478
|
+
* and the wire envelope (moved from the website's `lib/organizations/organizationRequired*.ts`,
|
|
479
|
+
* 2026-10-12). The envelope is byte-for-byte aidream's `matrx_connect.org_hold.organization_hold_detail`
|
|
480
|
+
* (`details.organizations`, status 400), so one recogniser covers both servers.
|
|
481
|
+
*
|
|
482
|
+
* Ruling (Arman, 2026-09-19): nothing but the picker may choose an organization. A request that
|
|
483
|
+
* needs one and has none is HELD: the person is shown their memberships, sets one, and it proceeds.
|
|
484
|
+
*/
|
|
485
|
+
/** The wire code both servers answer a missing organization with. */
|
|
486
|
+
declare const ORGANIZATION_REQUIRED_CODE: "organization_required";
|
|
487
|
+
/** Same value, the name the website's callers already read. */
|
|
488
|
+
declare const ORGANIZATION_REQUIRED_WIRE_CODE: "organization_required";
|
|
489
|
+
/** The transport kernel's client-side code for the same refusal (`OrganizationContextError`). */
|
|
490
|
+
declare const ORGANIZATION_CONTEXT_REQUIRED_CODE: "organization_context_required";
|
|
491
|
+
/** aidream's `MEMBERSHIPS_URL` literal — informational parity with the canonical envelope. */
|
|
492
|
+
declare const MEMBERSHIPS_URL: "/auth/organizations";
|
|
493
|
+
/** One organization the refusal offers the person. */
|
|
494
|
+
interface OrganizationMembershipSummary {
|
|
495
|
+
id: string;
|
|
496
|
+
name: string;
|
|
497
|
+
abbreviation?: string;
|
|
498
|
+
}
|
|
499
|
+
type OrganizationRequiredWireMembership = OrganizationMembershipSummary;
|
|
500
|
+
type OrganizationHoldSetOn = "request" | "mcp_connection" | "coding_session";
|
|
501
|
+
/**
|
|
502
|
+
* True when `err` is the fail-closed "no organization selected" refusal — from a transport kernel
|
|
503
|
+
* (`code: "organization_context_required"`), a route handler or either server
|
|
504
|
+
* (`code: "organization_required"`). Matched by CODE, never by message, so it survives a
|
|
505
|
+
* serialization boundary and copy changes.
|
|
506
|
+
*/
|
|
507
|
+
declare function isOrganizationRequiredError(err: unknown): boolean;
|
|
508
|
+
/** The parsed 400 body of an organization refusal (a plain `fetch` rather than a throwing transport). */
|
|
509
|
+
declare function isOrganizationRequiredEnvelope(body: unknown): body is {
|
|
510
|
+
code: typeof ORGANIZATION_REQUIRED_CODE;
|
|
511
|
+
message?: string;
|
|
512
|
+
user_message?: string;
|
|
513
|
+
details?: {
|
|
514
|
+
organizations?: OrganizationMembershipSummary[] | null;
|
|
515
|
+
memberships_url?: string;
|
|
516
|
+
set_on?: string;
|
|
517
|
+
remedy?: string;
|
|
518
|
+
};
|
|
519
|
+
};
|
|
520
|
+
/**
|
|
521
|
+
* What organizations does this refusal offer? Reads `.details.organizations` (either server's
|
|
522
|
+
* envelope or a `BackendApiError`) or `.serverDetail.organizations` (a normalized `ApiCallError`).
|
|
523
|
+
* `null` = absent or unreadable ("could not ask" — fall back to the picker's list); `[]` is the
|
|
524
|
+
* honest "you belong to nothing".
|
|
525
|
+
*/
|
|
526
|
+
declare function extractOrganizationHoldMemberships(err: unknown): OrganizationMembershipSummary[] | null;
|
|
527
|
+
/** The refusal, as a throwable. Nothing recovers from it by choosing — choosing is the person's act. */
|
|
528
|
+
declare class OrganizationRequiredServerError extends Error {
|
|
529
|
+
name: "OrganizationRequiredServerError";
|
|
530
|
+
readonly code: "organization_required";
|
|
531
|
+
/** `null` only when the list could not be read ("could not ask"), distinct from `[]`. */
|
|
532
|
+
readonly memberships: OrganizationMembershipSummary[] | null;
|
|
533
|
+
constructor(message: string, memberships?: OrganizationMembershipSummary[] | null);
|
|
534
|
+
}
|
|
535
|
+
declare function isOrganizationRequiredServerError(error: unknown): error is OrganizationRequiredServerError;
|
|
536
|
+
/** The minimal client shape `readCallerMemberships` needs (any Supabase client). */
|
|
537
|
+
interface MembershipReadClient {
|
|
538
|
+
auth: {
|
|
539
|
+
getClaims(): Promise<{
|
|
540
|
+
data: {
|
|
541
|
+
claims?: {
|
|
542
|
+
sub?: unknown;
|
|
543
|
+
};
|
|
544
|
+
} | null;
|
|
545
|
+
error: unknown;
|
|
546
|
+
}>;
|
|
547
|
+
};
|
|
548
|
+
schema(name: string): {
|
|
549
|
+
from(table: string): {
|
|
550
|
+
select(columns: string): unknown;
|
|
551
|
+
};
|
|
552
|
+
};
|
|
553
|
+
}
|
|
554
|
+
/**
|
|
555
|
+
* The caller's own active organization memberships — the only ones a refusal may offer (reads
|
|
556
|
+
* `iam.memberships`, never every organization row security returns: for a platform admin that is
|
|
557
|
+
* every tenant). `null` on any failure, so "could not ask" is never "you belong to nothing".
|
|
558
|
+
*/
|
|
559
|
+
declare function readCallerMemberships(client: MembershipReadClient): Promise<OrganizationMembershipSummary[] | null>;
|
|
560
|
+
/** Refuse, with the choices attached. */
|
|
561
|
+
declare function organizationRequired(client: MembershipReadClient, message: string): Promise<never>;
|
|
562
|
+
interface OrganizationHoldDetails {
|
|
563
|
+
hold: typeof ORGANIZATION_REQUIRED_CODE;
|
|
564
|
+
can_choose: true;
|
|
565
|
+
set_on: OrganizationHoldSetOn;
|
|
566
|
+
remedy: string;
|
|
567
|
+
organizations: OrganizationMembershipSummary[] | null;
|
|
568
|
+
memberships_url: string;
|
|
569
|
+
}
|
|
570
|
+
interface OrganizationRequiredEnvelope {
|
|
571
|
+
error: typeof ORGANIZATION_REQUIRED_CODE;
|
|
572
|
+
code: typeof ORGANIZATION_REQUIRED_CODE;
|
|
573
|
+
message: string;
|
|
574
|
+
user_message: string;
|
|
575
|
+
details: OrganizationHoldDetails;
|
|
576
|
+
}
|
|
577
|
+
/** The wire body (status 400) — aidream's `organization_hold_detail`, field for field. */
|
|
578
|
+
declare function organizationRequiredEnvelope(error: OrganizationRequiredServerError, setOn?: OrganizationHoldSetOn): OrganizationRequiredEnvelope;
|
|
579
|
+
/** The standard `Response` (status 400) a route answers the refusal with — no framework needed. */
|
|
580
|
+
declare function organizationRequiredResponse(error: OrganizationRequiredServerError): Response;
|
|
581
|
+
|
|
582
|
+
export { type AccountOrganizationChoices, type ActiveOrganization, type ActiveOrganizationSnapshot, type ActiveOrganizationStatus, type AdminSeat, type AdminSeatInput, type CreateActiveOrganizationOptions, type HeldOrganizationStore, LINK_ORGANIZATION_QUERY_KEY, type LadderInput, type LinkOrganizationDecision, type LinkOrganizationDecisionInput, type LinkOrganizationMembership, type LinkOrganizationMessages, type LinkOrganizationParam, MEMBERSHIPS_URL, type MembershipReadClient, NOT_A_MEMBER_RECHECK_GAP_MS, NoActiveOrganizationError, NotAMemberError, type NotAMemberRefusalNotice, ORGANIZATION_CONTEXT_REQUIRED_CODE, ORGANIZATION_ENTITY_TYPE, ORGANIZATION_REQUIRED_CODE, ORGANIZATION_REQUIRED_WIRE_CODE, ORGANIZATION_RESOLUTION_TIMEOUT_MS, type OrganizationBootstrapGate, type OrganizationHoldDetails, type OrganizationHoldSetOn, type OrganizationMembership, type OrganizationMembershipSummary, type OrganizationRefusal, type OrganizationRequiredEnvelope, OrganizationRequiredServerError, type OrganizationRequiredWireMembership, type OrganizationRung, type OrganizationsDb, type ParentOrganization, type ResolveWithLinkInput, type ResolvedOrganization, type ResolvedWithLink, adminSeatReplacesUserContext, classifyLinkOrganizationValue, classifyOrganizationRefusal, createActiveOrganization, createNotAMemberRefusalNotice, createOrganizationBootstrapGate, decideLinkOrganization, extractOrganizationHoldMemberships, isNotAMemberRefusal, isOrganizationRequiredEnvelope, isOrganizationRequiredError, isOrganizationRequiredServerError, linkOrganizationMalformedMessage, linkOrganizationNotAMemberMessage, linkOrganizationOfferMessage, linkOrganizationSwitchAnnouncement, memoryHeldOrganization, oldestMembership, orderOrganizations, organizationMatches, organizationRequired, organizationRequiredEnvelope, organizationRequiredResponse, readAccountOrganizationChoices, readCallerMemberships, readLinkOrganizationParam, readMemberships, readOrganizationFavourites, resolveActiveOrganization, resolveActiveOrganizationLazily, resolveAdminSeat, resolveChildOrganizationId, resolveOrganizationWithLink, setOrganizationFavourite, storageHeldOrganization, toAccountOrganizationChoices, writeLastActiveOrganization, writeStartupOrganization };
|