@w6w/sdk 0.5.0 → 0.9.8

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 (132) hide show
  1. package/README.md +185 -32
  2. package/dist/mod.d.ts +10 -4
  3. package/dist/mod.d.ts.map +1 -1
  4. package/dist/mod.js +3 -0
  5. package/dist/mod.js.map +1 -1
  6. package/dist/src/client.d.ts +37 -5
  7. package/dist/src/client.d.ts.map +1 -1
  8. package/dist/src/client.js +40 -5
  9. package/dist/src/client.js.map +1 -1
  10. package/dist/src/config.d.ts +83 -6
  11. package/dist/src/config.d.ts.map +1 -1
  12. package/dist/src/config.js +41 -5
  13. package/dist/src/config.js.map +1 -1
  14. package/dist/src/connections.d.ts +3 -2
  15. package/dist/src/connections.d.ts.map +1 -1
  16. package/dist/src/connections.js +7 -2
  17. package/dist/src/connections.js.map +1 -1
  18. package/dist/src/console/aliases.d.ts +137 -0
  19. package/dist/src/console/aliases.d.ts.map +1 -0
  20. package/dist/src/console/aliases.js +113 -0
  21. package/dist/src/console/aliases.js.map +1 -0
  22. package/dist/src/console/api-calls.d.ts +4 -3
  23. package/dist/src/console/api-calls.d.ts.map +1 -1
  24. package/dist/src/console/api-calls.js +4 -3
  25. package/dist/src/console/api-calls.js.map +1 -1
  26. package/dist/src/console/apps.d.ts +181 -8
  27. package/dist/src/console/apps.d.ts.map +1 -1
  28. package/dist/src/console/apps.js +67 -12
  29. package/dist/src/console/apps.js.map +1 -1
  30. package/dist/src/console/auth.d.ts +245 -7
  31. package/dist/src/console/auth.d.ts.map +1 -1
  32. package/dist/src/console/auth.js +177 -8
  33. package/dist/src/console/auth.js.map +1 -1
  34. package/dist/src/console/commerce.d.ts +428 -0
  35. package/dist/src/console/commerce.d.ts.map +1 -0
  36. package/dist/src/console/commerce.js +220 -0
  37. package/dist/src/console/commerce.js.map +1 -0
  38. package/dist/src/console/dashboard.d.ts +8 -0
  39. package/dist/src/console/dashboard.d.ts.map +1 -1
  40. package/dist/src/console/dashboard.js.map +1 -1
  41. package/dist/src/console/endpoints.d.ts +79 -6
  42. package/dist/src/console/endpoints.d.ts.map +1 -1
  43. package/dist/src/console/endpoints.js.map +1 -1
  44. package/dist/src/console/functions.d.ts +35 -4
  45. package/dist/src/console/functions.d.ts.map +1 -1
  46. package/dist/src/console/functions.js +13 -0
  47. package/dist/src/console/functions.js.map +1 -1
  48. package/dist/src/console/mod.d.ts +32 -7
  49. package/dist/src/console/mod.d.ts.map +1 -1
  50. package/dist/src/console/mod.js +26 -1
  51. package/dist/src/console/mod.js.map +1 -1
  52. package/dist/src/console/otp.d.ts +127 -0
  53. package/dist/src/console/otp.d.ts.map +1 -0
  54. package/dist/src/console/otp.js +118 -0
  55. package/dist/src/console/otp.js.map +1 -0
  56. package/dist/src/console/passkeys.d.ts +246 -0
  57. package/dist/src/console/passkeys.d.ts.map +1 -0
  58. package/dist/src/console/passkeys.js +192 -0
  59. package/dist/src/console/passkeys.js.map +1 -0
  60. package/dist/src/console/reliability.d.ts +101 -6
  61. package/dist/src/console/reliability.d.ts.map +1 -1
  62. package/dist/src/console/reliability.js +16 -5
  63. package/dist/src/console/reliability.js.map +1 -1
  64. package/dist/src/console/step-tests.d.ts +7 -1
  65. package/dist/src/console/step-tests.d.ts.map +1 -1
  66. package/dist/src/console/step-tests.js +1 -1
  67. package/dist/src/console/step-tests.js.map +1 -1
  68. package/dist/src/console/subscriptions.d.ts +38 -16
  69. package/dist/src/console/subscriptions.d.ts.map +1 -1
  70. package/dist/src/console/subscriptions.js +7 -13
  71. package/dist/src/console/subscriptions.js.map +1 -1
  72. package/dist/src/console/tenant-login-flags.d.ts +106 -0
  73. package/dist/src/console/tenant-login-flags.d.ts.map +1 -0
  74. package/dist/src/console/tenant-login-flags.js +113 -0
  75. package/dist/src/console/tenant-login-flags.js.map +1 -0
  76. package/dist/src/console/tenant-oauth-apps.d.ts +75 -14
  77. package/dist/src/console/tenant-oauth-apps.d.ts.map +1 -1
  78. package/dist/src/console/tenant-oauth-apps.js +37 -11
  79. package/dist/src/console/tenant-oauth-apps.js.map +1 -1
  80. package/dist/src/console/tokens.d.ts +2 -0
  81. package/dist/src/console/tokens.d.ts.map +1 -1
  82. package/dist/src/console/tokens.js.map +1 -1
  83. package/dist/src/console/workflows.d.ts +14 -0
  84. package/dist/src/console/workflows.d.ts.map +1 -1
  85. package/dist/src/console/workflows.js +13 -0
  86. package/dist/src/console/workflows.js.map +1 -1
  87. package/dist/src/documents.d.ts +9 -5
  88. package/dist/src/documents.d.ts.map +1 -1
  89. package/dist/src/documents.js +6 -3
  90. package/dist/src/documents.js.map +1 -1
  91. package/dist/src/endpoints.d.ts +75 -0
  92. package/dist/src/endpoints.d.ts.map +1 -0
  93. package/dist/src/endpoints.js +47 -0
  94. package/dist/src/endpoints.js.map +1 -0
  95. package/dist/src/functions.d.ts +236 -0
  96. package/dist/src/functions.d.ts.map +1 -0
  97. package/dist/src/functions.js +201 -0
  98. package/dist/src/functions.js.map +1 -0
  99. package/dist/src/http.d.ts +58 -10
  100. package/dist/src/http.d.ts.map +1 -1
  101. package/dist/src/http.js +82 -11
  102. package/dist/src/http.js.map +1 -1
  103. package/dist/src/me.d.ts +3 -2
  104. package/dist/src/me.d.ts.map +1 -1
  105. package/dist/src/me.js +7 -2
  106. package/dist/src/me.js.map +1 -1
  107. package/dist/src/run.d.ts +19 -5
  108. package/dist/src/run.d.ts.map +1 -1
  109. package/dist/src/run.js +14 -4
  110. package/dist/src/run.js.map +1 -1
  111. package/dist/src/server/mod.d.ts +100 -0
  112. package/dist/src/server/mod.d.ts.map +1 -0
  113. package/dist/src/server/mod.js +121 -0
  114. package/dist/src/server/mod.js.map +1 -0
  115. package/dist/src/team.d.ts +204 -0
  116. package/dist/src/team.d.ts.map +1 -0
  117. package/dist/src/team.js +161 -0
  118. package/dist/src/team.js.map +1 -0
  119. package/dist/src/types.d.ts +143 -10
  120. package/dist/src/types.d.ts.map +1 -1
  121. package/dist/src/types.js +27 -0
  122. package/dist/src/types.js.map +1 -1
  123. package/dist/src/vars.d.ts +5 -3
  124. package/dist/src/vars.d.ts.map +1 -1
  125. package/dist/src/vars.js +14 -4
  126. package/dist/src/vars.js.map +1 -1
  127. package/dist/src/version.js +1 -1
  128. package/dist/src/workflows.d.ts +261 -9
  129. package/dist/src/workflows.d.ts.map +1 -1
  130. package/dist/src/workflows.js +246 -7
  131. package/dist/src/workflows.js.map +1 -1
  132. package/package.json +5 -1
