@gemmein/sdk 0.8.0 → 0.10.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.
- package/CHANGELOG.md +209 -0
- package/README.md +82 -19
- package/REFERENCE.md +401 -50
- package/dist/expo.cjs +423 -0
- package/dist/expo.d.cts +152 -0
- package/dist/expo.d.ts +152 -0
- package/dist/expo.js +387 -0
- package/dist/index.cjs +330 -44
- package/dist/index.d.cts +243 -21
- package/dist/index.d.ts +243 -21
- package/dist/index.js +329 -44
- package/llms.txt +460 -78
- package/migrations/README.md +2 -0
- package/migrations/raw-calls-off.md +51 -0
- package/migrations/secure-store-set-throws.md +75 -0
- package/package.json +23 -2
package/dist/index.d.ts
CHANGED
|
@@ -2,6 +2,37 @@ export type GemmeinOptions = {
|
|
|
2
2
|
appKey: string;
|
|
3
3
|
apiUrl?: string;
|
|
4
4
|
tokenStore?: TokenStore;
|
|
5
|
+
/**
|
|
6
|
+
* W10 §1 A — the fetch EVERY request this client makes goes through.
|
|
7
|
+
* Defaults to `globalThis.fetch`, read at CALL time so a polyfill
|
|
8
|
+
* installed after construction still counts. Expo passes `expo/fetch`,
|
|
9
|
+
* whose streaming answers React Native's own fetch cannot give.
|
|
10
|
+
*/
|
|
11
|
+
fetch?: typeof fetch;
|
|
12
|
+
/**
|
|
13
|
+
* W10 §1 A — where "is the app in front of the user?" comes from, for
|
|
14
|
+
* `watch()`'s sleep-while-hidden. Absent, it is the browser's
|
|
15
|
+
* `document.visibilityState`, exactly as before. Expo passes an
|
|
16
|
+
* AppState-driven hook.
|
|
17
|
+
*/
|
|
18
|
+
visibility?: VisibilityHook;
|
|
19
|
+
/**
|
|
20
|
+
* W10 §1 A — the platform appended to `x-client-info`
|
|
21
|
+
* (`gemmein-sdk/<version> expo-ios`). A report of which build called,
|
|
22
|
+
* never a proof. Cleaned and capped here — see `clientInfoFor`.
|
|
23
|
+
*/
|
|
24
|
+
platform?: string;
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* W10 §1 A — a platform's answer to "is the app in front of the user?".
|
|
28
|
+
* The browser answers it with `document.visibilityState`; React Native
|
|
29
|
+
* answers it with `AppState`. `onChange` registers a listener and returns
|
|
30
|
+
* the function that removes it — one shape, so `watch()` never has to know
|
|
31
|
+
* which platform it is running on.
|
|
32
|
+
*/
|
|
33
|
+
export type VisibilityHook = {
|
|
34
|
+
isHidden(): boolean;
|
|
35
|
+
onChange(cb: () => void): () => void;
|
|
5
36
|
};
|
|
6
37
|
export type TokenStore = {
|
|
7
38
|
get(): string | undefined | Promise<string | undefined>;
|
|
@@ -101,10 +132,18 @@ export type CurrentUser = {
|
|
|
101
132
|
authenticated: true;
|
|
102
133
|
userId: string;
|
|
103
134
|
email: string;
|
|
135
|
+
/**
|
|
136
|
+
* W10 — the store account token, when the engine carries one. It is
|
|
137
|
+
* passed through exactly as `GET /auth/current-user` sent it, never
|
|
138
|
+
* synthesised here; an engine that does not send it leaves this
|
|
139
|
+
* absent — read that as "not carried", never as "no account".
|
|
140
|
+
*/
|
|
141
|
+
storeAccountToken?: string | null;
|
|
104
142
|
} | {
|
|
105
143
|
authenticated: false;
|
|
106
144
|
userId?: undefined;
|
|
107
145
|
email?: undefined;
|
|
146
|
+
storeAccountToken?: undefined;
|
|
108
147
|
};
|
|
109
148
|
export type AuthSession = {
|
|
110
149
|
token: string;
|
|
@@ -120,13 +159,21 @@ export type AuthSession = {
|
|
|
120
159
|
* second module). `scripts/sync-version.mjs` rewrites the literal from
|
|
121
160
|
* package.json before every build (`prebuild`), and a test pins the two
|
|
122
161
|
* equal, so a bump can never ship with a stale header. */
|
|
123
|
-
export declare const SDK_VERSION = "0.
|
|
162
|
+
export declare const SDK_VERSION = "0.10.0";
|
|
124
163
|
/** W9.1 / CLIENT-INFO-1: every request the SDK makes to Gemmein carries
|
|
125
164
|
* `x-client-info: gemmein-sdk/<version>`. The server records it on the
|
|
126
165
|
* secret-key usage ledger ("last seen from gemmein-sdk/0.5.0"), so a
|
|
127
166
|
* misbehaving integration can be attributed to an SDK version from day
|
|
128
167
|
* one. It is a report, not a proof — any caller can set it. */
|
|
129
|
-
export declare const CLIENT_INFO = "gemmein-sdk/0.
|
|
168
|
+
export declare const CLIENT_INFO = "gemmein-sdk/0.10.0";
|
|
169
|
+
/** W10 §1 A: a mobile entry adds its platform — `gemmein-sdk/<version>
|
|
170
|
+
* expo-ios`. The ledger that records this header caps it at 64 characters
|
|
171
|
+
* and strips control characters (`MAX_CLIENT_LENGTH` / `capClient`,
|
|
172
|
+
* packages/db/src/keyUsageStore.ts), so the value is cleaned and capped
|
|
173
|
+
* HERE: a tag that arrives truncated attributes nothing. Anything outside
|
|
174
|
+
* `[A-Za-z0-9._/-]` collapses to a hyphen, so the label can never carry a
|
|
175
|
+
* newline — or a second space — into the ledger. */
|
|
176
|
+
export declare function clientInfoFor(platform?: string): string;
|
|
130
177
|
export declare class GemmeinError extends Error {
|
|
131
178
|
readonly status: number;
|
|
132
179
|
readonly code: string;
|
|
@@ -141,12 +188,19 @@ export declare class GemmeinError extends Error {
|
|
|
141
188
|
* plans by name through checkout, the server never hands out the list.
|
|
142
189
|
*/
|
|
143
190
|
readonly requires?: string;
|
|
191
|
+
/**
|
|
192
|
+
* Present on `network_unreachable` — the fetch implementation's own throw,
|
|
193
|
+
* kept so a bug report can say WHICH transport failure it was. Read it for
|
|
194
|
+
* a log; never branch on it (its shape is the runtime's, not Gemmein's).
|
|
195
|
+
*/
|
|
196
|
+
readonly cause?: unknown;
|
|
144
197
|
constructor(input: {
|
|
145
198
|
status: number;
|
|
146
199
|
code: string;
|
|
147
200
|
message: string;
|
|
148
201
|
resetAt?: string;
|
|
149
202
|
requires?: string;
|
|
203
|
+
cause?: unknown;
|
|
150
204
|
});
|
|
151
205
|
}
|
|
152
206
|
export declare class MemoryTokenStore implements TokenStore {
|
|
@@ -159,6 +213,16 @@ export declare class BrowserTokenStore implements TokenStore {
|
|
|
159
213
|
private readonly key;
|
|
160
214
|
constructor(appKey: string);
|
|
161
215
|
get(): string | undefined;
|
|
216
|
+
/**
|
|
217
|
+
* A blocked `localStorage` — Safari's private mode past its quota, a
|
|
218
|
+
* browser set to block site data, a sandboxed iframe whose access throws
|
|
219
|
+
* — throws `secure_store_unavailable` (status 0), the same code the
|
|
220
|
+
* mobile stores answer, with the browser's own error on `cause`.
|
|
221
|
+
* `auth.verifyEmailCode()` carries it to the caller: the session is real
|
|
222
|
+
* (the server minted it), so an app that would rather run than stop
|
|
223
|
+
* catches this one code and rebuilds its client with a
|
|
224
|
+
* `MemoryTokenStore`, which never throws.
|
|
225
|
+
*/
|
|
162
226
|
set(token: string): void;
|
|
163
227
|
clear(): void;
|
|
164
228
|
}
|
|
@@ -208,6 +272,12 @@ type ClientConfig = {
|
|
|
208
272
|
apiUrl: string;
|
|
209
273
|
appKey: string;
|
|
210
274
|
tokenStore: TokenStore;
|
|
275
|
+
/** W10 §1 A — always present: the injected fetch, or the lazy default. */
|
|
276
|
+
fetch: typeof fetch;
|
|
277
|
+
/** W10 §1 A — absent in a browser; `watch()` falls back to `document`. */
|
|
278
|
+
visibility?: VisibilityHook | undefined;
|
|
279
|
+
/** W10 §1 A — `CLIENT_INFO`, plus the platform when one was named. */
|
|
280
|
+
clientInfo: string;
|
|
211
281
|
};
|
|
212
282
|
export declare class AuthClient {
|
|
213
283
|
private readonly config;
|
|
@@ -217,6 +287,17 @@ export declare class AuthClient {
|
|
|
217
287
|
email: string;
|
|
218
288
|
code: string;
|
|
219
289
|
}): Promise<AuthSession>;
|
|
290
|
+
/**
|
|
291
|
+
* End this device's session. IDEMPOTENT: signing out of a session that is
|
|
292
|
+
* already gone is the outcome asked for, not a failure.
|
|
293
|
+
*
|
|
294
|
+
* W10 row 9, found by driving the Expo app: the commonest way this
|
|
295
|
+
* round-trip fails is `401 auth_expired` — the owner already signed this
|
|
296
|
+
* person out everywhere from the console, which is the remedy for a
|
|
297
|
+
* stolen phone. The session IS ended; throwing there made an app that did
|
|
298
|
+
* everything right show an error for the thing it asked for. Every other
|
|
299
|
+
* failure still throws, and the token store is cleared either way.
|
|
300
|
+
*/
|
|
220
301
|
logout(): Promise<void>;
|
|
221
302
|
currentUser(): Promise<CurrentUser>;
|
|
222
303
|
private request;
|
|
@@ -275,7 +356,7 @@ export declare class PurchasesClient {
|
|
|
275
356
|
}>>;
|
|
276
357
|
}
|
|
277
358
|
/**
|
|
278
|
-
* A file reference — `file
|
|
359
|
+
* A file reference — `file:<uuid>`. What `upload()` gives you and what your
|
|
279
360
|
* record should store.
|
|
280
361
|
*
|
|
281
362
|
* Branded so it cannot be mistaken for a URL: `<img src={record.poster}>` is a
|
|
@@ -285,6 +366,33 @@ export declare class PurchasesClient {
|
|
|
285
366
|
export type FileRef = string & {
|
|
286
367
|
readonly __gemmeinFileRef: unique symbol;
|
|
287
368
|
};
|
|
369
|
+
/**
|
|
370
|
+
* W10 §1 A — what `upload()` takes. A browser hands it a `File` or a
|
|
371
|
+
* `Blob`.
|
|
372
|
+
*
|
|
373
|
+
* On a phone the thing a picker returns is a `{ uri, name, type, size }`
|
|
374
|
+
* object, and it reaches the wire two ways (W10 row 9, found by driving
|
|
375
|
+
* the Expo app):
|
|
376
|
+
*
|
|
377
|
+
* * through `@gemmein/sdk/expo` — `createExpoGemmein` turns the picker
|
|
378
|
+
* shape into an `expo-file-system` `File`, which IS a `Blob`, before it
|
|
379
|
+
* reaches here. This is the path an Expo app has: Expo's own fetch (the
|
|
380
|
+
* entry's default, and the only one that can stream an AI answer)
|
|
381
|
+
* refuses a bare picker part with
|
|
382
|
+
* `Unsupported FormDataPart implementation`.
|
|
383
|
+
* * through a client given React Native's own fetch
|
|
384
|
+
* (`gemmein(key, { fetch })`) — RN's `FormData` reads the bytes at
|
|
385
|
+
* `uri` itself, so the part is appended exactly as the picker gave it.
|
|
386
|
+
*
|
|
387
|
+
* Carry the picker's `size` with it — the server refuses a presign that
|
|
388
|
+
* declares nothing (it cannot accept an empty file).
|
|
389
|
+
*/
|
|
390
|
+
export type UploadInput = Blob | File | {
|
|
391
|
+
uri: string;
|
|
392
|
+
name?: string;
|
|
393
|
+
type?: string;
|
|
394
|
+
size?: number;
|
|
395
|
+
};
|
|
288
396
|
/**
|
|
289
397
|
* Turn a stored file reference into a URL you can actually use.
|
|
290
398
|
*
|
|
@@ -360,9 +468,14 @@ export declare class PaymentsClient {
|
|
|
360
468
|
* WHAT is being bought when one product covers many things (e.g. a
|
|
361
469
|
* license tier across a catalog):
|
|
362
470
|
* `g.payments.buy("premium license", { item: "beat_37" })`.
|
|
363
|
-
*
|
|
364
|
-
* the
|
|
365
|
-
*
|
|
471
|
+
* Gemmein records every completed payment itself: `g.purchases.mine()` is
|
|
472
|
+
* the buyer's proof, and a product that delivers a file carries
|
|
473
|
+
* `delivery` on it. Gate fulfilment on the purchase (or the entitlement it
|
|
474
|
+
* granted), never on the redirect coming back. A receipts collection is
|
|
475
|
+
* optional, for proof records only.
|
|
476
|
+
*
|
|
477
|
+
* A product sold via a RELAY, or not sold yet, has no Payment Link to
|
|
478
|
+
* open: this answers 409 `product_not_sellable`.
|
|
366
479
|
*/
|
|
367
480
|
buy(product: string, options?: {
|
|
368
481
|
item?: string;
|
|
@@ -387,6 +500,23 @@ export declare class AccountClient {
|
|
|
387
500
|
delete(): Promise<unknown>;
|
|
388
501
|
}
|
|
389
502
|
export type AiProvider = "openai" | "anthropic" | "google";
|
|
503
|
+
/** W9.6 §16: one of the person's own AI calls, as `g.ai.calls()` lists them. */
|
|
504
|
+
export type AiCallRecord = {
|
|
505
|
+
id: string;
|
|
506
|
+
tool: string;
|
|
507
|
+
kind: string;
|
|
508
|
+
provider: string;
|
|
509
|
+
model: string | null;
|
|
510
|
+
tokensIn: number | null;
|
|
511
|
+
tokensOut: number | null;
|
|
512
|
+
credits: number;
|
|
513
|
+
outcome: "ok" | "refused" | "provider_error" | "unreachable" | "client_closed" | "stream_ended";
|
|
514
|
+
refusalCode: string | null;
|
|
515
|
+
latencyMs: number | null;
|
|
516
|
+
prompt: string | null;
|
|
517
|
+
answer: string | null;
|
|
518
|
+
createdAt: string;
|
|
519
|
+
};
|
|
390
520
|
export type AiChatOptions = {
|
|
391
521
|
/** Which configured provider answers. Optional when exactly one key is
|
|
392
522
|
* set; refused `provider_required` (400) when it is ambiguous. Refused
|
|
@@ -396,7 +526,10 @@ export type AiChatOptions = {
|
|
|
396
526
|
/** W9.3b: a named AI tool (owner-configured in the console — credits,
|
|
397
527
|
* gate and provider/model are the tool's, not this call's). Sent as
|
|
398
528
|
* `?tool=`, never in the body. Omitted → the implicit default tool: one
|
|
399
|
-
* credit, any allowed model, no gate.
|
|
529
|
+
* credit, any allowed model, no gate. With or without `tool`, `chat` is
|
|
530
|
+
* a RAW call — off by default (`raw_calls_off`, 403) until the founder
|
|
531
|
+
* switches raw calls on for that provider's key on the AI tools page;
|
|
532
|
+
* the normal path to a named tool is `run(name, inputs)`. */
|
|
400
533
|
tool?: string;
|
|
401
534
|
/** Abort the call — the stream closes; a call that dies mid-stream is
|
|
402
535
|
* not refunded. */
|
|
@@ -433,16 +566,24 @@ export declare class CreditsClient {
|
|
|
433
566
|
}>;
|
|
434
567
|
}
|
|
435
568
|
/**
|
|
436
|
-
* The AI route.
|
|
437
|
-
*
|
|
438
|
-
*
|
|
439
|
-
*
|
|
440
|
-
*
|
|
441
|
-
* `
|
|
442
|
-
*
|
|
443
|
-
*
|
|
444
|
-
*
|
|
445
|
-
*
|
|
569
|
+
* The AI route. The primary path is a NAMED TOOL defined on the server:
|
|
570
|
+
* `run(name, inputs)` sends a name and inputs, the server composes the
|
|
571
|
+
* provider request from the tool's own instructions and template (never
|
|
572
|
+
* the browser), gates it, spends the tool's credits and streams the
|
|
573
|
+
* answer back; `runText` is the same call collected to one string;
|
|
574
|
+
* `calls()` is the signed-in person's own history. `chat` is the RAW
|
|
575
|
+
* call: it takes the provider's own request body — exactly what you would
|
|
576
|
+
* POST to OpenAI's /v1/chat/completions, Anthropic's /v1/messages or
|
|
577
|
+
* Google's generateContent — and answers with the fetch `Response`
|
|
578
|
+
* untouched, streaming intact (SSE stays SSE). Raw calls are off by
|
|
579
|
+
* default for every provider key (`raw_calls_off`, 403) until the founder
|
|
580
|
+
* switches them on for that key on the AI tools page. Gemmein spends a
|
|
581
|
+
* credit, adds the owner's key, forwards, and passes status and bytes
|
|
582
|
+
* back. Pass `tool` (W9.3b) to a raw call to price and gate it as a named
|
|
583
|
+
* tool instead of the implicit default (one credit, any allowed model, no
|
|
584
|
+
* gate). Response headers: `x-gemmein-credits-remaining` on every answer
|
|
585
|
+
* that passed the spend; `x-gemmein-credit: refunded` when the provider
|
|
586
|
+
* failed before its first byte.
|
|
446
587
|
*/
|
|
447
588
|
export declare class AiClient {
|
|
448
589
|
private readonly config;
|
|
@@ -452,7 +593,10 @@ export declare class AiClient {
|
|
|
452
593
|
* for await (const chunk of res.body) { … }
|
|
453
594
|
*
|
|
454
595
|
* Browser sessions only — a server key is refused (`scope_denied`, 403).
|
|
455
|
-
* Refusals, all `GemmeinError`: `
|
|
596
|
+
* Refusals, all `GemmeinError`: `raw_calls_off` (403 — raw calls are off
|
|
597
|
+
* for this provider until the founder switches them on for its key on
|
|
598
|
+
* the AI tools page; call a named tool with `run` instead) ·
|
|
599
|
+
* `session_required` (401) ·
|
|
456
600
|
* `credits_exhausted` (402 — the message carries the balance; show your
|
|
457
601
|
* own "buy more" door, which is a product checkout) · `ai_not_configured`
|
|
458
602
|
* (409 — the owner has set no key) · `provider_required` (400) ·
|
|
@@ -472,6 +616,63 @@ export declare class AiClient {
|
|
|
472
616
|
* on the implicit default.
|
|
473
617
|
*/
|
|
474
618
|
chat(body: Record<string, unknown>, options?: AiChatOptions): Promise<Response>;
|
|
619
|
+
/**
|
|
620
|
+
* W9.6: run a named tool with INPUTS — the server composes the provider
|
|
621
|
+
* request from the tool's own instructions and template (never the
|
|
622
|
+
* browser), gates it, spends its credits and streams the answer back.
|
|
623
|
+
* The answer is the provider's own shape for the tool's provider (SSE
|
|
624
|
+
* when `stream`), so read it as you would `chat()`'s.
|
|
625
|
+
*
|
|
626
|
+
* const res = await g.ai.run("summarise", { text }, { stream: true });
|
|
627
|
+
*
|
|
628
|
+
* Browser sessions only — a server key is refused (`scope_denied`, 403).
|
|
629
|
+
* Refusals, all `GemmeinError`: `session_required` (401 — sign in
|
|
630
|
+
* first) · `ai_capped` (429 — 20 calls a minute per person;
|
|
631
|
+
* `err.resetAt`) · `unknown_tool` (404 — no tool by that name in this
|
|
632
|
+
* environment) · `tool_disabled` (403 — the owner switched it off) ·
|
|
633
|
+
* `entitlement_required` (403 — the message names the plan or product
|
|
634
|
+
* it needs) · `payload_too_large` (413 — inputs over 64 KB) ·
|
|
635
|
+
* `invalid_body` (400 — the body must be a JSON object
|
|
636
|
+
* `{ inputs, stream? }`) · `invalid_inputs` (400 — the message names the
|
|
637
|
+
* input and the rule) · `tool_incomplete` (409 — the tool composes
|
|
638
|
+
* nothing; a founder's fix) · `ai_not_configured` (409 — the tool's
|
|
639
|
+
* provider has no key set; the owner pastes one) · `credits_exhausted`
|
|
640
|
+
* (402 — the message names the tool, its price and the balance) ·
|
|
641
|
+
* `provider_unreachable` (502 — no answer before the first byte; the
|
|
642
|
+
* tool's credits are refunded, header `x-gemmein-credit: refunded`).
|
|
643
|
+
* The provider's own answer — 2xx or not — is returned as it came; read
|
|
644
|
+
* `res.ok` yourself. `x-gemmein-tool` names the tool.
|
|
645
|
+
*/
|
|
646
|
+
run(tool: string, inputs?: Record<string, string | number | boolean>, options?: {
|
|
647
|
+
stream?: boolean;
|
|
648
|
+
signal?: AbortSignal;
|
|
649
|
+
}): Promise<Response>;
|
|
650
|
+
/**
|
|
651
|
+
* W9.6: `run()` without a stream, as one string — the text lifted out
|
|
652
|
+
* of the tool's provider's answer (the same readers `text()` uses).
|
|
653
|
+
* `run()`'s refusals, plus: a provider's own non-2xx throws
|
|
654
|
+
* `provider_error` with the provider's status and message; an answer
|
|
655
|
+
* with no text to lift out throws `invalid_response` (status 0).
|
|
656
|
+
*
|
|
657
|
+
* const summary = await g.ai.runText("summarise", { text });
|
|
658
|
+
*/
|
|
659
|
+
runText(tool: string, inputs?: Record<string, string | number | boolean>, options?: {
|
|
660
|
+
signal?: AbortSignal;
|
|
661
|
+
}): Promise<string>;
|
|
662
|
+
/**
|
|
663
|
+
* W9.6 §16: the signed-in person's OWN AI calls, newest first — what they
|
|
664
|
+
* ran, when, what it cost, how it ended; the prompt and answer only where
|
|
665
|
+
* the tool keeps them. Session required.
|
|
666
|
+
*
|
|
667
|
+
* const { calls, nextCursor } = await g.ai.calls();
|
|
668
|
+
*/
|
|
669
|
+
calls(options?: {
|
|
670
|
+
limit?: number;
|
|
671
|
+
before?: string | null;
|
|
672
|
+
}): Promise<{
|
|
673
|
+
calls: AiCallRecord[];
|
|
674
|
+
nextCursor: string | null;
|
|
675
|
+
}>;
|
|
475
676
|
/**
|
|
476
677
|
* The non-streaming convenience: one call, one string. Pass a body that
|
|
477
678
|
* does NOT stream (`stream` unset or false); the provider's JSON answer is
|
|
@@ -600,7 +801,7 @@ export declare class CollectionClient<T extends Record<string, unknown> = Record
|
|
|
600
801
|
}): Promise<GemmeinRecord<T>>;
|
|
601
802
|
delete(id: string): Promise<void>;
|
|
602
803
|
/**
|
|
603
|
-
* Upload a file and get back a REFERENCE — `file
|
|
804
|
+
* Upload a file and get back a REFERENCE — `file:<uuid>` — not a URL.
|
|
604
805
|
*
|
|
605
806
|
* Store the reference. It never expires, it is safe to log and export, and
|
|
606
807
|
* it grants nothing on its own. To show or download the file, call
|
|
@@ -627,7 +828,7 @@ export declare class CollectionClient<T extends Record<string, unknown> = Record
|
|
|
627
828
|
* There is deliberately no `url` here. A URL that outlives a refund is the
|
|
628
829
|
* bug this replaced.
|
|
629
830
|
*/
|
|
630
|
-
upload(file:
|
|
831
|
+
upload(file: UploadInput, options?: {
|
|
631
832
|
name?: string;
|
|
632
833
|
contentType?: string;
|
|
633
834
|
for?: string;
|
|
@@ -642,6 +843,11 @@ export declare class CollectionClient<T extends Record<string, unknown> = Record
|
|
|
642
843
|
export type GemmeinServerOptions = {
|
|
643
844
|
secretKey: string;
|
|
644
845
|
apiUrl?: string;
|
|
846
|
+
/** The same seam the client has: a `fetch` to use instead of the global
|
|
847
|
+
* one. Every request this class makes goes through `resolveFetch`, so a
|
|
848
|
+
* transport failure is a `GemmeinError` `network_unreachable` here too
|
|
849
|
+
* (W10 review row 14a — the parity law: one seam, both rails). */
|
|
850
|
+
fetch?: typeof fetch;
|
|
645
851
|
};
|
|
646
852
|
/**
|
|
647
853
|
* Where a grant came from — the KIND only. The gate never returns the
|
|
@@ -680,6 +886,13 @@ export type Holdings = {
|
|
|
680
886
|
balance: number;
|
|
681
887
|
} | null;
|
|
682
888
|
};
|
|
889
|
+
/**
|
|
890
|
+
* The person behind a token or an id. The role you read here is the EFFECTIVE
|
|
891
|
+
* one — account membership (owner/admin) wins over the stored role, so
|
|
892
|
+
* a founder signed into their own app reads `owner` here and not the `member`
|
|
893
|
+
* every person is born as. `verifySession` and `holdings` answer with
|
|
894
|
+
* the same one — one person has one role, whichever door asked for it.
|
|
895
|
+
*/
|
|
683
896
|
export type GatePerson = {
|
|
684
897
|
id: string;
|
|
685
898
|
email: string;
|
|
@@ -698,6 +911,12 @@ export type InvitedPerson = GatePerson & {
|
|
|
698
911
|
export declare class GemmeinServer {
|
|
699
912
|
private readonly apiUrl;
|
|
700
913
|
private readonly secretKey;
|
|
914
|
+
/** W10 review row 14a: THE ONE TRANSPORT SEAM, on this rail too. Every
|
|
915
|
+
* call below goes through it, so a refused connection is a typed
|
|
916
|
+
* `network_unreachable` and never a raw `TypeError` — the same law the
|
|
917
|
+
* client rail has held since row 9, and what makes "everything the
|
|
918
|
+
* package throws is a GemmeinError" true of the whole package. */
|
|
919
|
+
private readonly fetch;
|
|
701
920
|
constructor(options: GemmeinServerOptions);
|
|
702
921
|
collection(name: string): ServerCollectionClient;
|
|
703
922
|
/**
|
|
@@ -929,7 +1148,10 @@ declare class ServerCollectionClient {
|
|
|
929
1148
|
private readonly apiUrl;
|
|
930
1149
|
private readonly secretKey;
|
|
931
1150
|
private readonly name;
|
|
932
|
-
|
|
1151
|
+
/** Handed down from `GemmeinServer` — never resolved again here, so one
|
|
1152
|
+
* client has one transport and a test's injected fetch reaches it. */
|
|
1153
|
+
private readonly fetch;
|
|
1154
|
+
constructor(apiUrl: string, secretKey: string, name: string, fetchImpl: typeof fetch);
|
|
933
1155
|
get(id: string): Promise<unknown>;
|
|
934
1156
|
list(options?: {
|
|
935
1157
|
limit?: number;
|