@fias/create-fias-plugin 1.1.2 → 1.1.4
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/package.json +4 -1
- package/templates/default/AGENTS.md +401 -25
- package/templates/default/CLAUDE.md +401 -25
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fias/create-fias-plugin",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.4",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -8,6 +8,9 @@
|
|
|
8
8
|
"bin": {
|
|
9
9
|
"create-fias-plugin": "index.js"
|
|
10
10
|
},
|
|
11
|
+
"scripts": {
|
|
12
|
+
"prepublishOnly": "node ../../scripts/check-plugin-sdk-docs-mirror.js"
|
|
13
|
+
},
|
|
11
14
|
"files": [
|
|
12
15
|
"index.js",
|
|
13
16
|
"templates"
|
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
This project is a FIAS platform plugin — a React application that runs in a sandboxed iframe within the FIAS marketplace. This file provides the context AI coding assistants need to build, test, and submit plugins effectively.
|
|
4
4
|
|
|
5
|
-
For other AI tool instruction files, see `CLAUDE.md` (identical content).
|
|
6
|
-
|
|
7
5
|
## Project Structure
|
|
8
6
|
|
|
9
7
|
```
|
|
@@ -183,13 +181,17 @@ function AISummarizer() {
|
|
|
183
181
|
});
|
|
184
182
|
}
|
|
185
183
|
|
|
184
|
+
// `streamingText` accumulates tokens during the call AND continues to hold
|
|
185
|
+
// the full text after the call resolves — it is NOT cleared. `result.output`
|
|
186
|
+
// also contains the full text once `invoke()` resolves. Render ONE slot only
|
|
187
|
+
// — `streamingText` while loading, `result.output` afterwards — or the
|
|
188
|
+
// response appears twice.
|
|
186
189
|
return (
|
|
187
190
|
<div>
|
|
188
191
|
<button onClick={() => summarize('...')} disabled={isLoading}>
|
|
189
192
|
Summarize
|
|
190
193
|
</button>
|
|
191
|
-
{isLoading
|
|
192
|
-
{result && <p>{result.output}</p>}
|
|
194
|
+
<p>{isLoading ? streamingText : result?.output}</p>
|
|
193
195
|
{error && <p>Error: {error.message}</p>}
|
|
194
196
|
</div>
|
|
195
197
|
);
|
|
@@ -203,7 +205,43 @@ The `entityId` references a published model entity. Browse available models with
|
|
|
203
205
|
**Permission:** `entities:image_generate`
|
|
204
206
|
**Returns:** `ImageGenerationApi`
|
|
205
207
|
|
|
206
|
-
Generate images using platform image models. Images are saved to the user's Fias file system and a display URL is returned.
|
|
208
|
+
Generate images using platform image models. Images are saved to the user's Fias file system and a display URL is returned.
|
|
209
|
+
|
|
210
|
+
#### Choosing an image model
|
|
211
|
+
|
|
212
|
+
The `entityId` parameter accepts three forms. **Prefer the selector forms** (`platformRecommended` / `providerRecommended`) over hardcoded entity IDs: the platform's recommendations evolve, models get retired, and a selector lets your plugin pick up the current best automatically without a code edit. Hardcoded IDs are still supported for back-compat and for cases where you want a specific model — but if the platform retires that exact entity, your plugin breaks unless the platform has registered a successor.
|
|
213
|
+
|
|
214
|
+
```tsx
|
|
215
|
+
// 1. Platform's blessed pick for a workflow + optional style (RECOMMENDED).
|
|
216
|
+
// Asking for `image-to-image` will never return a model that can't do it.
|
|
217
|
+
generate({
|
|
218
|
+
entityId: { platformRecommended: { mode: 'text-to-image', style: 'illustration' } },
|
|
219
|
+
prompt: "A child's storybook page of a fox in the forest",
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
// 2. A specific provider's blessed pick. Use when your plugin's value prop
|
|
223
|
+
// depends on a particular provider's quirks.
|
|
224
|
+
generate({
|
|
225
|
+
entityId: { providerRecommended: { provider: 'openai', mode: 'image-to-image' } },
|
|
226
|
+
prompt: 'Make it look like an oil painting',
|
|
227
|
+
referenceImage: { fileId: previousImage.fileId },
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
// 3. Explicit entityId — back-compat path. Use only when you want a specific
|
|
231
|
+
// model. If the entity has been deprecated, the response includes
|
|
232
|
+
// `deprecation: { requestedEntityId, resolvedEntityId, deprecatedAt }` and
|
|
233
|
+
// you get the successor.
|
|
234
|
+
generate({
|
|
235
|
+
entityId: 'ent_modeldef_gpt_image_1_5',
|
|
236
|
+
prompt: 'A serene mountain landscape at sunset',
|
|
237
|
+
});
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
Mode values: `'text-to-image'` (baseline), `'image-to-image'` (requires `referenceImage`), `'vector'` (SVG output). Style values: `'illustration'` (stylized / digital-art) or `'photoreal'`.
|
|
241
|
+
|
|
242
|
+
Use `npx fias-dev entities --detail <entityId>` to check supported sizes, qualities, and styles for each model.
|
|
243
|
+
|
|
244
|
+
#### Full example
|
|
207
245
|
|
|
208
246
|
```tsx
|
|
209
247
|
import { useImageGeneration } from '@fias/arche-sdk';
|
|
@@ -216,23 +254,237 @@ function ImageMaker() {
|
|
|
216
254
|
<button
|
|
217
255
|
onClick={() =>
|
|
218
256
|
generate({
|
|
219
|
-
entityId: '
|
|
257
|
+
entityId: { platformRecommended: { mode: 'text-to-image' } },
|
|
220
258
|
prompt: 'A serene mountain landscape at sunset',
|
|
221
|
-
size: '
|
|
222
|
-
quality: '
|
|
259
|
+
size: '16:9',
|
|
260
|
+
quality: 'high',
|
|
223
261
|
})
|
|
224
262
|
}
|
|
225
263
|
disabled={isLoading}
|
|
226
264
|
>
|
|
227
265
|
{isLoading ? 'Generating...' : 'Generate Image'}
|
|
228
266
|
</button>
|
|
229
|
-
{result &&
|
|
267
|
+
{result && (
|
|
268
|
+
<>
|
|
269
|
+
<img src={result.imageUrl} alt="Generated" />
|
|
270
|
+
{result.deprecation && (
|
|
271
|
+
<p style={{ color: 'orange' }}>
|
|
272
|
+
Note: requested entity "{result.deprecation.requestedEntityId}" is deprecated;
|
|
273
|
+
auto-substituted "{result.deprecation.resolvedEntityId}". Update your code.
|
|
274
|
+
</p>
|
|
275
|
+
)}
|
|
276
|
+
</>
|
|
277
|
+
)}
|
|
230
278
|
{error && <p>Error: {error.message}</p>}
|
|
231
279
|
</div>
|
|
232
280
|
);
|
|
233
281
|
}
|
|
234
282
|
```
|
|
235
283
|
|
|
284
|
+
### `useImageEntities()` — Discover image-generation entities
|
|
285
|
+
|
|
286
|
+
**Permission:** `entities:image_generate`
|
|
287
|
+
**Returns:** `{ entities, isLoading, error, refetch }`
|
|
288
|
+
|
|
289
|
+
Use to render a "let the user pick a model" picker. For the common case of "just give me something good," skip discovery and pass a selector directly to `useImageGeneration`:
|
|
290
|
+
|
|
291
|
+
```tsx
|
|
292
|
+
await generate({
|
|
293
|
+
entityId: { platformRecommended: { mode: 'text-to-image' } },
|
|
294
|
+
prompt: '...',
|
|
295
|
+
});
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
Discovery hook usage:
|
|
299
|
+
|
|
300
|
+
```tsx
|
|
301
|
+
import { useImageEntities } from '@fias/arche-sdk';
|
|
302
|
+
|
|
303
|
+
const { entities, isLoading } = useImageEntities({
|
|
304
|
+
modes: ['image-to-image'],
|
|
305
|
+
supportsReferenceImage: true,
|
|
306
|
+
});
|
|
307
|
+
// entities[i]: { entityId, displayName, provider, modes, supportedSizes,
|
|
308
|
+
// supportsReferenceImage, isPlatformRecommended, ... }
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
Each entry is scrubbed — only fields a UI legitimately needs (no provider model strings, no endpoints, no execution config).
|
|
312
|
+
|
|
313
|
+
### `useBackgroundRemoval()` — Client-side background removal
|
|
314
|
+
|
|
315
|
+
**Permission:** `entities:image_remove_background`
|
|
316
|
+
**Returns:** `BackgroundRemovalApi`
|
|
317
|
+
|
|
318
|
+
Runs the imgly WASM model inside the host page — bytes never leave the user's device. Returns a transparent PNG.
|
|
319
|
+
|
|
320
|
+
```tsx
|
|
321
|
+
import { useBackgroundRemoval } from '@fias/arche-sdk';
|
|
322
|
+
|
|
323
|
+
const { removeBackground, isLoading } = useBackgroundRemoval();
|
|
324
|
+
const transparentPng = await removeBackground(jpegBlob);
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
**Limits:** input ≤ 25 MiB, PNG/JPEG only, rate-limited to 10/min per arche per user. Throws on size violation rather than returning a result.
|
|
328
|
+
|
|
329
|
+
### Audio capability hooks (auto-generated)
|
|
330
|
+
|
|
331
|
+
**Permission:** `entities:audio_generate`
|
|
332
|
+
**Returns (per hook):** `{ invoke, isLoading, result, error }`
|
|
333
|
+
|
|
334
|
+
Specialty capabilities expose **typed convenience hooks** generated from the platform's surface registry. Each hook bakes in a `surfaceKey` and infers params/result types from the surface's schemas.
|
|
335
|
+
|
|
336
|
+
Currently shipped audio hooks: `useLyriaMusic`, `useElevenLabsTts`, `useElevenLabsMusic`, `useElevenLabsSfx`, `useElevenLabsStt`, `useElevenLabsAudioIsolation`, `useElevenLabsForcedAlignment`, `useElevenLabsVoiceChanger`, `useElevenLabsVoiceDesign`. Browse the full surface list with `npx fias-dev entities`.
|
|
337
|
+
|
|
338
|
+
A legacy `useAudioGeneration()` hook still ships for back-compat with code written before the typed-surface migration. New plugins should use the typed hooks above — the legacy hook will be removed in a future major version.
|
|
339
|
+
|
|
340
|
+
```tsx
|
|
341
|
+
import { useElevenLabsTts } from '@fias/arche-sdk';
|
|
342
|
+
|
|
343
|
+
const { invoke, isLoading, result } = useElevenLabsTts();
|
|
344
|
+
await invoke({ text: 'Hello world', voiceId: '...' });
|
|
345
|
+
// result: { audioUrl, audioRef, durationMinutes, costCredits, ... }
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
For surfaces without a typed wrapper yet, the generic substrate:
|
|
349
|
+
|
|
350
|
+
```tsx
|
|
351
|
+
import { useSurface } from '@fias/arche-sdk';
|
|
352
|
+
|
|
353
|
+
const { invoke } = useSurface<MyParams, MyResult>('my.surface-key');
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
Default per-request timeout is 180 s (covers TTS for long text and Lyria multi-clip generation).
|
|
357
|
+
|
|
358
|
+
### `useVaultDocuments()` — User-owned Vault documents
|
|
359
|
+
|
|
360
|
+
**Permissions:** `vault:documents:read` (list / read / getDownloadUrl / search), `vault:documents:write` (write / update / delete / attach / detach / upload)
|
|
361
|
+
**Returns:** `VaultDocumentsApi`
|
|
362
|
+
|
|
363
|
+
The Vault is the platform's persistent document store for the signed-in user. Distinct from `useFiasStorage` (per-plugin sandbox): Vault docs live in the user's My Data, survive plugin uninstall, and can be cross-referenced from other arches. Documents this arche creates are scoped to it (`source_arche_id`) and surfaced to the user under `/My-Fias/Arches/<archeId>/`.
|
|
364
|
+
|
|
365
|
+
**Most common use:** images returned from `useImageGeneration()` are auto-saved here. The result includes a `documentId` — pass it to `getDownloadUrl()` later to refresh the presigned URL after the original ~1h TTL expires.
|
|
366
|
+
|
|
367
|
+
```tsx
|
|
368
|
+
import { useVaultDocuments } from '@fias/arche-sdk';
|
|
369
|
+
|
|
370
|
+
const vault = useVaultDocuments();
|
|
371
|
+
|
|
372
|
+
// Refresh a presigned URL (cached client-side, auto-refreshed before expiry)
|
|
373
|
+
const { url, expiresAt, contentType } = await vault.getDownloadUrl(documentId);
|
|
374
|
+
|
|
375
|
+
// List documents this arche owns
|
|
376
|
+
const { documents, nextCursor } = await vault.list({ search: 'invoice', limit: 50 });
|
|
377
|
+
|
|
378
|
+
// Write a small text/JSON document (UTF-8, ≤ 1 MB)
|
|
379
|
+
const { documentId } = await vault.write({
|
|
380
|
+
name: 'settings.json',
|
|
381
|
+
content: JSON.stringify(settings),
|
|
382
|
+
contentType: 'application/json',
|
|
383
|
+
tags: ['config'],
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
// Upload a binary or larger document — wraps the two-step presigned-PUT flow
|
|
387
|
+
const result = await vault.upload(bytes, {
|
|
388
|
+
name: 'photo.jpg',
|
|
389
|
+
mimeType: 'image/jpeg',
|
|
390
|
+
});
|
|
391
|
+
// result.status transitions 'uploaded' → 'available' once indexed for search
|
|
392
|
+
|
|
393
|
+
// Semantic search across documents this arche owns
|
|
394
|
+
// (burns user credits per the AI Markup Invariant — call sparingly)
|
|
395
|
+
const { matches } = await vault.search('quarterly revenue', { topK: 5 });
|
|
396
|
+
|
|
397
|
+
// Update / delete
|
|
398
|
+
await vault.update(documentId, { name: 'new-name.json', tags: ['archived'] });
|
|
399
|
+
await vault.delete(documentId); // soft-delete, recoverable from My Data Trash
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
**Cross-arche attachment.** A document can be referenced from another arche's record (Business Contact, Company, Fias 360 Renewal in V-1). The reference points at the document but does NOT expose its contents to the target arche.
|
|
403
|
+
|
|
404
|
+
```tsx
|
|
405
|
+
const { referenceId } = await vault.attach(documentId, {
|
|
406
|
+
regardingType: 'vault_business_contact',
|
|
407
|
+
regardingId: contactId,
|
|
408
|
+
});
|
|
409
|
+
await vault.detach(documentId, referenceId);
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
**Sensitivity tiers** (`'standard'` | `'confidential'` | `'proprietary'`) gate downstream read access per the Vault's standard matrix. Defaults to `'standard'`.
|
|
413
|
+
|
|
414
|
+
**`fetchVaultDocumentDownloadUrl(documentId)`** — non-React function that shares the hook's client-side URL cache. Use from PDF exporters, image preloaders, or other non-component code paths.
|
|
415
|
+
|
|
416
|
+
### `useArcheAssets()` — Contributor-published asset library
|
|
417
|
+
|
|
418
|
+
**Permission:** `assets:read`
|
|
419
|
+
**Returns:** `ArcheAssetsApi`
|
|
420
|
+
|
|
421
|
+
A frozen set of images the arche's contributor uploaded and pinned to the published version — logos, brand images, hole maps, reference photos. Each entry has an immutable `assetId` and a short-lived `signedUrl` (~5 min) suitable for `<img src>`.
|
|
422
|
+
|
|
423
|
+
```tsx
|
|
424
|
+
import { useArcheAssets } from '@fias/arche-sdk';
|
|
425
|
+
|
|
426
|
+
const { list, getUrl } = useArcheAssets();
|
|
427
|
+
|
|
428
|
+
const { entries, nextCursor } = await list({ limit: 50 });
|
|
429
|
+
// entries[i]: { assetId, signedUrl, expiresAt, contentType, width, height,
|
|
430
|
+
// sizeBytes, name, altText, tags }
|
|
431
|
+
|
|
432
|
+
// Refresh a signed URL when it's about to expire
|
|
433
|
+
const fresh = await getUrl(assetId);
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
Cache the `assetId`; refresh `signedUrl` via `getUrl()` rather than persisting URLs across sessions.
|
|
437
|
+
|
|
438
|
+
### `useFiasStore()` — In-app purchases (IAP)
|
|
439
|
+
|
|
440
|
+
**Permission:** `store:purchase`
|
|
441
|
+
**Returns:** `FiasStoreApi`
|
|
442
|
+
|
|
443
|
+
How a plugin charges the signed-in user for anything inside the arche — one-time unlocks, consumables, subscriptions, paid sign-ups, donations. **All in-arche payments go through this hook.** The arche never handles payment directly: the platform shows a confirmation overlay, debits the user's Fias credit balance, and returns a result. Do not import Stripe or any external payment SDK — they are sandboxed out and not needed.
|
|
444
|
+
|
|
445
|
+
Products are declared in `fias-plugin.json` under a `products` array (see Manifest Reference below). Each product has a stable `identifier` your code passes to `purchase()`. Prices are denominated in **Fias credits**, not USD.
|
|
446
|
+
|
|
447
|
+
```tsx
|
|
448
|
+
import { useFiasStore } from '@fias/arche-sdk';
|
|
449
|
+
|
|
450
|
+
function UnlockButton() {
|
|
451
|
+
const { products, purchase, hasEntitlement, isLoading } = useFiasStore();
|
|
452
|
+
const product = products.find((p) => p.productIdentifier === 'pro_unlock');
|
|
453
|
+
|
|
454
|
+
if (isLoading || !product) return null;
|
|
455
|
+
if (hasEntitlement('pro_unlock')) return <p>Pro features unlocked.</p>;
|
|
456
|
+
|
|
457
|
+
async function buy() {
|
|
458
|
+
const result = await purchase('pro_unlock');
|
|
459
|
+
if (!result.success) {
|
|
460
|
+
// Common codes: INSUFFICIENT_CREDITS, USER_CANCELLED, PRODUCT_NOT_FOUND
|
|
461
|
+
console.error(result.error);
|
|
462
|
+
}
|
|
463
|
+
// On success, `entitlements` updates automatically.
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
return <button onClick={buy}>Unlock for {product.priceCredits} credits</button>;
|
|
467
|
+
}
|
|
468
|
+
```
|
|
469
|
+
|
|
470
|
+
**Product types:**
|
|
471
|
+
|
|
472
|
+
- `consumable` — buyable repeatedly (tokens, energy, single donations, sign-up entries). Does NOT create an entitlement; track usage in `useFiasDataStore`.
|
|
473
|
+
- `non_consumable` — one-time purchase, permanent entitlement.
|
|
474
|
+
- `auto_renewable` — subscription that renews automatically. Requires `subscriptionPeriod`: `weekly` | `monthly` | `quarterly` | `yearly`.
|
|
475
|
+
- `non_renewing` — time-limited access that does NOT renew (season pass).
|
|
476
|
+
|
|
477
|
+
**API surface:**
|
|
478
|
+
|
|
479
|
+
- `products: StoreProduct[]` — loaded on mount.
|
|
480
|
+
- `purchase(productIdentifier, { quantity? }) → StorePurchaseResult` — triggers the platform confirmation overlay. `quantity` only applies to consumables.
|
|
481
|
+
- `entitlements: StoreEntitlement[]` — current non-consumable + subscription entitlements; updated automatically after a successful purchase.
|
|
482
|
+
- `hasEntitlement(productIdentifier) → boolean` — convenience check.
|
|
483
|
+
- `getPurchaseHistory() → Promise<StorePurchase[]>` — full log including consumables.
|
|
484
|
+
- `restorePurchases() → Promise<StoreEntitlement[]>` — re-sync entitlements from the platform.
|
|
485
|
+
|
|
486
|
+
**Error handling:** `purchase()` returns `{ success: false, error, code }` rather than throwing — always branch on `result.success`. The user must be signed in to a Fias account; IAP is not available to anonymous visitors on public arches.
|
|
487
|
+
|
|
236
488
|
### `useFiasNavigation()` — In-plugin routing
|
|
237
489
|
|
|
238
490
|
**Permission:** None required
|
|
@@ -247,14 +499,22 @@ navigateTo('/settings');
|
|
|
247
499
|
|
|
248
500
|
### `useStepNavigation()` — Multi-step workflows
|
|
249
501
|
|
|
502
|
+
**Permission:** None for in-memory use; `storage:sandbox` when `persistKey` is set (it reads/writes `__state/<persistKey>` via the storage bridge).
|
|
250
503
|
**Returns:** `StepNavigationApi`
|
|
251
504
|
|
|
252
505
|
```tsx
|
|
253
506
|
import { useStepNavigation } from '@fias/arche-sdk';
|
|
254
507
|
|
|
255
|
-
|
|
508
|
+
// Pass `persistKey` to survive preview rebuilds (do NOT additionally wrap
|
|
509
|
+
// currentStep in usePersistentState — that creates two state sources and
|
|
510
|
+
// a bidirectional sync loop).
|
|
511
|
+
const { currentStep, setCurrentStep } = useStepNavigation('step-1', {
|
|
512
|
+
persistKey: 'workflow-step',
|
|
513
|
+
});
|
|
256
514
|
```
|
|
257
515
|
|
|
516
|
+
The host can also drive step changes from outside the iframe — for example, when the user clicks a node in an external graph view. The hook listens for those `step_navigate` messages and updates `currentStep` automatically, so unexpected step transitions aren't a bug to chase.
|
|
517
|
+
|
|
258
518
|
### `usePersistentState()` — Auto-saving state
|
|
259
519
|
|
|
260
520
|
**Permission:** `storage:sandbox`
|
|
@@ -272,13 +532,36 @@ const [count, setCount] = usePersistentState<number>('counter', 0);
|
|
|
272
532
|
|
|
273
533
|
### `fias` — Imperative utilities
|
|
274
534
|
|
|
535
|
+
Use the `fias` namespace when you need bridge operations from outside a React component (event handlers attached imperatively, utility modules, non-React entry points).
|
|
536
|
+
|
|
275
537
|
```tsx
|
|
276
538
|
import { fias } from '@fias/arche-sdk';
|
|
277
539
|
|
|
540
|
+
fias.ready(); // Manual ready signal (FiasProvider does this automatically)
|
|
278
541
|
fias.resize(800); // Resize iframe height
|
|
279
542
|
fias.showToast('Saved!', 'success'); // Toast: 'info' | 'success' | 'warning' | 'error'
|
|
543
|
+
|
|
544
|
+
// fias.dataStore mirrors useFiasDataStore() — same operations, same limits.
|
|
545
|
+
// Requires the `data:store` permission.
|
|
546
|
+
await fias.dataStore.createCollection('scores', { userScope: 'user' });
|
|
547
|
+
await fias.dataStore.put('scores', 'doc-key', { score: 100 });
|
|
548
|
+
const doc = await fias.dataStore.get('scores', 'doc-key');
|
|
549
|
+
await fias.dataStore.query('scores', {
|
|
550
|
+
filters: [{ field: 'score', op: 'gte', value: 50 }],
|
|
551
|
+
});
|
|
552
|
+
await fias.dataStore.delete('scores', 'doc-key');
|
|
553
|
+
await fias.dataStore.listCollections();
|
|
554
|
+
await fias.dataStore.deleteCollection('scores');
|
|
280
555
|
```
|
|
281
556
|
|
|
557
|
+
### Advanced exports (rarely needed)
|
|
558
|
+
|
|
559
|
+
The SDK also exports the following for advanced use cases. Most plugins don't need them.
|
|
560
|
+
|
|
561
|
+
- `VALID_PLUGIN_PERMISSIONS`, `isValidPluginPermission(perm)` — runtime permission validation.
|
|
562
|
+
- Theme catalog: `DARK_THEME`, `LIGHT_THEME`, `getDefaultTheme()`, `THEME_CATALOG`, `getThemeById()`, `FONT_PAIRINGS`, `getFontPairingById()` — useful when the plugin lets the user pick from preset themes/fonts.
|
|
563
|
+
- Bridge introspection: `FiasBridge`, `getBridge()`, `resetBridge()`, `SDK_BRIDGE_PROTOCOL_VERSION`, `SDK_REQUIRES_HOST_PROTOCOL_VERSION` — testing and advanced cases that need direct bridge control.
|
|
564
|
+
|
|
282
565
|
## Manifest Reference (`fias-plugin.json`)
|
|
283
566
|
|
|
284
567
|
```json
|
|
@@ -298,23 +581,78 @@ fias.showToast('Saved!', 'success'); // Toast: 'info' | 'success' | 'warning' |
|
|
|
298
581
|
|
|
299
582
|
**Fields:**
|
|
300
583
|
|
|
301
|
-
| Field
|
|
302
|
-
|
|
|
303
|
-
| `name`
|
|
304
|
-
| `version`
|
|
305
|
-
| `description`
|
|
306
|
-
| `
|
|
307
|
-
| `
|
|
308
|
-
| `
|
|
309
|
-
| `
|
|
310
|
-
| `
|
|
311
|
-
| `
|
|
312
|
-
| `
|
|
313
|
-
|
|
314
|
-
|
|
584
|
+
| Field | Req | Description |
|
|
585
|
+
| --------------------- | ---- | ------------------------------------------------------------------------------------------------------- |
|
|
586
|
+
| `name` | Yes | Plugin identifier (lowercase, hyphens) |
|
|
587
|
+
| `version` | Yes | Semver (e.g., `"1.0.0"`) |
|
|
588
|
+
| `description` | Yes | Short marketplace description |
|
|
589
|
+
| `expandedDescription` | No | Long-form marketplace copy |
|
|
590
|
+
| `main` | Yes | Entry point source file |
|
|
591
|
+
| `archeType` | Yes | `"tool"` or `"site"` |
|
|
592
|
+
| `categorySlug` | No | Marketplace category for discovery |
|
|
593
|
+
| `icon` | No | Relative path to icon asset (shown in marketplace + arche header) |
|
|
594
|
+
| `tags` | No | Discovery tags |
|
|
595
|
+
| `pricing` | Yes | Marketplace **listing** pricing (see "Pricing detail" below). NOT for in-arche charges — use `products` |
|
|
596
|
+
| `permissions` | Yes | Array of permission scopes (see below) |
|
|
597
|
+
| `products` | No | IAP product catalog for `useFiasStore()` (see "Defining IAP products" below) |
|
|
598
|
+
| `isPublic` | No | Default `false`. Anonymous visitors can view (see "Public arches" below) |
|
|
599
|
+
| `isFullScreen` | No | Default `false`. Renders without platform chrome — implies `archeType: "site"` |
|
|
600
|
+
| `isListed` | No | Default `true`. Visible in marketplace store |
|
|
601
|
+
| `sdk` | Yes | SDK version range |
|
|
602
|
+
| `dependencies` | No | npm packages with **exact** versions (max 20) |
|
|
603
|
+
| `archeIds` | Auto | Per-environment IDs written by the CLI after first publish — don't hand-edit |
|
|
604
|
+
|
|
605
|
+
**Pricing detail:**
|
|
606
|
+
|
|
607
|
+
`pricing` is the marketplace **listing** model — controls what the platform charges users to access the arche itself. It does NOT cover charges the plugin makes from inside (entry fees, unlocks, donations) — for those, use IAP via `products`.
|
|
608
|
+
|
|
609
|
+
| `pricing.model` | Required sub-fields |
|
|
610
|
+
| --------------- | ------------------------------- |
|
|
611
|
+
| `"free"` | none |
|
|
612
|
+
| `"fixed"` | `priceCents` |
|
|
613
|
+
| `"per_use"` | `baseFeeCents` |
|
|
614
|
+
| `"tiered"` | `tiers: [{ upTo, priceCents }]` |
|
|
615
|
+
|
|
616
|
+
Other optional sub-fields: `currency: "usd"` (only USD supported today), `platformFeePercent` (override the default platform cut — non-standard).
|
|
617
|
+
|
|
618
|
+
**Permissions:** `theme:read`, `user:profile:read`, `storage:sandbox`, `data:store`, `entities:invoke`, `entities:image_generate`, `entities:image_remove_background`, `entities:audio_generate`, `store:purchase`, `vault:documents:read`, `vault:documents:write`, `assets:read`
|
|
315
619
|
|
|
316
620
|
**Using AI:** Add `"entities:invoke"` to permissions, then use `useEntityInvocation()` with a model entity ID and your own `systemPrompt`. Browse available models with `npx fias-dev entities`.
|
|
317
621
|
|
|
622
|
+
**Defining IAP products (for `useFiasStore`):**
|
|
623
|
+
|
|
624
|
+
Add a `products` array to declare what users can buy inside the arche. Each entry needs a stable `identifier` your code passes to `purchase()`. Prices are in Fias credits.
|
|
625
|
+
|
|
626
|
+
```json
|
|
627
|
+
{
|
|
628
|
+
"products": [
|
|
629
|
+
{
|
|
630
|
+
"identifier": "pro_unlock",
|
|
631
|
+
"type": "non_consumable",
|
|
632
|
+
"name": "Pro features",
|
|
633
|
+
"description": "Permanent unlock for advanced features.",
|
|
634
|
+
"priceCredits": 500
|
|
635
|
+
},
|
|
636
|
+
{
|
|
637
|
+
"identifier": "monthly_sub",
|
|
638
|
+
"type": "auto_renewable",
|
|
639
|
+
"name": "Monthly subscription",
|
|
640
|
+
"description": "Renewing access.",
|
|
641
|
+
"priceCredits": 200,
|
|
642
|
+
"subscriptionPeriod": "monthly",
|
|
643
|
+
"subscriptionGroup": "pro"
|
|
644
|
+
}
|
|
645
|
+
],
|
|
646
|
+
"permissions": ["store:purchase"]
|
|
647
|
+
}
|
|
648
|
+
```
|
|
649
|
+
|
|
650
|
+
`store:purchase` must be in `permissions` whenever `products` is non-empty. Use `consumable` for things bought repeatedly (single donations, sign-up entries), `non_consumable` for one-time unlocks, `auto_renewable` / `non_renewing` for time-bounded access.
|
|
651
|
+
|
|
652
|
+
**Public arches (`isPublic: true`):**
|
|
653
|
+
|
|
654
|
+
Setting `isPublic: true` lets anonymous visitors (no Fias account) view the arche at `/a/<archeId>`. The UI renders without the platform sidebar. **Bridge operations still require auth** — `useFiasDataStore` writes, `useFiasStore.purchase()`, `useFiasStorage` reads, vault operations, etc. all require the visitor to be signed in. Public mode is for read-only landing pages, marketing pages, and shared-content viewers — not for collecting registrations or payments from anonymous users.
|
|
655
|
+
|
|
318
656
|
## Plugin Constraints
|
|
319
657
|
|
|
320
658
|
These are hard limits enforced by the platform. Code that violates these will fail review or be blocked at runtime.
|
|
@@ -418,7 +756,7 @@ npx fias-dev login --env production # Authenticate with production
|
|
|
418
756
|
npx fias-dev entities # List all
|
|
419
757
|
npx fias-dev entities --search "image" # Search by keyword
|
|
420
758
|
npx fias-dev entities --type "model-definition" # Filter by type
|
|
421
|
-
npx fias-dev entities --detail
|
|
759
|
+
npx fias-dev entities --detail ent_modeldef_gpt_image_1_5 # Full entity details (capabilities, sizes, pricing)
|
|
422
760
|
```
|
|
423
761
|
|
|
424
762
|
### Validating the Manifest
|
|
@@ -443,6 +781,44 @@ If the AI review rejects your submission, the listing-fee portion is
|
|
|
443
781
|
refunded automatically (the per-review portion is not, since review work
|
|
444
782
|
happened either way).
|
|
445
783
|
|
|
784
|
+
### Managing the asset library (for `useArcheAssets`)
|
|
785
|
+
|
|
786
|
+
`useArcheAssets()` reads a contributor-curated set of images pinned to the arche's published version. Populate that library with the `assets` subcommands. Each command accepts `--env <staging|prod|local>` (default `staging`) and `--arche-id <id>` (auto-resolved from the manifest when omitted).
|
|
787
|
+
|
|
788
|
+
```bash
|
|
789
|
+
npx fias-dev assets enable # Turn on the asset library for this arche
|
|
790
|
+
npx fias-dev assets status # Quota usage + billing summary
|
|
791
|
+
npx fias-dev assets upload <dir> # Bulk-upload images; subfolder name → default tag
|
|
792
|
+
# Flags: --concurrency <1-16>, --dry-run
|
|
793
|
+
npx fias-dev assets list # List assets; --tag <tag>, --limit <1-100>
|
|
794
|
+
npx fias-dev assets tag <assetId> --add <t> # Add or remove tags; --remove <t> also supported
|
|
795
|
+
npx fias-dev assets delete <assetId> # Soft-delete (excluded from future publishes); -y to skip confirm
|
|
796
|
+
npx fias-dev assets disable # Turn off the asset library
|
|
797
|
+
```
|
|
798
|
+
|
|
799
|
+
Uploads stage into the contributor's draft set; they only become visible to plugin runtimes after the next `npm run submit` publishes a new arche version. Existing published versions keep their original frozen snapshot.
|
|
800
|
+
|
|
801
|
+
### Managing collaborators
|
|
802
|
+
|
|
803
|
+
Multi-developer plugins use `arche_collaborators` for operational ownership (publishing, team management) — distinct from financial ownership (`contributor_id`, which is immutable in v1). Every arche must keep ≥1 active owner; revokes that would drop to zero return `MUST_KEEP_ONE_OWNER`.
|
|
804
|
+
|
|
805
|
+
```bash
|
|
806
|
+
npx fias-dev collaborators list # List active collaborators
|
|
807
|
+
npx fias-dev collaborators add <email|username|userId> \ # Default role: publisher
|
|
808
|
+
--role <owner|publisher|viewer> --expires <iso> # Owners cannot have expiry
|
|
809
|
+
npx fias-dev collaborators set <identifier> \ # Change role and/or expiry
|
|
810
|
+
--role <role> --expires <iso> # --no-expires clears expiry
|
|
811
|
+
npx fias-dev collaborators remove <identifier> # Revoke a collaborator
|
|
812
|
+
```
|
|
813
|
+
|
|
814
|
+
All commands accept `--env <staging|production|local>` (default `staging`).
|
|
815
|
+
|
|
816
|
+
### Other CLI diagnostics
|
|
817
|
+
|
|
818
|
+
```bash
|
|
819
|
+
npx fias-dev check-auth # Print per-environment auth status (which envs have saved keys)
|
|
820
|
+
```
|
|
821
|
+
|
|
446
822
|
## Common Patterns
|
|
447
823
|
|
|
448
824
|
### Theme-Aware Card Component
|
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
This project is a FIAS platform plugin — a React application that runs in a sandboxed iframe within the FIAS marketplace. This file provides the context AI coding assistants need to build, test, and submit plugins effectively.
|
|
4
4
|
|
|
5
|
-
For other AI tool instruction files, see `AGENTS.md` (identical content).
|
|
6
|
-
|
|
7
5
|
## Project Structure
|
|
8
6
|
|
|
9
7
|
```
|
|
@@ -183,13 +181,17 @@ function AISummarizer() {
|
|
|
183
181
|
});
|
|
184
182
|
}
|
|
185
183
|
|
|
184
|
+
// `streamingText` accumulates tokens during the call AND continues to hold
|
|
185
|
+
// the full text after the call resolves — it is NOT cleared. `result.output`
|
|
186
|
+
// also contains the full text once `invoke()` resolves. Render ONE slot only
|
|
187
|
+
// — `streamingText` while loading, `result.output` afterwards — or the
|
|
188
|
+
// response appears twice.
|
|
186
189
|
return (
|
|
187
190
|
<div>
|
|
188
191
|
<button onClick={() => summarize('...')} disabled={isLoading}>
|
|
189
192
|
Summarize
|
|
190
193
|
</button>
|
|
191
|
-
{isLoading
|
|
192
|
-
{result && <p>{result.output}</p>}
|
|
194
|
+
<p>{isLoading ? streamingText : result?.output}</p>
|
|
193
195
|
{error && <p>Error: {error.message}</p>}
|
|
194
196
|
</div>
|
|
195
197
|
);
|
|
@@ -203,7 +205,43 @@ The `entityId` references a published model entity. Browse available models with
|
|
|
203
205
|
**Permission:** `entities:image_generate`
|
|
204
206
|
**Returns:** `ImageGenerationApi`
|
|
205
207
|
|
|
206
|
-
Generate images using platform image models. Images are saved to the user's Fias file system and a display URL is returned.
|
|
208
|
+
Generate images using platform image models. Images are saved to the user's Fias file system and a display URL is returned.
|
|
209
|
+
|
|
210
|
+
#### Choosing an image model
|
|
211
|
+
|
|
212
|
+
The `entityId` parameter accepts three forms. **Prefer the selector forms** (`platformRecommended` / `providerRecommended`) over hardcoded entity IDs: the platform's recommendations evolve, models get retired, and a selector lets your plugin pick up the current best automatically without a code edit. Hardcoded IDs are still supported for back-compat and for cases where you want a specific model — but if the platform retires that exact entity, your plugin breaks unless the platform has registered a successor.
|
|
213
|
+
|
|
214
|
+
```tsx
|
|
215
|
+
// 1. Platform's blessed pick for a workflow + optional style (RECOMMENDED).
|
|
216
|
+
// Asking for `image-to-image` will never return a model that can't do it.
|
|
217
|
+
generate({
|
|
218
|
+
entityId: { platformRecommended: { mode: 'text-to-image', style: 'illustration' } },
|
|
219
|
+
prompt: "A child's storybook page of a fox in the forest",
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
// 2. A specific provider's blessed pick. Use when your plugin's value prop
|
|
223
|
+
// depends on a particular provider's quirks.
|
|
224
|
+
generate({
|
|
225
|
+
entityId: { providerRecommended: { provider: 'openai', mode: 'image-to-image' } },
|
|
226
|
+
prompt: 'Make it look like an oil painting',
|
|
227
|
+
referenceImage: { fileId: previousImage.fileId },
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
// 3. Explicit entityId — back-compat path. Use only when you want a specific
|
|
231
|
+
// model. If the entity has been deprecated, the response includes
|
|
232
|
+
// `deprecation: { requestedEntityId, resolvedEntityId, deprecatedAt }` and
|
|
233
|
+
// you get the successor.
|
|
234
|
+
generate({
|
|
235
|
+
entityId: 'ent_modeldef_gpt_image_1_5',
|
|
236
|
+
prompt: 'A serene mountain landscape at sunset',
|
|
237
|
+
});
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
Mode values: `'text-to-image'` (baseline), `'image-to-image'` (requires `referenceImage`), `'vector'` (SVG output). Style values: `'illustration'` (stylized / digital-art) or `'photoreal'`.
|
|
241
|
+
|
|
242
|
+
Use `npx fias-dev entities --detail <entityId>` to check supported sizes, qualities, and styles for each model.
|
|
243
|
+
|
|
244
|
+
#### Full example
|
|
207
245
|
|
|
208
246
|
```tsx
|
|
209
247
|
import { useImageGeneration } from '@fias/arche-sdk';
|
|
@@ -216,23 +254,237 @@ function ImageMaker() {
|
|
|
216
254
|
<button
|
|
217
255
|
onClick={() =>
|
|
218
256
|
generate({
|
|
219
|
-
entityId: '
|
|
257
|
+
entityId: { platformRecommended: { mode: 'text-to-image' } },
|
|
220
258
|
prompt: 'A serene mountain landscape at sunset',
|
|
221
|
-
size: '
|
|
222
|
-
quality: '
|
|
259
|
+
size: '16:9',
|
|
260
|
+
quality: 'high',
|
|
223
261
|
})
|
|
224
262
|
}
|
|
225
263
|
disabled={isLoading}
|
|
226
264
|
>
|
|
227
265
|
{isLoading ? 'Generating...' : 'Generate Image'}
|
|
228
266
|
</button>
|
|
229
|
-
{result &&
|
|
267
|
+
{result && (
|
|
268
|
+
<>
|
|
269
|
+
<img src={result.imageUrl} alt="Generated" />
|
|
270
|
+
{result.deprecation && (
|
|
271
|
+
<p style={{ color: 'orange' }}>
|
|
272
|
+
Note: requested entity "{result.deprecation.requestedEntityId}" is deprecated;
|
|
273
|
+
auto-substituted "{result.deprecation.resolvedEntityId}". Update your code.
|
|
274
|
+
</p>
|
|
275
|
+
)}
|
|
276
|
+
</>
|
|
277
|
+
)}
|
|
230
278
|
{error && <p>Error: {error.message}</p>}
|
|
231
279
|
</div>
|
|
232
280
|
);
|
|
233
281
|
}
|
|
234
282
|
```
|
|
235
283
|
|
|
284
|
+
### `useImageEntities()` — Discover image-generation entities
|
|
285
|
+
|
|
286
|
+
**Permission:** `entities:image_generate`
|
|
287
|
+
**Returns:** `{ entities, isLoading, error, refetch }`
|
|
288
|
+
|
|
289
|
+
Use to render a "let the user pick a model" picker. For the common case of "just give me something good," skip discovery and pass a selector directly to `useImageGeneration`:
|
|
290
|
+
|
|
291
|
+
```tsx
|
|
292
|
+
await generate({
|
|
293
|
+
entityId: { platformRecommended: { mode: 'text-to-image' } },
|
|
294
|
+
prompt: '...',
|
|
295
|
+
});
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
Discovery hook usage:
|
|
299
|
+
|
|
300
|
+
```tsx
|
|
301
|
+
import { useImageEntities } from '@fias/arche-sdk';
|
|
302
|
+
|
|
303
|
+
const { entities, isLoading } = useImageEntities({
|
|
304
|
+
modes: ['image-to-image'],
|
|
305
|
+
supportsReferenceImage: true,
|
|
306
|
+
});
|
|
307
|
+
// entities[i]: { entityId, displayName, provider, modes, supportedSizes,
|
|
308
|
+
// supportsReferenceImage, isPlatformRecommended, ... }
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
Each entry is scrubbed — only fields a UI legitimately needs (no provider model strings, no endpoints, no execution config).
|
|
312
|
+
|
|
313
|
+
### `useBackgroundRemoval()` — Client-side background removal
|
|
314
|
+
|
|
315
|
+
**Permission:** `entities:image_remove_background`
|
|
316
|
+
**Returns:** `BackgroundRemovalApi`
|
|
317
|
+
|
|
318
|
+
Runs the imgly WASM model inside the host page — bytes never leave the user's device. Returns a transparent PNG.
|
|
319
|
+
|
|
320
|
+
```tsx
|
|
321
|
+
import { useBackgroundRemoval } from '@fias/arche-sdk';
|
|
322
|
+
|
|
323
|
+
const { removeBackground, isLoading } = useBackgroundRemoval();
|
|
324
|
+
const transparentPng = await removeBackground(jpegBlob);
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
**Limits:** input ≤ 25 MiB, PNG/JPEG only, rate-limited to 10/min per arche per user. Throws on size violation rather than returning a result.
|
|
328
|
+
|
|
329
|
+
### Audio capability hooks (auto-generated)
|
|
330
|
+
|
|
331
|
+
**Permission:** `entities:audio_generate`
|
|
332
|
+
**Returns (per hook):** `{ invoke, isLoading, result, error }`
|
|
333
|
+
|
|
334
|
+
Specialty capabilities expose **typed convenience hooks** generated from the platform's surface registry. Each hook bakes in a `surfaceKey` and infers params/result types from the surface's schemas.
|
|
335
|
+
|
|
336
|
+
Currently shipped audio hooks: `useLyriaMusic`, `useElevenLabsTts`, `useElevenLabsMusic`, `useElevenLabsSfx`, `useElevenLabsStt`, `useElevenLabsAudioIsolation`, `useElevenLabsForcedAlignment`, `useElevenLabsVoiceChanger`, `useElevenLabsVoiceDesign`. Browse the full surface list with `npx fias-dev entities`.
|
|
337
|
+
|
|
338
|
+
A legacy `useAudioGeneration()` hook still ships for back-compat with code written before the typed-surface migration. New plugins should use the typed hooks above — the legacy hook will be removed in a future major version.
|
|
339
|
+
|
|
340
|
+
```tsx
|
|
341
|
+
import { useElevenLabsTts } from '@fias/arche-sdk';
|
|
342
|
+
|
|
343
|
+
const { invoke, isLoading, result } = useElevenLabsTts();
|
|
344
|
+
await invoke({ text: 'Hello world', voiceId: '...' });
|
|
345
|
+
// result: { audioUrl, audioRef, durationMinutes, costCredits, ... }
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
For surfaces without a typed wrapper yet, the generic substrate:
|
|
349
|
+
|
|
350
|
+
```tsx
|
|
351
|
+
import { useSurface } from '@fias/arche-sdk';
|
|
352
|
+
|
|
353
|
+
const { invoke } = useSurface<MyParams, MyResult>('my.surface-key');
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
Default per-request timeout is 180 s (covers TTS for long text and Lyria multi-clip generation).
|
|
357
|
+
|
|
358
|
+
### `useVaultDocuments()` — User-owned Vault documents
|
|
359
|
+
|
|
360
|
+
**Permissions:** `vault:documents:read` (list / read / getDownloadUrl / search), `vault:documents:write` (write / update / delete / attach / detach / upload)
|
|
361
|
+
**Returns:** `VaultDocumentsApi`
|
|
362
|
+
|
|
363
|
+
The Vault is the platform's persistent document store for the signed-in user. Distinct from `useFiasStorage` (per-plugin sandbox): Vault docs live in the user's My Data, survive plugin uninstall, and can be cross-referenced from other arches. Documents this arche creates are scoped to it (`source_arche_id`) and surfaced to the user under `/My-Fias/Arches/<archeId>/`.
|
|
364
|
+
|
|
365
|
+
**Most common use:** images returned from `useImageGeneration()` are auto-saved here. The result includes a `documentId` — pass it to `getDownloadUrl()` later to refresh the presigned URL after the original ~1h TTL expires.
|
|
366
|
+
|
|
367
|
+
```tsx
|
|
368
|
+
import { useVaultDocuments } from '@fias/arche-sdk';
|
|
369
|
+
|
|
370
|
+
const vault = useVaultDocuments();
|
|
371
|
+
|
|
372
|
+
// Refresh a presigned URL (cached client-side, auto-refreshed before expiry)
|
|
373
|
+
const { url, expiresAt, contentType } = await vault.getDownloadUrl(documentId);
|
|
374
|
+
|
|
375
|
+
// List documents this arche owns
|
|
376
|
+
const { documents, nextCursor } = await vault.list({ search: 'invoice', limit: 50 });
|
|
377
|
+
|
|
378
|
+
// Write a small text/JSON document (UTF-8, ≤ 1 MB)
|
|
379
|
+
const { documentId } = await vault.write({
|
|
380
|
+
name: 'settings.json',
|
|
381
|
+
content: JSON.stringify(settings),
|
|
382
|
+
contentType: 'application/json',
|
|
383
|
+
tags: ['config'],
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
// Upload a binary or larger document — wraps the two-step presigned-PUT flow
|
|
387
|
+
const result = await vault.upload(bytes, {
|
|
388
|
+
name: 'photo.jpg',
|
|
389
|
+
mimeType: 'image/jpeg',
|
|
390
|
+
});
|
|
391
|
+
// result.status transitions 'uploaded' → 'available' once indexed for search
|
|
392
|
+
|
|
393
|
+
// Semantic search across documents this arche owns
|
|
394
|
+
// (burns user credits per the AI Markup Invariant — call sparingly)
|
|
395
|
+
const { matches } = await vault.search('quarterly revenue', { topK: 5 });
|
|
396
|
+
|
|
397
|
+
// Update / delete
|
|
398
|
+
await vault.update(documentId, { name: 'new-name.json', tags: ['archived'] });
|
|
399
|
+
await vault.delete(documentId); // soft-delete, recoverable from My Data Trash
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
**Cross-arche attachment.** A document can be referenced from another arche's record (Business Contact, Company, Fias 360 Renewal in V-1). The reference points at the document but does NOT expose its contents to the target arche.
|
|
403
|
+
|
|
404
|
+
```tsx
|
|
405
|
+
const { referenceId } = await vault.attach(documentId, {
|
|
406
|
+
regardingType: 'vault_business_contact',
|
|
407
|
+
regardingId: contactId,
|
|
408
|
+
});
|
|
409
|
+
await vault.detach(documentId, referenceId);
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
**Sensitivity tiers** (`'standard'` | `'confidential'` | `'proprietary'`) gate downstream read access per the Vault's standard matrix. Defaults to `'standard'`.
|
|
413
|
+
|
|
414
|
+
**`fetchVaultDocumentDownloadUrl(documentId)`** — non-React function that shares the hook's client-side URL cache. Use from PDF exporters, image preloaders, or other non-component code paths.
|
|
415
|
+
|
|
416
|
+
### `useArcheAssets()` — Contributor-published asset library
|
|
417
|
+
|
|
418
|
+
**Permission:** `assets:read`
|
|
419
|
+
**Returns:** `ArcheAssetsApi`
|
|
420
|
+
|
|
421
|
+
A frozen set of images the arche's contributor uploaded and pinned to the published version — logos, brand images, hole maps, reference photos. Each entry has an immutable `assetId` and a short-lived `signedUrl` (~5 min) suitable for `<img src>`.
|
|
422
|
+
|
|
423
|
+
```tsx
|
|
424
|
+
import { useArcheAssets } from '@fias/arche-sdk';
|
|
425
|
+
|
|
426
|
+
const { list, getUrl } = useArcheAssets();
|
|
427
|
+
|
|
428
|
+
const { entries, nextCursor } = await list({ limit: 50 });
|
|
429
|
+
// entries[i]: { assetId, signedUrl, expiresAt, contentType, width, height,
|
|
430
|
+
// sizeBytes, name, altText, tags }
|
|
431
|
+
|
|
432
|
+
// Refresh a signed URL when it's about to expire
|
|
433
|
+
const fresh = await getUrl(assetId);
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
Cache the `assetId`; refresh `signedUrl` via `getUrl()` rather than persisting URLs across sessions.
|
|
437
|
+
|
|
438
|
+
### `useFiasStore()` — In-app purchases (IAP)
|
|
439
|
+
|
|
440
|
+
**Permission:** `store:purchase`
|
|
441
|
+
**Returns:** `FiasStoreApi`
|
|
442
|
+
|
|
443
|
+
How a plugin charges the signed-in user for anything inside the arche — one-time unlocks, consumables, subscriptions, paid sign-ups, donations. **All in-arche payments go through this hook.** The arche never handles payment directly: the platform shows a confirmation overlay, debits the user's Fias credit balance, and returns a result. Do not import Stripe or any external payment SDK — they are sandboxed out and not needed.
|
|
444
|
+
|
|
445
|
+
Products are declared in `fias-plugin.json` under a `products` array (see Manifest Reference below). Each product has a stable `identifier` your code passes to `purchase()`. Prices are denominated in **Fias credits**, not USD.
|
|
446
|
+
|
|
447
|
+
```tsx
|
|
448
|
+
import { useFiasStore } from '@fias/arche-sdk';
|
|
449
|
+
|
|
450
|
+
function UnlockButton() {
|
|
451
|
+
const { products, purchase, hasEntitlement, isLoading } = useFiasStore();
|
|
452
|
+
const product = products.find((p) => p.productIdentifier === 'pro_unlock');
|
|
453
|
+
|
|
454
|
+
if (isLoading || !product) return null;
|
|
455
|
+
if (hasEntitlement('pro_unlock')) return <p>Pro features unlocked.</p>;
|
|
456
|
+
|
|
457
|
+
async function buy() {
|
|
458
|
+
const result = await purchase('pro_unlock');
|
|
459
|
+
if (!result.success) {
|
|
460
|
+
// Common codes: INSUFFICIENT_CREDITS, USER_CANCELLED, PRODUCT_NOT_FOUND
|
|
461
|
+
console.error(result.error);
|
|
462
|
+
}
|
|
463
|
+
// On success, `entitlements` updates automatically.
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
return <button onClick={buy}>Unlock for {product.priceCredits} credits</button>;
|
|
467
|
+
}
|
|
468
|
+
```
|
|
469
|
+
|
|
470
|
+
**Product types:**
|
|
471
|
+
|
|
472
|
+
- `consumable` — buyable repeatedly (tokens, energy, single donations, sign-up entries). Does NOT create an entitlement; track usage in `useFiasDataStore`.
|
|
473
|
+
- `non_consumable` — one-time purchase, permanent entitlement.
|
|
474
|
+
- `auto_renewable` — subscription that renews automatically. Requires `subscriptionPeriod`: `weekly` | `monthly` | `quarterly` | `yearly`.
|
|
475
|
+
- `non_renewing` — time-limited access that does NOT renew (season pass).
|
|
476
|
+
|
|
477
|
+
**API surface:**
|
|
478
|
+
|
|
479
|
+
- `products: StoreProduct[]` — loaded on mount.
|
|
480
|
+
- `purchase(productIdentifier, { quantity? }) → StorePurchaseResult` — triggers the platform confirmation overlay. `quantity` only applies to consumables.
|
|
481
|
+
- `entitlements: StoreEntitlement[]` — current non-consumable + subscription entitlements; updated automatically after a successful purchase.
|
|
482
|
+
- `hasEntitlement(productIdentifier) → boolean` — convenience check.
|
|
483
|
+
- `getPurchaseHistory() → Promise<StorePurchase[]>` — full log including consumables.
|
|
484
|
+
- `restorePurchases() → Promise<StoreEntitlement[]>` — re-sync entitlements from the platform.
|
|
485
|
+
|
|
486
|
+
**Error handling:** `purchase()` returns `{ success: false, error, code }` rather than throwing — always branch on `result.success`. The user must be signed in to a Fias account; IAP is not available to anonymous visitors on public arches.
|
|
487
|
+
|
|
236
488
|
### `useFiasNavigation()` — In-plugin routing
|
|
237
489
|
|
|
238
490
|
**Permission:** None required
|
|
@@ -247,14 +499,22 @@ navigateTo('/settings');
|
|
|
247
499
|
|
|
248
500
|
### `useStepNavigation()` — Multi-step workflows
|
|
249
501
|
|
|
502
|
+
**Permission:** None for in-memory use; `storage:sandbox` when `persistKey` is set (it reads/writes `__state/<persistKey>` via the storage bridge).
|
|
250
503
|
**Returns:** `StepNavigationApi`
|
|
251
504
|
|
|
252
505
|
```tsx
|
|
253
506
|
import { useStepNavigation } from '@fias/arche-sdk';
|
|
254
507
|
|
|
255
|
-
|
|
508
|
+
// Pass `persistKey` to survive preview rebuilds (do NOT additionally wrap
|
|
509
|
+
// currentStep in usePersistentState — that creates two state sources and
|
|
510
|
+
// a bidirectional sync loop).
|
|
511
|
+
const { currentStep, setCurrentStep } = useStepNavigation('step-1', {
|
|
512
|
+
persistKey: 'workflow-step',
|
|
513
|
+
});
|
|
256
514
|
```
|
|
257
515
|
|
|
516
|
+
The host can also drive step changes from outside the iframe — for example, when the user clicks a node in an external graph view. The hook listens for those `step_navigate` messages and updates `currentStep` automatically, so unexpected step transitions aren't a bug to chase.
|
|
517
|
+
|
|
258
518
|
### `usePersistentState()` — Auto-saving state
|
|
259
519
|
|
|
260
520
|
**Permission:** `storage:sandbox`
|
|
@@ -272,13 +532,36 @@ const [count, setCount] = usePersistentState<number>('counter', 0);
|
|
|
272
532
|
|
|
273
533
|
### `fias` — Imperative utilities
|
|
274
534
|
|
|
535
|
+
Use the `fias` namespace when you need bridge operations from outside a React component (event handlers attached imperatively, utility modules, non-React entry points).
|
|
536
|
+
|
|
275
537
|
```tsx
|
|
276
538
|
import { fias } from '@fias/arche-sdk';
|
|
277
539
|
|
|
540
|
+
fias.ready(); // Manual ready signal (FiasProvider does this automatically)
|
|
278
541
|
fias.resize(800); // Resize iframe height
|
|
279
542
|
fias.showToast('Saved!', 'success'); // Toast: 'info' | 'success' | 'warning' | 'error'
|
|
543
|
+
|
|
544
|
+
// fias.dataStore mirrors useFiasDataStore() — same operations, same limits.
|
|
545
|
+
// Requires the `data:store` permission.
|
|
546
|
+
await fias.dataStore.createCollection('scores', { userScope: 'user' });
|
|
547
|
+
await fias.dataStore.put('scores', 'doc-key', { score: 100 });
|
|
548
|
+
const doc = await fias.dataStore.get('scores', 'doc-key');
|
|
549
|
+
await fias.dataStore.query('scores', {
|
|
550
|
+
filters: [{ field: 'score', op: 'gte', value: 50 }],
|
|
551
|
+
});
|
|
552
|
+
await fias.dataStore.delete('scores', 'doc-key');
|
|
553
|
+
await fias.dataStore.listCollections();
|
|
554
|
+
await fias.dataStore.deleteCollection('scores');
|
|
280
555
|
```
|
|
281
556
|
|
|
557
|
+
### Advanced exports (rarely needed)
|
|
558
|
+
|
|
559
|
+
The SDK also exports the following for advanced use cases. Most plugins don't need them.
|
|
560
|
+
|
|
561
|
+
- `VALID_PLUGIN_PERMISSIONS`, `isValidPluginPermission(perm)` — runtime permission validation.
|
|
562
|
+
- Theme catalog: `DARK_THEME`, `LIGHT_THEME`, `getDefaultTheme()`, `THEME_CATALOG`, `getThemeById()`, `FONT_PAIRINGS`, `getFontPairingById()` — useful when the plugin lets the user pick from preset themes/fonts.
|
|
563
|
+
- Bridge introspection: `FiasBridge`, `getBridge()`, `resetBridge()`, `SDK_BRIDGE_PROTOCOL_VERSION`, `SDK_REQUIRES_HOST_PROTOCOL_VERSION` — testing and advanced cases that need direct bridge control.
|
|
564
|
+
|
|
282
565
|
## Manifest Reference (`fias-plugin.json`)
|
|
283
566
|
|
|
284
567
|
```json
|
|
@@ -298,23 +581,78 @@ fias.showToast('Saved!', 'success'); // Toast: 'info' | 'success' | 'warning' |
|
|
|
298
581
|
|
|
299
582
|
**Fields:**
|
|
300
583
|
|
|
301
|
-
| Field
|
|
302
|
-
|
|
|
303
|
-
| `name`
|
|
304
|
-
| `version`
|
|
305
|
-
| `description`
|
|
306
|
-
| `
|
|
307
|
-
| `
|
|
308
|
-
| `
|
|
309
|
-
| `
|
|
310
|
-
| `
|
|
311
|
-
| `
|
|
312
|
-
| `
|
|
313
|
-
|
|
314
|
-
|
|
584
|
+
| Field | Req | Description |
|
|
585
|
+
| --------------------- | ---- | ------------------------------------------------------------------------------------------------------- |
|
|
586
|
+
| `name` | Yes | Plugin identifier (lowercase, hyphens) |
|
|
587
|
+
| `version` | Yes | Semver (e.g., `"1.0.0"`) |
|
|
588
|
+
| `description` | Yes | Short marketplace description |
|
|
589
|
+
| `expandedDescription` | No | Long-form marketplace copy |
|
|
590
|
+
| `main` | Yes | Entry point source file |
|
|
591
|
+
| `archeType` | Yes | `"tool"` or `"site"` |
|
|
592
|
+
| `categorySlug` | No | Marketplace category for discovery |
|
|
593
|
+
| `icon` | No | Relative path to icon asset (shown in marketplace + arche header) |
|
|
594
|
+
| `tags` | No | Discovery tags |
|
|
595
|
+
| `pricing` | Yes | Marketplace **listing** pricing (see "Pricing detail" below). NOT for in-arche charges — use `products` |
|
|
596
|
+
| `permissions` | Yes | Array of permission scopes (see below) |
|
|
597
|
+
| `products` | No | IAP product catalog for `useFiasStore()` (see "Defining IAP products" below) |
|
|
598
|
+
| `isPublic` | No | Default `false`. Anonymous visitors can view (see "Public arches" below) |
|
|
599
|
+
| `isFullScreen` | No | Default `false`. Renders without platform chrome — implies `archeType: "site"` |
|
|
600
|
+
| `isListed` | No | Default `true`. Visible in marketplace store |
|
|
601
|
+
| `sdk` | Yes | SDK version range |
|
|
602
|
+
| `dependencies` | No | npm packages with **exact** versions (max 20) |
|
|
603
|
+
| `archeIds` | Auto | Per-environment IDs written by the CLI after first publish — don't hand-edit |
|
|
604
|
+
|
|
605
|
+
**Pricing detail:**
|
|
606
|
+
|
|
607
|
+
`pricing` is the marketplace **listing** model — controls what the platform charges users to access the arche itself. It does NOT cover charges the plugin makes from inside (entry fees, unlocks, donations) — for those, use IAP via `products`.
|
|
608
|
+
|
|
609
|
+
| `pricing.model` | Required sub-fields |
|
|
610
|
+
| --------------- | ------------------------------- |
|
|
611
|
+
| `"free"` | none |
|
|
612
|
+
| `"fixed"` | `priceCents` |
|
|
613
|
+
| `"per_use"` | `baseFeeCents` |
|
|
614
|
+
| `"tiered"` | `tiers: [{ upTo, priceCents }]` |
|
|
615
|
+
|
|
616
|
+
Other optional sub-fields: `currency: "usd"` (only USD supported today), `platformFeePercent` (override the default platform cut — non-standard).
|
|
617
|
+
|
|
618
|
+
**Permissions:** `theme:read`, `user:profile:read`, `storage:sandbox`, `data:store`, `entities:invoke`, `entities:image_generate`, `entities:image_remove_background`, `entities:audio_generate`, `store:purchase`, `vault:documents:read`, `vault:documents:write`, `assets:read`
|
|
315
619
|
|
|
316
620
|
**Using AI:** Add `"entities:invoke"` to permissions, then use `useEntityInvocation()` with a model entity ID and your own `systemPrompt`. Browse available models with `npx fias-dev entities`.
|
|
317
621
|
|
|
622
|
+
**Defining IAP products (for `useFiasStore`):**
|
|
623
|
+
|
|
624
|
+
Add a `products` array to declare what users can buy inside the arche. Each entry needs a stable `identifier` your code passes to `purchase()`. Prices are in Fias credits.
|
|
625
|
+
|
|
626
|
+
```json
|
|
627
|
+
{
|
|
628
|
+
"products": [
|
|
629
|
+
{
|
|
630
|
+
"identifier": "pro_unlock",
|
|
631
|
+
"type": "non_consumable",
|
|
632
|
+
"name": "Pro features",
|
|
633
|
+
"description": "Permanent unlock for advanced features.",
|
|
634
|
+
"priceCredits": 500
|
|
635
|
+
},
|
|
636
|
+
{
|
|
637
|
+
"identifier": "monthly_sub",
|
|
638
|
+
"type": "auto_renewable",
|
|
639
|
+
"name": "Monthly subscription",
|
|
640
|
+
"description": "Renewing access.",
|
|
641
|
+
"priceCredits": 200,
|
|
642
|
+
"subscriptionPeriod": "monthly",
|
|
643
|
+
"subscriptionGroup": "pro"
|
|
644
|
+
}
|
|
645
|
+
],
|
|
646
|
+
"permissions": ["store:purchase"]
|
|
647
|
+
}
|
|
648
|
+
```
|
|
649
|
+
|
|
650
|
+
`store:purchase` must be in `permissions` whenever `products` is non-empty. Use `consumable` for things bought repeatedly (single donations, sign-up entries), `non_consumable` for one-time unlocks, `auto_renewable` / `non_renewing` for time-bounded access.
|
|
651
|
+
|
|
652
|
+
**Public arches (`isPublic: true`):**
|
|
653
|
+
|
|
654
|
+
Setting `isPublic: true` lets anonymous visitors (no Fias account) view the arche at `/a/<archeId>`. The UI renders without the platform sidebar. **Bridge operations still require auth** — `useFiasDataStore` writes, `useFiasStore.purchase()`, `useFiasStorage` reads, vault operations, etc. all require the visitor to be signed in. Public mode is for read-only landing pages, marketing pages, and shared-content viewers — not for collecting registrations or payments from anonymous users.
|
|
655
|
+
|
|
318
656
|
## Plugin Constraints
|
|
319
657
|
|
|
320
658
|
These are hard limits enforced by the platform. Code that violates these will fail review or be blocked at runtime.
|
|
@@ -418,7 +756,7 @@ npx fias-dev login --env production # Authenticate with production
|
|
|
418
756
|
npx fias-dev entities # List all
|
|
419
757
|
npx fias-dev entities --search "image" # Search by keyword
|
|
420
758
|
npx fias-dev entities --type "model-definition" # Filter by type
|
|
421
|
-
npx fias-dev entities --detail
|
|
759
|
+
npx fias-dev entities --detail ent_modeldef_gpt_image_1_5 # Full entity details (capabilities, sizes, pricing)
|
|
422
760
|
```
|
|
423
761
|
|
|
424
762
|
### Validating the Manifest
|
|
@@ -443,6 +781,44 @@ If the AI review rejects your submission, the listing-fee portion is
|
|
|
443
781
|
refunded automatically (the per-review portion is not, since review work
|
|
444
782
|
happened either way).
|
|
445
783
|
|
|
784
|
+
### Managing the asset library (for `useArcheAssets`)
|
|
785
|
+
|
|
786
|
+
`useArcheAssets()` reads a contributor-curated set of images pinned to the arche's published version. Populate that library with the `assets` subcommands. Each command accepts `--env <staging|prod|local>` (default `staging`) and `--arche-id <id>` (auto-resolved from the manifest when omitted).
|
|
787
|
+
|
|
788
|
+
```bash
|
|
789
|
+
npx fias-dev assets enable # Turn on the asset library for this arche
|
|
790
|
+
npx fias-dev assets status # Quota usage + billing summary
|
|
791
|
+
npx fias-dev assets upload <dir> # Bulk-upload images; subfolder name → default tag
|
|
792
|
+
# Flags: --concurrency <1-16>, --dry-run
|
|
793
|
+
npx fias-dev assets list # List assets; --tag <tag>, --limit <1-100>
|
|
794
|
+
npx fias-dev assets tag <assetId> --add <t> # Add or remove tags; --remove <t> also supported
|
|
795
|
+
npx fias-dev assets delete <assetId> # Soft-delete (excluded from future publishes); -y to skip confirm
|
|
796
|
+
npx fias-dev assets disable # Turn off the asset library
|
|
797
|
+
```
|
|
798
|
+
|
|
799
|
+
Uploads stage into the contributor's draft set; they only become visible to plugin runtimes after the next `npm run submit` publishes a new arche version. Existing published versions keep their original frozen snapshot.
|
|
800
|
+
|
|
801
|
+
### Managing collaborators
|
|
802
|
+
|
|
803
|
+
Multi-developer plugins use `arche_collaborators` for operational ownership (publishing, team management) — distinct from financial ownership (`contributor_id`, which is immutable in v1). Every arche must keep ≥1 active owner; revokes that would drop to zero return `MUST_KEEP_ONE_OWNER`.
|
|
804
|
+
|
|
805
|
+
```bash
|
|
806
|
+
npx fias-dev collaborators list # List active collaborators
|
|
807
|
+
npx fias-dev collaborators add <email|username|userId> \ # Default role: publisher
|
|
808
|
+
--role <owner|publisher|viewer> --expires <iso> # Owners cannot have expiry
|
|
809
|
+
npx fias-dev collaborators set <identifier> \ # Change role and/or expiry
|
|
810
|
+
--role <role> --expires <iso> # --no-expires clears expiry
|
|
811
|
+
npx fias-dev collaborators remove <identifier> # Revoke a collaborator
|
|
812
|
+
```
|
|
813
|
+
|
|
814
|
+
All commands accept `--env <staging|production|local>` (default `staging`).
|
|
815
|
+
|
|
816
|
+
### Other CLI diagnostics
|
|
817
|
+
|
|
818
|
+
```bash
|
|
819
|
+
npx fias-dev check-auth # Print per-environment auth status (which envs have saved keys)
|
|
820
|
+
```
|
|
821
|
+
|
|
446
822
|
## Common Patterns
|
|
447
823
|
|
|
448
824
|
### Theme-Aware Card Component
|