@unisim/sdk 0.125.1 → 0.127.0

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 (50) hide show
  1. package/README.md +13 -0
  2. package/android/src/main/AndroidManifest.xml +12 -1
  3. package/dist/OAuthButtons.d.ts +21 -0
  4. package/dist/OAuthButtons.d.ts.map +1 -0
  5. package/dist/OAuthButtons.js +79 -0
  6. package/dist/OAuthButtons.js.map +1 -0
  7. package/dist/SignInDialog.d.ts.map +1 -1
  8. package/dist/SignInDialog.js +86 -3
  9. package/dist/SignInDialog.js.map +1 -1
  10. package/dist/access.d.ts +22 -3
  11. package/dist/access.d.ts.map +1 -1
  12. package/dist/access.js +21 -30
  13. package/dist/access.js.map +1 -1
  14. package/dist/admin.d.ts +32 -28
  15. package/dist/admin.d.ts.map +1 -1
  16. package/dist/admin.js +59 -95
  17. package/dist/admin.js.map +1 -1
  18. package/dist/auth.d.ts +9 -0
  19. package/dist/auth.d.ts.map +1 -1
  20. package/dist/auth.js +16 -0
  21. package/dist/auth.js.map +1 -1
  22. package/dist/i18n.d.ts.map +1 -1
  23. package/dist/i18n.js +56 -0
  24. package/dist/i18n.js.map +1 -1
  25. package/dist/index.d.ts +9 -1
  26. package/dist/index.d.ts.map +1 -1
  27. package/dist/index.js +5 -1
  28. package/dist/index.js.map +1 -1
  29. package/dist/mockAuth.d.ts.map +1 -1
  30. package/dist/mockAuth.js +56 -0
  31. package/dist/mockAuth.js.map +1 -1
  32. package/dist/oauth.d.ts +99 -0
  33. package/dist/oauth.d.ts.map +1 -0
  34. package/dist/oauth.js +132 -0
  35. package/dist/oauth.js.map +1 -0
  36. package/dist/seatSession.d.ts +48 -0
  37. package/dist/seatSession.d.ts.map +1 -0
  38. package/dist/seatSession.js +191 -0
  39. package/dist/seatSession.js.map +1 -0
  40. package/dist/security.d.ts +56 -0
  41. package/dist/security.d.ts.map +1 -0
  42. package/dist/security.js +129 -0
  43. package/dist/security.js.map +1 -0
  44. package/dist/suiteApps.d.ts +29 -6
  45. package/dist/suiteApps.d.ts.map +1 -1
  46. package/dist/suiteApps.js +25 -6
  47. package/dist/suiteApps.js.map +1 -1
  48. package/dist/types.d.ts +15 -0
  49. package/dist/types.d.ts.map +1 -1
  50. package/package.json +1 -1
