@unisim/sdk 0.153.0 → 0.155.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.
- package/README.md +41 -8
- package/dist/UserCountBreakdown.d.ts +22 -0
- package/dist/UserCountBreakdown.d.ts.map +1 -0
- package/dist/UserCountBreakdown.js +264 -0
- package/dist/UserCountBreakdown.js.map +1 -0
- package/dist/UserCountLine.d.ts +23 -1
- package/dist/UserCountLine.d.ts.map +1 -1
- package/dist/UserCountLine.js +132 -33
- package/dist/UserCountLine.js.map +1 -1
- package/dist/handoff.d.ts +45 -0
- package/dist/handoff.d.ts.map +1 -0
- package/dist/handoff.js +253 -0
- package/dist/handoff.js.map +1 -0
- package/dist/i18n.d.ts.map +1 -1
- package/dist/i18n.js +59 -0
- package/dist/i18n.js.map +1 -1
- package/dist/index.d.ts +6 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -2
- package/dist/index.js.map +1 -1
- package/dist/presence.d.ts +25 -0
- package/dist/presence.d.ts.map +1 -1
- package/dist/presence.js +74 -0
- package/dist/presence.js.map +1 -1
- package/dist/productNames.d.ts +18 -0
- package/dist/productNames.d.ts.map +1 -0
- package/dist/productNames.js +73 -0
- package/dist/productNames.js.map +1 -0
- package/dist/provider.d.ts.map +1 -1
- package/dist/provider.js +25 -1
- package/dist/provider.js.map +1 -1
- package/dist/sessionStorage.d.ts +13 -0
- package/dist/sessionStorage.d.ts.map +1 -1
- package/dist/sessionStorage.js +29 -1
- package/dist/sessionStorage.js.map +1 -1
- package/package.json +2 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"UserCountLine.js","sourceRoot":"","sources":["../src/UserCountLine.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAA;;AAEZ,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAsB,MAAM,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"UserCountLine.js","sourceRoot":"","sources":["../src/UserCountLine.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAA;;AAEZ,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAsB,MAAM,OAAO,CAAA;AACpF,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AACzD,OAAO,EAAE,CAAC,EAAE,MAAM,WAAW,CAAA;AAC7B,OAAO,EAAE,IAAI,EAAkB,MAAM,gBAAgB,CAAA;AACrD,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAC5D,OAAO,EACL,eAAe,EACf,gBAAgB,EAChB,gBAAgB,EAChB,eAAe,EACf,gBAAgB,GAGjB,MAAM,eAAe,CAAA;AAEtB;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAAC,MAAM,GAAG,IAAI,EAAE,QAAoB,OAAO;IACtE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,YAAY,EAAE,CAAA;IAC3C,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAClC,GAAG,EAAE,CAAC,gBAAgB,CAAC,KAAK,KAAK,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CACrE,CAAA;IAED,SAAS,CAAC,GAAG,EAAE;QACb,0EAA0E;QAC1E,wEAAwE;QACxE,SAAS,CAAC,gBAAgB,CAAC,KAAK,KAAK,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAA;QACzE,IAAI,CAAC,MAAM;YAAE,OAAM;QACnB,IAAI,SAAS,GAAG,KAAK,CAAA;QACrB,MAAM,IAAI,GAAG,GAAG,EAAE;YAChB,IAAI,OAAO,QAAQ,KAAK,WAAW,IAAI,QAAQ,CAAC,eAAe,KAAK,QAAQ;gBAAE,OAAM;YACpF,KAAK,eAAe,CAAC,QAAQ,EAAE,MAAM,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE;gBAC/D,IAAI,CAAC,SAAS,IAAI,CAAC;oBAAE,SAAS,CAAC,CAAC,CAAC,CAAA;YACnC,CAAC,CAAC,CAAA;QACJ,CAAC,CAAA;QACD,IAAI,EAAE,CAAA;QACN,MAAM,KAAK,GAAG,WAAW,CAAC,IAAI,EAAE,gBAAgB,CAAC,CAAA;QACjD,OAAO,GAAG,EAAE,GAAG,SAAS,GAAG,IAAI,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAA,CAAC,CAAC,CAAA;IACzD,CAAC,EAAE,CAAC,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC,CAAA;IAE7C,OAAO,MAAM,IAAI,MAAM,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAA;AACnD,CAAC;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,SAAS,iBAAiB;IACxB,IAAI,OAAO,MAAM,KAAK,WAAW;QAAE,OAAM;IACzC,IAAI,CAAC;QAAC,MAAM,CAAC,YAAY,CAAC,UAAU,CAAC,eAAe,CAAC,CAAA;IAAC,CAAC;IAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC;AAChF,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,GAAG,CAAA;AAiBhC;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,UAAU,aAAa,CAAC,EAC5B,MAAM,GAAG,IAAI,EAAE,KAAK,GAAG,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS,GAAG,IAAI,GAC/C;IACnB,MAAM,EAAE,MAAM,EAAE,GAAG,YAAY,EAAE,CAAA;IACjC,MAAM,EAAE,QAAQ,EAAE,GAAG,WAAW,EAAE,CAAA;IAClC,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAa,OAAO,CAAC,CAAA;IACvD,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;IAC/C,MAAM,GAAG,GAAG,MAAM,CAAC,OAAO,KAAK,SAAS,CAAA;IACxC,MAAM,MAAM,GAAG,aAAa,CAAC,MAAM,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,CAAA;IACnD,yEAAyE;IACzE,6EAA6E;IAC7E,2EAA2E;IAC3E,0EAA0E;IAC1E,4EAA4E;IAC5E,2EAA2E;IAC3E,mCAAmC;IACnC,MAAM,KAAK,GAAG,KAAK,KAAK,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAA;IAEpE,MAAM,UAAU,GAAG,MAAM,CAAuC,IAAI,CAAC,CAAA;IACrE,yEAAyE;IACzE,4EAA4E;IAC5E,2CAA2C;IAC3C,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,CAAA;IAE7B,MAAM,WAAW,GAAG,WAAW,CAAC,GAAG,EAAE;QACnC,IAAI,UAAU,CAAC,OAAO,EAAE,CAAC;YAAC,YAAY,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;YAAC,UAAU,CAAC,OAAO,GAAG,IAAI,CAAA;QAAC,CAAC;IACzF,CAAC,EAAE,EAAE,CAAC,CAAA;IAEN,MAAM,UAAU,GAAG,WAAW,CAAC,GAAG,EAAE;QAClC,IAAI,CAAC,SAAS;YAAE,OAAM;QACtB,WAAW,EAAE,CAAA;QACb,OAAO,CAAC,OAAO,GAAG,KAAK,CAAA;QACvB,UAAU,CAAC,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE;YACnC,UAAU,CAAC,OAAO,GAAG,IAAI,CAAA;YACzB,OAAO,CAAC,OAAO,GAAG,IAAI,CAAA;YACtB,WAAW,CAAC,IAAI,CAAC,CAAA;QACnB,CAAC,EAAE,aAAa,CAAC,CAAA;IACnB,CAAC,EAAE,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC,CAAA;IAE5B,8EAA8E;IAC9E,6CAA6C;IAC7C,SAAS,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE,CAAC,WAAW,CAAC,CAAC,CAAA;IAE3C,SAAS,CAAC,iBAAiB,EAAE,EAAE,CAAC,CAAA;IAEhC,MAAM,MAAM,GAAG,GAAG,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAA;IAErE,IAAI,GAAG,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAA;IAC/B,OAAO,CACL,8BACA,iBACE,IAAI,EAAC,QAAQ;gBACb,0EAA0E;gBAC1E,oEAAoE;gBACpE,2CAA2C;gBAC3C,IAAI,EAAC,MAAM;gBACX,sEAAsE;gBACtE,oEAAoE;gBACpE,oEAAoE;gBACpE,mCAAmC;gBACnC,OAAO,EAAE,GAAG,EAAE;oBACZ,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;wBAAC,OAAO,CAAC,OAAO,GAAG,KAAK,CAAC;wBAAC,OAAM;oBAAC,CAAC;oBACxD,MAAM,EAAE,CAAA;gBACV,CAAC,EACD,aAAa,EAAE,UAAU,EACzB,WAAW,EAAE,WAAW,EACxB,cAAc,EAAE,WAAW,EAC3B,eAAe,EAAE,WAAW;gBAC5B,oEAAoE;gBACpE,yEAAyE;gBACzE,yEAAyE;gBACzE,sEAAsE;gBACtE,QAAQ;gBACR,aAAa,EAAE,CAAC,CAAC,EAAE,EAAE;oBACnB,IAAI,CAAC,SAAS;wBAAE,OAAM;oBACtB,CAAC,CAAC,cAAc,EAAE,CAAA;oBAClB,WAAW,EAAE,CAAA;oBACb,OAAO,CAAC,OAAO,GAAG,IAAI,CAAA;oBACtB,WAAW,CAAC,IAAI,CAAC,CAAA;gBACnB,CAAC;gBACD,sEAAsE;gBACtE,qEAAqE;gBACrE,qEAAqE;gBACrE,2BAA2B;gBAC3B,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE;oBACf,kEAAkE;oBAClE,oEAAoE;oBACpE,iEAAiE;oBACjE,2BAA2B;oBAC3B,OAAO,CAAC,OAAO,GAAG,KAAK,CAAA;oBACvB,IAAI,CAAC,SAAS,IAAI,CAAC,CAAC,CAAC,QAAQ;wBAAE,OAAM;oBACrC,IAAI,CAAC,CAAC,GAAG,KAAK,OAAO,IAAI,CAAC,CAAC,GAAG,KAAK,GAAG,IAAI,CAAC,CAAC,GAAG,KAAK,UAAU;wBAAE,OAAM;oBACtE,CAAC,CAAC,cAAc,EAAE,CAAA;oBAClB,WAAW,CAAC,IAAI,CAAC,CAAA;gBACnB,CAAC,EACD,KAAK,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,sBAAsB,CAAC,CAAC,CAAC,CAAC,SAAS,EAClE,SAAS,EAAE,SAAS,EACpB,KAAK,EAAE;oBACL,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,EAAE,UAAU,EAAE,aAAa;oBACzE,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,SAAS,EAAE,QAAQ,EAAE,EAAE,EAAE,UAAU,EAAE,GAAG;oBAC7E,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS;oBAC3C,kEAAkE;oBAClE,mEAAmE;oBACnE,qEAAqE;oBACrE,oEAAoE;oBACpE,sEAAsE;oBACtE,6DAA6D;oBAC7D,kEAAkE;oBAClE,mEAAmE;oBACnE,uEAAuE;oBACvE,qCAAqC;oBACrC,EAAE;oBACF,iEAAiE;oBACjE,uEAAuE;oBACvE,wEAAwE;oBACxE,wEAAwE;oBACxE,uEAAuE;oBACvE,yEAAyE;oBACzE,uEAAuE;oBACvE,kBAAkB;oBAClB,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,YAAY,EAAE,YAAY;oBAC5E,sEAAsE;oBACtE,uEAAuE;oBACvE,oEAAoE;oBACpE,oEAAoE;oBACpE,8CAA8C;oBAC9C,gBAAgB,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,kBAAkB,EAAE,MAAM;oBACxE,WAAW,EAAE,cAAc;oBAC3B,GAAG,KAAK;iBACT,YAED,eAAM,IAAI,EAAC,QAAQ,YAAE,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC,GAAQ,GAC/D,EACR,SAAS,IAAI,CACZ,KAAC,kBAAkB,IACjB,IAAI,EAAE,QAAQ,EACd,OAAO,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC,KAAK,CAAC,EACjC,KAAK,EAAE,KAAK,EACZ,KAAK,EAAE,KAAK,GACZ,CACH,IACE,CACJ,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { Session, SupabaseClient } from '@supabase/supabase-js';
|
|
2
|
+
import { type SessionStorageAdapter } from './sessionStorage.js';
|
|
3
|
+
/** The fragment parameter that carries the code. */
|
|
4
|
+
export declare const HANDOFF_PARAM = "unisim_handoff";
|
|
5
|
+
/** The page that redeems codes: the Assess portal, at the root of the zone's `assess` host. */
|
|
6
|
+
export declare function handoffRedeemerUrl(cookieDomain: string): string;
|
|
7
|
+
/** The address a handed-over click goes to. */
|
|
8
|
+
export declare function handoffUrl(cookieDomain: string, tokenHash: string, next: string): string;
|
|
9
|
+
/**
|
|
10
|
+
* Where to go after redeeming, or null to stay. Only https pages inside the
|
|
11
|
+
* zone are honoured, so the fragment cannot be used to bounce anyone off-site.
|
|
12
|
+
*/
|
|
13
|
+
export declare function safeNext(next: string | null, cookieDomain: string, here?: string): string | null;
|
|
14
|
+
/**
|
|
15
|
+
* `storage`, made to wait for a handed-over sign-in when this page arrived with
|
|
16
|
+
* one. supabase-js reads its storage once while it initialises, and every
|
|
17
|
+
* `getSession()` waits for that — so holding the first read back is what stops
|
|
18
|
+
* an app's anonymous sign-in racing ahead of the real one.
|
|
19
|
+
*
|
|
20
|
+
* Returns `storage` untouched when there is nothing to redeem, which is every
|
|
21
|
+
* page load but the one straight after a handoff.
|
|
22
|
+
*/
|
|
23
|
+
export declare function withHandoffRedemption(storage: SessionStorageAdapter, opts: {
|
|
24
|
+
cookieDomain: string;
|
|
25
|
+
supabaseUrl: string;
|
|
26
|
+
supabaseAnonKey: string;
|
|
27
|
+
storageKey: string;
|
|
28
|
+
}): SessionStorageAdapter;
|
|
29
|
+
/**
|
|
30
|
+
* Whether links from this page into the zone need a handoff: a browser page
|
|
31
|
+
* with a zone configured that is not itself inside it.
|
|
32
|
+
*/
|
|
33
|
+
export declare function needsHandoff(cookieDomain: string | undefined): cookieDomain is string;
|
|
34
|
+
/**
|
|
35
|
+
* Hold clicks on links into the zone just long enough to attach a sign-in.
|
|
36
|
+
* Returns the uninstaller.
|
|
37
|
+
*
|
|
38
|
+
* Listens on the document in the BUBBLE phase, so a handler of the app's own
|
|
39
|
+
* that already dealt with the click (the suite switcher opening a native app,
|
|
40
|
+
* say) has had its turn and left `defaultPrevented` set; those are left alone.
|
|
41
|
+
* Modified and middle clicks are too — they open a tab the page cannot wait
|
|
42
|
+
* on, and arrive signed out as they always have.
|
|
43
|
+
*/
|
|
44
|
+
export declare function installHandoffLinks(supabase: SupabaseClient, cookieDomain: string, currentSession: () => Session | null): () => void;
|
|
45
|
+
//# sourceMappingURL=handoff.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handoff.d.ts","sourceRoot":"","sources":["../src/handoff.ts"],"names":[],"mappings":"AAoCA,OAAO,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AACpE,OAAO,EAAsC,KAAK,qBAAqB,EAAE,MAAM,qBAAqB,CAAA;AAEpG,oDAAoD;AACpD,eAAO,MAAM,aAAa,mBAAmB,CAAA;AAK7C,+FAA+F;AAC/F,wBAAgB,kBAAkB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAE/D;AAED,+CAA+C;AAC/C,wBAAgB,UAAU,CAAC,YAAY,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAGxF;AAED;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,EAAE,YAAY,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAYhG;AAmED;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,qBAAqB,EAC9B,IAAI,EAAE;IAAE,YAAY,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,eAAe,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,GAC/F,qBAAqB,CAkCvB;AAID;;;GAGG;AACH,wBAAgB,YAAY,CAAC,YAAY,EAAE,MAAM,GAAG,SAAS,GAAG,YAAY,IAAI,MAAM,CAErF;AAWD;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,cAAc,EACxB,YAAY,EAAE,MAAM,EACpB,cAAc,EAAE,MAAM,OAAO,GAAG,IAAI,GACnC,MAAM,IAAI,CA8BZ"}
|
package/dist/handoff.js
ADDED
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
2
|
+
// Carrying a sign-in INTO .unisim.co.uk from a product's own domain.
|
|
3
|
+
//
|
|
4
|
+
// James, 2026-09-19: "the signin should carry over from ergoassess.app to a
|
|
5
|
+
// assess.unisim.co.uk session".
|
|
6
|
+
//
|
|
7
|
+
// Inside the zone there is nothing to do: the session is one cookie on
|
|
8
|
+
// .unisim.co.uk and every subdomain reads it. A product that is ALSO served
|
|
9
|
+
// from its own domain (Ergo at ergoassess.app) cannot write that cookie, so its
|
|
10
|
+
// session is app-local (`chooseSessionStorage`) and a link to the zone arrives
|
|
11
|
+
// signed out. Browsers give a page no way to write another site's cookie, so
|
|
12
|
+
// the sign-in has to travel with the navigation itself:
|
|
13
|
+
//
|
|
14
|
+
// 1. OFF the zone, a click on a link into it is held for a moment while the
|
|
15
|
+
// `session-handoff` edge function mints a single-use magic-link code for
|
|
16
|
+
// the signed-in person (no email is sent).
|
|
17
|
+
// 2. The browser goes to the Assess portal with the code in the FRAGMENT
|
|
18
|
+
// (`#unisim_handoff=…&next=<the link>`) — a fragment is never sent to a
|
|
19
|
+
// server or logged by one.
|
|
20
|
+
// 3. The portal (any SDK page in the zone, in fact) takes the code out of the
|
|
21
|
+
// address bar before anything else runs, redeems it with GoTrue's /verify,
|
|
22
|
+
// writes the new session to the .unisim.co.uk cookie, and goes on to
|
|
23
|
+
// `next`. Every subdomain now has it, whatever SDK version it runs.
|
|
24
|
+
//
|
|
25
|
+
// One redeemer rather than "redeem wherever you land" because the link may
|
|
26
|
+
// point at a product still on an older SDK that would not know the fragment;
|
|
27
|
+
// the cookie, once written, needs no cooperation from anyone.
|
|
28
|
+
//
|
|
29
|
+
// ⚠️ It is a NEW session, not a copy. See the header of the edge function for
|
|
30
|
+
// why sharing one refresh token between two storages signs the person out of
|
|
31
|
+
// both.
|
|
32
|
+
//
|
|
33
|
+
// Anything that goes wrong — anonymous visitor, function down, slow network —
|
|
34
|
+
// degrades to the plain link: the person arrives signed out, exactly as before.
|
|
35
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
36
|
+
import { hostInCookieDomain, isInCookieZone } from './sessionStorage.js';
|
|
37
|
+
/** The fragment parameter that carries the code. */
|
|
38
|
+
export const HANDOFF_PARAM = 'unisim_handoff';
|
|
39
|
+
const NEXT_PARAM = 'next';
|
|
40
|
+
/** How long a click waits for a code before going on without one. */
|
|
41
|
+
const MINT_TIMEOUT_MS = 5000;
|
|
42
|
+
/** The page that redeems codes: the Assess portal, at the root of the zone's `assess` host. */
|
|
43
|
+
export function handoffRedeemerUrl(cookieDomain) {
|
|
44
|
+
return `https://assess.${cookieDomain.replace(/^\./, '')}/`;
|
|
45
|
+
}
|
|
46
|
+
/** The address a handed-over click goes to. */
|
|
47
|
+
export function handoffUrl(cookieDomain, tokenHash, next) {
|
|
48
|
+
const params = new URLSearchParams({ [HANDOFF_PARAM]: tokenHash, [NEXT_PARAM]: next });
|
|
49
|
+
return `${handoffRedeemerUrl(cookieDomain)}#${params.toString()}`;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Where to go after redeeming, or null to stay. Only https pages inside the
|
|
53
|
+
* zone are honoured, so the fragment cannot be used to bounce anyone off-site.
|
|
54
|
+
*/
|
|
55
|
+
export function safeNext(next, cookieDomain, here) {
|
|
56
|
+
if (!next)
|
|
57
|
+
return null;
|
|
58
|
+
let url;
|
|
59
|
+
try {
|
|
60
|
+
url = new URL(next);
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
if (url.protocol !== 'https:' || !hostInCookieDomain(url.hostname, cookieDomain))
|
|
66
|
+
return null;
|
|
67
|
+
if (here) {
|
|
68
|
+
try {
|
|
69
|
+
const h = new URL(here);
|
|
70
|
+
if (h.origin === url.origin && h.pathname === url.pathname && h.search === url.search && !url.hash)
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
catch { /* not comparable: go */ }
|
|
74
|
+
}
|
|
75
|
+
return url.toString();
|
|
76
|
+
}
|
|
77
|
+
// ── Receiving: the zone side ─────────────────────────────────────────────────
|
|
78
|
+
/**
|
|
79
|
+
* One redemption per page load, shared by every client built during it. React
|
|
80
|
+
* may build the provider's client twice (StrictMode, a remount); the fragment
|
|
81
|
+
* is gone after the first read, so the second must find the same promise
|
|
82
|
+
* rather than no code at all.
|
|
83
|
+
*/
|
|
84
|
+
let pending = null;
|
|
85
|
+
/** Remove the code from the address bar and return what it carried. */
|
|
86
|
+
function takeFromUrl() {
|
|
87
|
+
const hash = window.location.hash;
|
|
88
|
+
if (!hash.includes(`${HANDOFF_PARAM}=`))
|
|
89
|
+
return null;
|
|
90
|
+
const params = new URLSearchParams(hash.slice(1));
|
|
91
|
+
const tokenHash = params.get(HANDOFF_PARAM);
|
|
92
|
+
const next = params.get(NEXT_PARAM);
|
|
93
|
+
params.delete(HANDOFF_PARAM);
|
|
94
|
+
params.delete(NEXT_PARAM);
|
|
95
|
+
const rest = params.toString();
|
|
96
|
+
// Out of the address bar (and so out of history, bookmarks and a shared
|
|
97
|
+
// screenshot) before any network call is made with it.
|
|
98
|
+
try {
|
|
99
|
+
window.history.replaceState(window.history.state, '', `${window.location.pathname}${window.location.search}${rest ? `#${rest}` : ''}`);
|
|
100
|
+
}
|
|
101
|
+
catch { /* sandboxed frame: the code is single-use regardless */ }
|
|
102
|
+
return tokenHash ? { tokenHash, next } : null;
|
|
103
|
+
}
|
|
104
|
+
/** Whether a persisted session string belongs to a real (non-anonymous) account. */
|
|
105
|
+
function holdsRealSession(stored) {
|
|
106
|
+
if (!stored)
|
|
107
|
+
return false;
|
|
108
|
+
try {
|
|
109
|
+
const user = JSON.parse(stored).user;
|
|
110
|
+
return !!user?.id && user.is_anonymous !== true;
|
|
111
|
+
}
|
|
112
|
+
catch {
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
/** GoTrue's /verify, called directly: the client it would belong to does not exist yet. */
|
|
117
|
+
async function redeem(tokenHash, supabaseUrl, anonKey) {
|
|
118
|
+
const res = await fetch(`${supabaseUrl.replace(/\/$/, '')}/auth/v1/verify`, {
|
|
119
|
+
method: 'POST',
|
|
120
|
+
headers: { apikey: anonKey, 'Content-Type': 'application/json' },
|
|
121
|
+
body: JSON.stringify({ type: 'magiclink', token_hash: tokenHash }),
|
|
122
|
+
});
|
|
123
|
+
if (!res.ok)
|
|
124
|
+
return null;
|
|
125
|
+
const body = (await res.json());
|
|
126
|
+
if (!body.access_token || !body.refresh_token || !body.user)
|
|
127
|
+
return null;
|
|
128
|
+
const expiresIn = body.expires_in ?? 3600;
|
|
129
|
+
return {
|
|
130
|
+
...body,
|
|
131
|
+
expires_in: expiresIn,
|
|
132
|
+
expires_at: body.expires_at ?? Math.floor(Date.now() / 1000) + expiresIn,
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* `storage`, made to wait for a handed-over sign-in when this page arrived with
|
|
137
|
+
* one. supabase-js reads its storage once while it initialises, and every
|
|
138
|
+
* `getSession()` waits for that — so holding the first read back is what stops
|
|
139
|
+
* an app's anonymous sign-in racing ahead of the real one.
|
|
140
|
+
*
|
|
141
|
+
* Returns `storage` untouched when there is nothing to redeem, which is every
|
|
142
|
+
* page load but the one straight after a handoff.
|
|
143
|
+
*/
|
|
144
|
+
export function withHandoffRedemption(storage, opts) {
|
|
145
|
+
if (typeof window === 'undefined')
|
|
146
|
+
return storage;
|
|
147
|
+
if (!pending) {
|
|
148
|
+
const taken = takeFromUrl();
|
|
149
|
+
if (!taken)
|
|
150
|
+
return storage;
|
|
151
|
+
pending = (async () => {
|
|
152
|
+
try {
|
|
153
|
+
// ⚠️ A real sign-in already in the zone WINS, and the code is left
|
|
154
|
+
// unspent. Otherwise anyone could mail out a link carrying a code for
|
|
155
|
+
// THEIR account and sign the reader into it (login CSRF), and whatever
|
|
156
|
+
// the reader did next would land in the stranger's account. An
|
|
157
|
+
// anonymous trial is not a sign-in and gives way.
|
|
158
|
+
if (holdsRealSession(await storage.getItem(opts.storageKey)))
|
|
159
|
+
return;
|
|
160
|
+
const session = await redeem(taken.tokenHash, opts.supabaseUrl, opts.supabaseAnonKey);
|
|
161
|
+
if (!session) {
|
|
162
|
+
console.warn('[unisim/sdk] a handed-over sign-in could not be redeemed; continuing signed out');
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
await storage.setItem(opts.storageKey, JSON.stringify(session));
|
|
166
|
+
}
|
|
167
|
+
catch (err) {
|
|
168
|
+
console.warn('[unisim/sdk] a handed-over sign-in failed', err);
|
|
169
|
+
}
|
|
170
|
+
finally {
|
|
171
|
+
// On to where the link was going, signed in or not.
|
|
172
|
+
const next = safeNext(taken.next, opts.cookieDomain, window.location.href);
|
|
173
|
+
if (next)
|
|
174
|
+
window.location.replace(next);
|
|
175
|
+
}
|
|
176
|
+
})();
|
|
177
|
+
}
|
|
178
|
+
const wait = pending;
|
|
179
|
+
return {
|
|
180
|
+
async getItem(key) { await wait; return storage.getItem(key); },
|
|
181
|
+
async setItem(key, value) { await wait; return storage.setItem(key, value); },
|
|
182
|
+
async removeItem(key) { await wait; return storage.removeItem(key); },
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
// ── Sending: the off-zone side ───────────────────────────────────────────────
|
|
186
|
+
/**
|
|
187
|
+
* Whether links from this page into the zone need a handoff: a browser page
|
|
188
|
+
* with a zone configured that is not itself inside it.
|
|
189
|
+
*/
|
|
190
|
+
export function needsHandoff(cookieDomain) {
|
|
191
|
+
return !!cookieDomain && typeof window !== 'undefined' && !isInCookieZone(cookieDomain);
|
|
192
|
+
}
|
|
193
|
+
async function mintCode(supabase) {
|
|
194
|
+
const call = supabase.functions
|
|
195
|
+
.invoke('session-handoff', { body: {} })
|
|
196
|
+
.then(({ data, error }) => (error || !data?.token_hash ? null : data.token_hash))
|
|
197
|
+
.catch(() => null);
|
|
198
|
+
const timeout = new Promise((resolve) => setTimeout(() => resolve(null), MINT_TIMEOUT_MS));
|
|
199
|
+
return Promise.race([call, timeout]);
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Hold clicks on links into the zone just long enough to attach a sign-in.
|
|
203
|
+
* Returns the uninstaller.
|
|
204
|
+
*
|
|
205
|
+
* Listens on the document in the BUBBLE phase, so a handler of the app's own
|
|
206
|
+
* that already dealt with the click (the suite switcher opening a native app,
|
|
207
|
+
* say) has had its turn and left `defaultPrevented` set; those are left alone.
|
|
208
|
+
* Modified and middle clicks are too — they open a tab the page cannot wait
|
|
209
|
+
* on, and arrive signed out as they always have.
|
|
210
|
+
*/
|
|
211
|
+
export function installHandoffLinks(supabase, cookieDomain, currentSession) {
|
|
212
|
+
const onClick = (e) => {
|
|
213
|
+
if (e.defaultPrevented || e.button !== 0 || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey)
|
|
214
|
+
return;
|
|
215
|
+
const anchor = e.target?.closest?.('a[href]');
|
|
216
|
+
if (!anchor || anchor.hasAttribute('download'))
|
|
217
|
+
return;
|
|
218
|
+
let url;
|
|
219
|
+
try {
|
|
220
|
+
url = new URL(anchor.href);
|
|
221
|
+
}
|
|
222
|
+
catch {
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
if (url.protocol !== 'https:' || !hostInCookieDomain(url.hostname, cookieDomain))
|
|
226
|
+
return;
|
|
227
|
+
const session = currentSession();
|
|
228
|
+
const anonymous = session?.user?.is_anonymous === true;
|
|
229
|
+
if (!session || anonymous)
|
|
230
|
+
return;
|
|
231
|
+
e.preventDefault();
|
|
232
|
+
const target = anchor.target && anchor.target !== '_self' ? anchor.target : null;
|
|
233
|
+
// Opened NOW, inside the click, or a popup blocker eats it once we await.
|
|
234
|
+
const win = target ? window.open('', target) : null;
|
|
235
|
+
const href = url.toString();
|
|
236
|
+
void mintCode(supabase).then((code) => {
|
|
237
|
+
const dest = code ? handoffUrl(cookieDomain, code, href) : href;
|
|
238
|
+
if (win) {
|
|
239
|
+
try {
|
|
240
|
+
win.opener = null;
|
|
241
|
+
}
|
|
242
|
+
catch { /* cross-origin already: fine */ }
|
|
243
|
+
win.location.href = dest;
|
|
244
|
+
}
|
|
245
|
+
else {
|
|
246
|
+
window.location.assign(dest);
|
|
247
|
+
}
|
|
248
|
+
});
|
|
249
|
+
};
|
|
250
|
+
document.addEventListener('click', onClick);
|
|
251
|
+
return () => document.removeEventListener('click', onClick);
|
|
252
|
+
}
|
|
253
|
+
//# sourceMappingURL=handoff.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handoff.js","sourceRoot":"","sources":["../src/handoff.ts"],"names":[],"mappings":"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"}
|
package/dist/i18n.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"i18n.d.ts","sourceRoot":"","sources":["../src/i18n.ts"],"names":[],"mappings":"AA6BA,eAAO,MAAM,mBAAmB,0EAA2E,CAAA;AAE3G,MAAM,MAAM,QAAQ,GAAG,OAAO,mBAAmB,CAAC,MAAM,CAAC,CAAA;AAEzD,eAAO,MAAM,gBAAgB,EAAE,QAAe,CAAA;
|
|
1
|
+
{"version":3,"file":"i18n.d.ts","sourceRoot":"","sources":["../src/i18n.ts"],"names":[],"mappings":"AA6BA,eAAO,MAAM,mBAAmB,0EAA2E,CAAA;AAE3G,MAAM,MAAM,QAAQ,GAAG,OAAO,mBAAmB,CAAC,MAAM,CAAC,CAAA;AAEzD,eAAO,MAAM,gBAAgB,EAAE,QAAe,CAAA;AAorD9C,wBAAgB,CAAC,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAGtE;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,IAAI,IAAI,QAAQ,CAGrF;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,QAAQ,GAAG,IAAI,CAUhF;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,EAAE,CAS3E;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAC/B,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,SAAS,CAAC,CAAC,EAC9C,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAC9B,CAAC,GAAG,SAAS,CAUf"}
|
package/dist/i18n.js
CHANGED
|
@@ -238,6 +238,16 @@ const en = {
|
|
|
238
238
|
'users.count_other': "There are {total} total users ({live} live)",
|
|
239
239
|
'users.suite_one': "There is a total of {total} user across all UNI·SIM apps ({live} live)",
|
|
240
240
|
'users.suite_other': "There are a total of {total} users across all UNI·SIM apps ({live} live)",
|
|
241
|
+
// The breakdown behind the suite figure — one row per app, on a long
|
|
242
|
+
// press (0.154.0). Names of apps are NOT here: they are brand identity and
|
|
243
|
+
// come from the switcher catalogue in every language (productNames.ts).
|
|
244
|
+
'users.breakdown_hint': "Press and hold to see the users in each app",
|
|
245
|
+
'users.breakdown_title': "Users per app",
|
|
246
|
+
'users.breakdown_row': "{total} users · {live} live",
|
|
247
|
+
'users.breakdown_row_one': "{total} user · {live} live",
|
|
248
|
+
'users.breakdown_note': "One person who uses several apps appears in each of them, so these add up to more than the suite total.",
|
|
249
|
+
'users.breakdown_loading': "Counting…",
|
|
250
|
+
'users.breakdown_empty': "The breakdown is not available just now.",
|
|
241
251
|
};
|
|
242
252
|
// en-gb defers to en for chrome wording — spelling differences for this set
|
|
243
253
|
// of strings are minimal, but locale-aware date formatting picks up "en-gb"
|
|
@@ -439,6 +449,13 @@ const fr = {
|
|
|
439
449
|
'users.count_other': "Il y a {total} utilisateurs au total ({live} en ligne)",
|
|
440
450
|
'users.suite_one': "Il y a {total} utilisateur au total sur toutes les applications UNI·SIM ({live} en ligne)",
|
|
441
451
|
'users.suite_other': "Il y a {total} utilisateurs au total sur toutes les applications UNI·SIM ({live} en ligne)",
|
|
452
|
+
'users.breakdown_hint': "Appuyez longuement pour voir les utilisateurs de chaque application",
|
|
453
|
+
'users.breakdown_title': "Utilisateurs par application",
|
|
454
|
+
'users.breakdown_row': "{total} utilisateurs · {live} en ligne",
|
|
455
|
+
'users.breakdown_row_one': "{total} utilisateur · {live} en ligne",
|
|
456
|
+
'users.breakdown_note': "Une personne qui utilise plusieurs applications apparaît dans chacune d’elles : le cumul dépasse donc le total de la suite.",
|
|
457
|
+
'users.breakdown_loading': "Comptage…",
|
|
458
|
+
'users.breakdown_empty': "Le détail n’est pas disponible pour le moment.",
|
|
442
459
|
};
|
|
443
460
|
const es = {
|
|
444
461
|
'nav.for': 'para',
|
|
@@ -636,6 +653,13 @@ const es = {
|
|
|
636
653
|
'users.count_other': "Hay {total} usuarios en total ({live} en línea)",
|
|
637
654
|
'users.suite_one': "Hay {total} usuario en total en todas las aplicaciones UNI·SIM ({live} en línea)",
|
|
638
655
|
'users.suite_other': "Hay {total} usuarios en total en todas las aplicaciones UNI·SIM ({live} en línea)",
|
|
656
|
+
'users.breakdown_hint': "Mantén pulsado para ver los usuarios de cada aplicación",
|
|
657
|
+
'users.breakdown_title': "Usuarios por aplicación",
|
|
658
|
+
'users.breakdown_row': "{total} usuarios · {live} en línea",
|
|
659
|
+
'users.breakdown_row_one': "{total} usuario · {live} en línea",
|
|
660
|
+
'users.breakdown_note': "Una persona que usa varias aplicaciones aparece en todas ellas, así que la suma supera el total de la suite.",
|
|
661
|
+
'users.breakdown_loading': "Contando…",
|
|
662
|
+
'users.breakdown_empty': "El desglose no está disponible ahora mismo.",
|
|
639
663
|
};
|
|
640
664
|
const it = {
|
|
641
665
|
'nav.for': 'per',
|
|
@@ -833,6 +857,13 @@ const it = {
|
|
|
833
857
|
'users.count_other': "Ci sono {total} utenti in totale ({live} online)",
|
|
834
858
|
'users.suite_one': "C'è {total} utente in totale in tutte le app UNI·SIM ({live} online)",
|
|
835
859
|
'users.suite_other': "Ci sono {total} utenti in totale in tutte le app UNI·SIM ({live} online)",
|
|
860
|
+
'users.breakdown_hint': "Tieni premuto per vedere gli utenti di ogni app",
|
|
861
|
+
'users.breakdown_title': "Utenti per app",
|
|
862
|
+
'users.breakdown_row': "{total} utenti · {live} online",
|
|
863
|
+
'users.breakdown_row_one': "{total} utente · {live} online",
|
|
864
|
+
'users.breakdown_note': "Chi usa più app compare in ognuna, quindi la somma supera il totale della suite.",
|
|
865
|
+
'users.breakdown_loading': "Conteggio…",
|
|
866
|
+
'users.breakdown_empty': "Il dettaglio non è disponibile al momento.",
|
|
836
867
|
};
|
|
837
868
|
const de = {
|
|
838
869
|
'nav.for': 'für',
|
|
@@ -1030,6 +1061,13 @@ const de = {
|
|
|
1030
1061
|
'users.count_other': "Insgesamt {total} Nutzer ({live} gerade aktiv)",
|
|
1031
1062
|
'users.suite_one': "Insgesamt {total} Nutzer in allen UNI·SIM-Apps ({live} gerade aktiv)",
|
|
1032
1063
|
'users.suite_other': "Insgesamt {total} Nutzer in allen UNI·SIM-Apps ({live} gerade aktiv)",
|
|
1064
|
+
'users.breakdown_hint': "Gedrückt halten, um die Nutzer jeder App zu sehen",
|
|
1065
|
+
'users.breakdown_title': "Nutzer pro App",
|
|
1066
|
+
'users.breakdown_row': "{total} Nutzer · {live} gerade aktiv",
|
|
1067
|
+
'users.breakdown_row_one': "{total} Nutzer · {live} gerade aktiv",
|
|
1068
|
+
'users.breakdown_note': "Wer mehrere Apps nutzt, erscheint in jeder davon — die Summe liegt deshalb über dem Gesamtwert der Suite.",
|
|
1069
|
+
'users.breakdown_loading': "Wird gezählt…",
|
|
1070
|
+
'users.breakdown_empty': "Die Aufschlüsselung ist gerade nicht verfügbar.",
|
|
1033
1071
|
};
|
|
1034
1072
|
// European Portuguese — the SDK's original `pt`, unchanged but for the name.
|
|
1035
1073
|
const ptPT = {
|
|
@@ -1228,6 +1266,13 @@ const ptPT = {
|
|
|
1228
1266
|
'users.count_other': "Há {total} utilizadores no total ({live} online)",
|
|
1229
1267
|
'users.suite_one': "Há {total} utilizador no total em todas as aplicações UNI·SIM ({live} online)",
|
|
1230
1268
|
'users.suite_other': "Há {total} utilizadores no total em todas as aplicações UNI·SIM ({live} online)",
|
|
1269
|
+
'users.breakdown_hint': "Mantenha premido para ver os utilizadores de cada aplicação",
|
|
1270
|
+
'users.breakdown_title': "Utilizadores por aplicação",
|
|
1271
|
+
'users.breakdown_row': "{total} utilizadores · {live} online",
|
|
1272
|
+
'users.breakdown_row_one': "{total} utilizador · {live} online",
|
|
1273
|
+
'users.breakdown_note': "Quem usa várias aplicações aparece em todas elas, por isso a soma ultrapassa o total da suite.",
|
|
1274
|
+
'users.breakdown_loading': "A contar…",
|
|
1275
|
+
'users.breakdown_empty': "O detalhe não está disponível de momento.",
|
|
1231
1276
|
};
|
|
1232
1277
|
// Brazilian Portuguese — its own read-through, NOT pt-PT with words swapped
|
|
1233
1278
|
// (added 0.141.5). What differs, so the next edit keeps it Brazilian:
|
|
@@ -1440,6 +1485,13 @@ const ptBR = {
|
|
|
1440
1485
|
'users.count_other': "Há {total} usuários no total ({live} online)",
|
|
1441
1486
|
'users.suite_one': "Há {total} usuário no total em todos os apps UNI·SIM ({live} online)",
|
|
1442
1487
|
'users.suite_other': "Há {total} usuários no total em todos os apps UNI·SIM ({live} online)",
|
|
1488
|
+
'users.breakdown_hint': "Toque e segure para ver os usuários de cada app",
|
|
1489
|
+
'users.breakdown_title': "Usuários por app",
|
|
1490
|
+
'users.breakdown_row': "{total} usuários · {live} online",
|
|
1491
|
+
'users.breakdown_row_one': "{total} usuário · {live} online",
|
|
1492
|
+
'users.breakdown_note': "Quem usa vários apps aparece em cada um deles, então a soma fica maior que o total da suíte.",
|
|
1493
|
+
'users.breakdown_loading': "Contando…",
|
|
1494
|
+
'users.breakdown_empty': "O detalhamento não está disponível agora.",
|
|
1443
1495
|
};
|
|
1444
1496
|
const tr = {
|
|
1445
1497
|
'nav.for': 'için',
|
|
@@ -1637,6 +1689,13 @@ const tr = {
|
|
|
1637
1689
|
'users.count_other': "Toplam {total} kullanıcı ({live} çevrimiçi)",
|
|
1638
1690
|
'users.suite_one': "Tüm UNI·SIM uygulamalarında toplam {total} kullanıcı ({live} çevrimiçi)",
|
|
1639
1691
|
'users.suite_other': "Tüm UNI·SIM uygulamalarında toplam {total} kullanıcı ({live} çevrimiçi)",
|
|
1692
|
+
'users.breakdown_hint': "Her uygulamanın kullanıcılarını görmek için basılı tutun",
|
|
1693
|
+
'users.breakdown_title': "Uygulama başına kullanıcı",
|
|
1694
|
+
'users.breakdown_row': "{total} kullanıcı · {live} çevrimiçi",
|
|
1695
|
+
'users.breakdown_row_one': "{total} kullanıcı · {live} çevrimiçi",
|
|
1696
|
+
'users.breakdown_note': "Birden fazla uygulama kullanan biri her birinde görünür; bu yüzden toplamları paketin toplamından fazladır.",
|
|
1697
|
+
'users.breakdown_loading': "Sayılıyor…",
|
|
1698
|
+
'users.breakdown_empty': "Dağılım şu anda kullanılamıyor.",
|
|
1640
1699
|
};
|
|
1641
1700
|
const TRANSLATIONS = {
|
|
1642
1701
|
'en': en,
|