@ambasada/sdk 0.8.4 → 0.8.6
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/client.d.ts +9 -1
- package/dist/define.d.ts +18 -0
- package/dist/platform.d.ts +1 -1
- package/dist/platform.js +38 -4
- package/package.json +2 -2
package/dist/client.d.ts
CHANGED
|
@@ -15,7 +15,10 @@ export interface AmbasadaOptions {
|
|
|
15
15
|
fetch?: typeof fetch;
|
|
16
16
|
/** Per-request timeout in ms (default 45 s). */
|
|
17
17
|
timeoutMs?: number;
|
|
18
|
-
/**
|
|
18
|
+
/**
|
|
19
|
+
* Extra env source, e.g. a Worker's `env`. Default: `process.env` where it exists. A Worker hosted on ambasada.dev has
|
|
20
|
+
* an `AMBASADA_API` service binding there: the client calls the API through it (no zone in between, so no 522).
|
|
21
|
+
*/
|
|
19
22
|
env?: Record<string, unknown>;
|
|
20
23
|
/** Sign in with Ambasada credentials. Default: `AMBASADA_AUTH_CLIENT_ID`, `_CLIENT_SECRET`, `_ISSUER`, and `PUBLIC_URL`. */
|
|
21
24
|
auth?: {
|
|
@@ -58,6 +61,11 @@ export declare class Ambasada {
|
|
|
58
61
|
private projectPromise?;
|
|
59
62
|
constructor(options?: AmbasadaOptions);
|
|
60
63
|
protected env(name: string): string | undefined;
|
|
64
|
+
/**
|
|
65
|
+
* How this client fetches: `options.fetch`; else, with an `AMBASADA_API` service binding in `env` (hosted on
|
|
66
|
+
* ambasada.dev), the API's own URLs go through it and everything else (the hub, the issuer) through `fetch`.
|
|
67
|
+
*/
|
|
68
|
+
protected get fetcher(): typeof fetch;
|
|
61
69
|
get apiUrl(): string;
|
|
62
70
|
protected get apiKey(): string;
|
|
63
71
|
/**
|
package/dist/define.d.ts
CHANGED
|
@@ -12,6 +12,18 @@ export interface MiniAppConfig {
|
|
|
12
12
|
entry: string;
|
|
13
13
|
/** A 1024×1024 opaque PNG, a path on the app (default "/icon.png"). */
|
|
14
14
|
icon?: string;
|
|
15
|
+
/** Who it is for (default "4+"). The hub refuses to register a mini app without one; above 12+ it opens only for people old enough. */
|
|
16
|
+
age_rating?: "4+" | "9+" | "12+" | "17+";
|
|
17
|
+
/** How the Ambasada app shows it (default "tool"). */
|
|
18
|
+
kind?: "product" | "event" | "tool" | "assistant";
|
|
19
|
+
/** Where people get help: "mailto:you@team.ro" or an https URL (default: the app's `support`). Needed to be Listed. */
|
|
20
|
+
support?: string;
|
|
21
|
+
/** Up to 5 search words. */
|
|
22
|
+
tags?: string[];
|
|
23
|
+
/** Under the name on the card (≤ 40; default: `description`, cut to one line). */
|
|
24
|
+
subtitle?: string;
|
|
25
|
+
/** The store description (≤ 170; default: the app's `description`). */
|
|
26
|
+
description?: string;
|
|
15
27
|
/** Manifest fields beyond the defaults (docs/MINI-APPS.md §2). */
|
|
16
28
|
category?: "shopping" | "food" | "events" | "tools" | "learning" | "community" | "games" | "finance" | "other";
|
|
17
29
|
accent?: string;
|
|
@@ -26,6 +38,8 @@ export interface AppConfig {
|
|
|
26
38
|
name: string;
|
|
27
39
|
/** One line about the app (the mini app's subtitle and description, when there is one). */
|
|
28
40
|
description?: string;
|
|
41
|
+
/** Where people get help: an email ("you@team.ro" or "mailto:…") or an https URL. The mini app's `support` by default. */
|
|
42
|
+
support?: string;
|
|
29
43
|
/** Where the app runs; `ambasada link` sets it when you host elsewhere. */
|
|
30
44
|
product?: {
|
|
31
45
|
url?: string;
|
|
@@ -35,6 +49,10 @@ export interface AppConfig {
|
|
|
35
49
|
/** Add-ons to load besides the ones found in node_modules (package names, e.g. "@ambasada/village"). */
|
|
36
50
|
addons?: string[];
|
|
37
51
|
}
|
|
52
|
+
export declare const MINIAPP_AGE_RATINGS: readonly ["4+", "9+", "12+", "17+"];
|
|
53
|
+
export declare const MINIAPP_KINDS: readonly ["product", "event", "tool", "assistant"];
|
|
54
|
+
/** "you@team.ro" → "mailto:you@team.ro"; mailto: and https URLs as they are; anything else undefined. */
|
|
55
|
+
export declare function supportUrl(value: string | undefined): string | undefined;
|
|
38
56
|
/** A path the mini app may open at: absolute, no query, hash, `..` or `//`. */
|
|
39
57
|
export declare const MINIAPP_ENTRY: RegExp;
|
|
40
58
|
export declare function defineApp<T extends AppConfig>(config: T): T;
|
package/dist/platform.d.ts
CHANGED
|
@@ -10,7 +10,7 @@ export type * from "./types.js";
|
|
|
10
10
|
export { getHeader } from "./headers.js";
|
|
11
11
|
export type { HeaderSource } from "./headers.js";
|
|
12
12
|
export { defineApp } from "./define.js";
|
|
13
|
-
export { MINIAPP_ENTRY } from "./define.js";
|
|
13
|
+
export { MINIAPP_AGE_RATINGS, MINIAPP_ENTRY, MINIAPP_KINDS, supportUrl } from "./define.js";
|
|
14
14
|
export type { AppConfig, 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";
|
package/dist/platform.js
CHANGED
|
@@ -590,6 +590,7 @@ var AmbasadaAuth = class {
|
|
|
590
590
|
|
|
591
591
|
// src/client.ts
|
|
592
592
|
var DEFAULT_API_URL = "https://api.ambasada.dev";
|
|
593
|
+
var isBinding = (v) => typeof v === "object" && v !== null && typeof v.fetch === "function";
|
|
593
594
|
function processEnv() {
|
|
594
595
|
const p = globalThis.process;
|
|
595
596
|
return p?.env ?? {};
|
|
@@ -605,6 +606,22 @@ var Ambasada = class {
|
|
|
605
606
|
const v = this.options.env?.[name];
|
|
606
607
|
return typeof v === "string" ? v : processEnv()[name];
|
|
607
608
|
}
|
|
609
|
+
/**
|
|
610
|
+
* How this client fetches: `options.fetch`; else, with an `AMBASADA_API` service binding in `env` (hosted on
|
|
611
|
+
* ambasada.dev), the API's own URLs go through it and everything else (the hub, the issuer) through `fetch`.
|
|
612
|
+
*/
|
|
613
|
+
get fetcher() {
|
|
614
|
+
if (this.options.fetch) return this.options.fetch;
|
|
615
|
+
const binding = this.options.env?.AMBASADA_API;
|
|
616
|
+
if (!isBinding(binding)) return (input, init) => fetch(input, init);
|
|
617
|
+
const api = new Set(
|
|
618
|
+
[this.apiUrl, this.env("AMBASADA_API_URL"), this.env("AMBASADA_VILLAGE_API_URL")].filter((u) => !!u && URL.canParse(u)).map((u) => new URL(u).origin)
|
|
619
|
+
);
|
|
620
|
+
return (input, init) => {
|
|
621
|
+
const request = new Request(input, init);
|
|
622
|
+
return api.has(new URL(request.url).origin) ? binding.fetch(request) : fetch(request);
|
|
623
|
+
};
|
|
624
|
+
}
|
|
608
625
|
get apiUrl() {
|
|
609
626
|
return (this.options.apiUrl ?? this.env("AMBASADA_API_URL") ?? this.env("VILLAGE_API_URL") ?? DEFAULT_API_URL).replace(/\/+$/, "");
|
|
610
627
|
}
|
|
@@ -626,7 +643,7 @@ var Ambasada = class {
|
|
|
626
643
|
// Silent sign-in: a shell token must be for this app, by id or origin.
|
|
627
644
|
audiences: [this.appOrigin, this.options.app?.id ?? this.env("AMBASADA_APP_ID") ?? this.env("AMBASADA_COMPANY")].filter((a) => !!a),
|
|
628
645
|
hubUrl: this.hubUrl,
|
|
629
|
-
fetch: this.
|
|
646
|
+
fetch: this.fetcher
|
|
630
647
|
}));
|
|
631
648
|
get appOrigin() {
|
|
632
649
|
const url = this.options.app?.origin ?? this.env("AMBASADA_APP_ORIGIN") ?? this.options.auth?.publicUrl ?? this.env("PUBLIC_URL");
|
|
@@ -643,7 +660,7 @@ var Ambasada = class {
|
|
|
643
660
|
appSecret: this.options.app?.secret ?? this.env("AMBASADA_APP_SECRET"),
|
|
644
661
|
hubUrl: this.hubUrl,
|
|
645
662
|
origin: this.appOrigin,
|
|
646
|
-
fetch: this.
|
|
663
|
+
fetch: this.fetcher
|
|
647
664
|
}));
|
|
648
665
|
// ── HTTP ──────────────────────────────────────────────────────────────────
|
|
649
666
|
async send(method, path, opts = {}) {
|
|
@@ -657,7 +674,7 @@ var Ambasada = class {
|
|
|
657
674
|
headers["content-type"] = "application/json";
|
|
658
675
|
}
|
|
659
676
|
for (const [k, v] of Object.entries(opts.headers ?? {})) if (v !== void 0) headers[k.toLowerCase()] = v;
|
|
660
|
-
const doFetch = this.
|
|
677
|
+
const doFetch = this.fetcher;
|
|
661
678
|
const attempt = () => {
|
|
662
679
|
const timeout = AbortSignal.timeout(this.options.timeoutMs ?? 45e3);
|
|
663
680
|
const signal = opts.signal ? AbortSignal.any([opts.signal, timeout]) : timeout;
|
|
@@ -779,6 +796,15 @@ function getHeader(headers, name) {
|
|
|
779
796
|
}
|
|
780
797
|
|
|
781
798
|
// src/define.ts
|
|
799
|
+
var MINIAPP_AGE_RATINGS = ["4+", "9+", "12+", "17+"];
|
|
800
|
+
var MINIAPP_KINDS = ["product", "event", "tool", "assistant"];
|
|
801
|
+
function supportUrl(value) {
|
|
802
|
+
const v = value?.trim();
|
|
803
|
+
if (!v) return void 0;
|
|
804
|
+
if (/^mailto:[^@\s]+@[^@\s]+$/.test(v) || /^https:\/\/\S+$/.test(v)) return v;
|
|
805
|
+
if (/^[^@\s:/]+@[^@\s]+\.[^@\s]+$/.test(v)) return `mailto:${v}`;
|
|
806
|
+
return void 0;
|
|
807
|
+
}
|
|
782
808
|
var MINIAPP_ENTRY = /^\/(?:[A-Za-z0-9._~-]+(?:\/[A-Za-z0-9._~-]+)*)?$/;
|
|
783
809
|
function defineApp(config) {
|
|
784
810
|
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, -)`);
|
|
@@ -790,7 +816,12 @@ function defineApp(config) {
|
|
|
790
816
|
}
|
|
791
817
|
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"`);
|
|
792
818
|
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`);
|
|
819
|
+
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)})`);
|
|
820
|
+
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)})`);
|
|
821
|
+
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)})`);
|
|
822
|
+
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`);
|
|
793
823
|
}
|
|
824
|
+
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)})`);
|
|
794
825
|
return config;
|
|
795
826
|
}
|
|
796
827
|
|
|
@@ -808,7 +839,9 @@ export {
|
|
|
808
839
|
DEFAULT_API_URL,
|
|
809
840
|
ERROR_STATUS,
|
|
810
841
|
JWKS_TTL_MS,
|
|
842
|
+
MINIAPP_AGE_RATINGS,
|
|
811
843
|
MINIAPP_ENTRY,
|
|
844
|
+
MINIAPP_KINDS,
|
|
812
845
|
SESSION_TTL_S,
|
|
813
846
|
WebhookInvalidError,
|
|
814
847
|
ambasada,
|
|
@@ -819,5 +852,6 @@ export {
|
|
|
819
852
|
errorFromResponse,
|
|
820
853
|
getHeader,
|
|
821
854
|
isAmbasadaError,
|
|
822
|
-
signAppWebhook2 as signAppWebhook
|
|
855
|
+
signAppWebhook2 as signAppWebhook,
|
|
856
|
+
supportUrl
|
|
823
857
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ambasada/sdk",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.6",
|
|
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.6"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
33
|
"@types/node": "^22.20.5",
|