@gemmein/sdk 0.9.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 +179 -0
- package/README.md +79 -18
- package/REFERENCE.md +282 -14
- 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 +224 -34
- package/dist/index.d.cts +143 -9
- package/dist/index.d.ts +143 -9
- package/dist/index.js +223 -34
- package/llms.txt +320 -34
- package/migrations/README.md +1 -0
- package/migrations/secure-store-set-throws.md +75 -0
- package/package.json +23 -2
package/dist/index.d.cts
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;
|
|
@@ -688,7 +801,7 @@ export declare class CollectionClient<T extends Record<string, unknown> = Record
|
|
|
688
801
|
}): Promise<GemmeinRecord<T>>;
|
|
689
802
|
delete(id: string): Promise<void>;
|
|
690
803
|
/**
|
|
691
|
-
* Upload a file and get back a REFERENCE — `file
|
|
804
|
+
* Upload a file and get back a REFERENCE — `file:<uuid>` — not a URL.
|
|
692
805
|
*
|
|
693
806
|
* Store the reference. It never expires, it is safe to log and export, and
|
|
694
807
|
* it grants nothing on its own. To show or download the file, call
|
|
@@ -715,7 +828,7 @@ export declare class CollectionClient<T extends Record<string, unknown> = Record
|
|
|
715
828
|
* There is deliberately no `url` here. A URL that outlives a refund is the
|
|
716
829
|
* bug this replaced.
|
|
717
830
|
*/
|
|
718
|
-
upload(file:
|
|
831
|
+
upload(file: UploadInput, options?: {
|
|
719
832
|
name?: string;
|
|
720
833
|
contentType?: string;
|
|
721
834
|
for?: string;
|
|
@@ -730,6 +843,11 @@ export declare class CollectionClient<T extends Record<string, unknown> = Record
|
|
|
730
843
|
export type GemmeinServerOptions = {
|
|
731
844
|
secretKey: string;
|
|
732
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;
|
|
733
851
|
};
|
|
734
852
|
/**
|
|
735
853
|
* Where a grant came from — the KIND only. The gate never returns the
|
|
@@ -768,6 +886,13 @@ export type Holdings = {
|
|
|
768
886
|
balance: number;
|
|
769
887
|
} | null;
|
|
770
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
|
+
*/
|
|
771
896
|
export type GatePerson = {
|
|
772
897
|
id: string;
|
|
773
898
|
email: string;
|
|
@@ -786,6 +911,12 @@ export type InvitedPerson = GatePerson & {
|
|
|
786
911
|
export declare class GemmeinServer {
|
|
787
912
|
private readonly apiUrl;
|
|
788
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;
|
|
789
920
|
constructor(options: GemmeinServerOptions);
|
|
790
921
|
collection(name: string): ServerCollectionClient;
|
|
791
922
|
/**
|
|
@@ -1017,7 +1148,10 @@ declare class ServerCollectionClient {
|
|
|
1017
1148
|
private readonly apiUrl;
|
|
1018
1149
|
private readonly secretKey;
|
|
1019
1150
|
private readonly name;
|
|
1020
|
-
|
|
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);
|
|
1021
1155
|
get(id: string): Promise<unknown>;
|
|
1022
1156
|
list(options?: {
|
|
1023
1157
|
limit?: number;
|
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;
|
|
@@ -688,7 +801,7 @@ export declare class CollectionClient<T extends Record<string, unknown> = Record
|
|
|
688
801
|
}): Promise<GemmeinRecord<T>>;
|
|
689
802
|
delete(id: string): Promise<void>;
|
|
690
803
|
/**
|
|
691
|
-
* Upload a file and get back a REFERENCE — `file
|
|
804
|
+
* Upload a file and get back a REFERENCE — `file:<uuid>` — not a URL.
|
|
692
805
|
*
|
|
693
806
|
* Store the reference. It never expires, it is safe to log and export, and
|
|
694
807
|
* it grants nothing on its own. To show or download the file, call
|
|
@@ -715,7 +828,7 @@ export declare class CollectionClient<T extends Record<string, unknown> = Record
|
|
|
715
828
|
* There is deliberately no `url` here. A URL that outlives a refund is the
|
|
716
829
|
* bug this replaced.
|
|
717
830
|
*/
|
|
718
|
-
upload(file:
|
|
831
|
+
upload(file: UploadInput, options?: {
|
|
719
832
|
name?: string;
|
|
720
833
|
contentType?: string;
|
|
721
834
|
for?: string;
|
|
@@ -730,6 +843,11 @@ export declare class CollectionClient<T extends Record<string, unknown> = Record
|
|
|
730
843
|
export type GemmeinServerOptions = {
|
|
731
844
|
secretKey: string;
|
|
732
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;
|
|
733
851
|
};
|
|
734
852
|
/**
|
|
735
853
|
* Where a grant came from — the KIND only. The gate never returns the
|
|
@@ -768,6 +886,13 @@ export type Holdings = {
|
|
|
768
886
|
balance: number;
|
|
769
887
|
} | null;
|
|
770
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
|
+
*/
|
|
771
896
|
export type GatePerson = {
|
|
772
897
|
id: string;
|
|
773
898
|
email: string;
|
|
@@ -786,6 +911,12 @@ export type InvitedPerson = GatePerson & {
|
|
|
786
911
|
export declare class GemmeinServer {
|
|
787
912
|
private readonly apiUrl;
|
|
788
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;
|
|
789
920
|
constructor(options: GemmeinServerOptions);
|
|
790
921
|
collection(name: string): ServerCollectionClient;
|
|
791
922
|
/**
|
|
@@ -1017,7 +1148,10 @@ declare class ServerCollectionClient {
|
|
|
1017
1148
|
private readonly apiUrl;
|
|
1018
1149
|
private readonly secretKey;
|
|
1019
1150
|
private readonly name;
|
|
1020
|
-
|
|
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);
|
|
1021
1155
|
get(id: string): Promise<unknown>;
|
|
1022
1156
|
list(options?: {
|
|
1023
1157
|
limit?: number;
|