@domino-sdk/relay 1.61.0 → 1.62.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 (80) hide show
  1. package/CHANGELOG.md +156 -8
  2. package/README.md +3 -2
  3. package/dist/{schema-CZ6Rj0ZF.d.ts → accounts-CCqCKCVx.d.ts} +3127 -1764
  4. package/dist/action-9Xl0StBg.d.ts +33 -0
  5. package/dist/{integrations-B3y36OaB.d.ts → analytics-BwAKLi7O.d.ts} +347 -57
  6. package/dist/{attempt-captures-DYnJVkfg.d.ts → attempt-captures-Cm-5G0PC.d.ts} +1 -1
  7. package/dist/authoring.d.ts +130 -42
  8. package/dist/authoring.js +112 -37
  9. package/dist/{automatic-outcomes-If88LR9f.d.ts → automatic-outcomes-pAsOyIVp.d.ts} +5 -1
  10. package/dist/avatar.d.ts +1 -1
  11. package/dist/browser.d.ts +15 -11
  12. package/dist/browser.js +15 -11
  13. package/dist/{announcements-CHx3-HBw.d.ts → capability-error-DFMwSuSf.d.ts} +161 -4
  14. package/dist/{pages-K7-KjSXw.d.ts → catalog--ZIlskAo.d.ts} +39 -561
  15. package/dist/{chunk-DYXDZFKA.js → chunk-3KLC4AMA.js} +37 -11
  16. package/dist/{chunk-XBV2CK2H.js → chunk-3PYYGFSB.js} +14 -2
  17. package/dist/{chunk-RHBS5FJL.js → chunk-5TEYFX6X.js} +2 -2
  18. package/dist/chunk-6WCIWXUV.js +31 -0
  19. package/dist/chunk-CICDIBOF.js +373 -0
  20. package/dist/{chunk-MHPKEVEW.js → chunk-CZFXGGEK.js} +5 -0
  21. package/dist/chunk-D26YNACF.js +320 -0
  22. package/dist/{chunk-5I54XBK2.js → chunk-E6IKQHTX.js} +2 -2
  23. package/dist/chunk-FWLQ5XCS.js +21 -0
  24. package/dist/{chunk-SKGTNTLF.js → chunk-GKIFABGN.js} +150 -61
  25. package/dist/chunk-GTDW453U.js +522 -0
  26. package/dist/{chunk-VURRFVNP.js → chunk-HTZHBTIL.js} +69 -27
  27. package/dist/chunk-K2KS3JLY.js +188 -0
  28. package/dist/{chunk-ZDJLPN4L.js → chunk-MK425RXJ.js} +3143 -3209
  29. package/dist/{chunk-L77O64I4.js → chunk-QYPMPWVX.js} +1 -1
  30. package/dist/chunk-UAKYDVT3.js +565 -0
  31. package/dist/{chunk-DHXDBAJF.js → chunk-UPQPUJOU.js} +36 -123
  32. package/dist/{chunk-24I4R732.js → chunk-UW5232GG.js} +34 -19
  33. package/dist/chunk-WSBYWVTZ.js +717 -0
  34. package/dist/{chunk-PPB7HALD.js → chunk-XJFYAXET.js} +9 -8
  35. package/dist/{chunk-7A4J67ZL.js → chunk-XNKSSE32.js} +1 -1
  36. package/dist/{chunk-QEAS4ZGS.js → chunk-Y322OTCH.js} +1 -1
  37. package/dist/{client-C51w7fMb.d.ts → client-B-hbHX30.d.ts} +109 -40
  38. package/dist/{deployments-kWoHFaqj.d.ts → deployments-M4OHn7G3.d.ts} +407 -18
  39. package/dist/identity-integration-3mX6b5iH.d.ts +1241 -0
  40. package/dist/index.d.ts +13 -11
  41. package/dist/index.js +14 -11
  42. package/dist/internal.d.ts +14 -12
  43. package/dist/internal.js +26 -14
  44. package/dist/{offers-BoV4ryUc.d.ts → offers-DhAtss4_.d.ts} +21 -4
  45. package/dist/pages-B8q8Y_dQ.d.ts +715 -0
  46. package/dist/{participant-activity-DHL8QYks.d.ts → participant-activity-D-Drp24G.d.ts} +16 -3
  47. package/dist/portal-proxy.d.ts +59 -2
  48. package/dist/portal-proxy.js +109 -23
  49. package/dist/react/index.d.ts +206 -26
  50. package/dist/react/index.js +153 -25
  51. package/dist/{action-DBzILFx9.d.ts → request-error-D_dUPLwo.d.ts} +1 -31
  52. package/dist/runtime/authoring.js +1 -1
  53. package/dist/runtime/chunks/Y4OAVXFR.js +1 -0
  54. package/dist/runtime/manifest.json +3 -3
  55. package/dist/runtime/schema.js +1 -1
  56. package/dist/schema.d.ts +154 -30
  57. package/dist/schema.js +126 -75
  58. package/dist/server/index.d.ts +14 -12
  59. package/dist/server/index.js +2137 -1633
  60. package/dist/sign-in-providers-BkjcDsFF.d.ts +39 -0
  61. package/dist/submission-input-DHGKhXfp.d.ts +342 -0
  62. package/dist/{telegram-browser-BUceZIGZ.d.ts → telegram-browser-BCE7zdOb.d.ts} +46 -6
  63. package/dist/telegram.d.ts +64 -0
  64. package/dist/telegram.js +23 -0
  65. package/dist/testing.d.ts +112 -15
  66. package/dist/testing.js +321 -16
  67. package/dist/tracker-data-Hb1uQnk5.d.ts +1855 -0
  68. package/dist/{transport-BrX9pIGN.d.ts → transport-DkhX2Cbs.d.ts} +5764 -2217
  69. package/dist/{wallet-CIqFoxdm.d.ts → wallet-DTO7SXj7.d.ts} +20 -7
  70. package/package.json +5 -1
  71. package/dist/accounts-DoabriBX.d.ts +0 -306
  72. package/dist/capability-error-DufwG3G0.d.ts +0 -159
  73. package/dist/chunk-3Y3L2F54.js +0 -982
  74. package/dist/chunk-EN3M5Z4J.js +0 -13
  75. package/dist/chunk-QNUHWK7R.js +0 -602
  76. package/dist/chunk-SE4PFJPT.js +0 -247
  77. package/dist/groups-CqcA2Ycs.d.ts +0 -2827
  78. package/dist/runtime/chunks/5QVFB4TU.js +0 -1
  79. package/dist/submission-input-C54Q8yAD.d.ts +0 -146
  80. package/dist/x-D1PGi8Sq.d.ts +0 -331
