@fias/create-fias-plugin 1.0.5 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.js CHANGED
@@ -7,7 +7,7 @@ var path = require('path');
7
7
 
8
8
  var TEMPLATE_DIR = path.resolve(__dirname, 'templates/default');
9
9
 
10
- function copyDir(src, dest, replacements) {
10
+ function copyDir(src, dest, replacements, opts) {
11
11
  fs.mkdirSync(dest, { recursive: true });
12
12
 
13
13
  var entries = fs.readdirSync(src, { withFileTypes: true });
@@ -17,8 +17,17 @@ function copyDir(src, dest, replacements) {
17
17
  var destPath = path.join(dest, entry.name);
18
18
 
19
19
  if (entry.isDirectory()) {
20
- copyDir(srcPath, destPath, replacements);
20
+ copyDir(srcPath, destPath, replacements, opts);
21
21
  } else {
22
+ if (opts.inPlace && fs.existsSync(destPath)) {
23
+ console.error(
24
+ 'Error: refusing to overwrite existing file: ' + path.relative(opts.rootDest, destPath),
25
+ );
26
+ console.error(
27
+ 'In --in-place mode, the target directory must not already contain plugin files.',
28
+ );
29
+ process.exit(1);
30
+ }
22
31
  var content = fs.readFileSync(srcPath, 'utf-8');
23
32
  var keys = Object.keys(replacements);
24
33
  for (var k = 0; k < keys.length; k++) {
@@ -29,27 +38,59 @@ function copyDir(src, dest, replacements) {
29
38
  }
30
39
  }
31
40
 
32
- var projectName = process.argv[2];
33
-
34
- if (!projectName) {
41
+ function printUsage() {
35
42
  console.error('Usage: npm create @fias/fias-plugin <project-name>');
36
- process.exit(1);
43
+ console.error(' or: npm create @fias/fias-plugin -- --in-place (scaffold into current directory)');
44
+ console.error(' or: npm create @fias/fias-plugin . (alias for --in-place)');
45
+ }
46
+
47
+ var args = process.argv.slice(2);
48
+ var inPlace = false;
49
+ var positional = [];
50
+ for (var a = 0; a < args.length; a++) {
51
+ if (args[a] === '--in-place' || args[a] === '.') {
52
+ inPlace = true;
53
+ } else if (args[a].indexOf('--') === 0) {
54
+ console.error('Unknown option: ' + args[a]);
55
+ printUsage();
56
+ process.exit(1);
57
+ } else {
58
+ positional.push(args[a]);
59
+ }
37
60
  }
38
61
 
39
- var targetDir = path.resolve(process.cwd(), projectName);
62
+ var projectName;
63
+ var targetDir;
40
64
 
41
- if (fs.existsSync(targetDir)) {
42
- console.error('Error: Directory "' + projectName + '" already exists.');
43
- process.exit(1);
65
+ if (inPlace) {
66
+ targetDir = process.cwd();
67
+ projectName = positional[0] || path.basename(targetDir);
68
+ } else {
69
+ projectName = positional[0];
70
+ if (!projectName) {
71
+ printUsage();
72
+ process.exit(1);
73
+ }
74
+ targetDir = path.resolve(process.cwd(), projectName);
75
+ if (fs.existsSync(targetDir)) {
76
+ console.error('Error: Directory "' + projectName + '" already exists.');
77
+ process.exit(1);
78
+ }
44
79
  }
45
80
 
46
- console.log('Creating FIAS plugin project: ' + projectName);
81
+ console.log(
82
+ inPlace
83
+ ? 'Scaffolding FIAS plugin into current directory (' + projectName + ')'
84
+ : 'Creating FIAS plugin project: ' + projectName,
85
+ );
47
86
 
48
- copyDir(TEMPLATE_DIR, targetDir, { name: projectName });
87
+ copyDir(TEMPLATE_DIR, targetDir, { name: projectName }, { inPlace: inPlace, rootDest: targetDir });
49
88
 
50
- console.log('\nPlugin created at ./' + projectName + '\n');
89
+ console.log('\nPlugin scaffolded.\n');
51
90
  console.log('Next steps:');
52
- console.log(' cd ' + projectName);
91
+ if (!inPlace) {
92
+ console.log(' cd ' + projectName);
93
+ }
53
94
  console.log(' npm install');
54
95
  console.log(' npx fias-dev login # Authenticate with FIAS platform (opens browser)');
55
96
  console.log(' npm start # Start dev server + real AI harness (uses credits)');
package/package.json CHANGED
@@ -1,15 +1,10 @@
1
1
  {
2
2
  "name": "@fias/create-fias-plugin",
3
- "version": "1.0.5",
3
+ "version": "1.1.0",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
7
7
  "description": "Scaffold a new FIAS plugin arche project",
8
- "scripts": {
9
- "build": "pnpm build:ai-docs",
10
- "build:ai-docs": "node scripts/build-ai-docs.mjs",
11
- "check:ai-docs": "node scripts/build-ai-docs.mjs --check"
12
- },
13
8
  "bin": {
14
9
  "create-fias-plugin": "index.js"
15
10
  },
@@ -2,6 +2,8 @@
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
+
5
7
  ## Project Structure
6
8
 
7
9
  ```
@@ -266,6 +268,8 @@ const [count, setCount] = usePersistentState<number>('counter', 0);
266
268
  // Automatically persists to storage on change
267
269
  ```
268
270
 
271
+ **Writes are debounced (SDK ≥ 1.8.0).** The in-memory value updates synchronously, but the underlying `storage_write` is coalesced (250 ms trailing-edge debounce, 1 s max-wait, flushed on unmount). Safe to call from `requestAnimationFrame` and other high-frequency handlers. For state that updates every frame (game positions, drag coordinates), still prefer plain `useState` — persisting transient state is wasteful and not useful on reload.
272
+
269
273
  ### `fias` — Imperative utilities
270
274
 
271
275
  ```tsx
@@ -315,9 +319,15 @@ fias.showToast('Saved!', 'success'); // Toast: 'info' | 'success' | 'warning' |
315
319
 
316
320
  These are hard limits enforced by the platform. Code that violates these will fail review or be blocked at runtime.
317
321
 
322
+ ### Hitting a limit? Tell the user about Entity requests
323
+
324
+ Don't just say "can't do that" when the user asks for something blocked by these rules — most often a direct external API call, a third-party service, or a capability the platform hasn't surfaced yet. The Fias team adds new **Entities** on request: platform-managed wrappers that hold credentials, handle auth, and expose the capability to plugins through `useEntityInvocation()` (or `useImageGeneration()` for image models). The plugin never bypasses the sandbox — it invokes the new Entity like any other model.
325
+
326
+ When you hit a constraint, say so AND tell the user: file an Entity request on the Customer Support arche at `https://platform.fias.io/a/arche_customer_support`. Describe the service, endpoints, and auth method needed; once the Entity ships, the plugin can call it via `useEntityInvocation` with no sandbox change. Then propose a fallback that works inside the current sandbox (mock data, a simpler path, deferring the call) so the build keeps moving while the request is in flight.
327
+
318
328
  ### Sandboxing
319
329
 
320
- - Plugins run in an iframe with `sandbox="allow-scripts allow-forms allow-same-origin"`
330
+ - Plugins run in an iframe with `sandbox="allow-scripts allow-forms allow-same-origin allow-downloads"`
321
331
  - **No `fetch()` or `XMLHttpRequest`** — all network access is blocked
322
332
  - **No access** to parent DOM, cookies, or localStorage
323
333
  - **No external scripts or stylesheets** — everything must be bundled
@@ -336,6 +346,8 @@ These are hard limits enforced by the platform. Code that violates these will fa
336
346
  - `storage_read`: 300/minute
337
347
  - `storage_list`, `storage_delete`: 60/minute
338
348
 
349
+ A separate **runaway-loop detector** fires if any method is called >50 times in 5 s and blocks that method for 10 s. Errors include the target, e.g. `Runaway loop detected: "storage_write" (path: __state/gameState) …` — the path tells you where to debounce at the source.
350
+
339
351
  ### Security Rules (enforced during review)
340
352
 
341
353
  - No `eval()`, `Function()`, `innerHTML`, or dynamic code execution
@@ -413,9 +425,17 @@ npx fias-dev validate
413
425
  ```bash
414
426
  npm run submit
415
427
  # Builds, validates, packages, uploads, submits for AI review
416
- # First listing: 5000 credits ($50). Re-submissions: 100 credits ($1).
417
428
  ```
418
429
 
430
+ The first time you list a plugin in the marketplace there is a one-time
431
+ listing fee; subsequent submissions of the same plugin only pay a small
432
+ per-review fee. The harness fetches the exact amount from the server and
433
+ shows it before you confirm — never assume a hardcoded price.
434
+
435
+ If the AI review rejects your submission, the listing-fee portion is
436
+ refunded automatically (the per-review portion is not, since review work
437
+ happened either way).
438
+
419
439
  ## Common Patterns
420
440
 
421
441
  ### Theme-Aware Card Component
@@ -491,7 +511,3 @@ function Settings() {
491
511
  );
492
512
  }
493
513
  ```
494
-
495
- ## See also
496
-
497
- `CLAUDE.md` — equivalent guide with Claude-specific additions.
@@ -2,6 +2,8 @@
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
+
5
7
  ## Project Structure
6
8
 
7
9
  ```
@@ -266,6 +268,8 @@ const [count, setCount] = usePersistentState<number>('counter', 0);
266
268
  // Automatically persists to storage on change
267
269
  ```
268
270
 
271
+ **Writes are debounced (SDK ≥ 1.8.0).** The in-memory value updates synchronously, but the underlying `storage_write` is coalesced (250 ms trailing-edge debounce, 1 s max-wait, flushed on unmount). Safe to call from `requestAnimationFrame` and other high-frequency handlers. For state that updates every frame (game positions, drag coordinates), still prefer plain `useState` — persisting transient state is wasteful and not useful on reload.
272
+
269
273
  ### `fias` — Imperative utilities
270
274
 
271
275
  ```tsx
@@ -315,9 +319,15 @@ fias.showToast('Saved!', 'success'); // Toast: 'info' | 'success' | 'warning' |
315
319
 
316
320
  These are hard limits enforced by the platform. Code that violates these will fail review or be blocked at runtime.
317
321
 
322
+ ### Hitting a limit? Tell the user about Entity requests
323
+
324
+ Don't just say "can't do that" when the user asks for something blocked by these rules — most often a direct external API call, a third-party service, or a capability the platform hasn't surfaced yet. The Fias team adds new **Entities** on request: platform-managed wrappers that hold credentials, handle auth, and expose the capability to plugins through `useEntityInvocation()` (or `useImageGeneration()` for image models). The plugin never bypasses the sandbox — it invokes the new Entity like any other model.
325
+
326
+ When you hit a constraint, say so AND tell the user: file an Entity request on the Customer Support arche at `https://platform.fias.io/a/arche_customer_support`. Describe the service, endpoints, and auth method needed; once the Entity ships, the plugin can call it via `useEntityInvocation` with no sandbox change. Then propose a fallback that works inside the current sandbox (mock data, a simpler path, deferring the call) so the build keeps moving while the request is in flight.
327
+
318
328
  ### Sandboxing
319
329
 
320
- - Plugins run in an iframe with `sandbox="allow-scripts allow-forms allow-same-origin"`
330
+ - Plugins run in an iframe with `sandbox="allow-scripts allow-forms allow-same-origin allow-downloads"`
321
331
  - **No `fetch()` or `XMLHttpRequest`** — all network access is blocked
322
332
  - **No access** to parent DOM, cookies, or localStorage
323
333
  - **No external scripts or stylesheets** — everything must be bundled
@@ -336,6 +346,8 @@ These are hard limits enforced by the platform. Code that violates these will fa
336
346
  - `storage_read`: 300/minute
337
347
  - `storage_list`, `storage_delete`: 60/minute
338
348
 
349
+ A separate **runaway-loop detector** fires if any method is called >50 times in 5 s and blocks that method for 10 s. Errors include the target, e.g. `Runaway loop detected: "storage_write" (path: __state/gameState) …` — the path tells you where to debounce at the source.
350
+
339
351
  ### Security Rules (enforced during review)
340
352
 
341
353
  - No `eval()`, `Function()`, `innerHTML`, or dynamic code execution
@@ -413,9 +425,17 @@ npx fias-dev validate
413
425
  ```bash
414
426
  npm run submit
415
427
  # Builds, validates, packages, uploads, submits for AI review
416
- # First listing: 5000 credits ($50). Re-submissions: 100 credits ($1).
417
428
  ```
418
429
 
430
+ The first time you list a plugin in the marketplace there is a one-time
431
+ listing fee; subsequent submissions of the same plugin only pay a small
432
+ per-review fee. The harness fetches the exact amount from the server and
433
+ shows it before you confirm — never assume a hardcoded price.
434
+
435
+ If the AI review rejects your submission, the listing-fee portion is
436
+ refunded automatically (the per-review portion is not, since review work
437
+ happened either way).
438
+
419
439
  ## Common Patterns
420
440
 
421
441
  ### Theme-Aware Card Component
@@ -491,7 +511,3 @@ function Settings() {
491
511
  );
492
512
  }
493
513
  ```
494
-
495
- ## See also
496
-
497
- `AGENTS.md` — equivalent guide for non-Claude AI tools in this project.