@@ -0,0 +1,191 @@
1
+ 'use client';
2
+ /**
3
+ * Floating concurrent seats — the client half.
4
+ *
5
+ * A seat is not something you are given, it is something you are HOLDING. This
6
+ * module claims one when a seat-gated product opens, keeps it alive with a
7
+ * heartbeat while the product is in use, and hands it back on sign-out. If the
8
+ * app is closed without signing out the seat simply ages out of the idle TTL
9
+ * server-side (migration 0140) — there is nothing to clean up.
10
+ *
11
+ * ⚠️ **Claiming is opt-in per product, and must stay that way.** The claim lives
12
+ * here rather than in `UniversalProvider` on purpose: every Universal App mounts
13
+ * the provider, and a free org has ONE seat. If opening Universal QR took it,
14
+ * the customer's actual assessor would be locked out of the product they paid
15
+ * for by a free utility they left open in another tab. Only `useSeat()` and
16
+ * `useEntitlement()` claim, and only Assess-style products call those.
17
+ *
18
+ * The claim is refcounted and shared per org: Ergo alone renders three
19
+ * components that ask for entitlement, and they must be one seat and one
20
+ * heartbeat between them, not three.
21
+ */
22
+ import { useEffect, useState } from 'react';
23
+ import { useUniversal } from './provider.js';
24
+ /** How often to tell the server we are still here. Comfortably inside the
25
+ * server's idle TTL (60 minutes) so a working session never lapses, and rare
26
+ * enough that it costs nothing. */
27
+ const HEARTBEAT_MS = 5 * 60 * 1000;
28
+ const IDLE = {
29
+ held: false, reason: 'loading', seats: 0, inUse: 0, ttlMinutes: 0, loading: true,
30
+ };
31
+ /** The one seat this tab is holding, if any. Module-level so every hook in the
32
+ * app shares it — and so `signOut` can find it without being handed an org. */
33
+ let holder = null;
34
+ function publish(h, state) {
35
+ h.state = state;
36
+ for (const fn of h.listeners)
37
+ fn(state);
38
+ }
39
+ function verdictFrom(row) {
40
+ const r = (row ?? {});
41
+ return {
42
+ held: r.ok === true,
43
+ reason: r.ok === true ? null : (r.reason ?? 'no_org'),
44
+ seats: r.seats ?? 0,
45
+ inUse: r.in_use ?? 0,
46
+ ttlMinutes: r.ttl_minutes ?? 0,
47
+ loading: false,
48
+ };
49
+ }
50
+ async function claimOnce(h) {
51
+ // The Supabase access token carries a stable `session_id` per login that
52
+ // survives token refresh — the same claim on-prem and Ergo's single-session
53
+ // rule key on. Read it from the session rather than minting our own id, so
54
+ // the server sees the same session the backend does.
55
+ const { data } = await h.supabase.auth.getSession();
56
+ const sessionId = readSessionIdClaim(data.session?.access_token);
57
+ const { data: row, error } = await h.supabase.rpc('claim_seat', {
58
+ p_org: h.orgId,
59
+ p_session_id: sessionId,
60
+ });
61
+ if (error) {
62
+ // Fail OPEN on a transport/storage error, exactly as the server-side
63
+ // enforcement does: a network blip must never read as "your licence is
64
+ // full". Keep whatever verdict we last had; if we never had one, assume
65
+ // held so the product opens and the backend gets the final say.
66
+ console.error('[unisim/sdk] claim_seat failed', error);
67
+ if (h.state.loading) {
68
+ publish(h, { ...h.state, held: true, reason: null, loading: false });
69
+ }
70
+ return;
71
+ }
72
+ publish(h, verdictFrom(row));
73
+ }
74
+ /** Pull the `session_id` claim out of a Supabase access token without adding a
75
+ * JWT dependency. Payload only — this is not verification, and nothing is
76
+ * trusted on the strength of it; the server re-reads the real claim. */
77
+ function readSessionIdClaim(accessToken) {
78
+ if (!accessToken)
79
+ return null;
80
+ try {
81
+ const payload = accessToken.split('.')[1];
82
+ if (!payload)
83
+ return null;
84
+ const json = atob(payload.replace(/-/g, '+').replace(/_/g, '/'));
85
+ const claims = JSON.parse(json);
86
+ return claims.session_id ?? null;
87
+ }
88
+ catch {
89
+ return null;
90
+ }
91
+ }
92
+ function acquire(supabase, orgId) {
93
+ if (holder && holder.orgId === orgId) {
94
+ holder.refs += 1;
95
+ return holder;
96
+ }
97
+ // Org switched under us — give the old seat back before taking a new one.
98
+ if (holder)
99
+ releaseHolder(holder);
100
+ const h = {
101
+ orgId, supabase, refs: 1, timer: null, state: IDLE, listeners: new Set(),
102
+ };
103
+ holder = h;
104
+ void claimOnce(h);
105
+ h.timer = setInterval(() => { void claimOnce(h); }, HEARTBEAT_MS);
106
+ return h;
107
+ }
108
+ function releaseHolder(h) {
109
+ if (h.timer)
110
+ clearInterval(h.timer);
111
+ h.timer = null;
112
+ if (holder === h)
113
+ holder = null;
114
+ }
115
+ function drop(h) {
116
+ h.refs -= 1;
117
+ if (h.refs > 0)
118
+ return;
119
+ // Last seat-gated component unmounted. Stop the heartbeat but do NOT release
120
+ // the seat: an unmount is usually a route change inside the same product, and
121
+ // handing the seat back only to re-claim it a moment later is how you lose it
122
+ // to a colleague mid-assessment. The idle TTL is what frees an abandoned one.
123
+ releaseHolder(h);
124
+ }
125
+ /**
126
+ * Hand back the seat this tab is holding, now.
127
+ *
128
+ * Called by `signOut` BEFORE the Supabase sign-out, because the RPC needs the
129
+ * caller's own token to run. Without this a colleague would wait out the full
130
+ * idle TTL for a seat whose owner deliberately signed off.
131
+ */
132
+ export async function releaseHeldSeat() {
133
+ const h = holder;
134
+ if (!h)
135
+ return;
136
+ releaseHolder(h);
137
+ publish(h, { ...IDLE, loading: false, reason: null });
138
+ try {
139
+ await h.supabase.rpc('release_seat', { p_org: h.orgId });
140
+ }
141
+ catch (e) {
142
+ // Nothing to recover: the seat expires on its own within the TTL.
143
+ console.error('[unisim/sdk] release_seat failed', e);
144
+ }
145
+ }
146
+ /**
147
+ * Claim and hold a concurrent seat in the active org for as long as this
148
+ * component is mounted. Safe to call from several components at once — they
149
+ * share one claim.
150
+ */
151
+ export function useSeatSession() {
152
+ const { supabase, session, activeOrgId, loading: providerLoading } = useUniversal();
153
+ const isAnon = session?.user?.is_anonymous === true;
154
+ const [state, setState] = useState(IDLE);
155
+ useEffect(() => {
156
+ if (providerLoading)
157
+ return;
158
+ if (!session?.user || isAnon || !activeOrgId) {
159
+ // Anonymous/trial users are not on a licence and must never take a seat
160
+ // from the org that is paying for it.
161
+ setState({ ...IDLE, loading: false, reason: 'no_org' });
162
+ return;
163
+ }
164
+ const h = acquire(supabase, activeOrgId);
165
+ setState(h.state);
166
+ h.listeners.add(setState);
167
+ return () => {
168
+ h.listeners.delete(setState);
169
+ drop(h);
170
+ };
171
+ }, [supabase, session?.user, activeOrgId, isAnon, providerLoading]);
172
+ return providerLoading ? IDLE : state;
173
+ }
174
+ /**
175
+ * Sign a colleague out of their seat so someone else can work (org admin or
176
+ * platform admin). This is what "revoke seat" became: there is no assignment to
177
+ * take away any more, only a session to end.
178
+ */
179
+ export async function adminReleaseSeat(supabase, args) {
180
+ const { error } = await supabase.rpc('admin_release_seat', {
181
+ p_org: args.orgId, p_user: args.userId,
182
+ });
183
+ return error ? { ok: false, error: error.message } : { ok: true };
184
+ }
185
+ /** Minutes of idleness after which a seat frees itself, read from the server so
186
+ * there is exactly one definition of it (migration 0140). */
187
+ export async function seatIdleTtlMinutes(supabase) {
188
+ const { data, error } = await supabase.rpc('seat_idle_ttl_minutes');
189
+ return error ? 60 : (data ?? 60);
190
+ }
191
+ //# sourceMappingURL=seatSession.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"seatSession.js","sourceRoot":"","sources":["../src/seatSession.ts"],"names":[],"mappings":"AAAA,YAAY,CAAA;AAEZ;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAC3C,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAI5C;;oCAEoC;AACpC,MAAM,YAAY,GAAG,CAAC,GAAG,EAAE,GAAG,IAAI,CAAA;AAuBlC,MAAM,IAAI,GAAc;IACtB,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI;CACjF,CAAA;AAWD;gFACgF;AAChF,IAAI,MAAM,GAAkB,IAAI,CAAA;AAEhC,SAAS,OAAO,CAAC,CAAS,EAAE,KAAgB;IAC1C,CAAC,CAAC,KAAK,GAAG,KAAK,CAAA;IACf,KAAK,MAAM,EAAE,IAAI,CAAC,CAAC,SAAS;QAAE,EAAE,CAAC,KAAK,CAAC,CAAA;AACzC,CAAC;AAED,SAAS,WAAW,CAAC,GAAY;IAC/B,MAAM,CAAC,GAAG,CAAC,GAAG,IAAI,EAAE,CAGnB,CAAA;IACD,OAAO;QACL,IAAI,EAAQ,CAAC,CAAC,EAAE,KAAK,IAAI;QACzB,MAAM,EAAM,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAE,CAAC,CAAC,CAAC,MAAM,IAAI,QAAQ,CAAyB;QAClF,KAAK,EAAO,CAAC,CAAC,KAAK,IAAI,CAAC;QACxB,KAAK,EAAO,CAAC,CAAC,MAAM,IAAI,CAAC;QACzB,UAAU,EAAE,CAAC,CAAC,WAAW,IAAI,CAAC;QAC9B,OAAO,EAAK,KAAK;KAClB,CAAA;AACH,CAAC;AAED,KAAK,UAAU,SAAS,CAAC,CAAS;IAChC,yEAAyE;IACzE,4EAA4E;IAC5E,2EAA2E;IAC3E,qDAAqD;IACrD,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,EAAE,CAAA;IACnD,MAAM,SAAS,GAAG,kBAAkB,CAAC,IAAI,CAAC,OAAO,EAAE,YAAY,CAAC,CAAA;IAEhE,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,MAAM,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,YAAY,EAAE;QAC9D,KAAK,EAAE,CAAC,CAAC,KAAK;QACd,YAAY,EAAE,SAAS;KACxB,CAAC,CAAA;IAEF,IAAI,KAAK,EAAE,CAAC;QACV,qEAAqE;QACrE,uEAAuE;QACvE,wEAAwE;QACxE,gEAAgE;QAChE,OAAO,CAAC,KAAK,CAAC,gCAAgC,EAAE,KAAK,CAAC,CAAA;QACtD,IAAI,CAAC,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC;YACpB,OAAO,CAAC,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAA;QACtE,CAAC;QACD,OAAM;IACR,CAAC;IACD,OAAO,CAAC,CAAC,EAAE,WAAW,CAAC,GAAG,CAAC,CAAC,CAAA;AAC9B,CAAC;AAED;;yEAEyE;AACzE,SAAS,kBAAkB,CAAC,WAAoB;IAC9C,IAAI,CAAC,WAAW;QAAE,OAAO,IAAI,CAAA;IAC7B,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAA;QACzC,IAAI,CAAC,OAAO;YAAE,OAAO,IAAI,CAAA;QACzB,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAA;QAChE,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAA4B,CAAA;QAC1D,OAAO,MAAM,CAAC,UAAU,IAAI,IAAI,CAAA;IAClC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAA;IACb,CAAC;AACH,CAAC;AAED,SAAS,OAAO,CAAC,QAAkB,EAAE,KAAa;IAChD,IAAI,MAAM,IAAI,MAAM,CAAC,KAAK,KAAK,KAAK,EAAE,CAAC;QACrC,MAAM,CAAC,IAAI,IAAI,CAAC,CAAA;QAChB,OAAO,MAAM,CAAA;IACf,CAAC;IACD,0EAA0E;IAC1E,IAAI,MAAM;QAAE,aAAa,CAAC,MAAM,CAAC,CAAA;IAEjC,MAAM,CAAC,GAAW;QAChB,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,GAAG,EAAE;KACzE,CAAA;IACD,MAAM,GAAG,CAAC,CAAA;IACV,KAAK,SAAS,CAAC,CAAC,CAAC,CAAA;IACjB,CAAC,CAAC,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,CAAA,CAAC,CAAC,EAAE,YAAY,CAAC,CAAA;IAChE,OAAO,CAAC,CAAA;AACV,CAAC;AAED,SAAS,aAAa,CAAC,CAAS;IAC9B,IAAI,CAAC,CAAC,KAAK;QAAE,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC,CAAA;IACnC,CAAC,CAAC,KAAK,GAAG,IAAI,CAAA;IACd,IAAI,MAAM,KAAK,CAAC;QAAE,MAAM,GAAG,IAAI,CAAA;AACjC,CAAC;AAED,SAAS,IAAI,CAAC,CAAS;IACrB,CAAC,CAAC,IAAI,IAAI,CAAC,CAAA;IACX,IAAI,CAAC,CAAC,IAAI,GAAG,CAAC;QAAE,OAAM;IACtB,6EAA6E;IAC7E,8EAA8E;IAC9E,8EAA8E;IAC9E,8EAA8E;IAC9E,aAAa,CAAC,CAAC,CAAC,CAAA;AAClB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe;IACnC,MAAM,CAAC,GAAG,MAAM,CAAA;IAChB,IAAI,CAAC,CAAC;QAAE,OAAM;IACd,aAAa,CAAC,CAAC,CAAC,CAAA;IAChB,OAAO,CAAC,CAAC,EAAE,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAA;IACrD,IAAI,CAAC;QACH,MAAM,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,cAAc,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAA;IAC1D,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,kEAAkE;QAClE,OAAO,CAAC,KAAK,CAAC,kCAAkC,EAAE,CAAC,CAAC,CAAA;IACtD,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,cAAc;IAC5B,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,eAAe,EAAE,GAAG,YAAY,EAAE,CAAA;IACnF,MAAM,MAAM,GACT,OAAO,EAAE,IAA+C,EAAE,YAAY,KAAK,IAAI,CAAA;IAClF,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAY,IAAI,CAAC,CAAA;IAEnD,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,eAAe;YAAE,OAAM;QAC3B,IAAI,CAAC,OAAO,EAAE,IAAI,IAAI,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC;YAC7C,wEAAwE;YACxE,sCAAsC;YACtC,QAAQ,CAAC,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAA;YACvD,OAAM;QACR,CAAC;QAED,MAAM,CAAC,GAAG,OAAO,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAA;QACxC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAA;QACjB,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;QACzB,OAAO,GAAG,EAAE;YACV,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAA;YAC5B,IAAI,CAAC,CAAC,CAAC,CAAA;QACT,CAAC,CAAA;IACH,CAAC,EAAE,CAAC,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,eAAe,CAAC,CAAC,CAAA;IAEnE,OAAO,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAA;AACvC,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,QAAkB,EAClB,IAAuC;IAEvC,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,QAAQ,CAAC,GAAG,CAAC,oBAAoB,EAAE;QACzD,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM;KACvC,CAAC,CAAA;IACF,OAAO,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,CAAA;AACnE,CAAC;AAED;8DAC8D;AAC9D,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,QAAkB;IACzD,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,QAAQ,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAA;IACnE,OAAO,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAE,IAAsB,IAAI,EAAE,CAAC,CAAA;AACrD,CAAC"}
@@ -0,0 +1,56 @@
1
+ import { useUniversal } from './provider.js';
2
+ export interface OrgSecuritySettings {
3
+ requireMfa: boolean;
4
+ requireSso: boolean;
5
+ }
6
+ export interface UseOrgSecurityResult {
7
+ settings: OrgSecuritySettings;
8
+ loading: boolean;
9
+ /**
10
+ * Non-null when the query FAILED. Callers must not read this as "nothing is
11
+ * required" — a policy that disappears whenever the network hiccups is not a
12
+ * policy. Gates should hold, or retry, rather than fail open.
13
+ */
14
+ error: string | null;
15
+ refresh: () => void;
16
+ /** Admin write. Rejected by RLS for anyone who isn't owner/admin of the org. */
17
+ save: (next: Partial<OrgSecuritySettings>) => Promise<{
18
+ ok: true;
19
+ } | {
20
+ ok: false;
21
+ error: string;
22
+ }>;
23
+ }
24
+ export declare function useOrgSecurity(orgId?: string | null): UseOrgSecurityResult;
25
+ export interface MfaFactor {
26
+ id: string;
27
+ friendlyName: string | null;
28
+ /** Supabase marks a factor 'unverified' until the first correct code. */
29
+ verified: boolean;
30
+ createdAt: string | null;
31
+ }
32
+ export interface UseMfaFactorsResult {
33
+ factors: MfaFactor[];
34
+ /** True once at least one factor is VERIFIED — an unverified one protects nothing. */
35
+ enrolled: boolean;
36
+ loading: boolean;
37
+ error: string | null;
38
+ refresh: () => void;
39
+ }
40
+ export declare function useMfaFactors(): UseMfaFactorsResult;
41
+ /**
42
+ * Whether this session has actually passed a second factor, as opposed to
43
+ * merely having one enrolled.
44
+ *
45
+ * `nextLevel === 'aal2'` means the user HAS a verified factor;
46
+ * `currentLevel === 'aal2'` means they have used it in this session. The gap
47
+ * between the two is the challenge step — read them separately, because
48
+ * conflating them either nags a user who has just passed the challenge or
49
+ * waves through one who never started it.
50
+ */
51
+ export declare function readAssuranceLevel(supabase: ReturnType<typeof useUniversal>['supabase']): Promise<{
52
+ current: string | null;
53
+ next: string | null;
54
+ challengeRequired: boolean;
55
+ }>;
56
+ //# sourceMappingURL=security.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"security.d.ts","sourceRoot":"","sources":["../src/security.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAgB5C,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,OAAO,CAAA;IACnB,UAAU,EAAE,OAAO,CAAA;CACpB;AAID,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,mBAAmB,CAAA;IAC7B,OAAO,EAAE,OAAO,CAAA;IAChB;;;;OAIG;IACH,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,OAAO,EAAE,MAAM,IAAI,CAAA;IACnB,gFAAgF;IAChF,IAAI,EAAE,CAAC,IAAI,EAAE,OAAO,CAAC,mBAAmB,CAAC,KAAK,OAAO,CAAC;QAAE,EAAE,EAAE,IAAI,CAAA;KAAE,GAAG;QAAE,EAAE,EAAE,KAAK,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CACnG;AAED,wBAAgB,cAAc,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,oBAAoB,CAgE1E;AAID,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAA;IACV,YAAY,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,yEAAyE;IACzE,QAAQ,EAAE,OAAO,CAAA;IACjB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;CACzB;AAED,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,SAAS,EAAE,CAAA;IACpB,sFAAsF;IACtF,QAAQ,EAAE,OAAO,CAAA;IACjB,OAAO,EAAE,OAAO,CAAA;IAChB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,OAAO,EAAE,MAAM,IAAI,CAAA;CACpB;AAED,wBAAgB,aAAa,IAAI,mBAAmB,CAsDnD;AAED;;;;;;;;;GASG;AACH,wBAAsB,kBAAkB,CACtC,QAAQ,EAAE,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC,UAAU,CAAC,GACpD,OAAO,CAAC;IAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,iBAAiB,EAAE,OAAO,CAAA;CAAE,CAAC,CAQtF"}
@@ -0,0 +1,129 @@
1
+ 'use client';
2
+ import { useCallback, useEffect, useState } from 'react';
3
+ import { useUniversal } from './provider.js';
4
+ const NOTHING_REQUIRED = { requireMfa: false, requireSso: false };
5
+ export function useOrgSecurity(orgId) {
6
+ const { supabase, activeOrgId, session } = useUniversal();
7
+ const targetOrg = orgId ?? activeOrgId ?? null;
8
+ const [settings, setSettings] = useState(NOTHING_REQUIRED);
9
+ const [loading, setLoading] = useState(true);
10
+ const [error, setError] = useState(null);
11
+ const [nonce, setNonce] = useState(0);
12
+ const refresh = useCallback(() => setNonce((n) => n + 1), []);
13
+ useEffect(() => {
14
+ if (!session || !targetOrg) {
15
+ setSettings(NOTHING_REQUIRED);
16
+ setError(null);
17
+ setLoading(false);
18
+ return;
19
+ }
20
+ let cancelled = false;
21
+ setLoading(true);
22
+ supabase
23
+ .from('org_security_settings')
24
+ .select('require_mfa, require_sso')
25
+ .eq('org_id', targetOrg)
26
+ .maybeSingle()
27
+ .then(({ data, error: queryError }) => {
28
+ if (cancelled)
29
+ return;
30
+ if (queryError) {
31
+ setError(queryError.message);
32
+ setSettings(NOTHING_REQUIRED);
33
+ }
34
+ else {
35
+ setError(null);
36
+ setSettings({
37
+ requireMfa: data?.require_mfa === true,
38
+ requireSso: data?.require_sso === true,
39
+ });
40
+ }
41
+ setLoading(false);
42
+ });
43
+ return () => { cancelled = true; };
44
+ }, [supabase, session, targetOrg, nonce]);
45
+ const save = useCallback(async (next) => {
46
+ if (!targetOrg)
47
+ return { ok: false, error: 'No active organisation' };
48
+ const merged = { ...settings, ...next };
49
+ // Upsert, because the common case is that no row exists yet. updated_at
50
+ // and updated_by are written by the 0138 trigger — never send them.
51
+ const { error: writeError } = await supabase
52
+ .from('org_security_settings')
53
+ .upsert({ org_id: targetOrg, require_mfa: merged.requireMfa, require_sso: merged.requireSso }, { onConflict: 'org_id' });
54
+ if (writeError)
55
+ return { ok: false, error: writeError.message };
56
+ setSettings(merged);
57
+ return { ok: true };
58
+ }, [supabase, targetOrg, settings]);
59
+ return { settings, loading, error, refresh, save };
60
+ }
61
+ export function useMfaFactors() {
62
+ const { supabase, session } = useUniversal();
63
+ const [factors, setFactors] = useState([]);
64
+ const [loading, setLoading] = useState(true);
65
+ const [error, setError] = useState(null);
66
+ const [nonce, setNonce] = useState(0);
67
+ const refresh = useCallback(() => setNonce((n) => n + 1), []);
68
+ const userId = session?.user?.id ?? null;
69
+ const isAnonymous = session?.user?.is_anonymous === true;
70
+ useEffect(() => {
71
+ // An anonymous trial user has no factors and cannot enrol one — asking
72
+ // costs a round trip per page and answers nothing.
73
+ if (!userId || isAnonymous) {
74
+ setFactors([]);
75
+ setError(null);
76
+ setLoading(false);
77
+ return;
78
+ }
79
+ let cancelled = false;
80
+ setLoading(true);
81
+ supabase.auth.mfa.listFactors().then(({ data, error: listError }) => {
82
+ if (cancelled)
83
+ return;
84
+ if (listError) {
85
+ setError(listError.message);
86
+ setFactors([]);
87
+ }
88
+ else {
89
+ setError(null);
90
+ setFactors((data?.all ?? []).map((f) => ({
91
+ id: f.id,
92
+ friendlyName: f.friendly_name ?? null,
93
+ verified: f.status === 'verified',
94
+ createdAt: f.created_at ?? null,
95
+ })));
96
+ }
97
+ setLoading(false);
98
+ });
99
+ return () => { cancelled = true; };
100
+ }, [supabase, userId, isAnonymous, nonce]);
101
+ return {
102
+ factors,
103
+ enrolled: factors.some((f) => f.verified),
104
+ loading,
105
+ error,
106
+ refresh,
107
+ };
108
+ }
109
+ /**
110
+ * Whether this session has actually passed a second factor, as opposed to
111
+ * merely having one enrolled.
112
+ *
113
+ * `nextLevel === 'aal2'` means the user HAS a verified factor;
114
+ * `currentLevel === 'aal2'` means they have used it in this session. The gap
115
+ * between the two is the challenge step — read them separately, because
116
+ * conflating them either nags a user who has just passed the challenge or
117
+ * waves through one who never started it.
118
+ */
119
+ export async function readAssuranceLevel(supabase) {
120
+ const { data, error } = await supabase.auth.mfa.getAuthenticatorAssuranceLevel();
121
+ if (error || !data)
122
+ return { current: null, next: null, challengeRequired: false };
123
+ return {
124
+ current: data.currentLevel,
125
+ next: data.nextLevel,
126
+ challengeRequired: data.nextLevel === 'aal2' && data.currentLevel !== 'aal2',
127
+ };
128
+ }
129
+ //# sourceMappingURL=security.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"security.js","sourceRoot":"","sources":["../src/security.ts"],"names":[],"mappings":"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"}
@@ -8,7 +8,12 @@ export interface SuiteNativeApp {
8
8
  * not legal in a URL scheme and hyphens are.
9
9
  */
10
10
  scheme: string;
11
- /** iOS bundle identifier — the app's `appId` in its capacitor.config. */
11
+ /**
12
+ * iOS bundle identifier — the app's `appId` in its capacitor.config, or for a
13
+ * natively-built app (Ergo Assess) its `PRODUCT_BUNDLE_IDENTIFIER`. Used to
14
+ * work out which app a plist belongs to, never to open one: iOS opens on the
15
+ * scheme.
16
+ */
12
17
  iosBundleId: string;
13
18
  /** Android application id. Usually the same string; Universal AI's is not. */
14
19
  androidPackage: string;
@@ -16,15 +21,33 @@ export interface SuiteNativeApp {
16
21
  /**
17
22
  * Every suite product that has a native build, and only those.
18
23
  *
19
- * ⚠️ **Being in the switcher is not enough to be in here.** Ergo Assess, Exports
20
- * and the rest are web-only; listing them would put a scheme nobody answers
21
- * into thirteen Info.plists and mark rows "Installed" that can never be. A
22
- * product missing from this list simply keeps today's behaviour — the https
23
- * link — which is the correct answer for a product with no app.
24
+ * ⚠️ **Being in the switcher is not enough to be in here.** Exports, Webinar and
25
+ * the rest are web-only; listing them would put a scheme nobody answers into
26
+ * fourteen Info.plists and mark rows "Installed" that can never be. A product
27
+ * missing from this list simply keeps today's behaviour — the https link —
28
+ * which is the correct answer for a product with no app.
24
29
  *
25
30
  * Universal Family has a native build and is deliberately absent for the same
26
31
  * reason: it has no row in the switcher to open.
27
32
  *
33
+ * ⚠️ **Ergo Assess used to be in that web-only sentence and is the reason this
34
+ * paragraph is worth re-reading rather than trusting.** It shipped a native app
35
+ * on both platforms while this list still called it web-only, so its switcher
36
+ * row went on falling back to the https link — the website, inside the webview
37
+ * the user was already in — while every other Assess app handed off. Nothing
38
+ * reported it: a missing registry entry is indistinguishable from "not
39
+ * installed", which is the same silence the three copies of this list have
40
+ * always had. **An app gaining a native build is a change to THIS file.**
41
+ *
42
+ * Ergo is also the first entry that is not a Capacitor app: it is a SwiftUI /
43
+ * Compose pair, so it has no `ios/App/App/` and its bundle id keeps the
44
+ * `com.universalsimulation.` prefix its Xcode project was generated under
45
+ * rather than the `uk.co.unisim.` the Capacitor apps share. Neither matters to
46
+ * the handoff — iOS matches on the scheme and Android on the package, and both
47
+ * are declared below — but it does mean `add-suite-app-links.mjs` has to find
48
+ * its plist by a different path, and that its own switcher rows cannot hand off
49
+ * yet, because its native nav bar has no switcher to tap.
50
+ *
28
51
  * Universal AI is listed, and is the one entry where the two platform ids
29
52
  * differ: its Capacitor `appId` `com.universal-ai.app` is legal on iOS and
30
53
  * illegal on Android (a hyphen cannot appear in a Java package), so its Android
@@ -1 +1 @@
1
- {"version":3,"file":"suiteApps.d.ts","sourceRoot":"","sources":["../src/suiteApps.ts"],"names":[],"mappings":"AAoCA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AAExD,MAAM,WAAW,cAAc;IAC7B,mEAAmE;IACnE,EAAE,EAAE,cAAc,CAAA;IAClB;;;;OAIG;IACH,MAAM,EAAE,MAAM,CAAA;IACd,yEAAyE;IACzE,WAAW,EAAE,MAAM,CAAA;IACnB,8EAA8E;IAC9E,cAAc,EAAE,MAAM,CAAA;CACvB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,iBAAiB,EAAE,SAAS,cAAc,EActD,CAAA;AAED,wBAAgB,cAAc,CAAC,EAAE,EAAE,cAAc,GAAG,cAAc,GAAG,SAAS,CAE7E;AA2BD;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,IAAI,OAAO,CAE3C;AAOD;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,IAAI,OAAO,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAkBjE;AAUD,iDAAiD;AACjD,wBAAgB,uBAAuB,SAEtC;AAED;;;;;GAKG;AACH,wBAAsB,YAAY,CAAC,EAAE,EAAE,cAAc,GAAG,OAAO,CAAC,OAAO,CAAC,CAWvE"}
1
+ {"version":3,"file":"suiteApps.d.ts","sourceRoot":"","sources":["../src/suiteApps.ts"],"names":[],"mappings":"AAoCA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AAExD,MAAM,WAAW,cAAc;IAC7B,mEAAmE;IACnE,EAAE,EAAE,cAAc,CAAA;IAClB;;;;OAIG;IACH,MAAM,EAAE,MAAM,CAAA;IACd;;;;;OAKG;IACH,WAAW,EAAE,MAAM,CAAA;IACnB,8EAA8E;IAC9E,cAAc,EAAE,MAAM,CAAA;CACvB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,eAAO,MAAM,iBAAiB,EAAE,SAAS,cAAc,EAetD,CAAA;AAED,wBAAgB,cAAc,CAAC,EAAE,EAAE,cAAc,GAAG,cAAc,GAAG,SAAS,CAE7E;AA2BD;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,IAAI,OAAO,CAE3C;AAOD;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,IAAI,OAAO,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAkBjE;AAUD,iDAAiD;AACjD,wBAAgB,uBAAuB,SAEtC;AAED;;;;;GAKG;AACH,wBAAsB,YAAY,CAAC,EAAE,EAAE,cAAc,GAAG,OAAO,CAAC,OAAO,CAAC,CAWvE"}
package/dist/suiteApps.js CHANGED
@@ -19,7 +19,7 @@
19
19
  // • **iOS** matches on SCHEME, and `canOpenURL` answers `false` — with only a
20
20
  // console line to say why — for any scheme the CALLING app has not listed
21
21
  // in its own `LSApplicationQueriesSchemes`. So every app needs every other
22
- // app's scheme in its Info.plist. `scripts/sync-native-app-links.mjs`
22
+ // app's scheme in its Info.plist. `scripts/add-suite-app-links.mjs`
23
23
  // writes that from this file; nobody should be hand-editing the lists.
24
24
  //
25
25
  // • **Android** matches on PACKAGE, and needs no per-app change at all: the
@@ -36,15 +36,33 @@ import { isNativeShell, capacitorPlugin } from './sessionStorage.js';
36
36
  /**
37
37
  * Every suite product that has a native build, and only those.
38
38
  *
39
- * ⚠️ **Being in the switcher is not enough to be in here.** Ergo Assess, Exports
40
- * and the rest are web-only; listing them would put a scheme nobody answers
41
- * into thirteen Info.plists and mark rows "Installed" that can never be. A
42
- * product missing from this list simply keeps today's behaviour — the https
43
- * link — which is the correct answer for a product with no app.
39
+ * ⚠️ **Being in the switcher is not enough to be in here.** Exports, Webinar and
40
+ * the rest are web-only; listing them would put a scheme nobody answers into
41
+ * fourteen Info.plists and mark rows "Installed" that can never be. A product
42
+ * missing from this list simply keeps today's behaviour — the https link —
43
+ * which is the correct answer for a product with no app.
44
44
  *
45
45
  * Universal Family has a native build and is deliberately absent for the same
46
46
  * reason: it has no row in the switcher to open.
47
47
  *
48
+ * ⚠️ **Ergo Assess used to be in that web-only sentence and is the reason this
49
+ * paragraph is worth re-reading rather than trusting.** It shipped a native app
50
+ * on both platforms while this list still called it web-only, so its switcher
51
+ * row went on falling back to the https link — the website, inside the webview
52
+ * the user was already in — while every other Assess app handed off. Nothing
53
+ * reported it: a missing registry entry is indistinguishable from "not
54
+ * installed", which is the same silence the three copies of this list have
55
+ * always had. **An app gaining a native build is a change to THIS file.**
56
+ *
57
+ * Ergo is also the first entry that is not a Capacitor app: it is a SwiftUI /
58
+ * Compose pair, so it has no `ios/App/App/` and its bundle id keeps the
59
+ * `com.universalsimulation.` prefix its Xcode project was generated under
60
+ * rather than the `uk.co.unisim.` the Capacitor apps share. Neither matters to
61
+ * the handoff — iOS matches on the scheme and Android on the package, and both
62
+ * are declared below — but it does mean `add-suite-app-links.mjs` has to find
63
+ * its plist by a different path, and that its own switcher rows cannot hand off
64
+ * yet, because its native nav bar has no switcher to tap.
65
+ *
48
66
  * Universal AI is listed, and is the one entry where the two platform ids
49
67
  * differ: its Capacitor `appId` `com.universal-ai.app` is legal on iOS and
50
68
  * illegal on Android (a hyphen cannot appear in a Java package), so its Android
@@ -53,6 +71,7 @@ import { isNativeShell, capacitorPlugin } from './sessionStorage.js';
53
71
  * is here so that stops being true the moment the badge comes off.
54
72
  */
55
73
  export const SUITE_NATIVE_APPS = [
74
+ { id: 'ergo_assess', scheme: 'unisim-ergo-assess', iosBundleId: 'com.universalsimulation.ergoassesscapture', androidPackage: 'com.universalsimulation.ergoassesscapture' },
56
75
  { id: 'cyber_assess', scheme: 'unisim-cyber-assess', iosBundleId: 'uk.co.unisim.cyberassess', androidPackage: 'uk.co.unisim.cyberassess' },
57
76
  { id: 'workplace_assess', scheme: 'unisim-workplace-assess', iosBundleId: 'uk.co.unisim.wfhassess', androidPackage: 'uk.co.unisim.wfhassess' },
58
77
  { id: 'fire_assess', scheme: 'unisim-fire-assess', iosBundleId: 'uk.co.unisim.fireassess', androidPackage: 'uk.co.unisim.fireassess' },
@@ -1 +1 @@
1
- {"version":3,"file":"suiteApps.js","sourceRoot":"","sources":["../src/suiteApps.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"suiteApps.js","sourceRoot":"","sources":["../src/suiteApps.ts"],"names":[],"mappings":"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"}
package/dist/types.d.ts CHANGED
@@ -141,16 +141,31 @@ export interface Subscription {
141
141
  * is lifetime_at + 3 years. Null for everyone else (migration 0044). */
142
142
  lifetime_at: string | null;
143
143
  }
144
+ /**
145
+ * One seat in an org's floating concurrent pool.
146
+ *
147
+ * ⚠️ Since migration 0140 a seat is OCCUPIED, not assigned. `assigned_user_id`
148
+ * is whoever is holding it at this instant, and it empties on its own once
149
+ * `last_seen_at` falls outside the idle TTL. Never read these fields as "this
150
+ * person's seat" — that is the named-seat model we stopped selling.
151
+ */
144
152
  export interface Seat {
145
153
  id: string;
146
154
  org_id: string;
155
+ /** Who is holding this seat right now. Null = free. */
147
156
  assigned_user_id: string | null;
157
+ /** When the current holder took it (not when an admin granted it). */
148
158
  assigned_at: string | null;
149
159
  revoked_at: string | null;
150
160
  status: SeatStatus;
161
+ /** The JWT session holding the seat — informational. */
162
+ session_id?: string | null;
163
+ /** Heartbeat. The seat is held while this is inside the idle TTL. */
164
+ last_seen_at?: string | null;
151
165
  }
152
166
  export interface SeatPool {
153
167
  total: number;
168
+ /** Seats occupied by a live session right now. */
154
169
  assigned: number;
155
170
  available: number;
156
171
  }
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unisim/sdk",
3
- "version": "0.125.1",
3
+ "version": "0.127.0",
4
4
  "description": "Shared React SDK for the Universal Suite — auth, entitlements, usage telemetry, changelog, org admin.",
5
5
  "license": "MIT",
6
6
  "author": "Universal Simulation Ltd",