@@ -0,0 +1,100 @@
1
+ /**
2
+ * `@w6w/sdk/server` — a backend-only token exchange, for a partner embedding
3
+ * w6w inside its own product.
4
+ *
5
+ * A **separate** entry point from the package root (`@w6w/sdk`) and from
6
+ * `@w6w/sdk/console`: deliberately excluded from `endpoints.json`'s
7
+ * `operations[]` and from the root barrel (`../../mod.ts`), documented
8
+ * instead in `docs/sdk-surface.md` (R-5). Nothing here is reachable from
9
+ * either of those entry points, and this module imports nothing from
10
+ * `../console/mod.ts`.
11
+ *
12
+ * **Egress / trust boundary.** {@linkcode exchangeToken} sends a tenant's
13
+ * client secret over the wire, once per call, and only as an HTTP Basic
14
+ * credential — never in the body, the URL or a query string. It is built on
15
+ * the package's existing transport (`../http.ts`'s `request`, `../config.ts`'s
16
+ * `resolveConfig`) with `requireAuth: false` — the same escape hatch
17
+ * `console.auth.login` uses for a route that authenticates itself rather than
18
+ * via a bearer — so this is a thin caller of the one HTTP path this package
19
+ * has, never a second one.
20
+ *
21
+ * This function is meant to run on a partner's OWN backend, never in a
22
+ * browser: the client secret it takes must never reach client-side code. See
23
+ * `README.md`'s "Embedding for enterprise tenants" section for the worked
24
+ * route this is designed to sit behind.
25
+ *
26
+ * @module
27
+ */
28
+ import { type FetchLike } from "../config.ts";
29
+ /** Options for {@linkcode exchangeToken}. */
30
+ export interface ExchangeTokenOptions {
31
+ /**
32
+ * The w6w server's origin, e.g. `https://api.example.com`. Same rules as
33
+ * {@linkcode W6WClientOptions.baseUrl} — an absolute `http(s)` URL with a
34
+ * host.
35
+ */
36
+ baseUrl: string;
37
+ /** The tenant's client id. Must not contain `:` or a non-latin-1 character. */
38
+ clientId: string;
39
+ /** The tenant's client secret. Must be latin-1 encodable. */
40
+ clientSecret: string;
41
+ /**
42
+ * The partner's end-user id. Minted into the returned token's `sub` claim
43
+ * verbatim — this function does not validate or canonicalise it.
44
+ */
45
+ subject: string;
46
+ /**
47
+ * Optional account claim. **Trusted verbatim**: the server mints whatever
48
+ * `account` it is given into the token, so the caller — this function's own
49
+ * caller, on the partner's backend — is responsible for deriving it from
50
+ * ITS OWN membership data, never from an unauthenticated client input. See
51
+ * `README.md`'s embedding example.
52
+ */
53
+ account?: string;
54
+ /** Transport override. Defaults to `globalThis.fetch`, bound. */
55
+ fetch?: FetchLike;
56
+ }
57
+ /** The shape `POST /auth/exchange` answers with on success. */
58
+ export interface ExchangeTokenResult {
59
+ /** The minted, short-lived bearer token. */
60
+ token: string;
61
+ /** The identity the token carries. */
62
+ user: {
63
+ /** The `subject` this call passed, echoed back. */
64
+ subject: string;
65
+ /** The tenant the client credentials resolved to. */
66
+ tenant: string;
67
+ /** Always `"user"` for a token minted this way. */
68
+ role: string;
69
+ /** The resolved account claim — the `account` passed, or the tenant id when omitted. */
70
+ account: string;
71
+ };
72
+ /** Token lifetime, in seconds. */
73
+ expiresIn: number;
74
+ }
75
+ /**
76
+ * Exchange a tenant's client credentials for a short-lived, per-user w6w
77
+ * token: `POST /auth/exchange`.
78
+ *
79
+ * Credentials travel ONLY as `Authorization: Basic base64(clientId:clientSecret)`
80
+ * — never in the body, the URL or a query string. The body sent is exactly
81
+ * `{ subject }`, or `{ subject, account }` when `account` is given; omitting
82
+ * `account` never puts the key in the body at all (not even as `null` or
83
+ * `undefined`).
84
+ *
85
+ * Every validation failure below is a local {@linkcode ConfigError}, raised
86
+ * **before any network call**, and none of them ever echo `clientSecret`.
87
+ *
88
+ * @param options - See {@linkcode ExchangeTokenOptions}.
89
+ * @returns The minted token and the identity it carries.
90
+ * @throws {ConfigError} Blank `clientId`/`clientSecret`/`subject`; a `clientId`
91
+ * containing `:`; a `clientId`/`clientSecret` outside latin-1; no base URL;
92
+ * no runtime `fetch`.
93
+ * @throws {ApiError} `invalid_client` (401, unknown/disabled credentials),
94
+ * `invalid_body` / `invalid_subject` / `invalid_account` (400), or any of
95
+ * the transport's own failure modes (`../http.ts`). Never retried: this
96
+ * call always passes `requireAuth: false`, which `request()` never grants a
97
+ * recovery attempt.
98
+ */
99
+ export declare function exchangeToken(options: ExchangeTokenOptions): Promise<ExchangeTokenResult>;
100
+ //# sourceMappingURL=mod.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../../../src/server/mod.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,EAAE,KAAK,SAAS,EAAiB,MAAM,cAAc,CAAC;AAI7D,6CAA6C;AAC7C,MAAM,WAAW,oBAAoB;IACnC;;;;OAIG;IACH,OAAO,EAAE,MAAM,CAAC;IAChB,+EAA+E;IAC/E,QAAQ,EAAE,MAAM,CAAC;IACjB,6DAA6D;IAC7D,YAAY,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,OAAO,EAAE,MAAM,CAAC;IAChB;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iEAAiE;IACjE,KAAK,CAAC,EAAE,SAAS,CAAC;CACnB;AAED,+DAA+D;AAC/D,MAAM,WAAW,mBAAmB;IAClC,4CAA4C;IAC5C,KAAK,EAAE,MAAM,CAAC;IACd,sCAAsC;IACtC,IAAI,EAAE;QACJ,mDAAmD;QACnD,OAAO,EAAE,MAAM,CAAC;QAChB,qDAAqD;QACrD,MAAM,EAAE,MAAM,CAAC;QACf,mDAAmD;QACnD,IAAI,EAAE,MAAM,CAAC;QACb,wFAAwF;QACxF,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC;IACF,kCAAkC;IAClC,SAAS,EAAE,MAAM,CAAC;CACnB;AAsDD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAsB,aAAa,CACjC,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,mBAAmB,CAAC,CAwB9B"}
@@ -0,0 +1,121 @@
1
+ /**
2
+ * `@w6w/sdk/server` — a backend-only token exchange, for a partner embedding
3
+ * w6w inside its own product.
4
+ *
5
+ * A **separate** entry point from the package root (`@w6w/sdk`) and from
6
+ * `@w6w/sdk/console`: deliberately excluded from `endpoints.json`'s
7
+ * `operations[]` and from the root barrel (`../../mod.ts`), documented
8
+ * instead in `docs/sdk-surface.md` (R-5). Nothing here is reachable from
9
+ * either of those entry points, and this module imports nothing from
10
+ * `../console/mod.ts`.
11
+ *
12
+ * **Egress / trust boundary.** {@linkcode exchangeToken} sends a tenant's
13
+ * client secret over the wire, once per call, and only as an HTTP Basic
14
+ * credential — never in the body, the URL or a query string. It is built on
15
+ * the package's existing transport (`../http.ts`'s `request`, `../config.ts`'s
16
+ * `resolveConfig`) with `requireAuth: false` — the same escape hatch
17
+ * `console.auth.login` uses for a route that authenticates itself rather than
18
+ * via a bearer — so this is a thin caller of the one HTTP path this package
19
+ * has, never a second one.
20
+ *
21
+ * This function is meant to run on a partner's OWN backend, never in a
22
+ * browser: the client secret it takes must never reach client-side code. See
23
+ * `README.md`'s "Embedding for enterprise tenants" section for the worked
24
+ * route this is designed to sit behind.
25
+ *
26
+ * @module
27
+ */
28
+ import { resolveConfig } from "../config.js";
29
+ import { ConfigError } from "../errors.js";
30
+ import { request } from "../http.js";
31
+ /** Non-blank after trimming. */
32
+ function required(value, field) {
33
+ if (value.trim().length === 0) {
34
+ throw new ConfigError(`exchangeToken: \`${field}\` must not be blank.`);
35
+ }
36
+ }
37
+ /**
38
+ * Base64-encode `clientId:clientSecret` the way the server decodes it:
39
+ * latin-1 (`atob`'s own alphabet), via `btoa`.
40
+ *
41
+ * `btoa` itself rejects any character outside latin-1 (U+0000–U+00FF),
42
+ * raising for us — this is NOT re-implemented with a UTF-8 path, because that
43
+ * would silently encode a secret the server's `atob` could never decode back
44
+ * to the same bytes.
45
+ *
46
+ * @throws {ConfigError} When `clientId` contains `:` (indistinguishable from
47
+ * the Basic separator on decode) or either value is not latin-1.
48
+ */
49
+ function basicAuthHeader(clientId, clientSecret) {
50
+ if (clientId.includes(":")) {
51
+ throw new ConfigError('exchangeToken: `clientId` must not contain ":" — the server splits a ' +
52
+ "decoded Basic credential on the FIRST colon, so a colon in `clientId` " +
53
+ "would be read as part of the secret instead.");
54
+ }
55
+ try {
56
+ return btoa(`${clientId}:${clientSecret}`);
57
+ }
58
+ catch {
59
+ throw new ConfigError("exchangeToken: `clientId`/`clientSecret` must be representable as " +
60
+ "latin-1 (ISO-8859-1) — the server decodes the Basic header with " +
61
+ "`atob`, which cannot represent a wider character set.");
62
+ }
63
+ }
64
+ function resolveFetch(fetchOption) {
65
+ if (fetchOption)
66
+ return fetchOption;
67
+ const global = globalThis.fetch;
68
+ if (typeof global !== "function") {
69
+ throw new ConfigError("This runtime has no global fetch. Pass an implementation " +
70
+ "(exchangeToken({ ..., fetch })) or run on Node 18+, Deno or Bun.");
71
+ }
72
+ // Bound, so it keeps working when called as a bare function reference —
73
+ // exactly W6WClient's own default (../client.ts).
74
+ return global.bind(globalThis);
75
+ }
76
+ /**
77
+ * Exchange a tenant's client credentials for a short-lived, per-user w6w
78
+ * token: `POST /auth/exchange`.
79
+ *
80
+ * Credentials travel ONLY as `Authorization: Basic base64(clientId:clientSecret)`
81
+ * — never in the body, the URL or a query string. The body sent is exactly
82
+ * `{ subject }`, or `{ subject, account }` when `account` is given; omitting
83
+ * `account` never puts the key in the body at all (not even as `null` or
84
+ * `undefined`).
85
+ *
86
+ * Every validation failure below is a local {@linkcode ConfigError}, raised
87
+ * **before any network call**, and none of them ever echo `clientSecret`.
88
+ *
89
+ * @param options - See {@linkcode ExchangeTokenOptions}.
90
+ * @returns The minted token and the identity it carries.
91
+ * @throws {ConfigError} Blank `clientId`/`clientSecret`/`subject`; a `clientId`
92
+ * containing `:`; a `clientId`/`clientSecret` outside latin-1; no base URL;
93
+ * no runtime `fetch`.
94
+ * @throws {ApiError} `invalid_client` (401, unknown/disabled credentials),
95
+ * `invalid_body` / `invalid_subject` / `invalid_account` (400), or any of
96
+ * the transport's own failure modes (`../http.ts`). Never retried: this
97
+ * call always passes `requireAuth: false`, which `request()` never grants a
98
+ * recovery attempt.
99
+ */
100
+ export async function exchangeToken(options) {
101
+ const { baseUrl, clientId, clientSecret, subject, account } = options;
102
+ required(clientId, "clientId");
103
+ required(clientSecret, "clientSecret");
104
+ required(subject, "subject");
105
+ const basic = basicAuthHeader(clientId, clientSecret);
106
+ const config = resolveConfig({ baseUrl });
107
+ const fetchImpl = resolveFetch(options.fetch);
108
+ const body = { subject };
109
+ if (account !== undefined) {
110
+ body.account = account;
111
+ }
112
+ const res = await request(config, fetchImpl, {
113
+ method: "POST",
114
+ path: "/auth/exchange",
115
+ body,
116
+ headers: { authorization: `Basic ${basic}` },
117
+ requireAuth: false,
118
+ });
119
+ return res.body;
120
+ }
121
+ //# sourceMappingURL=mod.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mod.js","sourceRoot":"","sources":["../../../src/server/mod.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,EAAkB,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7D,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAkDrC,gCAAgC;AAChC,SAAS,QAAQ,CAAC,KAAa,EAAE,KAAa;IAC5C,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC9B,MAAM,IAAI,WAAW,CAAC,oBAAoB,KAAK,uBAAuB,CAAC,CAAC;IAC1E,CAAC;AACH,CAAC;AAED;;;;;;;;;;;GAWG;AACH,SAAS,eAAe,CAAC,QAAgB,EAAE,YAAoB;IAC7D,IAAI,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QAC3B,MAAM,IAAI,WAAW,CACnB,uEAAuE;YACrE,wEAAwE;YACxE,8CAA8C,CACjD,CAAC;IACJ,CAAC;IACD,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,GAAG,QAAQ,IAAI,YAAY,EAAE,CAAC,CAAC;IAC7C,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,WAAW,CACnB,oEAAoE;YAClE,kEAAkE;YAClE,uDAAuD,CAC1D,CAAC;IACJ,CAAC;AACH,CAAC;AAED,SAAS,YAAY,CAAC,WAAkC;IACtD,IAAI,WAAW;QAAE,OAAO,WAAW,CAAC;IACpC,MAAM,MAAM,GAAG,UAAU,CAAC,KAAK,CAAC;IAChC,IAAI,OAAO,MAAM,KAAK,UAAU,EAAE,CAAC;QACjC,MAAM,IAAI,WAAW,CACnB,2DAA2D;YACzD,kEAAkE,CACrE,CAAC;IACJ,CAAC;IACD,wEAAwE;IACxE,kDAAkD;IAClD,OAAO,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;AACjC,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,OAA6B;IAE7B,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC;IAEtE,QAAQ,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;IAC/B,QAAQ,CAAC,YAAY,EAAE,cAAc,CAAC,CAAC;IACvC,QAAQ,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;IAC7B,MAAM,KAAK,GAAG,eAAe,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;IAEtD,MAAM,MAAM,GAAG,aAAa,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC;IAC1C,MAAM,SAAS,GAAG,YAAY,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAE9C,MAAM,IAAI,GAA0C,EAAE,OAAO,EAAE,CAAC;IAChE,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;QAC1B,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,CAAC;IAED,MAAM,GAAG,GAAG,MAAM,OAAO,CAAsB,MAAM,EAAE,SAAS,EAAE;QAChE,MAAM,EAAE,MAAM;QACd,IAAI,EAAE,gBAAgB;QACtB,IAAI;QACJ,OAAO,EAAE,EAAE,aAAa,EAAE,SAAS,KAAK,EAAE,EAAE;QAC5C,WAAW,EAAE,KAAK;KACnB,CAAC,CAAC;IACH,OAAO,GAAG,CAAC,IAAI,CAAC;AAClB,CAAC"}
@@ -0,0 +1,204 @@
1
+ /**
2
+ * `client.team.*` — the caller's account team, self-service.
3
+ *
4
+ * Six operations, one HTTP call each: list the roster, invite someone (or mint
5
+ * an open, shareable invite link), list open invites, revoke one, change a
6
+ * member's role, remove a member. Nothing here composes two requests or
7
+ * filters a list client-side — `team.invites()` returns only OPEN invites
8
+ * because the **server** filters them, not because this module scans the
9
+ * account's whole invite history and drops the closed ones
10
+ * (`docs/implementation.md`'s "what a wrapper is" rule, mirrored from
11
+ * `documents.ts`'s header).
12
+ *
13
+ * **Not project-scoped.** Team membership is an account-wide concept, so
14
+ * (unlike `documents`) this namespace carries no `?project=` anywhere and is
15
+ * handed the transport only — the same narrow host `connections.ts` and
16
+ * `vars.ts` use, so a caller cannot even accidentally reach a default project
17
+ * to send.
18
+ *
19
+ * `docs/team.md`'s pinned wire contract (mirrored in this task's `plan.md`
20
+ * §"Pinned wire contract") is the source these six methods transcribe:
21
+ *
22
+ * ```
23
+ * GET /me/account/members → 200 { members: TeamMember[] }
24
+ * POST /me/account/invites { email?, role? } → 201 { invite: TeamInviteWithLink }
25
+ * GET /me/account/invites → 200 { invites: TeamInvite[] }
26
+ * DELETE /me/account/invites/:id → 200 { ok: true }
27
+ * PATCH /me/account/members/:userId { role } → 200 { member: TeamMember }
28
+ * DELETE /me/account/members/:userId → 200 { ok: true }
29
+ * ```
30
+ *
31
+ * This module implements the client half of the server's live
32
+ * `/me/account/...` routes (`endpoints.json`: `status: "required"` for each).
33
+ * Calling any of these against a server that has not shipped T1.2.1 yet
34
+ * answers `404`, which reaches the caller as an ordinary `ApiError`.
35
+ *
36
+ * @module
37
+ */
38
+ import { type HttpResponse, type RequestOptions } from "./http.ts";
39
+ /**
40
+ * The slice of `W6WClient` this namespace needs: the transport, and nothing
41
+ * else. Team operations carry no per-call scope to resolve, so — as with
42
+ * `connections` and `vars` — this host cannot reach the client's
43
+ * configuration even by accident.
44
+ */
45
+ export interface TeamHost {
46
+ /** Perform one request. */
47
+ request<T>(options: RequestOptions): Promise<HttpResponse<T>>;
48
+ }
49
+ /**
50
+ * One member of the caller's account team, as the roster projects it.
51
+ *
52
+ * `email`/`displayName` are nullable rather than defaulted to `""`: a member
53
+ * whose profile carries neither is a real, distinct state (a machine
54
+ * principal, or a user who has set up neither) and flattening it to an empty
55
+ * string would make "no display name" indistinguishable from "the server sent
56
+ * an empty one".
57
+ */
58
+ export interface TeamMember {
59
+ /** The member's `usr_…` id — addresses `setRole` and `removeMember`. */
60
+ userId: string;
61
+ /** The member's email, or `null` when the profile carries none. */
62
+ email: string | null;
63
+ /** The member's display name, or `null` when unset. */
64
+ displayName: string | null;
65
+ /** The member's role within the account, e.g. `"owner"`, `"admin"`, `"member"`. */
66
+ role: string;
67
+ /** ISO-8601 timestamp: when this membership began. */
68
+ createdAt: string;
69
+ }
70
+ /**
71
+ * One invite, as `team.invites()` lists it.
72
+ *
73
+ * Deliberately carries no `token` — see {@linkcode TeamInviteWithLink}, the
74
+ * only response that does, and only once.
75
+ */
76
+ export interface TeamInvite {
77
+ /** The invite's own id — addresses `revokeInvite`. */
78
+ id: string;
79
+ /** The account this invite joins. */
80
+ account: string;
81
+ /** The invited email, or `null` for an open (link-only) invite. */
82
+ email: string | null;
83
+ /** The role the invite grants on redemption, or `null` (server defaults to `"member"`). */
84
+ role: string | null;
85
+ /** ISO-8601 expiry, or `null` for an invite that does not expire. */
86
+ expiresAt: string | null;
87
+ /** ISO-8601 timestamp: when this invite was created. */
88
+ createdAt: string;
89
+ }
90
+ /**
91
+ * What `team.invite()` returns: a {@linkcode TeamInvite} plus the redemption
92
+ * material, present **only** in this one response.
93
+ *
94
+ * The server never re-sends `token` or `redemptionLink` from any other route
95
+ * — `team.invites()` lists the invite without them — so a caller that drops
96
+ * this return value cannot recover it and must revoke and re-invite instead.
97
+ */
98
+ export interface TeamInviteWithLink extends TeamInvite {
99
+ /** The plaintext redemption token. Shown once. */
100
+ token: string;
101
+ /** The ready-to-share redemption URL, built around `token`. Shown once. */
102
+ redemptionLink: string;
103
+ }
104
+ /**
105
+ * The body of `team.invite()`.
106
+ *
107
+ * Both fields are optional: an omitted `email` mints an OPEN invite (a
108
+ * shareable link with no target address), and an omitted `role` defaults
109
+ * server-side to `"member"`. `"owner"` is refused — there is no self-service
110
+ * path to a second owner.
111
+ */
112
+ export interface TeamInviteInput {
113
+ /** The address to invite. Omitted for an open, shareable invite. */
114
+ email?: string;
115
+ /** The role the invite grants on redemption. Omitted defaults to `"member"`. */
116
+ role?: string;
117
+ }
118
+ /**
119
+ * The `team` namespace on a `W6WClient`.
120
+ *
121
+ * @example
122
+ * ```ts
123
+ * const members = await client.team.members();
124
+ * const { redemptionLink } = await client.team.invite({ role: "admin" });
125
+ * await client.team.setRole(members[0].userId, "admin");
126
+ * ```
127
+ */
128
+ export declare class TeamApi {
129
+ #private;
130
+ /**
131
+ * @param host - The client this namespace issues requests through.
132
+ */
133
+ constructor(host: TeamHost);
134
+ /**
135
+ * List the caller's account team.
136
+ *
137
+ * Member-readable: any active member of the account may call this,
138
+ * regardless of role — only the write operations below require
139
+ * `canManageMembers`.
140
+ *
141
+ * @returns The team, unwrapped from the `members` envelope.
142
+ * @throws {ApiError} On any non-2xx.
143
+ */
144
+ members(): Promise<TeamMember[]>;
145
+ /**
146
+ * Invite someone to the account, or mint an open, shareable invite link.
147
+ *
148
+ * @param input - `email` and `role`, both optional.
149
+ * @returns The created invite, including its one-time `token` and `redemptionLink`.
150
+ * @throws {ApiError} `403 forbidden` without `canManageMembers`.
151
+ * @throws {ApiError} `400 invalid_role` for `role: "owner"` or an unrecognised role.
152
+ */
153
+ invite(input?: TeamInviteInput): Promise<TeamInviteWithLink>;
154
+ /**
155
+ * List the account's open (pending, unrevoked, unexpired) invites.
156
+ *
157
+ * The filtering happens server-side — this is one `GET`, never a
158
+ * list-then-filter over the account's whole invite history.
159
+ *
160
+ * @returns The open invites, unwrapped from the `invites` envelope.
161
+ * @throws {ApiError} `403 forbidden` without `canManageMembers`.
162
+ */
163
+ invites(): Promise<TeamInvite[]>;
164
+ /**
165
+ * Revoke a pending invite before it is redeemed.
166
+ *
167
+ * Not idempotent: revoking an invite that is already used or already
168
+ * revoked is a rejected request, not a silent success.
169
+ *
170
+ * @param id - The invite's own id (see: `team.invites()`).
171
+ * @throws {ApiError} `403 forbidden` without `canManageMembers`.
172
+ * @throws {ApiError} `404 invite_not_found` for an unknown id.
173
+ * @throws {ApiError} `409 invite_not_open` when it was already used or revoked.
174
+ */
175
+ revokeInvite(id: string): Promise<void>;
176
+ /**
177
+ * Change a team member's role.
178
+ *
179
+ * @param userId - The member's `usr_…` id (see: `team.members()`).
180
+ * @param role - The role to set.
181
+ * @returns The updated member.
182
+ * @throws {ApiError} `403 forbidden` without `canManageMembers`.
183
+ * @throws {ApiError} `403 cannot_change_owner_role` for `role: "owner"` or when
184
+ * `userId` is the account's current owner — there is no self-service ownership transfer.
185
+ * @throws {ApiError} `400 invalid_role` for an unrecognised role.
186
+ * @throws {ApiError} `404 member_not_found` for an unknown `userId`.
187
+ */
188
+ setRole(userId: string, role: string): Promise<TeamMember>;
189
+ /**
190
+ * Remove a member from the account.
191
+ *
192
+ * Tombstones the membership server-side rather than deleting it outright
193
+ * (D-R3), but that is a server implementation detail this method does not
194
+ * surface — it returns nothing, the same pin as `documents.delete`.
195
+ *
196
+ * @param userId - The member's `usr_…` id (see: `team.members()`).
197
+ * @throws {ApiError} `403 forbidden` without `canManageMembers`.
198
+ * @throws {ApiError} `403 cannot_remove_owner` when `userId` is the account's owner.
199
+ * @throws {ApiError} `404 member_not_found` for an unknown `userId`.
200
+ * @throws {ApiError} `409 last_member` when `userId` is the account's only active member.
201
+ */
202
+ removeMember(userId: string): Promise<void>;
203
+ }
204
+ //# sourceMappingURL=team.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"team.d.ts","sourceRoot":"","sources":["../../src/team.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAEH,OAAO,EAAE,KAAK,YAAY,EAAQ,KAAK,cAAc,EAAE,MAAM,WAAW,CAAC;AAGzE;;;;;GAKG;AACH,MAAM,WAAW,QAAQ;IACvB,2BAA2B;IAC3B,OAAO,CAAC,CAAC,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC;CAC/D;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,UAAU;IACzB,wEAAwE;IACxE,MAAM,EAAE,MAAM,CAAC;IACf,mEAAmE;IACnE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,uDAAuD;IACvD,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,mFAAmF;IACnF,IAAI,EAAE,MAAM,CAAC;IACb,sDAAsD;IACtD,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;;GAKG;AACH,MAAM,WAAW,UAAU;IACzB,sDAAsD;IACtD,EAAE,EAAE,MAAM,CAAC;IACX,qCAAqC;IACrC,OAAO,EAAE,MAAM,CAAC;IAChB,mEAAmE;IACnE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,2FAA2F;IAC3F,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,qEAAqE;IACrE,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,wDAAwD;IACxD,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,kBAAmB,SAAQ,UAAU;IACpD,kDAAkD;IAClD,KAAK,EAAE,MAAM,CAAC;IACd,2EAA2E;IAC3E,cAAc,EAAE,MAAM,CAAC;CACxB;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,eAAe;IAC9B,oEAAoE;IACpE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gFAAgF;IAChF,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;;;;;;GASG;AACH,qBAAa,OAAO;;IAGlB;;OAEG;gBACS,IAAI,EAAE,QAAQ;IAI1B;;;;;;;;;OASG;IACG,OAAO,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;IAKtC;;;;;;;OAOG;IACG,MAAM,CAAC,KAAK,GAAE,eAAoB,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAYtE;;;;;;;;OAQG;IACG,OAAO,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;IAKtC;;;;;;;;;;OAUG;IACG,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAO7C;;;;;;;;;;;OAWG;IACG,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAShE;;;;;;;;;;;;OAYG;IACG,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAMlD"}
@@ -0,0 +1,161 @@
1
+ /**
2
+ * `client.team.*` — the caller's account team, self-service.
3
+ *
4
+ * Six operations, one HTTP call each: list the roster, invite someone (or mint
5
+ * an open, shareable invite link), list open invites, revoke one, change a
6
+ * member's role, remove a member. Nothing here composes two requests or
7
+ * filters a list client-side — `team.invites()` returns only OPEN invites
8
+ * because the **server** filters them, not because this module scans the
9
+ * account's whole invite history and drops the closed ones
10
+ * (`docs/implementation.md`'s "what a wrapper is" rule, mirrored from
11
+ * `documents.ts`'s header).
12
+ *
13
+ * **Not project-scoped.** Team membership is an account-wide concept, so
14
+ * (unlike `documents`) this namespace carries no `?project=` anywhere and is
15
+ * handed the transport only — the same narrow host `connections.ts` and
16
+ * `vars.ts` use, so a caller cannot even accidentally reach a default project
17
+ * to send.
18
+ *
19
+ * `docs/team.md`'s pinned wire contract (mirrored in this task's `plan.md`
20
+ * §"Pinned wire contract") is the source these six methods transcribe:
21
+ *
22
+ * ```
23
+ * GET /me/account/members → 200 { members: TeamMember[] }
24
+ * POST /me/account/invites { email?, role? } → 201 { invite: TeamInviteWithLink }
25
+ * GET /me/account/invites → 200 { invites: TeamInvite[] }
26
+ * DELETE /me/account/invites/:id → 200 { ok: true }
27
+ * PATCH /me/account/members/:userId { role } → 200 { member: TeamMember }
28
+ * DELETE /me/account/members/:userId → 200 { ok: true }
29
+ * ```
30
+ *
31
+ * This module implements the client half of the server's live
32
+ * `/me/account/...` routes (`endpoints.json`: `status: "required"` for each).
33
+ * Calling any of these against a server that has not shipped T1.2.1 yet
34
+ * answers `404`, which reaches the caller as an ordinary `ApiError`.
35
+ *
36
+ * @module
37
+ */
38
+ import { path } from "./http.js";
39
+ import { unwrap } from "./types.js";
40
+ /**
41
+ * The `team` namespace on a `W6WClient`.
42
+ *
43
+ * @example
44
+ * ```ts
45
+ * const members = await client.team.members();
46
+ * const { redemptionLink } = await client.team.invite({ role: "admin" });
47
+ * await client.team.setRole(members[0].userId, "admin");
48
+ * ```
49
+ */
50
+ export class TeamApi {
51
+ #host;
52
+ /**
53
+ * @param host - The client this namespace issues requests through.
54
+ */
55
+ constructor(host) {
56
+ this.#host = host;
57
+ }
58
+ /**
59
+ * List the caller's account team.
60
+ *
61
+ * Member-readable: any active member of the account may call this,
62
+ * regardless of role — only the write operations below require
63
+ * `canManageMembers`.
64
+ *
65
+ * @returns The team, unwrapped from the `members` envelope.
66
+ * @throws {ApiError} On any non-2xx.
67
+ */
68
+ async members() {
69
+ const res = await this.#host.request({ method: "GET", path: "/me/account/members" });
70
+ return unwrap(res, "members");
71
+ }
72
+ /**
73
+ * Invite someone to the account, or mint an open, shareable invite link.
74
+ *
75
+ * @param input - `email` and `role`, both optional.
76
+ * @returns The created invite, including its one-time `token` and `redemptionLink`.
77
+ * @throws {ApiError} `403 forbidden` without `canManageMembers`.
78
+ * @throws {ApiError} `400 invalid_role` for `role: "owner"` or an unrecognised role.
79
+ */
80
+ async invite(input = {}) {
81
+ const res = await this.#host.request({
82
+ method: "POST",
83
+ path: "/me/account/invites",
84
+ // Assembled field by field, exactly the two documented fields: an
85
+ // `undefined` one is dropped by JSON serialisation rather than sent as
86
+ // an explicit `null`.
87
+ body: { email: input.email, role: input.role },
88
+ });
89
+ return unwrap(res, "invite");
90
+ }
91
+ /**
92
+ * List the account's open (pending, unrevoked, unexpired) invites.
93
+ *
94
+ * The filtering happens server-side — this is one `GET`, never a
95
+ * list-then-filter over the account's whole invite history.
96
+ *
97
+ * @returns The open invites, unwrapped from the `invites` envelope.
98
+ * @throws {ApiError} `403 forbidden` without `canManageMembers`.
99
+ */
100
+ async invites() {
101
+ const res = await this.#host.request({ method: "GET", path: "/me/account/invites" });
102
+ return unwrap(res, "invites");
103
+ }
104
+ /**
105
+ * Revoke a pending invite before it is redeemed.
106
+ *
107
+ * Not idempotent: revoking an invite that is already used or already
108
+ * revoked is a rejected request, not a silent success.
109
+ *
110
+ * @param id - The invite's own id (see: `team.invites()`).
111
+ * @throws {ApiError} `403 forbidden` without `canManageMembers`.
112
+ * @throws {ApiError} `404 invite_not_found` for an unknown id.
113
+ * @throws {ApiError} `409 invite_not_open` when it was already used or revoked.
114
+ */
115
+ async revokeInvite(id) {
116
+ await this.#host.request({
117
+ method: "DELETE",
118
+ path: path `/me/account/invites/${id}`,
119
+ });
120
+ }
121
+ /**
122
+ * Change a team member's role.
123
+ *
124
+ * @param userId - The member's `usr_…` id (see: `team.members()`).
125
+ * @param role - The role to set.
126
+ * @returns The updated member.
127
+ * @throws {ApiError} `403 forbidden` without `canManageMembers`.
128
+ * @throws {ApiError} `403 cannot_change_owner_role` for `role: "owner"` or when
129
+ * `userId` is the account's current owner — there is no self-service ownership transfer.
130
+ * @throws {ApiError} `400 invalid_role` for an unrecognised role.
131
+ * @throws {ApiError} `404 member_not_found` for an unknown `userId`.
132
+ */
133
+ async setRole(userId, role) {
134
+ const res = await this.#host.request({
135
+ method: "PATCH",
136
+ path: path `/me/account/members/${userId}`,
137
+ body: { role },
138
+ });
139
+ return unwrap(res, "member");
140
+ }
141
+ /**
142
+ * Remove a member from the account.
143
+ *
144
+ * Tombstones the membership server-side rather than deleting it outright
145
+ * (D-R3), but that is a server implementation detail this method does not
146
+ * surface — it returns nothing, the same pin as `documents.delete`.
147
+ *
148
+ * @param userId - The member's `usr_…` id (see: `team.members()`).
149
+ * @throws {ApiError} `403 forbidden` without `canManageMembers`.
150
+ * @throws {ApiError} `403 cannot_remove_owner` when `userId` is the account's owner.
151
+ * @throws {ApiError} `404 member_not_found` for an unknown `userId`.
152
+ * @throws {ApiError} `409 last_member` when `userId` is the account's only active member.
153
+ */
154
+ async removeMember(userId) {
155
+ await this.#host.request({
156
+ method: "DELETE",
157
+ path: path `/me/account/members/${userId}`,
158
+ });
159
+ }
160
+ }
161
+ //# sourceMappingURL=team.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"team.js","sourceRoot":"","sources":["../../src/team.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAEH,OAAO,EAAqB,IAAI,EAAuB,MAAM,WAAW,CAAC;AACzE,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAsFpC;;;;;;;;;GASG;AACH,MAAM,OAAO,OAAO;IACT,KAAK,CAAW;IAEzB;;OAEG;IACH,YAAY,IAAc;QACxB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;IACpB,CAAC;IAED;;;;;;;;;OASG;IACH,KAAK,CAAC,OAAO;QACX,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,CAAU,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,qBAAqB,EAAE,CAAC,CAAC;QAC9F,OAAO,MAAM,CAAe,GAAG,EAAE,SAAS,CAAC,CAAC;IAC9C,CAAC;IAED;;;;;;;OAOG;IACH,KAAK,CAAC,MAAM,CAAC,QAAyB,EAAE;QACtC,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,CAAU;YAC5C,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,qBAAqB;YAC3B,kEAAkE;YAClE,uEAAuE;YACvE,sBAAsB;YACtB,IAAI,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE;SAC/C,CAAC,CAAC;QACH,OAAO,MAAM,CAAqB,GAAG,EAAE,QAAQ,CAAC,CAAC;IACnD,CAAC;IAED;;;;;;;;OAQG;IACH,KAAK,CAAC,OAAO;QACX,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,CAAU,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,qBAAqB,EAAE,CAAC,CAAC;QAC9F,OAAO,MAAM,CAAe,GAAG,EAAE,SAAS,CAAC,CAAC;IAC9C,CAAC;IAED;;;;;;;;;;OAUG;IACH,KAAK,CAAC,YAAY,CAAC,EAAU;QAC3B,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,CAAU;YAChC,MAAM,EAAE,QAAQ;YAChB,IAAI,EAAE,IAAI,CAAA,uBAAuB,EAAE,EAAE;SACtC,CAAC,CAAC;IACL,CAAC;IAED;;;;;;;;;;;OAWG;IACH,KAAK,CAAC,OAAO,CAAC,MAAc,EAAE,IAAY;QACxC,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,CAAU;YAC5C,MAAM,EAAE,OAAO;YACf,IAAI,EAAE,IAAI,CAAA,uBAAuB,MAAM,EAAE;YACzC,IAAI,EAAE,EAAE,IAAI,EAAE;SACf,CAAC,CAAC;QACH,OAAO,MAAM,CAAa,GAAG,EAAE,QAAQ,CAAC,CAAC;IAC3C,CAAC;IAED;;;;;;;;;;;;OAYG;IACH,KAAK,CAAC,YAAY,CAAC,MAAc;QAC/B,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,CAAU;YAChC,MAAM,EAAE,QAAQ;YAChB,IAAI,EAAE,IAAI,CAAA,uBAAuB,MAAM,EAAE;SAC1C,CAAC,CAAC;IACL,CAAC;CACF"}