jazz-tools 2.0.0-alpha.35 → 2.0.0-alpha.37
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/bin/docs-index.db +0 -0
- package/bin/docs-index.txt +127 -117
- package/bin/native/jazz-tools-darwin-arm64 +0 -0
- package/bin/native/jazz-tools-darwin-x64 +0 -0
- package/bin/native/jazz-tools-linux-arm64 +0 -0
- package/bin/native/jazz-tools-linux-x64 +0 -0
- package/dist/backend/create-jazz-context.d.ts +4 -8
- package/dist/backend/create-jazz-context.d.ts.map +1 -1
- package/dist/backend/create-jazz-context.js +2 -25
- package/dist/backend/create-jazz-context.js.map +1 -1
- package/dist/better-auth-adapter/fixtures/schema.d.ts +58 -0
- package/dist/better-auth-adapter/fixtures/schema.d.ts.map +1 -0
- package/dist/better-auth-adapter/fixtures/schema.js +77 -0
- package/dist/better-auth-adapter/fixtures/schema.js.map +1 -0
- package/dist/better-auth-adapter/index.d.ts +13 -0
- package/dist/better-auth-adapter/index.d.ts.map +1 -0
- package/dist/better-auth-adapter/index.js +205 -0
- package/dist/better-auth-adapter/index.js.map +1 -0
- package/dist/better-auth-adapter/index.test.d.ts +2 -0
- package/dist/better-auth-adapter/index.test.d.ts.map +1 -0
- package/dist/better-auth-adapter/index.test.js +1032 -0
- package/dist/better-auth-adapter/index.test.js.map +1 -0
- package/dist/better-auth-adapter/schema.d.ts +49 -0
- package/dist/better-auth-adapter/schema.d.ts.map +1 -0
- package/dist/better-auth-adapter/schema.js +278 -0
- package/dist/better-auth-adapter/schema.js.map +1 -0
- package/dist/better-auth-adapter/schema.test.d.ts +2 -0
- package/dist/better-auth-adapter/schema.test.d.ts.map +1 -0
- package/dist/better-auth-adapter/schema.test.js +293 -0
- package/dist/better-auth-adapter/schema.test.js.map +1 -0
- package/dist/better-auth-adapter/types.d.ts +13 -0
- package/dist/better-auth-adapter/types.d.ts.map +1 -0
- package/dist/better-auth-adapter/types.js +2 -0
- package/dist/better-auth-adapter/types.js.map +1 -0
- package/dist/better-auth-adapter/utils.d.ts +27 -0
- package/dist/better-auth-adapter/utils.d.ts.map +1 -0
- package/dist/better-auth-adapter/utils.js +220 -0
- package/dist/better-auth-adapter/utils.js.map +1 -0
- package/dist/better-auth-adapter/utils.test.d.ts +2 -0
- package/dist/better-auth-adapter/utils.test.d.ts.map +1 -0
- package/dist/better-auth-adapter/utils.test.js +777 -0
- package/dist/better-auth-adapter/utils.test.js.map +1 -0
- package/dist/cli.d.ts +4 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +51 -24
- package/dist/cli.js.map +1 -1
- package/dist/cli.test.js +83 -4
- package/dist/cli.test.js.map +1 -1
- package/dist/dev/env-file.d.ts +17 -0
- package/dist/dev/env-file.d.ts.map +1 -0
- package/dist/dev/env-file.js +43 -0
- package/dist/dev/env-file.js.map +1 -0
- package/dist/dev/managed-runtime.d.ts.map +1 -1
- package/dist/dev/managed-runtime.js +43 -7
- package/dist/dev/managed-runtime.js.map +1 -1
- package/dist/dev/next.d.ts +1 -0
- package/dist/dev/next.d.ts.map +1 -1
- package/dist/dev/next.js +47 -4
- package/dist/dev/next.js.map +1 -1
- package/dist/dev/next.test.js +41 -3
- package/dist/dev/next.test.js.map +1 -1
- package/dist/dev/sveltekit.d.ts.map +1 -1
- package/dist/dev/sveltekit.js +6 -1
- package/dist/dev/sveltekit.js.map +1 -1
- package/dist/dev/sveltekit.test.js +17 -2
- package/dist/dev/sveltekit.test.js.map +1 -1
- package/dist/dev/vite.d.ts.map +1 -1
- package/dist/dev/vite.js +15 -4
- package/dist/dev/vite.js.map +1 -1
- package/dist/dev/vite.test.js +45 -27
- package/dist/dev/vite.test.js.map +1 -1
- package/dist/dev-tools/dev-tools.d.ts.map +1 -1
- package/dist/dev-tools/dev-tools.js +10 -3
- package/dist/dev-tools/dev-tools.js.map +1 -1
- package/dist/dev-tools/dev-tools.test.js +28 -18
- package/dist/dev-tools/dev-tools.test.js.map +1 -1
- package/dist/dsl.d.ts +51 -34
- package/dist/dsl.d.ts.map +1 -1
- package/dist/dsl.js +13 -6
- package/dist/dsl.js.map +1 -1
- package/dist/dsl.test.js +17 -5
- package/dist/dsl.test.js.map +1 -1
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/migrations.d.ts +34 -0
- package/dist/migrations.d.ts.map +1 -1
- package/dist/migrations.js +34 -0
- package/dist/migrations.js.map +1 -1
- package/dist/react/create-jazz-client.d.ts.map +1 -1
- package/dist/react/create-jazz-client.integration.test.js +2 -2
- package/dist/react/create-jazz-client.integration.test.js.map +1 -1
- package/dist/react/create-jazz-client.js +3 -0
- package/dist/react/create-jazz-client.js.map +1 -1
- package/dist/react/create-jazz-client.test.js +53 -2
- package/dist/react/create-jazz-client.test.js.map +1 -1
- package/dist/react/provider.d.ts +3 -0
- package/dist/react/provider.d.ts.map +1 -1
- package/dist/react/provider.js +3 -0
- package/dist/react/provider.js.map +1 -1
- package/dist/react-core/provider.d.ts +6 -0
- package/dist/react-core/provider.d.ts.map +1 -1
- package/dist/react-core/provider.js +6 -0
- package/dist/react-core/provider.js.map +1 -1
- package/dist/react-core/use-all.d.ts +15 -0
- package/dist/react-core/use-all.d.ts.map +1 -1
- package/dist/react-core/use-all.js +15 -0
- package/dist/react-core/use-all.js.map +1 -1
- package/dist/react-native/jazz-rn-runtime-adapter.d.ts +16 -5
- package/dist/react-native/jazz-rn-runtime-adapter.d.ts.map +1 -1
- package/dist/react-native/jazz-rn-runtime-adapter.js +85 -36
- package/dist/react-native/jazz-rn-runtime-adapter.js.map +1 -1
- package/dist/react-native/jazz-rn-runtime-adapter.test.js +52 -22
- package/dist/react-native/jazz-rn-runtime-adapter.test.js.map +1 -1
- package/dist/runtime/client.d.ts +90 -89
- package/dist/runtime/client.d.ts.map +1 -1
- package/dist/runtime/client.for-request.test.js +16 -33
- package/dist/runtime/client.for-request.test.js.map +1 -1
- package/dist/runtime/client.js +171 -246
- package/dist/runtime/client.js.map +1 -1
- package/dist/runtime/client.mutations.test.js +13 -90
- package/dist/runtime/client.mutations.test.js.map +1 -1
- package/dist/runtime/client.test.js +176 -2
- package/dist/runtime/client.test.js.map +1 -1
- package/dist/runtime/db.anonymous.test.js +11 -0
- package/dist/runtime/db.anonymous.test.js.map +1 -1
- package/dist/runtime/db.browser-storage-scope.test.js +17 -0
- package/dist/runtime/db.browser-storage-scope.test.js.map +1 -1
- package/dist/runtime/db.d.ts +71 -86
- package/dist/runtime/db.d.ts.map +1 -1
- package/dist/runtime/db.js +208 -260
- package/dist/runtime/db.js.map +1 -1
- package/dist/runtime/db.persisted.test.js +77 -67
- package/dist/runtime/db.persisted.test.js.map +1 -1
- package/dist/runtime/db.schema-order.test.js +86 -28
- package/dist/runtime/db.schema-order.test.js.map +1 -1
- package/dist/runtime/db.transaction.test.js +102 -125
- package/dist/runtime/db.transaction.test.js.map +1 -1
- package/dist/runtime/db.transport.test.js +30 -0
- package/dist/runtime/db.transport.test.js.map +1 -1
- package/dist/runtime/file-storage.d.ts +2 -5
- package/dist/runtime/file-storage.d.ts.map +1 -1
- package/dist/runtime/file-storage.js +3 -2
- package/dist/runtime/file-storage.js.map +1 -1
- package/dist/runtime/file-storage.test.js +21 -5
- package/dist/runtime/file-storage.test.js.map +1 -1
- package/dist/runtime/index.d.ts +2 -2
- package/dist/runtime/index.d.ts.map +1 -1
- package/dist/runtime/index.js +2 -2
- package/dist/runtime/index.js.map +1 -1
- package/dist/runtime/napi.for-request.test.js +147 -47
- package/dist/runtime/napi.for-request.test.js.map +1 -1
- package/dist/runtime/napi.integration.test.js +21 -18
- package/dist/runtime/napi.integration.test.js.map +1 -1
- package/dist/runtime/permissions.repro.test.js +12 -6
- package/dist/runtime/permissions.repro.test.js.map +1 -1
- package/dist/runtime/runtime-config.d.ts.map +1 -1
- package/dist/runtime/runtime-config.js +16 -2
- package/dist/runtime/runtime-config.js.map +1 -1
- package/dist/runtime/schema-marshalling.abstract-bench.test.d.ts +2 -0
- package/dist/runtime/schema-marshalling.abstract-bench.test.d.ts.map +1 -0
- package/dist/runtime/schema-marshalling.abstract-bench.test.js +49 -0
- package/dist/runtime/schema-marshalling.abstract-bench.test.js.map +1 -0
- package/dist/runtime/testing/schema-marshalling-bench.d.ts +40 -0
- package/dist/runtime/testing/schema-marshalling-bench.d.ts.map +1 -0
- package/dist/runtime/testing/schema-marshalling-bench.js +159 -0
- package/dist/runtime/testing/schema-marshalling-bench.js.map +1 -0
- package/dist/runtime/worker-bridge.test.js +5 -3
- package/dist/runtime/worker-bridge.test.js.map +1 -1
- package/dist/schema-loader.d.ts.map +1 -1
- package/dist/schema-loader.js +31 -4
- package/dist/schema-loader.js.map +1 -1
- package/dist/schema-source.d.ts +11 -0
- package/dist/schema-source.d.ts.map +1 -0
- package/dist/schema-source.js +25 -0
- package/dist/schema-source.js.map +1 -0
- package/dist/svelte/JazzSvelteProvider.svelte +4 -0
- package/dist/svelte/JazzSvelteProvider.svelte.d.ts.map +1 -1
- package/dist/svelte/context.svelte.d.ts +14 -0
- package/dist/svelte/context.svelte.d.ts.map +1 -1
- package/dist/svelte/context.svelte.js +14 -0
- package/dist/svelte/create-jazz-client.d.ts.map +1 -1
- package/dist/svelte/create-jazz-client.js +3 -0
- package/dist/svelte/use-all.svelte.d.ts +3 -0
- package/dist/svelte/use-all.svelte.d.ts.map +1 -1
- package/dist/svelte/use-all.svelte.js +3 -0
- package/dist/typed-app.d.ts +30 -0
- package/dist/typed-app.d.ts.map +1 -1
- package/dist/typed-app.js +15 -0
- package/dist/typed-app.js.map +1 -1
- package/dist/vue/create-jazz-client.d.ts.map +1 -1
- package/dist/vue/create-jazz-client.js +3 -0
- package/dist/vue/create-jazz-client.js.map +1 -1
- package/dist/vue/provider.d.ts +14 -0
- package/dist/vue/provider.d.ts.map +1 -1
- package/dist/vue/provider.js +14 -0
- package/dist/vue/provider.js.map +1 -1
- package/dist/vue/use-all.d.ts +7 -0
- package/dist/vue/use-all.d.ts.map +1 -1
- package/dist/vue/use-all.js +7 -0
- package/dist/vue/use-all.js.map +1 -1
- package/dist/window-client-storage.d.ts +22 -0
- package/dist/window-client-storage.d.ts.map +1 -0
- package/dist/window-client-storage.js +91 -0
- package/dist/window-client-storage.js.map +1 -0
- package/dist/worker/jazz-worker.js +14 -2
- package/dist/worker/jazz-worker.js.map +1 -1
- package/dist/worker/jazz-worker.test.d.ts +6 -10
- package/dist/worker/jazz-worker.test.d.ts.map +1 -1
- package/dist/worker/jazz-worker.test.js +88 -11
- package/dist/worker/jazz-worker.test.js.map +1 -1
- package/dist/worker/jazz-worker.ts +28 -10
- package/package.json +16 -4
package/bin/docs-index.db
CHANGED
|
Binary file
|
package/bin/docs-index.txt
CHANGED
|
@@ -4,11 +4,11 @@ DESCRIPTION:"How and when to use Jazz's auth modes, and how to manage JWT auth o
|
|
|
4
4
|
|
|
5
5
|
Jazz has three auth modes: `anonymous`, `local-first`, and `external`. You pick the mode implicitly by what you pass in `DbConfig`: nothing for anonymous, `secret` for local-first, or `jwtToken` for external.
|
|
6
6
|
|
|
7
|
-
| Mode | What it does
|
|
8
|
-
| ------------- |
|
|
9
|
-
| `anonymous` | Ephemeral read-only identity, no secret, no server
|
|
10
|
-
| `local-first` | Stable identity from a device secret, no server needed
|
|
11
|
-
| `external` | Validates a JWT from your auth provider via JWKS
|
|
7
|
+
| Mode | What it does | When to use it |
|
|
8
|
+
| ------------- | --------------------------------------------------------------------------- | ------------------------------------------------ |
|
|
9
|
+
| `anonymous` | Ephemeral read-only identity, no secret, no server | Public/marketing surfaces, try-before-anything |
|
|
10
|
+
| `local-first` | Stable identity from a device secret, no server needed | Production offline-first apps, try-before-signup |
|
|
11
|
+
| `external` | Validates a JWT from your auth provider via JWKS or a configured static key | Production apps with real user accounts |
|
|
12
12
|
|
|
13
13
|
Anonymous sessions can subscribe to queries but are **structurally denied writes** — every insert, update, and delete path checks the session's auth mode before any policy evaluation runs, and surfaces an `AnonymousWriteDeniedError` to the client. Gate reads the same way you gate any other access, via the permissions DSL (`session.where({ authMode: "anonymous" })`).
|
|
14
14
|
|
|
@@ -18,9 +18,9 @@ Local-first auth lets users start using your app without signing up. They can la
|
|
|
18
18
|
|
|
19
19
|
## External auth for production
|
|
20
20
|
|
|
21
|
-
Pass a JWT from your auth provider using the `jwtToken` option. Jazz validates it against your JWKS endpoint.
|
|
21
|
+
Pass a JWT from your auth provider using the `jwtToken` option. Jazz validates it against your server's configured JWKS endpoint or static key.
|
|
22
22
|
|
|
23
|
-
JWTs, or JSON Web Tokens, are small JSON payloads signed by an authority — normally this is your authentication provider. Often this JSON payload includes details about your identity, but it can also include various other pieces of information known as 'claims'. Jazz can read the signed payload and use it in your permissions policies. To validate the signature and protect against spoofing, Jazz retrieves the signing key from the JWKS endpoint you specify.
|
|
23
|
+
JWTs, or JSON Web Tokens, are small JSON payloads signed by an authority — normally this is your authentication provider. Often this JSON payload includes details about your identity, but it can also include various other pieces of information known as 'claims'. Jazz can read the signed payload and use it in your permissions policies. To validate the signature and protect against spoofing, Jazz either retrieves the signing key from the JWKS endpoint you specify or uses a single configured JWK / public key directly.
|
|
24
24
|
|
|
25
25
|
For more details, the [Auth0 docs](https://auth0.com/docs/secure/tokens/json-web-tokens) are a great starting point.
|
|
26
26
|
|
|
@@ -210,7 +210,7 @@ jazz-tools server "$JAZZ_APP_ID" \
|
|
|
210
210
|
When the server receives a request, it tries each auth method in priority order and uses the first match:
|
|
211
211
|
|
|
212
212
|
1. **Backend impersonation** — the request includes `X-Jazz-Backend-Secret` and `X-Jazz-Session` headers. A trusted backend service (e.g. a cron job or webhook handler) can act as any user by providing the shared secret and the session as a base64-encoded JSON string in `X-Jazz-Session`.
|
|
213
|
-
2. **External JWT** — the request includes an `Authorization: Bearer <jwt>` header. The token is validated against the
|
|
213
|
+
2. **External JWT** — the request includes an `Authorization: Bearer <jwt>` header. The token is validated against the configured `--jwks-url` or `--jwt-public-key`.
|
|
214
214
|
3. **Local-first auth** — the request includes an `Authorization: Bearer <jwt>` header with a self-signed local-first token.
|
|
215
215
|
4. **No session** — none of the above matched.
|
|
216
216
|
|
|
@@ -565,7 +565,7 @@ We can define permissions in `permissions.ts`:
|
|
|
565
565
|
|
|
566
566
|
Write your permissions policies in `permissions.ts` next to `schema.ts`. By default Jazz looks for both files at your project root — except in SvelteKit projects, where they should live in `src/lib/` (the standard location for shared app code).
|
|
567
567
|
|
|
568
|
-
Run `npx jazz-tools@alpha validate` before publishing to identify any issues. You do not need to write a schema migration to update permissions policies. Push the updated policies by running `npx jazz-tools@alpha deploy
|
|
568
|
+
Run `npx jazz-tools@alpha validate` before publishing to identify any issues. You do not need to write a schema migration to update permissions policies. Push the updated policies by running `npx jazz-tools@alpha deploy <appId>`.
|
|
569
569
|
|
|
570
570
|
Apps that do not need user-scoped filtering should still declare explicit grants (`policy.todos.allowRead.always()` or `policy.todos.allowRead.where({})`) once a compiled bundle is loaded.
|
|
571
571
|
|
|
@@ -1311,6 +1311,56 @@ no local-first reconciliation information is discarded.
|
|
|
1311
1311
|
| **Source of truth** | Single authoritative database | Every client with the same row-history updates sees the same state |
|
|
1312
1312
|
| **Conflict handling** | Server rejects or last-request-wins | Automatic visible-state reconciliation with retained history |
|
|
1313
1313
|
|
|
1314
|
+
===PAGE:faq===
|
|
1315
|
+
TITLE:FAQ
|
|
1316
|
+
DESCRIPTION:Frequently asked questions about Jazz.
|
|
1317
|
+
|
|
1318
|
+
In browser apps using the React, Vue, or Svelte Jazz clients, open the devtools console and run:
|
|
1319
|
+
|
|
1320
|
+
```ts
|
|
1321
|
+
await window.__jazz.clearStorage();
|
|
1322
|
+
```
|
|
1323
|
+
|
|
1324
|
+
If the page has more than one live Jazz storage context, inspect the available namespaces and then choose one explicitly:
|
|
1325
|
+
|
|
1326
|
+
```ts
|
|
1327
|
+
window.__jazz.listLiveStorageNamespaces();
|
|
1328
|
+
await window.__jazz.clearStorage("my-app::alice");
|
|
1329
|
+
```
|
|
1330
|
+
|
|
1331
|
+
If you're working directly with a `Db` handle instead of the window helper, `await db.deleteClientStorage()` is the underlying API.
|
|
1332
|
+
|
|
1333
|
+
- Browser persistent storage only.
|
|
1334
|
+
- If exactly one live namespace exists, `clearStorage()` uses it automatically.
|
|
1335
|
+
- If multiple live namespaces exist, Jazz throws and lists the available namespaces until you choose one.
|
|
1336
|
+
- Can be initiated from either leader or follower tabs; Jazz coordinates the reset across tabs for that namespace.
|
|
1337
|
+
- Deletes OPFS storage only. It does not clear `localStorage` local-first auth data.
|
|
1338
|
+
- Reopens a clean worker/runtime so the same live client remains usable after the wipe.
|
|
1339
|
+
|
|
1340
|
+
This is useful when iterating on your schema during development.
|
|
1341
|
+
|
|
1342
|
+
`useAll` and `QuerySubscription` return `undefined` until the first response arrives from the requested tier. After that, the value is an array — empty (`[]`) if no rows match, or populated. See [The undefined loading state](/docs/reading/queries#the-undefined-loading-state) for details.
|
|
1343
|
+
|
|
1344
|
+
Yes. Omit `serverUrl` from your config — data will be persisted locally only.
|
|
1345
|
+
|
|
1346
|
+
Yes. When a user signs up with an external provider, their identity carries over. See [Signing up with BetterAuth](/docs/auth/local-first-auth#signing-up-with-betterauth).
|
|
1347
|
+
|
|
1348
|
+
No. Rust services use the same TypeScript migration files. The Rust runtime consumes the compiled schema representation through the CLI. See [Migrations](/docs/schemas/migrations) for details.
|
|
1349
|
+
|
|
1350
|
+
Jazz may return the following errors when a client's request is rejected by the server:
|
|
1351
|
+
|
|
1352
|
+
- **`PermissionDenied`** — a write was rejected because it failed the table's
|
|
1353
|
+
[permission policy](/docs/auth/permissions). Check that the session has the right to perform
|
|
1354
|
+
that operation on the row.
|
|
1355
|
+
- **`SessionRequired`** — a write was attempted without an authenticated session.
|
|
1356
|
+
Make sure the client is using a valid auth mode (local-first or external JWT).
|
|
1357
|
+
- **`CatalogueWriteDenied`** — a client attempted to write a schema or lens
|
|
1358
|
+
catalogue object without the required admin secret. In production, catalogue writes require
|
|
1359
|
+
`--admin-secret`.
|
|
1360
|
+
- **`QuerySubscriptionRejected`** — a query subscription was rejected by the
|
|
1361
|
+
server, typically because the query references a table or schema the server doesn't know about.
|
|
1362
|
+
This can happen if the schema hasn't synced yet or if there's a version mismatch.
|
|
1363
|
+
|
|
1314
1364
|
===PAGE:getting-started/client-setup===
|
|
1315
1365
|
TITLE:Client Setup
|
|
1316
1366
|
DESCRIPTION:Set up Jazz in your app — works out of the box with most frameworks, with manual configuration available when needed.
|
|
@@ -1546,11 +1596,12 @@ npx jazz-tools@alpha server "$JAZZ_APP_ID" \
|
|
|
1546
1596
|
| `-d, --data-dir ` | Persistent storage directory | - | `./data` |
|
|
1547
1597
|
| `--in-memory` | Use in-memory storage instead of files; data is lost when the process exits | - | off |
|
|
1548
1598
|
| `--jwks-url ` | JWKS endpoint for external JWT validation | `JAZZ_JWKS_URL` | unset |
|
|
1599
|
+
| `--jwt-public-key ` | Single JWK JSON object or PEM public key for external JWT validation. Accepts inline contents or a path to a key file. | `JAZZ_JWT_PUBLIC_KEY` | unset |
|
|
1549
1600
|
| `--allow-local-first-auth` | Allow local-first auth (`Authorization: Bearer <self-signed Jazz JWT>`) | `JAZZ_ALLOW_LOCAL_FIRST_AUTH` | see `NODE_ENV` note below |
|
|
1550
1601
|
| `--backend-secret ` | Enable backend session impersonation | `JAZZ_BACKEND_SECRET` | unset |
|
|
1551
1602
|
| `--admin-secret ` | Required for `deploy`, `migrations push`, and schema catalogue reads. In development mode, structural schema auto-sync works without it. | `JAZZ_ADMIN_SECRET` | unset |
|
|
1552
1603
|
|
|
1553
|
-
Local-first auth is enabled by default in development and requires `--allow-local-first-auth` in production. External JWT auth requires `--jwks-url
|
|
1604
|
+
Local-first auth is enabled by default in development and requires `--allow-local-first-auth` in production. External JWT auth requires either `--jwks-url` or `--jwt-public-key`, but not both.
|
|
1554
1605
|
|
|
1555
1606
|
## Backend context setup
|
|
1556
1607
|
|
|
@@ -2087,7 +2138,9 @@ const todo = computed(() => todos.value?.[0]);
|
|
|
2087
2138
|
|
|
2088
2139
|
return (
|
|
2089
2140
|
|
|
2090
|
-
|
|
2141
|
+
{
|
|
2142
|
+
db.update(app.todos, id, { done: !todo.done });
|
|
2143
|
+
}}
|
|
2091
2144
|
/>
|
|
2092
2145
|
{todo.title}
|
|
2093
2146
|
db.delete(app.todos, id)}>
|
|
@@ -2245,6 +2298,7 @@ Then publish the permissions bundle:
|
|
|
2245
2298
|
|
|
2246
2299
|
```bash title="Terminal"
|
|
2247
2300
|
npx jazz-tools@alpha deploy \
|
|
2301
|
+
<your-app-id> \
|
|
2248
2302
|
--server-url http://127.0.0.1:1625 \
|
|
2249
2303
|
--admin-secret secret
|
|
2250
2304
|
```
|
|
@@ -2263,7 +2317,8 @@ Update your client config to use the same app ID, and add `serverUrl`:
|
|
|
2263
2317
|
|
|
2264
2318
|
Clients pick up the schema from the server when they connect. If you update `schema.ts` you need to [create and push a migration to the new schema](/docs/schemas/migrations) so that clients can understand existing data with the new schema.
|
|
2265
2319
|
|
|
2266
|
-
Permissions can be updated without adding a new schema by using
|
|
2320
|
+
Permissions can be updated without adding a new schema by using
|
|
2321
|
+
`npx jazz-tools@alpha deploy <your-app-id>`.
|
|
2267
2322
|
|
|
2268
2323
|
For production deployment and hosting options, see [Server Setup](/docs/getting-started/server-setup).
|
|
2269
2324
|
|
|
@@ -2375,7 +2430,7 @@ const api = new Hono();
|
|
|
2375
2430
|
- `app` is your typed schema export.
|
|
2376
2431
|
- `permissions` is the server-side policy bundle.
|
|
2377
2432
|
- `serverUrl` + `backendSecret` let request-scoped handles sync through a Jazz server.
|
|
2378
|
-
- `jwksUrl`
|
|
2433
|
+
- `jwksUrl` verifies external JWTs inside `await context.forRequest(req)`. Without it, the backend only accepts Jazz self-signed tokens unless you set `allowLocalFirstAuth: false`.
|
|
2379
2434
|
- `dataPath` controls where local server state persists.
|
|
2380
2435
|
|
|
2381
2436
|
Each route handler awaits `context.forRequest(c.req)` to get a database handle with [permissions](/docs/auth/permissions) scoped to the request.
|
|
@@ -2400,7 +2455,7 @@ api.post("/api/todos", async (c) => {
|
|
|
2400
2455
|
const db = await context.forRequest(c.req);
|
|
2401
2456
|
const { title } = await c.req.json();
|
|
2402
2457
|
|
|
2403
|
-
const todo = db.insert(schemaApp.todos, {
|
|
2458
|
+
const { value: todo } = db.insert(schemaApp.todos, {
|
|
2404
2459
|
title,
|
|
2405
2460
|
done: false,
|
|
2406
2461
|
owner_id: "system",
|
|
@@ -2487,8 +2542,8 @@ curl -X DELETE http://localhost:3000/api/todos/<id> \
|
|
|
2487
2542
|
|
|
2488
2543
|
`forRequest` verifies the caller's bearer token inside the backend context. The token above is a
|
|
2489
2544
|
Jazz self-signed dev token, which works because `allowLocalFirstAuth` defaults to `true`. If you
|
|
2490
|
-
want to accept external JWTs from your auth provider, also set `jwksUrl`
|
|
2491
|
-
|
|
2545
|
+
want to accept external JWTs from your auth provider, also set `jwksUrl` so the backend can verify
|
|
2546
|
+
them via JWKS.
|
|
2492
2547
|
|
|
2493
2548
|
## Authentication
|
|
2494
2549
|
|
|
@@ -3399,7 +3454,7 @@ Insert from the top down — create the project first, then tasks
|
|
|
3399
3454
|
const session = useSession();
|
|
3400
3455
|
|
|
3401
3456
|
async function handleCreate() {
|
|
3402
|
-
const project = db.insert(app.projects, {
|
|
3457
|
+
const { value: project } = db.insert(app.projects, {
|
|
3403
3458
|
name: "Website redesign",
|
|
3404
3459
|
});
|
|
3405
3460
|
|
|
@@ -3730,7 +3785,7 @@ See [Queries](/docs/reading/queries) for subscriptions, one-shot queries, and du
|
|
|
3730
3785
|
}
|
|
3731
3786
|
```
|
|
3732
3787
|
|
|
3733
|
-
Use `
|
|
3788
|
+
Use `db.insert(...).wait({ tier: "..." })` if you need confirmation that the write reached a specific [durability tier](/docs/reference/durability-tiers).
|
|
3734
3789
|
|
|
3735
3790
|
If ownership can be transferred after creation, use an explicit `owner_id` column instead of `$createdBy`.
|
|
3736
3791
|
|
|
@@ -3770,13 +3825,7 @@ For background on how data flows between tiers, see [How Sync Works](/docs/conce
|
|
|
3770
3825
|
|
|
3771
3826
|
## Write tiers
|
|
3772
3827
|
|
|
3773
|
-
`insert`, `update`, and `delete` apply locally with no durability guarantee.
|
|
3774
|
-
|
|
3775
|
-
Options:
|
|
3776
|
-
|
|
3777
|
-
- `options.tier`: `"local"` \| `"edge"` \| `"global"`
|
|
3778
|
-
- Browser/client default: `"local"`
|
|
3779
|
-
- Backend/server default: `"edge"`
|
|
3828
|
+
`insert`, `update`, and `delete` apply locally with no durability guarantee, and return a write handle. Call `.wait({ tier: ... })` on those handles when you need confirmation that the write reached a specific durability tier.
|
|
3780
3829
|
|
|
3781
3830
|
See [Writing Data](/docs/writing/writing-data#write-durability-tiers) for detailed guidance on which tier to use and code examples.
|
|
3782
3831
|
|
|
@@ -3850,46 +3899,6 @@ For most queries and subscriptions, omitting a tier is the right choice: Jazz de
|
|
|
3850
3899
|
clients may arrive through edge tiers before being globally available **even if the durability of
|
|
3851
3900
|
the write is set to 'global'**.
|
|
3852
3901
|
|
|
3853
|
-
===PAGE:reference/faq===
|
|
3854
|
-
TITLE:FAQ
|
|
3855
|
-
DESCRIPTION:Frequently asked questions about Jazz.
|
|
3856
|
-
|
|
3857
|
-
Call `db.deleteClientStorage()` to delete the local OPFS database for the current namespace:
|
|
3858
|
-
|
|
3859
|
-
```ts
|
|
3860
|
-
await db.deleteClientStorage();
|
|
3861
|
-
```
|
|
3862
|
-
|
|
3863
|
-
- Browser worker-backed `Db` only.
|
|
3864
|
-
- Must be called from the leader tab; otherwise it logs an error and returns without deleting. Close other tabs first.
|
|
3865
|
-
- Deletes OPFS storage only (`${namespace}.opfsbtree` for the active namespace).
|
|
3866
|
-
- Does not clear `localStorage` local-first auth data.
|
|
3867
|
-
- Reopens a clean worker runtime, so the same `db` instance remains usable.
|
|
3868
|
-
|
|
3869
|
-
This is useful when iterating on your schema during development.
|
|
3870
|
-
|
|
3871
|
-
`useAll` and `QuerySubscription` return `undefined` until the first response arrives from the requested tier. After that, the value is an array — empty (`[]`) if no rows match, or populated. See [The undefined loading state](/docs/reading/queries#the-undefined-loading-state) for details.
|
|
3872
|
-
|
|
3873
|
-
Yes. Omit `serverUrl` from your config — data will be persisted locally only.
|
|
3874
|
-
|
|
3875
|
-
Yes. When a user signs up with an external provider, their identity carries over. See [Signing up with BetterAuth](/docs/auth/local-first-auth#signing-up-with-betterauth).
|
|
3876
|
-
|
|
3877
|
-
No. Rust services use the same TypeScript migration files. The Rust runtime consumes the compiled schema representation through the CLI. See [Migrations](/docs/schemas/migrations) for details.
|
|
3878
|
-
|
|
3879
|
-
Jazz may return the following errors when a client's request is rejected by the server:
|
|
3880
|
-
|
|
3881
|
-
- **`PermissionDenied`** — a write was rejected because it failed the table's
|
|
3882
|
-
[permission policy](/docs/auth/permissions). Check that the session has the right to perform
|
|
3883
|
-
that operation on the row.
|
|
3884
|
-
- **`SessionRequired`** — a write was attempted without an authenticated session.
|
|
3885
|
-
Make sure the client is using a valid auth mode (local-first or external JWT).
|
|
3886
|
-
- **`CatalogueWriteDenied`** — a client attempted to write a schema or lens
|
|
3887
|
-
catalogue object without the required admin secret. In production, catalogue writes require
|
|
3888
|
-
`--admin-secret`.
|
|
3889
|
-
- **`QuerySubscriptionRejected`** — a query subscription was rejected by the
|
|
3890
|
-
server, typically because the query references a table or schema the server doesn't know about.
|
|
3891
|
-
This can happen if the schema hasn't synced yet or if there's a version mismatch.
|
|
3892
|
-
|
|
3893
3902
|
===PAGE:reference/framework-patterns===
|
|
3894
3903
|
TITLE:Framework Patterns
|
|
3895
3904
|
DESCRIPTION:Side-by-side reference for React/Expo, Vue, and Svelte Jazz APIs.
|
|
@@ -4149,7 +4158,7 @@ fall back to surprise table scans.
|
|
|
4149
4158
|
|
|
4150
4159
|
### Deletion
|
|
4151
4160
|
|
|
4152
|
-
The user-facing `delete`
|
|
4161
|
+
The user-facing `delete` API performs a **soft delete**. The row is preserved in
|
|
4153
4162
|
history, but it disappears from ordinary live queries.
|
|
4154
4163
|
|
|
4155
4164
|
Internally, the current visible state leaves the live `_id` index and can still be addressed
|
|
@@ -4270,14 +4279,11 @@ correct and simple, but worth remembering when including across very large resul
|
|
|
4270
4279
|
|
|
4271
4280
|
### Transport
|
|
4272
4281
|
|
|
4273
|
-
Jazz uses
|
|
4282
|
+
Jazz uses a single WebSocket sync transport plus a small HTTP surface for health and admin reads.
|
|
4274
4283
|
|
|
4275
|
-
- **
|
|
4276
|
-
|
|
4277
|
-
`
|
|
4278
|
-
- **Client -> server**: `POST /sync` — sends row-version updates, query subscription changes, and
|
|
4279
|
-
related sync payloads.
|
|
4280
|
-
- **Admin**: `GET /schemas`, `GET /schema/:hash` — schema catalogue reads (requires admin access).
|
|
4284
|
+
- **Sync**: `GET /apps/<appId>/ws` upgrades to a WebSocket carrying the typed sync protocol.
|
|
4285
|
+
- **Admin**: `GET /apps/<appId>/schemas`, `GET /apps/<appId>/schema/:hash`, and
|
|
4286
|
+
`POST /apps/<appId>/admin/...` handle schema and permissions publication/read flows.
|
|
4281
4287
|
- **Health**: `GET /health`.
|
|
4282
4288
|
|
|
4283
4289
|
### Client identity
|
|
@@ -4659,7 +4665,7 @@ Tables are defined in `schema.ts` using the Jazz DSL. Each `s.table(...)` call r
|
|
|
4659
4665
|
|
|
4660
4666
|
When you change your schema on a shared app, create and push a migration. See [Migrations](/docs/schemas/migrations) for details.
|
|
4661
4667
|
|
|
4662
|
-
If you need to clear local browser data after a schema change, see [How do I reset browser storage?](/docs/
|
|
4668
|
+
If you need to clear local browser data after a schema change, see [How do I reset browser storage?](/docs/faq#reset-browser-storage).
|
|
4663
4669
|
|
|
4664
4670
|
## Exporting the app
|
|
4665
4671
|
|
|
@@ -4719,13 +4725,13 @@ Traditional migration systems run a linear sequence and require peers to converg
|
|
|
4719
4725
|
6. **Publish** — push the migration to the server:
|
|
4720
4726
|
|
|
4721
4727
|
```bash
|
|
4722
|
-
npx jazz-tools@alpha migrations push <fromHash> <toHash>
|
|
4728
|
+
npx jazz-tools@alpha migrations push <appId> <fromHash> <toHash>
|
|
4723
4729
|
```
|
|
4724
4730
|
|
|
4725
4731
|
If you also want to publish the current schema, the migration and permissions in one step, you can run:
|
|
4726
4732
|
|
|
4727
4733
|
```bash
|
|
4728
|
-
npx jazz-tools@alpha deploy
|
|
4734
|
+
npx jazz-tools@alpha deploy <appId>
|
|
4729
4735
|
```
|
|
4730
4736
|
|
|
4731
4737
|
`deploy` publishes the current schema if the server does not already know it, checks whether the
|
|
@@ -4733,7 +4739,7 @@ Traditional migration systems run a linear sequence and require peers to converg
|
|
|
4733
4739
|
if needed, and then publishes the current permissions.
|
|
4734
4740
|
|
|
4735
4741
|
Permission-only changes in `permissions.ts` do not need migrations, but they do still require
|
|
4736
|
-
`npx jazz-tools@alpha deploy
|
|
4742
|
+
`npx jazz-tools@alpha deploy <appId>`. See [Permissions](/docs/auth/permissions) for details.
|
|
4737
4743
|
|
|
4738
4744
|
## Generated stub
|
|
4739
4745
|
|
|
@@ -4872,8 +4878,8 @@ The Jazz server will detect when there are rows that are not reachable from the
|
|
|
4872
4878
|
In order to do so, you'll need to **create the migration using explicit to/from schema hashes**:
|
|
4873
4879
|
|
|
4874
4880
|
```bash
|
|
4875
|
-
npx jazz-tools@alpha migrations create --fromHash <fromHash>
|
|
4876
|
-
npx jazz-tools@alpha migrations create --fromHash <fromHash> --toHash <toHash>
|
|
4881
|
+
npx jazz-tools@alpha migrations create <appId> --fromHash <fromHash>
|
|
4882
|
+
npx jazz-tools@alpha migrations create <appId> --fromHash <fromHash> --toHash <toHash>
|
|
4877
4883
|
```
|
|
4878
4884
|
|
|
4879
4885
|
`--toHash` defaults to the current local schema. When a requested hash is not already saved locally, Jazz resolves it from the
|
|
@@ -4887,13 +4893,16 @@ also saves a snapshot of the schema in the local snapshot directory.
|
|
|
4887
4893
|
```bash
|
|
4888
4894
|
npx jazz-tools@alpha schema export
|
|
4889
4895
|
npx jazz-tools@alpha schema export --schema-dir ./packages/app
|
|
4890
|
-
npx jazz-tools@alpha schema export --schema-hash <hash> --server-url http://localhost:4200 --admin-secret <secret>
|
|
4896
|
+
npx jazz-tools@alpha schema export <appId> --schema-hash <hash> --server-url http://localhost:4200 --admin-secret <secret>
|
|
4891
4897
|
```
|
|
4892
4898
|
|
|
4893
4899
|
Without `--schema-hash`, Jazz exports the current local `schema.ts`. With `--schema-hash`, it
|
|
4894
4900
|
loads the schema from the local snapshot folder or, if missing, from the server.
|
|
4895
4901
|
`--schema-dir` and `--schema-hash` are mutually exclusive.
|
|
4896
4902
|
|
|
4903
|
+
Server-backed commands require the app id so Jazz can resolve app-scoped routes like
|
|
4904
|
+
`/apps/<appId>/schema/:hash`.
|
|
4905
|
+
|
|
4897
4906
|
| Flag | Default | Description |
|
|
4898
4907
|
| ---------------------- | ------------------- | --------------------------------------------------------------- |
|
|
4899
4908
|
| `--schema-dir <path>` | current directory | Path to app root containing `schema.ts` |
|
|
@@ -4904,7 +4913,8 @@ loads the schema from the local snapshot folder or, if missing, from the server.
|
|
|
4904
4913
|
|
|
4905
4914
|
## Migration flags
|
|
4906
4915
|
|
|
4907
|
-
`migrations create` uses flags rather than positional hashes.
|
|
4916
|
+
`migrations create` uses flags rather than positional hashes. When it needs to resolve missing
|
|
4917
|
+
schema hashes from a server, pass `<appId>` as the leading positional argument.
|
|
4908
4918
|
|
|
4909
4919
|
| Flag | Default | Description |
|
|
4910
4920
|
| ---------------------- | ------------------- | ------------------------------------------------ |
|
|
@@ -4993,15 +5003,14 @@ policies.
|
|
|
4993
5003
|
|
|
4994
5004
|
const file = await db.createFileFromBlob(app, blob, { tier: "edge" });
|
|
4995
5005
|
|
|
4996
|
-
return db.
|
|
5006
|
+
return db.insert(
|
|
4997
5007
|
app.uploads,
|
|
4998
5008
|
{
|
|
4999
5009
|
owner_id: EXAMPLE_OWNER_ID,
|
|
5000
5010
|
label: "Profile photo",
|
|
5001
5011
|
fileId: file.id,
|
|
5002
5012
|
},
|
|
5003
|
-
|
|
5004
|
-
);
|
|
5013
|
+
).wait({ tier: "edge" });
|
|
5005
5014
|
}
|
|
5006
5015
|
```
|
|
5007
5016
|
|
|
@@ -5075,15 +5084,14 @@ Returns the file row; store its id on your own table.
|
|
|
5075
5084
|
mimeType: "application/octet-stream",
|
|
5076
5085
|
});
|
|
5077
5086
|
|
|
5078
|
-
return db.
|
|
5087
|
+
return db.insert(
|
|
5079
5088
|
app.uploads,
|
|
5080
5089
|
{
|
|
5081
5090
|
owner_id: EXAMPLE_OWNER_ID,
|
|
5082
5091
|
label: "Camera import",
|
|
5083
5092
|
fileId: file.id,
|
|
5084
|
-
}
|
|
5085
|
-
|
|
5086
|
-
);
|
|
5093
|
+
}
|
|
5094
|
+
).wait({ tier: "edge" });
|
|
5087
5095
|
}
|
|
5088
5096
|
```
|
|
5089
5097
|
|
|
@@ -5285,11 +5293,10 @@ DESCRIPTION:Insert, update, and delete APIs with local-first execution, framewor
|
|
|
5285
5293
|
|
|
5286
5294
|
## Local-first writes
|
|
5287
5295
|
|
|
5288
|
-
All writes execute against the local database first. `insert`, `update`, and `delete` return immediately
|
|
5296
|
+
All writes execute against the local database first. `insert`, `update`, and `delete` return write handles immediately. Call `.wait({ tier: ... })` on those handles when you need confirmation that the write reached a specific [durability tier](#write-durability-tiers).
|
|
5289
5297
|
|
|
5290
|
-
|
|
5298
|
+
Jazz also exposes explicit batch builders:
|
|
5291
5299
|
|
|
5292
|
-
- `insertPersisted`, `updatePersisted`, `deletePersisted` return `DbPersistedWrite`
|
|
5293
5300
|
- `beginTransaction(...)` returns `DbTransaction`
|
|
5294
5301
|
- `beginDirectBatch(...)` returns `DbDirectBatch`
|
|
5295
5302
|
|
|
@@ -5370,7 +5377,7 @@ pub async fn write_todo_crud(client: &JazzClient, existing_id: ObjectId) -> jazz
|
|
|
5370
5377
|
|
|
5371
5378
|
### Partial updates and nullable fields
|
|
5372
5379
|
|
|
5373
|
-
`update(...)`
|
|
5380
|
+
`update(...)` only modify the keys you pass.
|
|
5374
5381
|
Omitted fields are left unchanged; explicitly passing `undefined` also leaves a field unchanged.
|
|
5375
5382
|
To clear a nullable column in TypeScript, pass `null`.
|
|
5376
5383
|
Required fields cannot be set to `null`.
|
|
@@ -5399,17 +5406,17 @@ pub async fn clear_nullable_fields(
|
|
|
5399
5406
|
|
|
5400
5407
|
## Write durability tiers
|
|
5401
5408
|
|
|
5402
|
-
When using `
|
|
5409
|
+
When using `insert(...).wait({ tier })`, `update(...).wait({ tier })`, or `delete(...).wait({ tier })`, the tier controls how far the mutation must propagate before the promise resolves: locally on the client (`local`), the nearest edge server (`edge`), or the global core (`global`).
|
|
5403
5410
|
|
|
5404
|
-
| Tier | Resolves when |
|
|
5405
|
-
| -------- | ----------------------------------- |
|
|
5406
|
-
| `local` | Persisted to local OPFS |
|
|
5407
|
-
| `edge` | Acknowledged by nearest sync server |
|
|
5408
|
-
| `global` | Propagated to global core |
|
|
5411
|
+
| Tier | Resolves when |
|
|
5412
|
+
| -------- | ----------------------------------- |
|
|
5413
|
+
| `local` | Persisted to local OPFS |
|
|
5414
|
+
| `edge` | Acknowledged by nearest sync server |
|
|
5415
|
+
| `global` | Propagated to global core |
|
|
5409
5416
|
|
|
5410
5417
|
```ts
|
|
5411
5418
|
|
|
5412
|
-
const { id } = await db.
|
|
5419
|
+
const { id } = await db.insert(
|
|
5413
5420
|
app.todos,
|
|
5414
5421
|
{
|
|
5415
5422
|
title: "Write docs with durability tier",
|
|
@@ -5417,11 +5424,10 @@ When using `insertDurable`, `updateDurable`, or `deleteDurable`, you can pass a
|
|
|
5417
5424
|
owner_id: EXAMPLE_OWNER_ID,
|
|
5418
5425
|
projectId: EXAMPLE_PROJECT_ID,
|
|
5419
5426
|
},
|
|
5420
|
-
|
|
5421
|
-
);
|
|
5427
|
+
).wait({ tier: "edge" });
|
|
5422
5428
|
|
|
5423
|
-
await db.
|
|
5424
|
-
await db.
|
|
5429
|
+
await db.update(app.todos, id, { done: true }).wait({ tier: "global" });
|
|
5430
|
+
await db.delete(app.todos, id).wait({ tier: "global" });
|
|
5425
5431
|
}
|
|
5426
5432
|
```
|
|
5427
5433
|
|
|
@@ -5444,33 +5450,31 @@ pub async fn write_todo_with_default_durability(
|
|
|
5444
5450
|
|
|
5445
5451
|
See [Durability Tiers](/docs/reference/durability-tiers) for the full reference, including read durability, data flow between tiers, and consistency semantics.
|
|
5446
5452
|
|
|
5447
|
-
Need to clear local data during development? See [How do I reset browser storage?](/docs/
|
|
5453
|
+
Need to clear local data during development? See [How do I reset browser storage?](/docs/faq#reset-browser-storage)
|
|
5448
5454
|
|
|
5449
|
-
##
|
|
5455
|
+
## Write handles
|
|
5450
5456
|
|
|
5451
|
-
|
|
5457
|
+
Write handles let you wait for a write to persisted up to a specific durability tier, and also access the value (in the case of inserts).
|
|
5452
5458
|
|
|
5453
5459
|
```ts
|
|
5454
|
-
const pending = db.
|
|
5460
|
+
const pending = db.insert(app.todos, {
|
|
5455
5461
|
title: "Ship review fixes",
|
|
5456
5462
|
done: false,
|
|
5457
5463
|
});
|
|
5458
5464
|
|
|
5459
|
-
console.log(pending.batchId
|
|
5460
|
-
console.log(pending.localBatchRecord());
|
|
5465
|
+
console.log(pending.batchId);
|
|
5461
5466
|
|
|
5462
5467
|
try {
|
|
5463
|
-
const row = await pending.wait();
|
|
5468
|
+
const row = await pending.wait({ tier: "global" });
|
|
5464
5469
|
console.log(row.id);
|
|
5465
5470
|
} catch (error) {
|
|
5466
5471
|
if (error instanceof PersistedWriteRejectedError) {
|
|
5467
5472
|
console.error(error.code, error.reason);
|
|
5468
|
-
pending.acknowledgeRejectedBatch();
|
|
5469
5473
|
}
|
|
5470
5474
|
}
|
|
5471
5475
|
```
|
|
5472
5476
|
|
|
5473
|
-
`wait()` resolves when the batch reaches the requested durability tier. If the batch is
|
|
5477
|
+
`wait({ tier })` resolves when the batch reaches the requested durability tier. If the batch is rejected, it rejects with `PersistedWriteRejectedError` instead of hanging.
|
|
5474
5478
|
|
|
5475
5479
|
## Explicit batches
|
|
5476
5480
|
|
|
@@ -5480,13 +5484,21 @@ Use an explicit transaction when several writes should settle together after an
|
|
|
5480
5484
|
const tx = db.beginTransaction(app.todos);
|
|
5481
5485
|
|
|
5482
5486
|
tx.insert(app.todos, { title: "Draft copy", done: false });
|
|
5487
|
+
const stagedDrafts = await tx.all(app.todos.where({ done: false }));
|
|
5483
5488
|
tx.update(app.todos, todoId, { done: true });
|
|
5484
5489
|
|
|
5485
|
-
const
|
|
5486
|
-
|
|
5490
|
+
const committed = tx.commit();
|
|
5491
|
+
await committed.wait({ tier: "edge" });
|
|
5492
|
+
console.log(committed.batchId);
|
|
5487
5493
|
```
|
|
5488
5494
|
|
|
5489
|
-
|
|
5495
|
+
The changes made as part of the transaction are scoped to it, and will only be
|
|
5496
|
+
globally visible once it's committed and accepted by the authority.
|
|
5497
|
+
|
|
5498
|
+
`DbTransaction` can also read its own staged state through `all(...)` and `one(...)` before commit.
|
|
5499
|
+
|
|
5500
|
+
Use a direct batch when you want to group several ordinary writes under one batch id, but still want them
|
|
5501
|
+
to be globally visible immediately:
|
|
5490
5502
|
|
|
5491
5503
|
```ts
|
|
5492
5504
|
const batch = db.beginDirectBatch(app.todos);
|
|
@@ -5496,5 +5508,3 @@ batch.update(app.todos, todoId, { done: true });
|
|
|
5496
5508
|
|
|
5497
5509
|
console.log(batch.batchId());
|
|
5498
5510
|
```
|
|
5499
|
-
|
|
5500
|
-
Both builders can also issue persisted writes, expose `localBatchRecord()` / `localBatchRecords()`, and let you acknowledge replayable rejections by batch id.
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -1,16 +1,12 @@
|
|
|
1
1
|
import type { JWK } from "jose";
|
|
2
|
-
import type { WasmSchema } from "../drivers/types.js";
|
|
3
2
|
import type { CompiledPermissions } from "../permissions/index.js";
|
|
4
3
|
import { type RequestLike } from "../runtime/client.js";
|
|
5
4
|
import type { AppContext, Session } from "../runtime/context.js";
|
|
6
5
|
import { type Db } from "../runtime/db.js";
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
export
|
|
11
|
-
_schema: WasmSchema;
|
|
12
|
-
}
|
|
13
|
-
export type BackendSchemaInput = WasmSchema | BackendSchemaSource | BackendQuerySchemaSource;
|
|
6
|
+
import { type QuerySchemaSource, type SchemaSourceInput, type WasmSchemaSource } from "../schema-source.js";
|
|
7
|
+
export type BackendSchemaSource = WasmSchemaSource;
|
|
8
|
+
export type BackendQuerySchemaSource = QuerySchemaSource;
|
|
9
|
+
export type BackendSchemaInput = SchemaSourceInput;
|
|
14
10
|
export type BackendJwtPublicKey = JWK | string;
|
|
15
11
|
export type BackendDriver = {
|
|
16
12
|
type: "persistent";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-jazz-context.d.ts","sourceRoot":"","sources":["../../src/backend/create-jazz-context.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"create-jazz-context.d.ts","sourceRoot":"","sources":["../../src/backend/create-jazz-context.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,6 +3,7 @@ import { serializeRuntimeSchema } from "../drivers/schema-wire.js";
|
|
|
3
3
|
import { JazzClient } from "../runtime/client.js";
|
|
4
4
|
import { createDbFromClient } from "../runtime/db.js";
|
|
5
5
|
import { mergePermissionsIntoWasmSchema } from "../schema-permissions.js";
|
|
6
|
+
import { resolveSchemaSource, } from "../schema-source.js";
|
|
6
7
|
import { resolveRequestSession } from "./request-auth.js";
|
|
7
8
|
function assertValidBackendConfig(config) {
|
|
8
9
|
if (config.driver.type === "memory" && !config.serverUrl) {
|
|
@@ -12,30 +13,6 @@ function assertValidBackendConfig(config) {
|
|
|
12
13
|
throw new Error("Backend auth config cannot set both jwksUrl and jwtPublicKey. Pick one external JWT verification mode.");
|
|
13
14
|
}
|
|
14
15
|
}
|
|
15
|
-
function isRecord(value) {
|
|
16
|
-
return typeof value === "object" && value !== null;
|
|
17
|
-
}
|
|
18
|
-
function isTableSchema(value) {
|
|
19
|
-
return isRecord(value) && Array.isArray(value.columns);
|
|
20
|
-
}
|
|
21
|
-
function isWasmSchema(value) {
|
|
22
|
-
return (isRecord(value) &&
|
|
23
|
-
!("_schema" in value) &&
|
|
24
|
-
!("wasmSchema" in value) &&
|
|
25
|
-
Object.values(value).every((table) => isTableSchema(table)));
|
|
26
|
-
}
|
|
27
|
-
function resolveSchema(input) {
|
|
28
|
-
if (isWasmSchema(input)) {
|
|
29
|
-
return input;
|
|
30
|
-
}
|
|
31
|
-
if (isRecord(input) && "_schema" in input && isWasmSchema(input._schema)) {
|
|
32
|
-
return input._schema;
|
|
33
|
-
}
|
|
34
|
-
if (isRecord(input) && "wasmSchema" in input && isWasmSchema(input.wasmSchema)) {
|
|
35
|
-
return input.wasmSchema;
|
|
36
|
-
}
|
|
37
|
-
throw new Error("Invalid schema source. Pass a WasmSchema, a generated app object, or a generated query/table object.");
|
|
38
|
-
}
|
|
39
16
|
/**
|
|
40
17
|
* Server-side Jazz context with lazy runtime setup.
|
|
41
18
|
*
|
|
@@ -63,7 +40,7 @@ export class JazzContext {
|
|
|
63
40
|
if (!selected) {
|
|
64
41
|
throw new Error("No schema source provided. Pass `app` to createJazzContext or provide a schema source when calling db()/asBackend()/forRequest()/forSession().");
|
|
65
42
|
}
|
|
66
|
-
const schema =
|
|
43
|
+
const schema = resolveSchemaSource(selected);
|
|
67
44
|
return this.config.permissions
|
|
68
45
|
? mergePermissionsIntoWasmSchema(schema, this.config.permissions)
|
|
69
46
|
: schema;
|