@ambasada/sdk 0.8.10 → 0.8.11

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/dist/define.d.ts CHANGED
@@ -31,6 +31,19 @@ export interface MiniAppConfig {
31
31
  scopes?: ("identity" | "notifications")[];
32
32
  visibility?: "public" | "builders" | "unlisted" | `event:${string}`;
33
33
  }
34
+ /**
35
+ * How the app is listed, whether or not it has a mini app (dry run 7 nit d: with the mini app off there was nowhere
36
+ * for these). The mini app's own `age_rating`, `kind` and `tags` win; these are its defaults, and `miniapp disable`
37
+ * keeps them here.
38
+ */
39
+ export interface ListingConfig {
40
+ /** Who it is for: "4+", "9+", "12+" or "17+" (the mini app's default "4+"). */
41
+ age_rating?: MiniAppConfig["age_rating"];
42
+ /** What it is: "product", "event", "tool" or "assistant" (the mini app's default "tool"). */
43
+ kind?: MiniAppConfig["kind"];
44
+ /** Up to 5 search words. */
45
+ tags?: string[];
46
+ }
34
47
  export interface AppConfig {
35
48
  /** The app's slug (lowercase): it lives at https://<id>.ambasada.dev. */
36
49
  id: string;
@@ -46,6 +59,8 @@ export interface AppConfig {
46
59
  };
47
60
  /** The mini app inside the Ambasada app, at a path of this one. Off without it. */
48
61
  miniapp?: MiniAppConfig;
62
+ /** age_rating, kind and tags, for an app with or without a mini app (the mini app's own win). */
63
+ listing?: ListingConfig;
49
64
  /** Add-ons to load besides the ones found in node_modules (package names, e.g. "@ambasada/village"). */
50
65
  addons?: string[];
51
66
  }
package/dist/errors.d.ts CHANGED
@@ -63,6 +63,8 @@ export interface ErrorDetails {
63
63
  upstream_status?: number;
64
64
  /** APPROVAL_REQUIRED: retry with `{ approval: approvalId }` once the team approved it. */
65
65
  approval_id?: string;
66
+ /** CAP_TOOLS_RATE, TOOL_UNAVAILABLE, a busy seller: seconds until it is worth trying again. */
67
+ retry_after_s?: number;
66
68
  [key: string]: unknown;
67
69
  }