@@ -92,14 +92,23 @@ declare function sessionMember(session: {
92
92
  declare const memberSummarySchema: z.ZodObject<{
93
93
  member: z.ZodString;
94
94
  avatarSeed: z.ZodString;
95
- email: z.ZodOptional<z.ZodNullable<z.ZodString>>;
96
- emails: z.ZodOptional<z.ZodArray<z.ZodString>>;
95
+ email: z.ZodDefault<z.ZodNullable<z.ZodString>>;
96
+ emails: z.ZodDefault<z.ZodArray<z.ZodString>>;
97
97
  clock: z.ZodOptional<z.ZodObject<{
98
98
  now: z.ZodNumber;
99
99
  offsetMs: z.ZodNumber;
100
100
  }, z.core.$strip>>;
101
101
  }, z.core.$strip>;
102
- type MemberSummary = z.infer<typeof memberSummarySchema>;
102
+ type MemberSummaryResponse = z.infer<typeof memberSummarySchema>;
103
+ /** @compat output */
104
+ type MemberSummary = Omit<MemberSummaryResponse, "clock"> & {
105
+ clock: NonNullable<MemberSummaryResponse["clock"]>;
106
+ };
107
+ /**
108
+ * @deprecated `POST /v1/auth/exchange` refuses this body with 400: it takes `{ subject, accounts?,
109
+ * previousToken? }` with an identity integration server key as the bearer. Use
110
+ * `exchangeParticipant` from `@domino-sdk/relay/portal-proxy`. Removed in 2.0.0.
111
+ */
103
112
  declare const exchangeSchema: z.ZodObject<{
104
113
  organization: z.ZodString;
105
114
  project: z.ZodString;
@@ -117,6 +126,10 @@ declare const exchangeSchema: z.ZodObject<{
117
126
  operator: "operator";
118
127
  }>;
119
128
  }, z.core.$strict>;
129
+ /**
130
+ * @deprecated `POST /v1/auth/exchange` refuses this body with 400. Use `exchangeParticipant` from
131
+ * `@domino-sdk/relay/portal-proxy`. Removed in 2.0.0.
132
+ */
120
133
  type ExchangeInput = z.infer<typeof exchangeSchema>;
121
134
  declare const exchangeResultSchema: z.ZodObject<{
122
135
  token: z.ZodString;
@@ -1,3 +1,8 @@
1
+ import { M as MemberImportVouchedAccount, P as ParticipantExchangeAccountResult, d as ParticipantExchangeResult } from './identity-integration-3mX6b5iH.js';
2
+ import { R as RequestError } from './request-error-D_dUPLwo.js';
3
+ import './tracker-data-Hb1uQnk5.js';
4
+ import 'zod';
5
+
1
6
  /**
2
7
  * Server-only proxy: browser cookies stay on the participant origin.
3
8
  * The shared API resolves the app's origin to its registered preview or staging
@@ -14,14 +19,66 @@ declare function proxyParticipant(request: Request, upstream: {
14
19
  */
15
20
  hosted?: boolean;
16
21
  }): Promise<Response>;
17
- /** Use only in an app server route. authenticate must verify the app's own session. */
22
+ declare const participantExchangeErrorBrand: unique symbol;
23
+ /**
24
+ * Whether `value` is a `ParticipantExchangeError` from any copy of the SDK. Prefer it to
25
+ * `instanceof`.
26
+ */
27
+ declare function isParticipantExchangeError(value: unknown): value is ParticipantExchangeError;
28
+ /**
29
+ * An exchange Domino refused: a `RequestError` of kind `http`, with `status` and `code` as the
30
+ * exchange answered them, and `retryAfter` the milliseconds its `Retry-After` asked to wait, such
31
+ * as on a rate-limited exchange.
32
+ *
33
+ * @compat sealed
34
+ */
35
+ declare class ParticipantExchangeError extends RequestError {
36
+ readonly name: string;
37
+ readonly [participantExchangeErrorBrand] = true;
38
+ readonly status: number;
39
+ readonly code: string;
40
+ constructor(message: string, details: {
41
+ status: number;
42
+ code: string;
43
+ retryAfter?: number;
44
+ });
45
+ }
46
+ /**
47
+ * Signs a member in from your server, without a browser: trades your identity integration key and
48
+ * the stable ID of a user your server verified for a participant session. Use it when no browser
49
+ * reaches Domino through `createParticipantBackend`, such as a backend that calls Domino for its
50
+ * users. `accounts` vouches for the user's accounts as `createParticipantBackend`'s does, and the
51
+ * answer's `accounts` gives each one's outcome. Pass the previous answer's `token` as
52
+ * `previousToken` to keep using that session while it lasts. Throws ParticipantExchangeError when
53
+ * Domino refuses the exchange.
54
+ */
55
+ declare function exchangeParticipant(options: {
56
+ baseUrl: string;
57
+ integrationKey: string;
58
+ subject: string;
59
+ previousToken?: string;
60
+ accounts?: MemberImportVouchedAccount[];
61
+ fetch?: typeof fetch;
62
+ }): Promise<ParticipantExchangeResult>;
63
+ /**
64
+ * Use only in an app server route. authenticate must verify the app's own session.
65
+ * `origin` is the app's exact HTTPS origin, or a loopback HTTP origin
66
+ * (`http://localhost`, `http://127.0.0.1`, `http://[::1]`, any port) for a
67
+ * local browser test. Relay registers only HTTPS origins, so a loopback origin
68
+ * works only against an injected `fetch`, such as `createFakeRelay`'s.
69
+ * `authenticate` may also return `accounts` the app vouches belong to the user, which needs the
70
+ * key's **Vouches accounts** setting; `onAccounts` receives each one's outcome, such as an account
71
+ * another member holds.
72
+ */
18
73
  declare function createParticipantBackend(options: {
19
74
  baseUrl: string;
20
75
  integrationKey: string;
21
76
  origin: string;
22
77
  authenticate: (request: Request) => Promise<{
23
78
  subject: string;
79
+ accounts?: MemberImportVouchedAccount[];
24
80
  } | null>;
81
+ onAccounts?: (results: ParticipantExchangeAccountResult[], request: Request) => void | Promise<void>;
25
82
  fetch?: typeof fetch;
26
83
  }): (request: Request) => Promise<Response>;
27
84
  /**
@@ -60,4 +117,4 @@ declare function signedInMember(request: Request, env: HostedAppEnv, options: {
60
117
  fetch?: typeof fetch;
61
118
  }): Promise<string | null>;
62
119
 
63
- export { type HostedAppEnv, createParticipantBackend, handleHostedApp, hostedAppRequest, proxyParticipant, signedInMember };
120
+ export { type HostedAppEnv, ParticipantExchangeError, createParticipantBackend, exchangeParticipant, handleHostedApp, hostedAppRequest, isParticipantExchangeError, proxyParticipant, signedInMember };
@@ -1,15 +1,23 @@
1
+ import {
2
+ participantExchangeAccountsSchema,
3
+ participantExchangeResultSchema
4
+ } from "./chunk-UAKYDVT3.js";
1
5
  import {
2
6
  isParticipantRoute
3
- } from "./chunk-MHPKEVEW.js";
7
+ } from "./chunk-CZFXGGEK.js";
4
8
  import {
5
- clientIdentity
6
- } from "./chunk-EN3M5Z4J.js";
9
+ clientIdentity,
10
+ retryAfter
11
+ } from "./chunk-3PYYGFSB.js";
7
12
  import {
8
- exchangeResultSchema,
9
13
  participantPrincipalSchema,
10
14
  sessionMember
11
- } from "./chunk-PPB7HALD.js";
12
- import "./chunk-ZDJLPN4L.js";
15
+ } from "./chunk-XJFYAXET.js";
16
+ import "./chunk-MK425RXJ.js";
17
+ import {
18
+ RequestError,
19
+ isRequestError
20
+ } from "./chunk-K2KS3JLY.js";
13
21
 
14
22
  // src/portal-proxy.ts
15
23
  import * as z from "zod";
@@ -86,10 +94,69 @@ async function proxyParticipant(request, upstream) {
86
94
  headers: resultHeaders
87
95
  });
88
96
  }
97
+ function requestExchange(options, body) {
98
+ return (options.fetch ?? fetch)(options.baseUrl + "/v1/auth/exchange", {
99
+ method: "POST",
100
+ redirect: "manual",
101
+ headers: {
102
+ Authorization: "Bearer " + options.integrationKey,
103
+ "X-Domino-Client": clientIdentity(),
104
+ "Content-Type": "application/json"
105
+ },
106
+ body: JSON.stringify({
107
+ subject: body.subject,
108
+ previousToken: body.previousToken,
109
+ accounts: body.accounts?.length ? participantExchangeAccountsSchema.parse(body.accounts) : void 0
110
+ })
111
+ });
112
+ }
113
+ var participantExchangeErrorBrand = /* @__PURE__ */ Symbol.for(
114
+ "@domino-sdk/relay.ParticipantExchangeError"
115
+ );
116
+ function isParticipantExchangeError(value) {
117
+ return isRequestError(value) && value[participantExchangeErrorBrand] === true;
118
+ }
119
+ var ParticipantExchangeError = class extends RequestError {
120
+ name = "ParticipantExchangeError";
121
+ [participantExchangeErrorBrand] = true;
122
+ constructor(message, details) {
123
+ super(message, { ...details, kind: "http" });
124
+ }
125
+ };
126
+ async function exchangeParticipant(options) {
127
+ const base = new URL(options.baseUrl);
128
+ if (base.protocol !== "https:" || base.origin !== options.baseUrl) {
129
+ throw new Error("Configure the exact HTTPS participant API origin");
130
+ }
131
+ if (!options.integrationKey.startsWith("di_")) {
132
+ throw new Error(
133
+ "Use an identity integration server key from Console Settings"
134
+ );
135
+ }
136
+ const exchanged = await requestExchange(options, {
137
+ subject: options.subject,
138
+ previousToken: options.previousToken,
139
+ accounts: options.accounts
140
+ });
141
+ if (!exchanged.ok) {
142
+ const body = await exchanged.json().catch(() => null);
143
+ throw new ParticipantExchangeError(
144
+ typeof body?.error === "string" ? body.error : `Domino identity exchange failed with status ${exchanged.status}`,
145
+ {
146
+ status: exchanged.status,
147
+ code: typeof body?.code === "string" ? body.code : statusCode(exchanged.status),
148
+ retryAfter: retryAfter(exchanged.headers)
149
+ }
150
+ );
151
+ }
152
+ return participantExchangeResultSchema.parse(await exchanged.json());
153
+ }
154
+ var loopbackHosts = /* @__PURE__ */ new Set(["localhost", "127.0.0.1", "[::1]"]);
89
155
  function createParticipantBackend(options) {
90
156
  const origin = new URL(options.origin);
91
157
  const base = new URL(options.baseUrl);
92
- if (origin.protocol !== "https:" || origin.origin !== options.origin || base.protocol !== "https:" || base.origin !== options.baseUrl) {
158
+ const loopback = origin.protocol === "http:" && loopbackHosts.has(origin.hostname);
159
+ if (origin.protocol !== "https:" && !loopback || origin.origin !== options.origin || base.protocol !== "https:" || base.origin !== options.baseUrl) {
93
160
  throw new Error(
94
161
  "Configure exact HTTPS application and participant API origins"
95
162
  );
@@ -100,7 +167,10 @@ function createParticipantBackend(options) {
100
167
  );
101
168
  }
102
169
  const send = options.fetch ?? fetch;
103
- const cookie = (token) => `domino_app_session=${token}; Path=/relay; HttpOnly; Secure; SameSite=Lax; Max-Age=${token ? 28800 : 0}`;
170
+ const cookie = (token) => (
171
+ // WebKit drops a Secure cookie on http://localhost, so a loopback origin sets it without.
172
+ `domino_app_session=${token}; Path=/relay; HttpOnly;${loopback ? "" : " Secure;"} SameSite=Lax; Max-Age=${token ? 28800 : 0}`
173
+ );
104
174
  return async (request) => {
105
175
  const url = new URL(request.url);
106
176
  const reject = (error, status, code) => Response.json(
@@ -126,24 +196,19 @@ function createParticipantBackend(options) {
126
196
  }
127
197
  );
128
198
  }
129
- const previousToken = request.headers.get("Cookie")?.split(";").map((value) => value.trim()).find((value) => value.startsWith("domino_app_session="))?.slice("domino_app_session=".length);
130
- const exchanged = await send(options.baseUrl + "/v1/auth/exchange", {
131
- method: "POST",
132
- redirect: "manual",
133
- headers: {
134
- Authorization: "Bearer " + options.integrationKey,
135
- "X-Domino-Client": clientIdentity(),
136
- "Content-Type": "application/json"
137
- },
138
- body: JSON.stringify({ subject: identity.subject, previousToken })
199
+ const previousToken = onlyCookie(request.headers.get("Cookie"), "domino_app_session") ?? void 0;
200
+ const exchanged = await requestExchange(options, {
201
+ subject: identity.subject,
202
+ previousToken,
203
+ accounts: identity.accounts
139
204
  });
140
205
  if (!exchanged.ok) {
141
206
  const body = await exchanged.json().catch(() => null);
142
207
  const code = typeof body?.code === "string" ? body.code : statusCode(exchanged.status);
143
- const retryAfter = exchanged.headers.get("Retry-After");
208
+ const wait = exchanged.headers.get("Retry-After");
144
209
  return Response.json(
145
210
  {
146
- error: exchanged.status === 409 && typeof body?.error === "string" ? body.error : exchanged.status === 409 ? "Domino refused this account. Ask an organizer." : "Domino identity exchange failed. Check the server integration key and its expiry in Console Settings.",
211
+ error: (exchanged.status === 409 || code === "ACCOUNT_VOUCHING_OFF") && typeof body?.error === "string" ? body.error : exchanged.status === 409 ? "Domino refused this account. Ask an organizer." : "Domino identity exchange failed. Check the server integration key and its expiry in Console Settings.",
147
212
  code
148
213
  },
149
214
  {
@@ -151,18 +216,23 @@ function createParticipantBackend(options) {
151
216
  headers: {
152
217
  "Set-Cookie": cookie(""),
153
218
  "Cache-Control": "no-store",
154
- ...retryAfter ? { "Retry-After": retryAfter } : {}
219
+ ...wait ? { "Retry-After": wait } : {}
155
220
  }
156
221
  }
157
222
  );
158
223
  }
159
- const { token } = exchangeResultSchema.parse(await exchanged.json());
224
+ const { token, accounts } = participantExchangeResultSchema.parse(
225
+ await exchanged.json()
226
+ );
227
+ if (accounts?.length && options.onAccounts) {
228
+ await options.onAccounts(accounts, request);
229
+ }
160
230
  const response = await proxyParticipant(request, {
161
231
  baseUrl: options.baseUrl,
162
232
  fetch: async (target, init) => {
163
233
  const headers2 = new Headers(init?.headers);
164
234
  headers2.delete("Cookie");
165
- const returnBinding = request.headers.get("Cookie")?.split(";").map((value) => value.trim()).find((value) => value.startsWith("relay_auth_return="));
235
+ const returnBinding = oauthReturnBinding(request.headers.get("Cookie"));
166
236
  if (returnBinding) {
167
237
  headers2.set("Cookie", returnBinding);
168
238
  }
@@ -180,6 +250,19 @@ function createParticipantBackend(options) {
180
250
  return new Response(response.body, { status: response.status, headers });
181
251
  };
182
252
  }
253
+ function onlyCookie(header, name) {
254
+ const values = (header ?? "").split(";").map((value) => value.trim()).filter((value) => value.startsWith(name + "="));
255
+ return values.length === 1 ? values[0].slice(name.length + 1) : null;
256
+ }
257
+ function oauthReturnBinding(header) {
258
+ for (const name of ["__Host-relay_auth_return", "relay_auth_return"]) {
259
+ if (header?.split(";").some((value) => value.trim().startsWith(name + "="))) {
260
+ const value = onlyCookie(header, name);
261
+ return value === null ? null : `${name}=${value}`;
262
+ }
263
+ }
264
+ return null;
265
+ }
183
266
  function hostedAppRequest(request, env) {
184
267
  if (!env.DOMINO_PREVIEW_ORIGIN) {
185
268
  return request;
@@ -239,9 +322,12 @@ async function signedInMember(request, env, options) {
239
322
  }
240
323
  var signedInSessionSchema = z.object({ principal: participantPrincipalSchema }).nullable();
241
324
  export {
325
+ ParticipantExchangeError,
242
326
  createParticipantBackend,
327
+ exchangeParticipant,
243
328
  handleHostedApp,
244
329
  hostedAppRequest,
330
+ isParticipantExchangeError,
245
331
  proxyParticipant,
246
332
  signedInMember
247
333
  };