@ambasada/sdk 0.8.9 → 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 +15 -0
- package/dist/errors.d.ts +7 -1
- package/dist/platform.d.ts +1 -1
- package/dist/platform.js +20 -5
- package/package.json +2 -2
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
|
@@ -40,9 +40,11 @@ export declare const ERROR_STATUS: {
|
|
|
40
40
|
readonly APPROVALS_PENDING: 429;
|
|
41
41
|
readonly PROVIDER_BUDGET: 503;
|
|
42
42
|
readonly PROVIDER_DENIED: 502;
|
|
43
|
+
readonly TOOL_UNAVAILABLE: 503;
|
|
43
44
|
readonly FROZEN: 403;
|
|
44
45
|
readonly CAP_INBOX_RATE: 429;
|
|
45
46
|
readonly CAP_CHAT_RATE: 429;
|
|
47
|
+
readonly CAP_TOOLS_RATE: 429;
|
|
46
48
|
readonly NETWORK: 0;
|
|
47
49
|
readonly CONFIG: 0;
|
|
48
50
|
readonly RECEIPT_INVALID: 402;
|
|
@@ -61,6 +63,8 @@ export interface ErrorDetails {
|
|
|
61
63
|
upstream_status?: number;
|
|
62
64
|
/** APPROVAL_REQUIRED: retry with `{ approval: approvalId }` once the team approved it. */
|
|
63
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;
|
|
64
68
|
[key: string]: unknown;
|
|
65
69
|
}
|
|
66
70
|
export declare class AmbasadaError extends Error {
|
|
@@ -74,6 +78,8 @@ export declare class AmbasadaError extends Error {
|
|
|
74
78
|
get callId(): string | undefined;
|
|
75
79
|
get refunded(): boolean;
|
|
76
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;
|
|
77
83
|
/** The wire shape, e.g. to pass an error on from your own endpoint. */
|
|
78
84
|
toJSON(): {
|
|
79
85
|
error: {
|
|
@@ -81,7 +87,7 @@ export declare class AmbasadaError extends Error {
|
|
|
81
87
|
message: string;
|
|
82
88
|
} & ErrorDetails;
|
|
83
89
|
};
|
|
84
|
-
/** 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. */
|
|
85
91
|
toResponse(): Response;
|
|
86
92
|
}
|
|
87
93
|
export type WebhookFailure = "missing_headers" | "bad_timestamp" | "too_old" | "too_new" | "bad_signature" | "bad_secret" | "bad_body";
|
package/dist/platform.d.ts
CHANGED
|
@@ -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
|
@@ -169,12 +169,14 @@ var ERROR_STATUS = {
|
|
|
169
169
|
// LLMOK mapping (utilities stream, docs/LLMOK.md)
|
|
170
170
|
PROVIDER_BUDGET: 503,
|
|
171
171
|
PROVIDER_DENIED: 502,
|
|
172
|
+
TOOL_UNAVAILABLE: 503,
|
|
172
173
|
// Clock windows (agent stream): deploys / steering refused while frozen
|
|
173
174
|
FROZEN: 403,
|
|
174
175
|
// Exchange stream: an agent sent too many inbox messages
|
|
175
176
|
CAP_INBOX_RATE: 429,
|
|
176
177
|
// The CEO chat: too many turns for one company
|
|
177
178
|
CAP_CHAT_RATE: 429,
|
|
179
|
+
CAP_TOOLS_RATE: 429,
|
|
178
180
|
// SDK-side
|
|
179
181
|
NETWORK: 0,
|
|
180
182
|
CONFIG: 0,
|
|
@@ -209,13 +211,19 @@ var AmbasadaError = class _AmbasadaError extends Error {
|
|
|
209
211
|
get approvalId() {
|
|
210
212
|
return this.details.approval_id;
|
|
211
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
|
+
}
|
|
212
219
|
/** The wire shape, e.g. to pass an error on from your own endpoint. */
|
|
213
220
|
toJSON() {
|
|
214
221
|
return { error: { code: this.code, message: this.message, ...this.details } };
|
|
215
222
|
}
|
|
216
|
-
/** 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. */
|
|
217
224
|
toResponse() {
|
|
218
|
-
|
|
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)) } } : {} });
|
|
219
227
|
}
|
|
220
228
|
};
|
|
221
229
|
var WebhookInvalidError = class extends AmbasadaError {
|
|
@@ -815,6 +823,11 @@ function supportUrl(value) {
|
|
|
815
823
|
return void 0;
|
|
816
824
|
}
|
|
817
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
|
+
}
|
|
818
831
|
function defineApp(config) {
|
|
819
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, -)`);
|
|
820
833
|
const m = config.miniapp;
|
|
@@ -825,10 +838,12 @@ function defineApp(config) {
|
|
|
825
838
|
}
|
|
826
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"`);
|
|
827
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`);
|
|
828
|
-
|
|
829
|
-
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);
|
|
830
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)})`);
|
|
831
|
-
|
|
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);
|
|
832
847
|
}
|
|
833
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)})`);
|
|
834
849
|
return config;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ambasada/sdk",
|
|
3
|
-
"version": "0.8.
|
|
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.
|
|
30
|
+
"@ambasada/village": "^0.8.11"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
33
|
"@types/node": "^22.20.5",
|