68
70
  export declare class AmbasadaError extends Error {
@@ -76,6 +78,8 @@ export declare class AmbasadaError extends Error {
76
78
  get callId(): string | undefined;
77
79
  get refunded(): boolean;
78
80
  get approvalId(): string | undefined;
81
+ /** Seconds until it is worth trying again (CAP_TOOLS_RATE, TOOL_UNAVAILABLE, a busy seller), when the error says. */
82
+ get retryAfterS(): number | undefined;
79
83
  /** The wire shape, e.g. to pass an error on from your own endpoint. */
80
84
  toJSON(): {
81
85
  error: {
@@ -83,7 +87,7 @@ export declare class AmbasadaError extends Error {
83
87
  message: string;
84
88
  } & ErrorDetails;
85
89
  };
86
- /** A `Response` with the wire shape and status (402 for receipt problems). */
90
+ /** A `Response` with the wire shape and status (402 for receipt problems), and `Retry-After` when it has one. */
87
91
  toResponse(): Response;
88
92
  }
89
93
  export type WebhookFailure = "missing_headers" | "bad_timestamp" | "too_old" | "too_new" | "bad_signature" | "bad_secret" | "bad_body";
@@ -11,7 +11,7 @@ export { getHeader } from "./headers.js";
11
11
  export type { HeaderSource } from "./headers.js";
12
12
  export { defineApp } from "./define.js";
13
13
  export { MINIAPP_AGE_RATINGS, MINIAPP_ENTRY, MINIAPP_KINDS, supportUrl } from "./define.js";
14
- export type { AppConfig, MiniAppConfig } from "./define.js";
14
+ export type { AppConfig, ListingConfig, MiniAppConfig } from "./define.js";
15
15
  export { AmbasadaAuth, AUTH_PATHS, JWKS_TTL_MS, SESSION_TTL_S } from "./auth.js";
16
16
  export type { AmbasadaUser, AuthConfig, LoginOptions, ShellUser, WithHeaders } from "./auth.js";
17
17
  export { AmbasadaApps, APP_SIGNATURE_HEADER, APP_TIMESTAMP_HEADER, appWebhookHeaders, signAppWebhook } from "./apps.js";
package/dist/platform.js CHANGED
@@ -211,13 +211,19 @@ var AmbasadaError = class _AmbasadaError extends Error {
211
211
  get approvalId() {
212
212
  return this.details.approval_id;
213
213
  }
214
+ /** Seconds until it is worth trying again (CAP_TOOLS_RATE, TOOL_UNAVAILABLE, a busy seller), when the error says. */
215
+ get retryAfterS() {
216
+ const s = this.details.retry_after_s;
217
+ return typeof s === "number" && Number.isFinite(s) ? s : void 0;
218
+ }
214
219
  /** The wire shape, e.g. to pass an error on from your own endpoint. */
215
220
  toJSON() {
216
221
  return { error: { code: this.code, message: this.message, ...this.details } };
217
222
  }
218
- /** A `Response` with the wire shape and status (402 for receipt problems). */
223
+ /** A `Response` with the wire shape and status (402 for receipt problems), and `Retry-After` when it has one. */
219
224
  toResponse() {
220
- return Response.json(this.toJSON(), { status: this.status || 500 });
225
+ const retry = this.details.retry_after_s;
226
+ return Response.json(this.toJSON(), { status: this.status || 500, ...typeof retry === "number" ? { headers: { "retry-after": String(Math.ceil(retry)) } } : {} });
221
227
  }
222
228
  };
223
229
  var WebhookInvalidError = class extends AmbasadaError {
@@ -817,6 +823,11 @@ function supportUrl(value) {
817
823
  return void 0;
818
824
  }
819
825
  var MINIAPP_ENTRY = /^\/(?:[A-Za-z0-9._~-]+(?:\/[A-Za-z0-9._~-]+)*)?$/;
826
+ function checkListing(id, key, l) {
827
+ if (l.age_rating !== void 0 && !MINIAPP_AGE_RATINGS.includes(l.age_rating)) throw new Error(`${id}: ${key}.age_rating must be one of ${MINIAPP_AGE_RATINGS.join(", ")} (got ${JSON.stringify(l.age_rating)})`);
828
+ if (l.kind !== void 0 && !MINIAPP_KINDS.includes(l.kind)) throw new Error(`${id}: ${key}.kind must be one of ${MINIAPP_KINDS.join(", ")} (got ${JSON.stringify(l.kind)})`);
829
+ if (l.tags !== void 0 && (!Array.isArray(l.tags) || l.tags.length > 5 || l.tags.some((t) => typeof t !== "string"))) throw new Error(`${id}: ${key}.tags must be up to 5 strings`);
830
+ }
820
831
  function defineApp(config) {
821
832
  if (typeof config.id !== "string" || !/^[a-z0-9][a-z0-9-]{0,62}$/.test(config.id)) throw new Error(`app id "${String(config.id)}" must be a lowercase slug (a-z, 0-9, -)`);
822
833
  const m = config.miniapp;
@@ -827,10 +838,12 @@ function defineApp(config) {
827
838
  }
828
839
  if (m.icon !== void 0 && (typeof m.icon !== "string" || !m.icon.startsWith("/"))) throw new Error(`${config.id}: miniapp.icon must be a path like "/icon.png"`);
829
840
  if (m.accent !== void 0 && !/^#[0-9a-fA-F]{6}$/.test(m.accent)) throw new Error(`${config.id}: miniapp.accent must be a #RRGGBB colour`);
830
- if (m.age_rating !== void 0 && !MINIAPP_AGE_RATINGS.includes(m.age_rating)) throw new Error(`${config.id}: miniapp.age_rating must be one of ${MINIAPP_AGE_RATINGS.join(", ")} (got ${JSON.stringify(m.age_rating)})`);
831
- if (m.kind !== void 0 && !MINIAPP_KINDS.includes(m.kind)) throw new Error(`${config.id}: miniapp.kind must be one of ${MINIAPP_KINDS.join(", ")} (got ${JSON.stringify(m.kind)})`);
841
+ checkListing(config.id, "miniapp", m);
832
842
  if (m.support !== void 0 && !supportUrl(m.support)) throw new Error(`${config.id}: miniapp.support must be an email or an https URL (got ${JSON.stringify(m.support)})`);
833
- if (m.tags !== void 0 && (!Array.isArray(m.tags) || m.tags.length > 5 || m.tags.some((t) => typeof t !== "string"))) throw new Error(`${config.id}: miniapp.tags must be up to 5 strings`);
843
+ }
844
+ if (config.listing !== void 0) {
845
+ if (!config.listing || typeof config.listing !== "object") throw new Error(`${config.id}: listing must be { age_rating, kind, tags }`);
846
+ checkListing(config.id, "listing", config.listing);
834
847
  }
835
848
  if (config.support !== void 0 && !supportUrl(config.support)) throw new Error(`${config.id}: support must be an email or an https URL (got ${JSON.stringify(config.support)})`);
836
849
  return config;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ambasada/sdk",
3
- "version": "0.8.10",
3
+ "version": "0.8.11",
4
4
  "description": "The Ambasada platform SDK: Sign in with Ambasada, mini-app notifications, the project store, files.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -27,7 +27,7 @@
27
27
  "node": ">=22"
28
28
  },
29
29
  "dependencies": {
30
- "@ambasada/village": "^0.8.10"
30
+ "@ambasada/village": "^0.8.11"
31
31
  },
32
32
  "devDependencies": {
33
33
  "@types/node": "^22.20.5",