@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/migrations/README.md
CHANGED
|
@@ -33,3 +33,5 @@ the same surface gets its own file.
|
|
|
33
33
|
| File | Since | Action required by |
|
|
34
34
|
|------|-------|--------------------|
|
|
35
35
|
| [`list-limit-refusal.md`](./list-limit-refusal.md) | 0.6.0 | 0.6.0 |
|
|
36
|
+
| [`raw-calls-off.md`](./raw-calls-off.md) | 0.9.0 | 0.9.0 |
|
|
37
|
+
| [`secure-store-set-throws.md`](./secure-store-set-throws.md) | 0.10.0 | 0.10.0 |
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# Raw AI calls are off until the owner switches them on
|
|
2
|
+
|
|
3
|
+
```
|
|
4
|
+
Since: 0.9.0
|
|
5
|
+
Action required by: 0.9.0
|
|
6
|
+
```
|
|
7
|
+
|
|
8
|
+
## What changed
|
|
9
|
+
|
|
10
|
+
Before 0.9.0 `g.ai.chat(body)` and `g.ai.text(body)` forwarded the
|
|
11
|
+
provider request the browser composed to any provider the owner had a key
|
|
12
|
+
for. From 0.9.0 that raw call is refused with `403 raw_calls_off` unless the
|
|
13
|
+
owner has switched raw calls on for that provider's key on the AI tools
|
|
14
|
+
page. The cloud applies this to every key, new and existing, from 7 Sep
|
|
15
|
+
2026; the local engine (`gemmein dev`) keeps its keyless fake provider open
|
|
16
|
+
and applies the same rule to a configured key.
|
|
17
|
+
|
|
18
|
+
The normal path is a named tool: the owner defines it on the AI tools page
|
|
19
|
+
or your AI writes `gemmein/ai/tools/<name>.json` (instructions, prompt
|
|
20
|
+
template, typed inputs, model, caps) and the app calls it with inputs only.
|
|
21
|
+
|
|
22
|
+
## Who is affected
|
|
23
|
+
|
|
24
|
+
Apps that call `g.ai.chat` or `g.ai.text` without `tool`, or with a `tool`
|
|
25
|
+
that only prices and gates a browser-composed body. An app that already
|
|
26
|
+
calls `g.ai.run` / `g.ai.runText`, or makes no AI calls, sees no
|
|
27
|
+
difference.
|
|
28
|
+
|
|
29
|
+
## What to do
|
|
30
|
+
|
|
31
|
+
Move each call to a named tool. The prompt leaves the browser and lives on
|
|
32
|
+
the tool:
|
|
33
|
+
|
|
34
|
+
```ts
|
|
35
|
+
// before
|
|
36
|
+
const res = await g.ai.chat({ model: "gpt-4o-mini", messages: [{ role: "user", content: `Summarise: ${text}` }] });
|
|
37
|
+
|
|
38
|
+
// after — gemmein/ai/tools/summarise.json carries the instructions and
|
|
39
|
+
// "promptTemplate": "Summarise: {{text}}", "inputs": [{ "name": "text", "type": "text", "required": true }]
|
|
40
|
+
const res = await g.ai.run("summarise", { text });
|
|
41
|
+
const answer = await g.ai.runText("summarise", { text });
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
An owner who wants the raw path back switches raw calls on for that
|
|
45
|
+
provider's key on the AI tools page; the switch is per key and audited.
|
|
46
|
+
|
|
47
|
+
## How to tell
|
|
48
|
+
|
|
49
|
+
A 403 with `code: "raw_calls_off"` in the response, `err.code ===
|
|
50
|
+
"raw_calls_off"` in the SDK, and the message naming the provider and the
|
|
51
|
+
switch. On the AI calls record the outcome is `refused` with that reason.
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# A token store that cannot keep the session says so
|
|
2
|
+
|
|
3
|
+
```
|
|
4
|
+
Since: 0.10.0
|
|
5
|
+
Action required by: 0.10.0
|
|
6
|
+
```
|
|
7
|
+
|
|
8
|
+
## What changed
|
|
9
|
+
|
|
10
|
+
Before 0.10.0 a token store that could not write swallowed the failure.
|
|
11
|
+
`auth.verifyEmailCode()` resolved, the app believed it was signed in, and the
|
|
12
|
+
session was gone on the next read — the app reported itself signed out with
|
|
13
|
+
nothing anywhere saying why.
|
|
14
|
+
|
|
15
|
+
From 0.10.0 `tokenStore.set()` THROWS a `GemmeinError` with code
|
|
16
|
+
`secure_store_unavailable` (status 0) when the store refuses the write, and
|
|
17
|
+
`auth.verifyEmailCode()` carries it to the caller. The law is all three
|
|
18
|
+
stores:
|
|
19
|
+
|
|
20
|
+
- `SecureStoreTokenStore` (`@gemmein/sdk/expo`) — `expo-secure-store` missing
|
|
21
|
+
or refusing (an unsigned simulator build has no keychain access group).
|
|
22
|
+
- `BrowserTokenStore` — a refused `localStorage` write: Safari private mode
|
|
23
|
+
past its quota, a browser set to block site data, a sandboxed iframe whose
|
|
24
|
+
access throws.
|
|
25
|
+
- `KeychainTokenStore` (`GemmeinSwift`) — the same, with the OSStatus and
|
|
26
|
+
`SecCopyErrorMessageString`'s words for it in the sentence.
|
|
27
|
+
|
|
28
|
+
The device's or browser's own error is on `err.cause`. `get()` and `clear()`
|
|
29
|
+
are unchanged and stay lenient: an unreadable store means signed out, which
|
|
30
|
+
every app already handles, and a crash at launch is worse than a sign-in
|
|
31
|
+
screen. `MemoryTokenStore.set()` never throws. The existing `token_too_large`
|
|
32
|
+
refusal is unchanged.
|
|
33
|
+
|
|
34
|
+
## Who is affected
|
|
35
|
+
|
|
36
|
+
Apps that call `auth.verifyEmailCode()` (or any call that stores a session)
|
|
37
|
+
in a place where the store may refuse the write, and that RELIED on the old
|
|
38
|
+
silence to keep running: a kiosk browser, an embedded or sandboxed iframe, a
|
|
39
|
+
private-mode visitor, an unsigned simulator or ad-hoc mobile build. An app in
|
|
40
|
+
an ordinary browser tab or a signed app sees no difference — nothing that
|
|
41
|
+
stored the token before throws now.
|
|
42
|
+
|
|
43
|
+
## What to do
|
|
44
|
+
|
|
45
|
+
Catch the one code and rebuild the client with a `MemoryTokenStore`. The
|
|
46
|
+
session is real either way — the server minted it — so an app that would
|
|
47
|
+
rather run than stop can carry it in memory: sign-in works, and ends with the
|
|
48
|
+
process.
|
|
49
|
+
|
|
50
|
+
```ts
|
|
51
|
+
import { gemmein, MemoryTokenStore, GemmeinError } from "@gemmein/sdk";
|
|
52
|
+
|
|
53
|
+
let g = gemmein({ appKey });
|
|
54
|
+
try {
|
|
55
|
+
await g.auth.verifyEmailCode(email, code);
|
|
56
|
+
} catch (err) {
|
|
57
|
+
if (err instanceof GemmeinError && err.code === "secure_store_unavailable") {
|
|
58
|
+
// This session will not survive a reload. Say so, or carry on knowingly.
|
|
59
|
+
g = gemmein({ appKey, tokenStore: new MemoryTokenStore() });
|
|
60
|
+
await g.auth.verifyEmailCode(email, code);
|
|
61
|
+
} else {
|
|
62
|
+
throw err;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
An app that knows it runs where nothing can be stored passes
|
|
68
|
+
`tokenStore: new MemoryTokenStore()` from the start and never sees the code.
|
|
69
|
+
|
|
70
|
+
## How to tell
|
|
71
|
+
|
|
72
|
+
`err.code === "secure_store_unavailable"` on the SDK (status 0, no HTTP
|
|
73
|
+
response — the request succeeded; the STORE refused), with the store's own
|
|
74
|
+
throw on `err.cause` and the fix in the message. In `GemmeinSwift` the same
|
|
75
|
+
case is a thrown `GemmeinError` whose message carries the keychain's OSStatus.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gemmein/sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"description": "Gemmein SDK \u2014 passwordless auth, safe storage, and Stripe-driven record flips for AI-built apps. Small enough that one prompt teaches the whole API.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -13,6 +13,11 @@
|
|
|
13
13
|
"import": "./dist/index.js",
|
|
14
14
|
"require": "./dist/index.cjs"
|
|
15
15
|
},
|
|
16
|
+
"./expo": {
|
|
17
|
+
"types": "./dist/expo.d.ts",
|
|
18
|
+
"import": "./dist/expo.js",
|
|
19
|
+
"require": "./dist/expo.cjs"
|
|
20
|
+
},
|
|
16
21
|
"./llms.txt": "./llms.txt",
|
|
17
22
|
"./REFERENCE.md": "./REFERENCE.md",
|
|
18
23
|
"./reaffirm.mjs": "./reaffirm.mjs",
|
|
@@ -27,6 +32,22 @@
|
|
|
27
32
|
"reaffirm.mjs"
|
|
28
33
|
],
|
|
29
34
|
"sideEffects": false,
|
|
35
|
+
"peerDependencies": {
|
|
36
|
+
"expo": "*",
|
|
37
|
+
"expo-secure-store": "*",
|
|
38
|
+
"react-native": "*"
|
|
39
|
+
},
|
|
40
|
+
"peerDependenciesMeta": {
|
|
41
|
+
"expo": {
|
|
42
|
+
"optional": true
|
|
43
|
+
},
|
|
44
|
+
"expo-secure-store": {
|
|
45
|
+
"optional": true
|
|
46
|
+
},
|
|
47
|
+
"react-native": {
|
|
48
|
+
"optional": true
|
|
49
|
+
}
|
|
50
|
+
},
|
|
30
51
|
"engines": {
|
|
31
52
|
"node": ">=20"
|
|
32
53
|
},
|
|
@@ -49,7 +70,7 @@
|
|
|
49
70
|
"scripts": {
|
|
50
71
|
"version:sync": "node scripts/sync-version.mjs",
|
|
51
72
|
"prebuild": "node scripts/sync-version.mjs",
|
|
52
|
-
"build": "rm -rf dist && tsc -p tsconfig.build.json && tsc -p tsconfig.cjs.json && mv dist/cjs/index.js dist/index.cjs && rm -rf dist/cjs && cp dist/index.d.ts dist/index.d.cts",
|
|
73
|
+
"build": "rm -rf dist && tsc -p tsconfig.build.json && tsc -p tsconfig.cjs.json && mv dist/cjs/index.js dist/index.cjs && mv dist/cjs/expo.js dist/expo.cjs && rm -rf dist/cjs && sed -i.bak 's#\"./index.js\"#\"./index.cjs\"#g' dist/expo.cjs && rm -f dist/expo.cjs.bak && cp dist/index.d.ts dist/index.d.cts && cp dist/expo.d.ts dist/expo.d.cts",
|
|
53
74
|
"prepack": "npm run build",
|
|
54
75
|
"prepublishOnly": "npm run build"
|
|
55
76
|
},
|