@civitai/sdk 0.19.0 → 0.19.1

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.
@@ -1,5 +1,5 @@
1
1
  import type { BlockContext, BlockSettings, Theme, ViewerInfo } from '../core/handshake.js';
2
- import type { BlockTransport } from '../core/transport.js';
2
+ import { type BlockTransport } from '../core/transport.js';
3
3
  import { type Host } from '../host/index.js';
4
4
  import { type OrchestrationClient } from '../orchestration/index.js';
5
5
  import { type GrantOptions, type Scope, type TokenOptions, type TokenSessionOptions } from '../session/index.js';
package/dist/app/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { BridgeError, CivitaiError } from '../core/errors.js';
2
2
  import { getTransport } from '../core/get-transport.js';
3
+ import { isLocalPreviewStorage } from '../core/transport.js';
3
4
  import { createHost, createHostSession } from '../host/index.js';
4
5
  import { ApiError, createHttp } from '../http/index.js';
5
6
  import { createOrchestrationClient, DEFAULT_ORCHESTRATION_URL, } from '../orchestration/index.js';
@@ -26,13 +27,16 @@ export async function initialize(options = {}) {
26
27
  // from `token.scopes`. A published app whose manifest forgot `apps:storage`
27
28
  // holds a token that looks the same as a preview's, and must keep getting the
28
29
  // real route's `insufficient_scope` rather than a silent local store.
29
- const local = snapshot().storageMode === 'local-preview'
30
+ const localPreview = isLocalPreviewStorage(snapshot());
31
+ // The same latched answer configures the session below, so `requestGrants`
32
+ // and the store agree on whether the document store is local.
33
+ const local = localPreview
30
34
  ? // The manifest arrives only from `blockManifestPlugin()`'s dev-server
31
35
  // global: there is deliberately no option to pass one.
32
36
  await createLocalPreviewStorage(readInjectedManifest(), snapshot().viewer)
33
37
  : undefined;
34
38
  return {
35
- ...createAppClient(createHostSession(transport), options, holdsBlockTokenNow, holdsOAuthTokenNow, local),
39
+ ...createAppClient(createHostSession(transport, { localPreviewStorage: localPreview }), options, holdsBlockTokenNow, holdsOAuthTokenNow, local),
36
40
  host: createHost(transport),
37
41
  get viewer() {
38
42
  return snapshot().viewer;
@@ -63,6 +63,15 @@ export interface BlockTransport {
63
63
  on(type: string, handler: (payload: unknown) => void): () => void;
64
64
  }
65
65
  export declare const EMPTY_SNAPSHOT: BlockSnapshot;
66
+ /**
67
+ * Did the host mark this frame a dev-tunnel preview whose document store is
68
+ * served locally? THE predicate for that question. `initialize()` reads it once
69
+ * and the one latched answer selects the local document store AND tells the
70
+ * host session which scopes no grant can add (`requestGrants`), so the two
71
+ * cannot disagree. Never inferred from `token.scopes`: a published app whose
72
+ * token lacks `apps:storage` looks the same as a preview's.
73
+ */
74
+ export declare function isLocalPreviewStorage(snapshot: Pick<BlockSnapshot, 'storageMode'>): boolean;
66
75
  /** Convert a wire `BlockInitPayload` (ISO string expiresAt) into a `BlockSnapshot`. */
67
76
  export declare function snapshotFromInit(payload: BlockInitPayload, hostOrigin: string): BlockSnapshot;
68
77
  /** Wire `WrappedToken` (ISO expiry) → runtime `BlockToken` (Date expiry). */
@@ -10,6 +10,17 @@ export const EMPTY_SNAPSHOT = {
10
10
  blockInstanceId: '',
11
11
  hostOrigin: null,
12
12
  };
13
+ /**
14
+ * Did the host mark this frame a dev-tunnel preview whose document store is
15
+ * served locally? THE predicate for that question. `initialize()` reads it once
16
+ * and the one latched answer selects the local document store AND tells the
17
+ * host session which scopes no grant can add (`requestGrants`), so the two
18
+ * cannot disagree. Never inferred from `token.scopes`: a published app whose
19
+ * token lacks `apps:storage` looks the same as a preview's.
20
+ */
21
+ export function isLocalPreviewStorage(snapshot) {
22
+ return snapshot.storageMode === LOCAL_PREVIEW_STORAGE;
23
+ }
13
24
  /** Convert a wire `BlockInitPayload` (ISO string expiresAt) into a `BlockSnapshot`. */
14
25
  export function snapshotFromInit(payload, hostOrigin) {
15
26
  return {
@@ -1,4 +1,5 @@
1
1
  import type { ViewerInfo } from '../core/handshake.js';
2
+ import type { Scope } from '../session/index.js';
2
3
  import { type DocumentStorage } from './index.js';
3
4
  /**
4
5
  * The document store for a DEV-TUNNEL PREVIEW: the host marked the frame
@@ -22,6 +23,15 @@ import { type DocumentStorage } from './index.js';
22
23
  * `tests/guards/local-preview-manifest-global.test.mjs`.
23
24
  */
24
25
  export declare const LOCAL_PREVIEW_MANIFEST_GLOBAL = "__CIVITAI_LOCAL_PREVIEW_MANIFEST__";
26
+ /**
27
+ * The scopes the local document store serves: the two the server's document
28
+ * store checks (`fake.ts` enforces the same pair). A preview token never
29
+ * carries them and no grant can add them, so `requestGrants` treats them as
30
+ * held in a local preview instead of asking the host. Shared storage
31
+ * (`apps:storage:shared:*`) and the deprecated key/value scopes are NOT here:
32
+ * they keep the real routes in a preview.
33
+ */
34
+ export declare const LOCAL_PREVIEW_STORAGE_SCOPES: ReadonlySet<Scope>;
25
35
  /** What a local preview reads from the manifest: the scopes it declares and its `storage` block. */
26
36
  export interface LocalPreviewManifest {
27
37
  scopes?: readonly string[];
@@ -21,6 +21,18 @@ import { createDocumentStorage, StorageError } from './index.js';
21
21
  * `tests/guards/local-preview-manifest-global.test.mjs`.
22
22
  */
23
23
  export const LOCAL_PREVIEW_MANIFEST_GLOBAL = '__CIVITAI_LOCAL_PREVIEW_MANIFEST__';
24
+ /**
25
+ * The scopes the local document store serves: the two the server's document
26
+ * store checks (`fake.ts` enforces the same pair). A preview token never
27
+ * carries them and no grant can add them, so `requestGrants` treats them as
28
+ * held in a local preview instead of asking the host. Shared storage
29
+ * (`apps:storage:shared:*`) and the deprecated key/value scopes are NOT here:
30
+ * they keep the real routes in a preview.
31
+ */
32
+ export const LOCAL_PREVIEW_STORAGE_SCOPES = new Set([
33
+ 'apps:storage',
34
+ 'apps:storage:publish',
35
+ ]);
24
36
  /** The manifest the dev server injected, if any. */
25
37
  export function readInjectedManifest() {
26
38
  const value = globalThis[LOCAL_PREVIEW_MANIFEST_GLOBAL];
@@ -124,5 +124,13 @@ export interface Host {
124
124
  }, opts?: HostCallOptions): Promise<number[]>;
125
125
  }
126
126
  export declare function createHost(transport: BlockTransport): Host;
127
+ export interface HostSessionOptions {
128
+ /**
129
+ * The document store is served by the in-tab local store (a dev-tunnel
130
+ * preview): the value `initialize()` latched from `isLocalPreviewStorage`.
131
+ * `requestGrants` then treats `LOCAL_PREVIEW_STORAGE_SCOPES` as held.
132
+ */
133
+ localPreviewStorage?: boolean;
134
+ }
127
135
  /** The token the host minted for this block, kept current as the host rotates it. */
128
- export declare function createHostSession(transport: BlockTransport): Session;
136
+ export declare function createHostSession(transport: BlockTransport, { localPreviewStorage }?: HostSessionOptions): Session;
@@ -1,6 +1,7 @@
1
1
  import { BridgeError } from '../core/errors.js';
2
2
  import { createCaller, createListener, createNotifier } from '../core/messaging.js';
3
3
  import { tokenFromWrapped } from '../core/transport.js';
4
+ import { LOCAL_PREVIEW_STORAGE_SCOPES } from '../doc-store/local-preview.js';
4
5
  const call = createCaller();
5
6
  const notify = createNotifier();
6
7
  const on = createListener();
@@ -254,7 +255,7 @@ function asScanResult(value) {
254
255
  return { status: 'error', ...(typeof v?.message === 'string' ? { message: v.message } : {}) };
255
256
  }
256
257
  /** The token the host minted for this block, kept current as the host rotates it. */
257
- export function createHostSession(transport) {
258
+ export function createHostSession(transport, { localPreviewStorage = false } = {}) {
258
259
  return {
259
260
  async getToken({ fresh, signal } = {}) {
260
261
  if (!fresh)
@@ -263,7 +264,14 @@ export function createHostSession(transport) {
263
264
  const { token } = await call('REQUEST_TOKEN', { blockInstanceId }, { transport, signal });
264
265
  return tokenFromWrapped(token).raw;
265
266
  },
266
- requestGrants: (scopes, opts = {}) => requestGrants(transport, scopes, opts),
267
+ requestGrants: (scopes, opts = {}) => requestGrants(transport,
268
+ // A preview token never carries a document-store scope and no grant can
269
+ // add one, so asking the host for it could only be refused — and the
270
+ // refusal would take the rest of the request down with it. The local
271
+ // store serves them; ask only for the rest. Nothing on the token changes.
272
+ localPreviewStorage
273
+ ? scopes.filter((scope) => !LOCAL_PREVIEW_STORAGE_SCOPES.has(scope))
274
+ : scopes, opts),
267
275
  };
268
276
  }
269
277
  /**
@@ -1,2 +1,2 @@
1
1
  /** This package's version, reported to the host as `sdkVersion` in `BLOCK_READY`. */
2
- export declare const VERSION = "0.19.0";
2
+ export declare const VERSION = "0.19.1";
@@ -1,3 +1,3 @@
1
1
  /* AUTOGENERATED from package.json by scripts/gen-version.mjs. DO NOT EDIT. */
2
2
  /** This package's version, reported to the host as `sdkVersion` in `BLOCK_READY`. */
3
- export const VERSION = "0.19.0";
3
+ export const VERSION = "0.19.1";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@civitai/sdk",
3
- "version": "0.19.0",
3
+ "version": "0.19.1",
4
4
  "description": "The Civitai SDK: an app holds a token and calls the Civitai API and the orchestrator; a block asks its host only to show host UI.",
5
5
  "license": "MIT",
6
6
  "type": "module",