afterpresets 0.1.0 → 0.2.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.
Files changed (82) hide show
  1. package/package.json +2 -2
  2. package/runtime/docs/cep/host-after-effects.md +57 -0
  3. package/runtime/docs/cep/host-premiere.md +84 -0
  4. package/runtime/docs/{host.md → cep/host.md} +34 -16
  5. package/runtime/docs/{README.md → common/README.md} +9 -7
  6. package/runtime/docs/{assets.md → common/assets.md} +16 -2
  7. package/runtime/docs/{licensing.md → common/licensing.md} +1 -1
  8. package/runtime/docs/{panels.md → common/panels.md} +5 -5
  9. package/runtime/docs/{storage.md → common/storage.md} +5 -5
  10. package/runtime/docs/{updates.md → common/updates.md} +1 -1
  11. package/runtime/package.json +1 -1
  12. package/runtime/src/host.js +1 -1
  13. package/runtime/src/updates.js +1 -1
  14. package/src/build/build.js +7 -7
  15. package/src/build/html.js +1 -1
  16. package/src/build/jsx.js +2 -2
  17. package/src/build/runtime.js +3 -3
  18. package/src/check/check.js +3 -3
  19. package/src/check/types.js +2 -2
  20. package/src/cli.js +5 -5
  21. package/src/commands/add.js +8 -3
  22. package/src/commands/check.js +3 -3
  23. package/src/commands/dev.js +2 -2
  24. package/src/commands/docs.js +1 -1
  25. package/src/commands/init.js +12 -3
  26. package/src/config.js +1 -1
  27. package/src/dev/cep-link.js +1 -1
  28. package/src/dev/debug-file.js +5 -5
  29. package/src/mcp/extendscript.js +9 -7
  30. package/src/mcp/panels.js +1 -1
  31. package/src/mcp/server.js +2 -2
  32. package/src/mcp/tools/host.js +1 -1
  33. package/src/mcp/tools/panel.js +4 -4
  34. package/src/mcp/tools/project.js +15 -15
  35. package/src/project/add-panel.js +1 -1
  36. package/src/project/docs.js +3 -1
  37. package/src/project/manifest.js +3 -2
  38. package/src/project/project.js +2 -2
  39. package/src/project/template.js +4 -1
  40. package/src/prompt.js +1 -1
  41. package/src/release/installers.js +4 -4
  42. package/src/release/package.js +1 -1
  43. package/src/release/publish.js +1 -1
  44. package/src/targets.js +1 -0
  45. package/src/user-config.js +2 -2
  46. package/template/{AGENTS.md → cep/AGENTS.md} +23 -22
  47. package/template/{README.md → cep/README.md} +9 -9
  48. package/template/{docs → cep/docs}/initial_setup.md +4 -4
  49. package/template/{src → cep/src}/features/home/home.html +4 -4
  50. package/template/{src → cep/src}/features/home/home.js +10 -11
  51. package/template/{src → cep/src}/shared/lib/host-theme.js +3 -3
  52. package/template/{src → cep/src}/shared/lib/view.js +1 -1
  53. package/template/{src → cep/src}/shared/ui/tokens.css +1 -1
  54. package/template/hosts/aeft/AGENTS.host.md +10 -0
  55. package/template/hosts/aeft/jsx/aeft/home.jsx +16 -0
  56. package/template/hosts/ppro/AGENTS.host.md +15 -0
  57. package/template/hosts/ppro/jsx/ppro/home.jsx +20 -0
  58. package/vendor/afterpresets-additions/AfterEffects.d.ts +291 -0
  59. package/vendor/afterpresets-additions/Premiere.d.ts +179 -0
  60. package/vendor/types-for-adobe/Premiere/24.0/index.d.ts +2567 -0
  61. package/vendor/types-for-adobe/README.md +8 -4
  62. package/template/jsx/home.jsx +0 -17
  63. /package/runtime/docs/{boot.md → common/boot.md} +0 -0
  64. /package/template/{.mcp.json → cep/.mcp.json} +0 -0
  65. /package/template/{gitignore → cep/gitignore} +0 -0
  66. /package/template/{package.json → cep/package.json} +0 -0
  67. /package/template/{src → cep/src}/features/home/home.css +0 -0
  68. /package/template/{src → cep/src}/features/license-screen/license-screen.css +0 -0
  69. /package/template/{src → cep/src}/features/license-screen/license-screen.html +0 -0
  70. /package/template/{src → cep/src}/features/license-screen/license-screen.js +0 -0
  71. /package/template/{src → cep/src}/features/update-screen/update-screen.css +0 -0
  72. /package/template/{src → cep/src}/features/update-screen/update-screen.html +0 -0
  73. /package/template/{src → cep/src}/features/update-screen/update-screen.js +0 -0
  74. /package/template/{src → cep/src}/panels/main/index.html +0 -0
  75. /package/template/{src → cep/src}/panels/main/main.js +0 -0
  76. /package/template/{src → cep/src}/shared/lib/dom.js +0 -0
  77. /package/template/{src → cep/src}/shared/lib/markdown.js +0 -0
  78. /package/template/{src → cep/src}/shared/ui/base.css +0 -0
  79. /package/template/{src → cep/src}/shared/ui/button.css +0 -0
  80. /package/template/{src → cep/src}/shared/ui/card.css +0 -0
  81. /package/template/{src → cep/src}/shared/ui/field.css +0 -0
  82. /package/template/{src → cep/src}/shared/ui/index.css +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "afterpresets",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Create, develop, and publish Adobe CEP extensions on AfterPresets.",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "homepage": "https://docs.afterpresets.com",
@@ -36,6 +36,6 @@
36
36
  "typescript": "5.9.3"
37
37
  },
38
38
  "afterpresets": {
39
- "runtimeVersion": "0.3.0"
39
+ "runtimeVersion": "0.4.0"
40
40
  }
41
41
  }
@@ -0,0 +1,57 @@
1
+ ---
2
+ title: After Effects ExtendScript
3
+ description: "Rules for ExtendScript in After Effects (jsx/aeft/): undo groups, the active composition, 1-based collections, and the version range."
4
+ ---
5
+
6
+ # After Effects ExtendScript
7
+
8
+ Read [host.md](host.md) first: it explains `AP.host.eval` and how `jsx/` is
9
+ loaded. This page is about code that runs in After Effects. Put code that only
10
+ makes sense in After Effects in `jsx/aeft/`.
11
+
12
+ ## Undo
13
+
14
+ Wrap every change in one undo group so the user undoes the whole action with
15
+ one Ctrl/Cmd+Z, and close it in `finally`:
16
+
17
+ ```js
18
+ app.beginUndoGroup("Rename layers");
19
+ try {
20
+ /* changes */
21
+ } finally {
22
+ app.endUndoGroup();
23
+ }
24
+ ```
25
+
26
+ The MCP `host_eval` tool already wraps each call in an undo group named
27
+ "AfterPresets MCP".
28
+
29
+ ## The active composition
30
+
31
+ `app.project.activeItem` is often null or not a composition (a footage item, a
32
+ folder, or nothing selected). Check before using it:
33
+
34
+ ```js
35
+ var comp = app.project.activeItem;
36
+ if (!comp || !(comp instanceof CompItem)) {
37
+ return JSON.stringify({ ok: false, message: "Open or select a composition first." });
38
+ }
39
+ ```
40
+
41
+ ## Collections and times
42
+
43
+ - Collections are 1-based: `comp.layer(1)`, `app.project.item(1)`,
44
+ `comp.selectedLayers[0]` (a plain array, 0-based).
45
+ - Times are seconds (floating point). `comp.frameDuration` is one frame.
46
+
47
+ ## Versions
48
+
49
+ The extension's range is `hosts[].minVersion` in afterpresets.json (default
50
+ 17.0, After Effects 2020). Check `parseFloat(app.version)` before using newer
51
+ APIs and return `{ ok: false, message }` when they are missing.
52
+
53
+ ## Type hints
54
+
55
+ `ap check --types` checks `jsx/` against the After Effects 26.0 declarations
56
+ from types-for-adobe and lists likely mistakes. Hints can be wrong; confirm
57
+ with the MCP `host_eval` tool before changing working code.
@@ -0,0 +1,84 @@
1
+ ---
2
+ title: Premiere Pro ExtendScript
3
+ description: "Rules for ExtendScript in Premiere Pro (jsx/ppro/): no undo groups, times in ticks, 0-based track and clip collections, no QE DOM, and the version range."
4
+ ---
5
+
6
+ # Premiere Pro ExtendScript
7
+
8
+ Read [host.md](host.md) first: it explains `AP.host.eval` and how `jsx/` is
9
+ loaded. This page is about code that runs in Premiere Pro. Put code that only
10
+ makes sense in Premiere Pro in `jsx/ppro/`.
11
+
12
+ ## No undo groups
13
+
14
+ Premiere Pro's ExtendScript has no `beginUndoGroup`. Every change a script
15
+ makes (a clip moved, a marker added, a property set) is its own step in
16
+ Edit → Undo. Keep scripted edits small, do the checks before the first change,
17
+ and tell the user how many undo steps an action adds. The MCP `host_eval`
18
+ tool cannot group them either.
19
+
20
+ ## The active sequence
21
+
22
+ `app.project.activeSequence` is null when no sequence is open. Check it:
23
+
24
+ ```js
25
+ function myTool_sequenceInfo() {
26
+ var sequence = app.project.activeSequence;
27
+ if (!sequence) return JSON.stringify({ ok: false, message: "Open a sequence first." });
28
+ var clips = 0;
29
+ for (var i = 0; i < sequence.videoTracks.numTracks; i++) {
30
+ clips += sequence.videoTracks[i].clips.numItems;
31
+ }
32
+ return JSON.stringify({ ok: true, name: sequence.name, videoClips: clips });
33
+ }
34
+ ```
35
+
36
+ ## Collections
37
+
38
+ Tracks, clips, sequences and project items are 0-based collections with a
39
+ count property: `sequence.videoTracks[0]` with `numTracks`,
40
+ `track.clips[0]` with `numItems`, `app.project.sequences[0]` with
41
+ `numSequences`, `app.project.rootItem.children[0]` with `numItems`. Use a
42
+ `for` loop; they are not arrays.
43
+
44
+ ## Times are ticks
45
+
46
+ Premiere measures time in ticks: **254016000000 ticks per second**. A `Time`
47
+ object has `.seconds` (a number) and `.ticks` (a string). Create one with
48
+ `new Time()` and set either:
49
+
50
+ ```js
51
+ var t = new Time();
52
+ t.seconds = 2.5;
53
+ app.project.activeSequence.setPlayerPosition(t.ticks); // move the playhead to 2.5 s
54
+ var startSeconds = clip.start.seconds; // read a clip's start
55
+ ```
56
+
57
+ Frame-accurate maths: convert with the sequence's timebase
58
+ (`sequence.timebase`, ticks per frame, a string) instead of rounding seconds.
59
+
60
+ ## Things not to use
61
+
62
+ - **The QE DOM** (`app.enableQE()`, `qe.*`): undocumented, unsupported, and
63
+ it changes between versions. Do not ship code that needs it.
64
+ - Dialogs (`alert`, `confirm`, `File.openDialog`) block Premiere Pro while
65
+ open; the panel can show its own UI instead.
66
+
67
+ ## Projects
68
+
69
+ - `app.project` is the active project. Premiere Pro can have several projects
70
+ open (`app.projects`, `numProjects`).
71
+ - Save with `app.project.save()`. The MCP `host_scratch_project` tool creates a
72
+ new project in the temp folder and leaves the user's project open.
73
+
74
+ ## Versions
75
+
76
+ The extension's range is `hosts[].minVersion` in afterpresets.json (default
77
+ 14.0, Premiere Pro 2020). Check `app.version` before using newer APIs and
78
+ return `{ ok: false, message }` when they are missing.
79
+
80
+ ## Type hints
81
+
82
+ `ap check --types` checks `jsx/` against the Premiere Pro 24.0 declarations
83
+ from types-for-adobe (the newest set; newer APIs may be missing) and lists
84
+ likely mistakes. Hints can be wrong; confirm with the MCP `host_eval` tool.
@@ -1,21 +1,38 @@
1
1
  ---
2
- title: Calling After Effects
3
- description: Call ExtendScript functions from a panel with AP.host.eval, write jsx/ functions in ES3 that return JSON, and handle host errors.
2
+ title: Calling the app (ExtendScript)
3
+ description: Call ExtendScript functions in After Effects or Premiere Pro from a panel with AP.host.eval, write jsx/ functions in ES3 that return JSON, keep app-only code in jsx/aeft/ and jsx/ppro/, and handle host errors.
4
4
  ---
5
5
 
6
- # Calling After Effects
6
+ # Calling the app (ExtendScript)
7
7
 
8
- Panel code runs in a browser. Anything that touches After Effects (project,
9
- comps, layers, effects, files through `File`/`Folder`) runs in ExtendScript, in
10
- `jsx/`. `AP.host.eval` connects the two.
8
+ Panel code runs in a browser. Anything that touches the app (the project, its
9
+ compositions or sequences, layers or clips, files through `File`/`Folder`) runs
10
+ in ExtendScript, in `jsx/`. `AP.host.eval` connects the two. It works the same
11
+ in After Effects and Premiere Pro. What you can do in each app:
12
+
13
+ - [host-after-effects.md](host-after-effects.md): After Effects
14
+ - [host-premiere.md](host-premiere.md): Premiere Pro
11
15
 
12
16
  ## Where JSX lives
13
17
 
14
18
  Put ExtendScript in `jsx/`, one file per feature (for example
15
19
  `jsx/layers.jsx`; subfolders are fine). Every `.jsx` file there is loaded into
16
- After Effects once, before your app starts, and its functions are shared by
20
+ the app once, before your app starts, and its functions are shared by
17
21
  all panels. Call one from panel code with `ctx.host.eval("fnName", [args], cb)`.
18
22
 
23
+ Two folders are special (afterpresets.json `hosts` lists the apps):
24
+
25
+ | Folder | Loaded in |
26
+ |---|---|
27
+ | `jsx/aeft/` | After Effects only |
28
+ | `jsx/ppro/` | Premiere Pro only |
29
+ | everything else in `jsx/` | every app the extension targets |
30
+
31
+ An extension for both apps can define the same function in `jsx/aeft/` and
32
+ `jsx/ppro/` (for example `myTool_activeItemName`) and call it from shared panel
33
+ code; each app loads its own version. `ap check` warns about a folder for an
34
+ app the project does not target.
35
+
19
36
  - There is no list to keep: the CLI joins every `.jsx` file in alphabetical
20
37
  path order, with JSON support (json2) first, embeds the result in every
21
38
  panel's `main.js` (readable in `ap dev`, compiled to JSXBIN for releases),
@@ -38,11 +55,11 @@ Rules:
38
55
  objects).
39
56
  3. Return `JSON.stringify(...)`. Return a result object such as `{ ok: true, ... }`
40
57
  or `{ ok: false, message: "..." }` for expected problems.
41
- 4. Wrap changes to the project in `app.beginUndoGroup("Name")` /
42
- `app.endUndoGroup()`.
58
+ 4. Undo: in After Effects wrap changes in one undo group; Premiere Pro has
59
+ none (every change is its own undo step). See the app pages.
43
60
 
44
61
  ```js
45
- /* jsx/layers.jsx */
62
+ /* jsx/aeft/layers.jsx (After Effects) */
46
63
  function myTool_addNull(name) {
47
64
  var comp = app.project.activeItem;
48
65
  if (!comp || !(comp instanceof CompItem)) {
@@ -64,7 +81,7 @@ function myTool_addNull(name) {
64
81
  ```js
65
82
  AP.host.eval("myTool_addNull", ["Controller"], function (result) {
66
83
  if (!result || result.error) {
67
- showError(result ? result.error : "No answer from After Effects.");
84
+ showError(result ? result.error : "No answer from the app.");
68
85
  return;
69
86
  }
70
87
  if (!result.ok) {
@@ -92,19 +109,20 @@ values through `args`.
92
109
  | `result` | Cause |
93
110
  |---|---|
94
111
  | `{ error: "<message>" }` | Your function threw; the message is the thrown error's message. |
95
- | `{ error: "...is undefined" }` or similar | The function does not exist: check the name, and that its file is in `jsx/` and ends in `.jsx`. |
112
+ | `{ error: "...is undefined" }` or similar | The function does not exist: check the name, that its file is in `jsx/` and ends in `.jsx`, and that it is not in another app's folder (`jsx/aeft/`, `jsx/ppro/`). |
96
113
  | `{ error: "The host returned a non-JSON result.", raw }` | Your function returned a plain string. Return `JSON.stringify(...)`. |
97
114
  | `{ error: "The host script failed to run." }` | ExtendScript syntax error or an ES5+ feature in `jsx/`. |
98
- | `{ error: "Could not load host script: ..." }` | The embedded JSX failed to load. Read the message; usually a syntax error. |
115
+ | `{ error: "Could not load host script: ..." }` | The embedded JSX failed to load. Read the message; usually a syntax error. "This extension has no host script for X" means the build has no code for the running app (afterpresets.json `hosts`). |
99
116
 
100
117
  The JSX loads once per page. During `ap dev` every save rebuilds and reloads
101
118
  the open panels, which loads the new JSX too; after an update,
102
119
  `AP.updates.reload()` does the same. The new functions replace the old ones.
103
- Functions removed from the new code stay defined in After Effects until it
120
+ Functions removed from the new code stay defined in the app until it
104
121
  restarts, so never rely on a function being absent.
105
122
 
106
123
  ## Testing
107
124
 
108
125
  Call the function from the live panel and check the result and the project
109
- state. Use a disposable project or a duplicate composition for anything that
110
- changes layers, effects, files, or project data.
126
+ state. Use a disposable project (the MCP `host_scratch_project` tool) for
127
+ anything that changes the project. With the MCP tools, `host_eval` runs in the
128
+ app that runs the connected panel.
@@ -5,8 +5,8 @@ description: What the AfterPresets runtime does, and which reference file to rea
5
5
 
6
6
  # AfterPresets runtime reference
7
7
 
8
- These files are for the AI coding agent that builds an After Effects extension
9
- with AfterPresets. They describe the `AP.*` API that every panel gets.
8
+ These files are for the AI coding agent that builds an After Effects or Premiere
9
+ Pro extension with AfterPresets. They describe the `AP.*` API that every panel gets.
10
10
 
11
11
  ## What the runtime does
12
12
 
@@ -19,7 +19,7 @@ It gives you:
19
19
  - `AP.boot` to start the panel.
20
20
  - Licensing, off by default. Paid extensions must turn it on.
21
21
  - Signed updates with changelogs.
22
- - `AP.host.eval` to call After Effects (ExtendScript) functions.
22
+ - `AP.host.eval` to call ExtendScript functions in the app (After Effects or Premiere Pro).
23
23
  - `AP.panels` and `AP.events` for extensions with more than one panel.
24
24
  - `AP.paths` to find the images, videos and other files you ship.
25
25
  - `AP.storage` to save settings and other small data on this computer.
@@ -40,15 +40,17 @@ and your memory disagree, the file wins.
40
40
  | [boot.md](boot.md) | call `AP.boot`, use `ctx`, or change when the app starts |
41
41
  | [licensing.md](licensing.md) | turn licensing on, write `renderLicense`, or change the license screen |
42
42
  | [updates.md](updates.md) | change update options or the update screen, or show a changelog |
43
- | [host.md](host.md) | call After Effects from the panel or write `jsx/` code |
43
+ | [host.md](host.md) | call the app from the panel or write `jsx/` code |
44
+ | [host-after-effects.md](host-after-effects.md) | write ExtendScript for After Effects (`jsx/aeft/`) |
45
+ | [host-premiere.md](host-premiere.md) | write ExtendScript for Premiere Pro (`jsx/ppro/`) |
44
46
  | [panels.md](panels.md) | add a panel or modal, open/close panels, or send data between panels |
45
- | [assets.md](assets.md) | add images, fonts, videos or other files, or import a file into After Effects |
47
+ | [assets.md](assets.md) | add images, fonts, videos or other files, or import a file into the app |
46
48
  | [storage.md](storage.md) | save settings, recent items or any other data between launches |
47
49
 
48
50
  ## Commands you will use
49
51
 
50
52
  ```sh
51
- ap dev # build, link into After Effects, rebuild on change
53
+ ap dev # build, link into the app, rebuild on change
52
54
  ap check # static checks; also run by ap dev and ap push
53
55
  ap add panel settings --type modal
54
56
  ap push # publish a release (asks for version bump and changelog)
@@ -57,7 +59,7 @@ ap docs # refresh docs/afterpresets/ from the runtime
57
59
 
58
60
  ## Compatibility
59
61
 
60
- Panels run in Adobe CEP 10 or later (After Effects 2020+). Its browser is old
62
+ Panels run in Adobe CEP 10 or later (After Effects 2020+, Premiere Pro 2020+). Its browser is old
61
63
  (Chromium 74 in CEP 10). Write plain ES5 in panel code: `var`, `function`, no
62
64
  arrow functions, no `let`/`const`, no `class`, no template strings, no
63
65
  `fetch`-only features. ExtendScript in `jsx/` is ES3 (see [host.md](host.md)).
@@ -51,7 +51,7 @@ Use `AP.paths`; never build paths by hand.
51
51
  | `AP.paths.extension()` | Absolute path of the installed extension folder. |
52
52
  | `AP.paths.data()` | A writable folder for your own files. It survives updates. Never write into the extension folder: updates replace it. For settings use `AP.storage`; see [storage.md](storage.md). |
53
53
 
54
- ## From ExtendScript (importing into After Effects)
54
+ ## From ExtendScript (importing into the app)
55
55
 
56
56
  ExtendScript cannot see the panel's folders by itself. Pass the absolute path
57
57
  from the panel:
@@ -64,7 +64,7 @@ ctx.host.eval("importClip", [AP.paths.asset("media/intro.mp4")], function (resul
64
64
  ```
65
65
 
66
66
  ```js
67
- // jsx/media.jsx (loaded automatically, like every .jsx file in jsx/)
67
+ // After Effects: jsx/aeft/media.jsx (loaded automatically, like every .jsx file in jsx/)
68
68
  function importClip(path) {
69
69
  var file = new File(path);
70
70
  if (!file.exists) return JSON.stringify({ error: "Missing file: " + path });
@@ -72,3 +72,17 @@ function importClip(path) {
72
72
  return JSON.stringify({ ok: true, name: item.name });
73
73
  }
74
74
  ```
75
+
76
+ ```js
77
+ // Premiere Pro: jsx/ppro/media.jsx
78
+ function importClip(path) {
79
+ var file = new File(path);
80
+ if (!file.exists) return JSON.stringify({ error: "Missing file: " + path });
81
+ // importFiles(paths, suppressUI, targetBin, importAsNumberedStills)
82
+ var ok = app.project.importFiles([file.fsName], true, app.project.getInsertionBin(), false);
83
+ return JSON.stringify({ ok: ok === true, name: file.name });
84
+ }
85
+ ```
86
+
87
+ Both files define the same function name: an extension for both apps calls
88
+ `importClip` and each app loads its own version.
@@ -35,7 +35,7 @@ once.
35
35
 
36
36
  After a successful online check the API returns a signed record of it, valid
37
37
  for 12 hours, and the runtime saves it with the token. Until it runs out,
38
- launching After Effects, reloading a panel (including `ap dev` reloads) or
38
+ launching the app, reloading a panel (including `ap dev` reloads) or
39
39
  opening another panel unlocks straight away, with no network call and no
40
40
  `checking` screen. After 12 hours the license is checked online again, without blocking the
41
41
  buyer:
@@ -12,9 +12,9 @@ HTML, and JavaScript. They share `js/`, `css/`, `jsx/`, and the license.
12
12
 
13
13
  | `type` | What it is | Use it for |
14
14
  |---|---|---|
15
- | `panel` | A dockable After Effects panel, listed in **Window → Extensions** when `menu` is true | The main UI |
16
- | `modal` | A dialog that blocks After Effects until closed | Settings, confirmations, one-off forms |
17
- | `invisible` | No window; starts with After Effects and runs in the background | Listening for events, background work |
15
+ | `panel` | A dockable panel, listed in **Window → Extensions** when `menu` is true | The main UI |
16
+ | `modal` | A dialog that blocks the app until closed | Settings, confirmations, one-off forms |
17
+ | `invisible` | No window; starts with the app and runs in the background | Listening for events, background work |
18
18
 
19
19
  Panels are declared in `afterpresets.json`:
20
20
 
@@ -37,7 +37,7 @@ This creates `src/panels/<id>/index.html` and `src/panels/<id>/main.js`, and
37
37
  adds the entry to `afterpresets.json`. Each panel calls `AP.boot` in its own
38
38
  `main.js` and imports the screens and helpers it uses from `src/features/`
39
39
  and `src/shared/`. After adding a panel, restart
40
- `ap dev` and then After Effects: CEP reads the manifest only at launch.
40
+ `ap dev` and then the app: CEP reads the manifest only at launch.
41
41
 
42
42
  ## AP.panels
43
43
 
@@ -49,7 +49,7 @@ AP.panels.close("settings"); // ask another open panel to close itself
49
49
  ```
50
50
 
51
51
  - Ids are the ones in `afterpresets.json`. An invalid id throws.
52
- - `open` asks After Effects to open the extension `<bundleId>.<id>`. It returns
52
+ - `open` asks the app to open the extension `<bundleId>.<id>`. It returns
53
53
  `true` when the request was sent; it does not wait for the panel to load.
54
54
  - Data cannot be passed to `open`. Send it with `AP.events` once the other
55
55
  panel is ready (see "Handshake" below).
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  title: Saving data
3
- description: Where an extension keeps settings and other local state with AP.storage and AP.paths.data(), what goes inside the After Effects project instead, and what never to store.
3
+ description: Where an extension keeps settings and other local state with AP.storage and AP.paths.data(), what goes inside the app's project file instead, and what never to store.
4
4
  ---
5
5
 
6
6
  # Saving data
@@ -11,7 +11,7 @@ description: Where an extension keeps settings and other local state with AP.sto
11
11
  |---|---|
12
12
  | Settings, preferences, recent items, small caches | `AP.storage` (below) |
13
13
  | Bigger files you create or download (images, media, generated presets) | A file in `AP.paths.data()` |
14
- | Data that belongs to one After Effects project | Inside the `.aep`, from `jsx/` (it travels with the project file) |
14
+ | Data that belongs to one After Effects or Premiere Pro project | Inside the `.aep` / `.prproj`, from `jsx/` (it travels with the project file) |
15
15
  | Secrets (passwords, API keys, tokens) | Nowhere. Everything above is a plain file the user can open. |
16
16
 
17
17
  Do **not** use `localStorage`, `sessionStorage` or IndexedDB: in CEP each panel
@@ -71,12 +71,12 @@ var path = require("path");
71
71
  var file = path.join(AP.paths.data(), "thumbnails", "intro.png");
72
72
  ```
73
73
 
74
- Pass such paths to ExtendScript as arguments when After Effects needs them
74
+ Pass such paths to ExtendScript as arguments when the app needs them
75
75
  (see [assets.md](assets.md)).
76
76
 
77
- ## Inside the After Effects project
77
+ ## Inside the project file
78
78
 
79
79
  Data about one project (which presets it uses, a layout you applied) belongs in
80
- the project, not on the computer: it should follow the `.aep` to another
80
+ the project, not on the computer: it should follow the `.aep` or `.prproj` to another
81
81
  machine. Read and write it from a `jsx/` function, for example in a project
82
82
  XMP field or on a layer or comp comment, and call it with `ctx.host.eval`.
@@ -230,7 +230,7 @@ callback only.
230
230
  | `dev_build` | `ap dev` builds never install updates | Expected during development. Do not show the failure popup. |
231
231
  | `busy` | Another install is running | Try again later. |
232
232
  | `bad_signature`, `bad_checksum`, `bad_zip`, `bad_update_info` | The download failed verification; nothing was installed | Show the failure popup. Do not retry in a loop. |
233
- | `verify_unsupported` | After Effects is too old to verify signatures | Show the failure popup (reinstall from the product page). |
233
+ | `verify_unsupported` | The app is too old to verify signatures | Show the failure popup (reinstall from the product page). |
234
234
  | `download_failed`, `install_failed` | Download or copy failed (the previous version is restored) | Show the failure popup. |
235
235
 
236
236
  ## Channels
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@afterpresets/runtime",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "private": true
5
5
  }
@@ -1 +1 @@
1
- (function(d){"use strict";var c=d.AP,i=c._,S=/^[A-Za-z_$][A-Za-z0-9_$]*(\.[A-Za-z_$][A-Za-z0-9_$]*)*$/,j="EvalScript error.",u="idle",f=null,s=[];function a(n){var e=JSON.stringify(n===void 0?null:n);return e===void 0&&(e="null"),e.replace(/\u2028/g,"\\u2028").replace(/\u2029/g,"\\u2029")}i.jsxLiteral=a;function p(n,e){for(var r=[],t=0;t<e.length;t++)r.push(a(e[t]));return["(function () {"," function apQ(s) { s = String(s); return '\"' + s.replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"')"," .replace(/\\r/g, '\\\\r').replace(/\\n/g, '\\\\n').replace(/\\t/g, '\\\\t') + '\"'; }"," try {"," var r = "+n+"("+r.join(", ")+");"," if (r === undefined || r === null) return 'null';"," return String(r);"," } catch (e) {"," return '{\"error\":' + apQ(e && e.message ? e.message : e) + '}';"," }","}())"].join("\n")}i.wrapHostCall=p;function v(n,e){var r=i.cs();if(!r){e(JSON.stringify({error:"CEP host API is unavailable."}));return}r.evalScript(n,e)}function A(){for(var n=i.node("fs"),e=i.node("path"),r=e.join(i.extensionPath(),"jsx"),t=i.isDev()?["main.jsx","main.jsxbin"]:["main.jsxbin","main.jsx"],l=0;l<t.length;l++){var o=e.join(r,t[l]);if(n.existsSync(o))return o}return null}function y(){var n=d.AP_JSX;return n&&typeof n.code=="string"&&n.code?n:null}function _(){var n=y(),e;if(n)e="eval("+a(n.code)+");";else{var r=null;try{r=A()}catch(t){r=null}if(!r)return null;e="$.evalFile("+a(r.replace(/\\/g,"/"))+");"}return"try { "+e+" 'ok'; } catch (e) { 'AP_LOAD_ERROR:' + (e && e.message ? e.message : e); }"}function h(n){if(n=n||function(){},u==="loaded"){n(null);return}if(u==="failed"){n(f);return}if(s.push(n),u==="loading")return;u="loading";function e(t){u=t?"failed":"loaded",f=t,t&&i.log("error",t);var l=s;s=[];for(var o=0;o<l.length;o++)l[o](t)}var r=_();if(!r){e(null);return}v(r,function(t){e(t==="ok"?null:String(t||"Could not load host script.").replace(/^AP_LOAD_ERROR:/,"Could not load host script: "))})}i.preloadHost=function(){h(null)};function g(n){if(n===j)return{error:"The host script failed to run."};if(n==null||n===""||n==="undefined")return null;try{return JSON.parse(n)}catch(e){return{error:"The host returned a non-JSON result.",raw:String(n)}}}i.parseHostResult=g,c.host={eval:function(n,e,r){if(typeof e=="function"&&r===void 0&&(r=e,e=[]),r=typeof r=="function"?r:function(){},typeof n!="string"||!S.test(n)){r({error:"Invalid host function name: "+String(n)});return}e==null&&(e=[]),Object.prototype.toString.call(e)!=="[object Array]"&&(e=[e]);var t=p(n,e);h(function(l){if(l){r({error:String(l)});return}v(t,function(o){r(g(o))})})},reload:function(){u="idle",f=null}}})(typeof window!="undefined"?window:this);
1
+ (function(p){"use strict";var c=p.AP,i=c._,S=/^[A-Za-z_$][A-Za-z0-9_$]*(\.[A-Za-z_$][A-Za-z0-9_$]*)*$/,y="EvalScript error.",o="idle",s=null,f=[];function a(n){var e=JSON.stringify(n===void 0?null:n);return e===void 0&&(e="null"),e.replace(/\u2028/g,"\\u2028").replace(/\u2029/g,"\\u2029")}i.jsxLiteral=a;function d(n,e){for(var t=[],r=0;r<e.length;r++)t.push(a(e[r]));return["(function () {"," function apQ(s) { s = String(s); return '\"' + s.replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"')"," .replace(/\\r/g, '\\\\r').replace(/\\n/g, '\\\\n').replace(/\\t/g, '\\\\t') + '\"'; }"," try {"," var r = "+n+"("+t.join(", ")+");"," if (r === undefined || r === null) return 'null';"," return String(r);"," } catch (e) {"," return '{\"error\":' + apQ(e && e.message ? e.message : e) + '}';"," }","}())"].join("\n")}i.wrapHostCall=d;function h(n,e){var t=i.cs();if(!t){e(JSON.stringify({error:"CEP host API is unavailable."}));return}t.evalScript(n,e)}function v(){try{var n=i.cs(),e=n&&n.getHostEnvironment();return e&&e.appName?String(e.appName):null}catch(t){return null}}i.hostAppName=v;function R(n){return!!n&&typeof n.code=="string"&&!!n.code}function _(){var n=p.AP_JSX;if(!n||typeof n!="object")return{missing:"This bundle has no host script (AP_JSX). Rebuild it with the AfterPresets CLI."};var e=v();return e&&Object.prototype.hasOwnProperty.call(n,e)&&R(n[e])?n[e]:{missing:"This extension has no host script for "+(e||"this app")+"."}}function O(){var n=_();return n.missing?"'AP_LOAD_ERROR:' + "+a(n.missing):"try { eval("+a(n.code)+"); 'ok'; } catch (e) { 'AP_LOAD_ERROR:' + (e && e.message ? e.message : e); }"}function g(n){if(n=n||function(){},o==="loaded"){n(null);return}if(o==="failed"){n(s);return}if(f.push(n),o==="loading")return;o="loading";function e(r){o=r?"failed":"loaded",s=r,r&&i.log("error",r);var u=f;f=[];for(var l=0;l<u.length;l++)u[l](r)}var t=O();h(t,function(r){e(r==="ok"?null:String(r||"Could not load host script.").replace(/^AP_LOAD_ERROR:/,"Could not load host script: "))})}i.preloadHost=function(){g(null)};function A(n){if(n===y)return{error:"The host script failed to run."};if(n==null||n===""||n==="undefined")return null;try{return JSON.parse(n)}catch(e){return{error:"The host returned a non-JSON result.",raw:String(n)}}}i.parseHostResult=A,c.host={eval:function(n,e,t){if(typeof e=="function"&&t===void 0&&(t=e,e=[]),t=typeof t=="function"?t:function(){},typeof n!="string"||!S.test(n)){t({error:"Invalid host function name: "+String(n)});return}e==null&&(e=[]),Object.prototype.toString.call(e)!=="[object Array]"&&(e=[e]);var r=d(n,e);g(function(u){if(u){t({error:String(u)});return}h(r,function(l){t(A(l))})})},reload:function(){o="idle",s=null}}})(typeof window!="undefined"?window:this);
@@ -1 +1 @@
1
- (function(g){"use strict";var x=g.AP,n=x._,N="afterpresets-release-v1",U=600*1e3,P=[],m=[],w=[],k=!1,v=null,R={background:!0,prompt:!0,silent:!0},y="background",f=null,E=null,b=!1;function S(e,t){return typeof t!="function"?function(){}:(e.push(t),function(){var r=e.indexOf(t);r!==-1&&e.splice(r,1)})}function p(e,t){for(var r=e.slice(),i=0;i<r.length;i++)n.safeCall(r[i],null,[t])}function s(e,t,r){var i=new Error(t);return i.code=e,r&&n.extend(i,r),i}function C(){return n.node("path").join(n.dataDir(),"updates.json")}function D(){if(v)return v;var e=null;try{e=n.readJson(C())}catch(t){e=null}return v=e&&(e.channel==="test"||e.channel==="production")?e.channel:n.config().channel==="test"?"test":"production",v}function K(e){if(e!=="test"&&e!=="production")throw s("bad_channel","Channel must be 'production' or 'test'.");v=e;try{n.writeJson(C(),{channel:e})}catch(t){n.log("warn","Could not save update channel",t&&t.message)}}n.publicKeyPem=function(e){var t=String(e||"").replace(/^\s+|\s+$/g,"");if(!t)throw s("no_public_key","This build has no update signing key.");if(t.indexOf("-----BEGIN")!==-1)return t;var r=n.Buffer(),i=r.from(t,"base64"),o=i.toString("utf8");if(o.indexOf("-----BEGIN")!==-1)return o;for(var l=i.toString("base64"),a=[],u=0;u<l.length;u+=64)a.push(l.slice(u,u+64));return"-----BEGIN PUBLIC KEY-----\n"+a.join("\n")+"\n-----END PUBLIC KEY-----\n"},n.signaturePayload=function(e,t,r){return N+"\n"+e+"\n"+t+"\n"+r},n.verifyReleaseSignature=function(e,t,r){var i=n.node("crypto");if(typeof i.verify!="function")throw s("verify_unsupported","This After Effects version cannot verify signed updates (Node 12+ is required). Download the update from AfterPresets instead.");var o=n.config(),l=n.Buffer(),a=!1;try{a=i.verify(null,l.from(n.signaturePayload(o.bundleId,e,t),"utf8"),n.publicKeyPem(o.publicKey),l.from(String(r),"base64"))}catch(u){throw u&&u.code==="no_public_key"?u:s("bad_signature","The update signature could not be verified: "+(u&&u.message))}if(!a)throw s("bad_signature","The update signature is not valid for this extension. The update was not installed.")};function G(e){if(!e||typeof e!="object")throw s("bad_update_info","No update information.");if(!/^https?:\/\//i.test(String(e.downloadUrl||"")))throw s("bad_update_info","The update has no download URL.");if(!/^[0-9a-fA-F]{64}$/.test(String(e.sha256||"")))throw s("bad_update_info","The update has no valid checksum.");if(!e.signature||typeof e.signature!="string")throw s("bad_update_info","The update is not signed.");if(!/^[0-9A-Za-z.+-]{1,64}$/.test(String(e.targetVersion||"")))throw s("bad_update_info","The update has an invalid version.")}function O(e){var t=n.extend({},e),r=String(e.targetVersion||e.version||""),i=[],o=e.releaseNotes;if(o&&o.length)for(var l=0;l<o.length;l++){var a=o[l]||{};i.push({version:String(a.version||""),changeLog:String(a.changeLog||""),releaseDate:a.releaseDate||null})}else e.changeLog&&i.push({version:r,changeLog:String(e.changeLog),releaseDate:null});return t.updateAvailable=!0,t.version=r,t.targetVersion=r,t.direction=e.direction==="downgrade"?"downgrade":"upgrade",t.changeLog=String(e.changeLog||""),t.releaseNotes=i,t}function _(e){return{updateAvailable:!0,version:String(e.version||e.targetVersion||""),direction:e.direction==="downgrade"?"downgrade":"upgrade",changeLog:String(e.changeLog||""),releaseNotes:e.releaseNotes||[],mode:y}}function I(e,t){e=typeof e=="function"?e:function(){};function r(a){a.stage="check",t&&p(w,a),e(a)}var i=n.license.enabled(),o={currentVersion:n.config().version,channel:D()};try{if(i){var l=n.license.storedToken();if(!l){r(s("no_license","Sign in to check for updates."));return}o.license_token=l,o.computer_id=n.computerId()}}catch(a){r(s("error",a.message));return}n.api("/updates/check",o,function(a,u){if(a){i&&a.kind==="rejected"&&n.license.isRejectionCode(a.code)&&n.license.applyRejection(a),r(s(a.kind==="network"?"network":a.code,a.message));return}if(!u||!u.updateAvailable){e(null,{updateAvailable:!1});return}var d=O(u);if(f&&f===d.version){d.alreadyInstalled=!0,e(null,d);return}if(e(null,d),y==="prompt"){p(P,d);return}t&&E===d.version||V(d,function(c){if(c){if(c.code==="busy"){n.log("info","Another panel is installing update "+d.version+".");return}E=d.version,c.stage="install",c.info=_(d),p(w,c)}})})}function q(){return n.node("path").join(n.dataDir(),"update.lock")}function z(){var e=n.node("fs"),t;try{t=q(),n.mkdirp(n.dataDir())}catch(o){return n.log("warn","Update lock unavailable",o&&o.message),function(){}}for(var r=0;r<2;r++)try{return e.closeSync(e.openSync(t,"wx")),function(){try{e.unlinkSync(t)}catch(o){}}}catch(o){if(!o||o.code!=="EEXIST")return n.log("warn","Update lock unavailable",o&&o.message),function(){};var i=!1;try{i=n.now()-e.statSync(t).mtime.getTime()>U}catch(l){i=!0}if(!i)return null;try{e.unlinkSync(t)}catch(l){}}return null}function F(){try{var e=n.node("fs"),t=e.readFileSync(n.node("path").join(n.extensionPath(),"CSXS","manifest.xml"),"utf8"),r=/ExtensionBundleVersion\s*=\s*"([^"]+)"/.exec(t);return r?r[1]:null}catch(i){return null}}function A(e,t){var r=_(e);f=r.version,p(m,r),t&&n.events.emit("update.installed",r)}function V(e,t){if(t=typeof t=="function"?t:function(){},k){t(s("busy","An update is already being installed."));return}if(n.isDev()){t(s("dev_build","Updates are not installed in dev builds."));return}e&&!e.targetVersion&&e.version&&(e=n.extend({},e,{targetVersion:e.version}));try{G(e),n.verifyReleaseSignature(String(e.targetVersion),String(e.sha256).toLowerCase(),e.signature)}catch(a){t(a);return}var r=String(e.targetVersion);if(r!==String(n.config().version)&&F()===r){var i={version:r,backupPath:null,alreadyInstalled:!0};f!==r&&A(e,!1),t(null,i);return}var o=z();if(!o){t(s("busy","Another panel is installing an update."));return}k=!0;function l(a,u){k=!1,o(),a||A(e,!0),t(a||null,u)}n.request("GET",e.downloadUrl,null,function(a,u){if(a){l(s("download_failed","Download failed: "+a.message));return}if(u.status!==200){l(s("download_failed","Download failed (HTTP "+u.status+")."));return}var d;try{d=X(u.body,e)}catch(c){l(c);return}l(null,d)})}function X(e,t){var r=n.node("path"),i=n.node("fs"),o=n.config(),l=String(t.sha256).toLowerCase();if(n.sha256Hex(e)!==l)throw s("bad_checksum","The downloaded update is corrupted (checksum mismatch). Nothing was installed.");var a=n.makeTempDir("afterpresets-update-"+String(o.bundleId).replace(/[^A-Za-z0-9.-]/g,"_")),u=r.join(a,"stage");try{n.mkdirp(u),n.extractBundle(e,o.bundleId,u)}catch(h){try{n.rmrf(a)}catch(L){}throw h}var d=n.extensionPath();if(!d||!i.existsSync(d)){try{n.rmrf(a)}catch(h){}throw s("install_failed","The extension folder could not be found.")}var c=r.join(a,"backup");try{n.copyDir(d,c)}catch(h){try{n.rmrf(a)}catch(L){}throw s("install_failed","Could not back up the current version: "+h.message)}try{n.emptyDir(d),n.copyDir(u,d)}catch(h){var T=!1;try{n.emptyDir(d),n.copyDir(c,d),T=!0}catch(L){n.log("error","Restoring the backup failed. Backup kept at "+c,L)}throw s("install_failed","The update could not be installed: "+h.message+(T?" The previous version was restored.":" The previous version is backed up at "+c+"."),{restored:T,backupPath:c})}try{n.rmrf(u)}catch(h){}return{version:String(t.targetVersion),backupPath:c}}function B(){try{g.location&&typeof g.location.reload=="function"&&g.location.reload()}catch(e){n.log("error","Could not reload the panel",e&&e.message)}}function $(){b||(b=!0,n.events.emit("reload",{version:f}),g.setTimeout(B,50))}x.updates={check:function(e){I(e,!1)},install:V,reload:$,onAvailable:function(e){return S(P,e)},onInstalled:function(e){return S(m,e)},onError:function(e){return S(w,e)},getChannel:D,setChannel:K},n.updates={configure:function(e){y=e&&R[e.mode]===!0?e.mode:"background",n.events.on("update.installed",function(t){!t||typeof t.version!="string"||t.version===f||(f=t.version,p(m,_(t)))}),n.events.on("reload",function(){b=!0,B()})},autoCheck:function(){I(null,!0)},mode:function(){return y}}})(typeof window!="undefined"?window:this);
1
+ (function(g){"use strict";var x=g.AP,n=x._,N="afterpresets-release-v1",U=600*1e3,P=[],m=[],w=[],k=!1,v=null,R={background:!0,prompt:!0,silent:!0},y="background",f=null,C=null,b=!1;function S(e,t){return typeof t!="function"?function(){}:(e.push(t),function(){var r=e.indexOf(t);r!==-1&&e.splice(r,1)})}function p(e,t){for(var r=e.slice(),i=0;i<r.length;i++)n.safeCall(r[i],null,[t])}function s(e,t,r){var i=new Error(t);return i.code=e,r&&n.extend(i,r),i}function D(){return n.node("path").join(n.dataDir(),"updates.json")}function E(){if(v)return v;var e=null;try{e=n.readJson(D())}catch(t){e=null}return v=e&&(e.channel==="test"||e.channel==="production")?e.channel:n.config().channel==="test"?"test":"production",v}function K(e){if(e!=="test"&&e!=="production")throw s("bad_channel","Channel must be 'production' or 'test'.");v=e;try{n.writeJson(D(),{channel:e})}catch(t){n.log("warn","Could not save update channel",t&&t.message)}}n.publicKeyPem=function(e){var t=String(e||"").replace(/^\s+|\s+$/g,"");if(!t)throw s("no_public_key","This build has no update signing key.");if(t.indexOf("-----BEGIN")!==-1)return t;var r=n.Buffer(),i=r.from(t,"base64"),o=i.toString("utf8");if(o.indexOf("-----BEGIN")!==-1)return o;for(var l=i.toString("base64"),a=[],u=0;u<l.length;u+=64)a.push(l.slice(u,u+64));return"-----BEGIN PUBLIC KEY-----\n"+a.join("\n")+"\n-----END PUBLIC KEY-----\n"},n.signaturePayload=function(e,t,r){return N+"\n"+e+"\n"+t+"\n"+r},n.verifyReleaseSignature=function(e,t,r){var i=n.node("crypto");if(typeof i.verify!="function")throw s("verify_unsupported","This app version cannot verify signed updates (Node 12+ is required). Download the update from AfterPresets instead.");var o=n.config(),l=n.Buffer(),a=!1;try{a=i.verify(null,l.from(n.signaturePayload(o.bundleId,e,t),"utf8"),n.publicKeyPem(o.publicKey),l.from(String(r),"base64"))}catch(u){throw u&&u.code==="no_public_key"?u:s("bad_signature","The update signature could not be verified: "+(u&&u.message))}if(!a)throw s("bad_signature","The update signature is not valid for this extension. The update was not installed.")};function G(e){if(!e||typeof e!="object")throw s("bad_update_info","No update information.");if(!/^https?:\/\//i.test(String(e.downloadUrl||"")))throw s("bad_update_info","The update has no download URL.");if(!/^[0-9a-fA-F]{64}$/.test(String(e.sha256||"")))throw s("bad_update_info","The update has no valid checksum.");if(!e.signature||typeof e.signature!="string")throw s("bad_update_info","The update is not signed.");if(!/^[0-9A-Za-z.+-]{1,64}$/.test(String(e.targetVersion||"")))throw s("bad_update_info","The update has an invalid version.")}function O(e){var t=n.extend({},e),r=String(e.targetVersion||e.version||""),i=[],o=e.releaseNotes;if(o&&o.length)for(var l=0;l<o.length;l++){var a=o[l]||{};i.push({version:String(a.version||""),changeLog:String(a.changeLog||""),releaseDate:a.releaseDate||null})}else e.changeLog&&i.push({version:r,changeLog:String(e.changeLog),releaseDate:null});return t.updateAvailable=!0,t.version=r,t.targetVersion=r,t.direction=e.direction==="downgrade"?"downgrade":"upgrade",t.changeLog=String(e.changeLog||""),t.releaseNotes=i,t}function _(e){return{updateAvailable:!0,version:String(e.version||e.targetVersion||""),direction:e.direction==="downgrade"?"downgrade":"upgrade",changeLog:String(e.changeLog||""),releaseNotes:e.releaseNotes||[],mode:y}}function I(e,t){e=typeof e=="function"?e:function(){};function r(a){a.stage="check",t&&p(w,a),e(a)}var i=n.license.enabled(),o={currentVersion:n.config().version,channel:E()};try{if(i){var l=n.license.storedToken();if(!l){r(s("no_license","Sign in to check for updates."));return}o.license_token=l,o.computer_id=n.computerId()}}catch(a){r(s("error",a.message));return}n.api("/updates/check",o,function(a,u){if(a){i&&a.kind==="rejected"&&n.license.isRejectionCode(a.code)&&n.license.applyRejection(a),r(s(a.kind==="network"?"network":a.code,a.message));return}if(!u||!u.updateAvailable){e(null,{updateAvailable:!1});return}var d=O(u);if(f&&f===d.version){d.alreadyInstalled=!0,e(null,d);return}if(e(null,d),y==="prompt"){p(P,d);return}t&&C===d.version||V(d,function(c){if(c){if(c.code==="busy"){n.log("info","Another panel is installing update "+d.version+".");return}C=d.version,c.stage="install",c.info=_(d),p(w,c)}})})}function q(){return n.node("path").join(n.dataDir(),"update.lock")}function z(){var e=n.node("fs"),t;try{t=q(),n.mkdirp(n.dataDir())}catch(o){return n.log("warn","Update lock unavailable",o&&o.message),function(){}}for(var r=0;r<2;r++)try{return e.closeSync(e.openSync(t,"wx")),function(){try{e.unlinkSync(t)}catch(o){}}}catch(o){if(!o||o.code!=="EEXIST")return n.log("warn","Update lock unavailable",o&&o.message),function(){};var i=!1;try{i=n.now()-e.statSync(t).mtime.getTime()>U}catch(l){i=!0}if(!i)return null;try{e.unlinkSync(t)}catch(l){}}return null}function F(){try{var e=n.node("fs"),t=e.readFileSync(n.node("path").join(n.extensionPath(),"CSXS","manifest.xml"),"utf8"),r=/ExtensionBundleVersion\s*=\s*"([^"]+)"/.exec(t);return r?r[1]:null}catch(i){return null}}function A(e,t){var r=_(e);f=r.version,p(m,r),t&&n.events.emit("update.installed",r)}function V(e,t){if(t=typeof t=="function"?t:function(){},k){t(s("busy","An update is already being installed."));return}if(n.isDev()){t(s("dev_build","Updates are not installed in dev builds."));return}e&&!e.targetVersion&&e.version&&(e=n.extend({},e,{targetVersion:e.version}));try{G(e),n.verifyReleaseSignature(String(e.targetVersion),String(e.sha256).toLowerCase(),e.signature)}catch(a){t(a);return}var r=String(e.targetVersion);if(r!==String(n.config().version)&&F()===r){var i={version:r,backupPath:null,alreadyInstalled:!0};f!==r&&A(e,!1),t(null,i);return}var o=z();if(!o){t(s("busy","Another panel is installing an update."));return}k=!0;function l(a,u){k=!1,o(),a||A(e,!0),t(a||null,u)}n.request("GET",e.downloadUrl,null,function(a,u){if(a){l(s("download_failed","Download failed: "+a.message));return}if(u.status!==200){l(s("download_failed","Download failed (HTTP "+u.status+")."));return}var d;try{d=X(u.body,e)}catch(c){l(c);return}l(null,d)})}function X(e,t){var r=n.node("path"),i=n.node("fs"),o=n.config(),l=String(t.sha256).toLowerCase();if(n.sha256Hex(e)!==l)throw s("bad_checksum","The downloaded update is corrupted (checksum mismatch). Nothing was installed.");var a=n.makeTempDir("afterpresets-update-"+String(o.bundleId).replace(/[^A-Za-z0-9.-]/g,"_")),u=r.join(a,"stage");try{n.mkdirp(u),n.extractBundle(e,o.bundleId,u)}catch(h){try{n.rmrf(a)}catch(L){}throw h}var d=n.extensionPath();if(!d||!i.existsSync(d)){try{n.rmrf(a)}catch(h){}throw s("install_failed","The extension folder could not be found.")}var c=r.join(a,"backup");try{n.copyDir(d,c)}catch(h){try{n.rmrf(a)}catch(L){}throw s("install_failed","Could not back up the current version: "+h.message)}try{n.emptyDir(d),n.copyDir(u,d)}catch(h){var T=!1;try{n.emptyDir(d),n.copyDir(c,d),T=!0}catch(L){n.log("error","Restoring the backup failed. Backup kept at "+c,L)}throw s("install_failed","The update could not be installed: "+h.message+(T?" The previous version was restored.":" The previous version is backed up at "+c+"."),{restored:T,backupPath:c})}try{n.rmrf(u)}catch(h){}return{version:String(t.targetVersion),backupPath:c}}function B(){try{g.location&&typeof g.location.reload=="function"&&g.location.reload()}catch(e){n.log("error","Could not reload the panel",e&&e.message)}}function $(){b||(b=!0,n.events.emit("reload",{version:f}),g.setTimeout(B,50))}x.updates={check:function(e){I(e,!1)},install:V,reload:$,onAvailable:function(e){return S(P,e)},onInstalled:function(e){return S(m,e)},onError:function(e){return S(w,e)},getChannel:E,setChannel:K},n.updates={configure:function(e){y=e&&R[e.mode]===!0?e.mode:"background",n.events.on("update.installed",function(t){!t||typeof t.version!="string"||t.version===f||(f=t.version,p(m,_(t)))}),n.events.on("reload",function(){b=!0,B()})},autoCheck:function(){I(null,!0)},mode:function(){return y}}})(typeof window!="undefined"?window:this);
@@ -1,9 +1,9 @@
1
- "use strict";const o=require("fs"),l=require("path"),w=require("../config"),{generateManifest:F}=require("../project/manifest"),{bundlePanel:D,assetUrl:A}=require("./bundle"),{concatJsx:B}=require("./jsx"),{loadRuntime:K,concatFiles:I}=require("./runtime"),{copyAssets:k}=require("./assets"),{processIndexHtml:E}=require("./html"),{debugFileXml:R,debugPorts:N}=require("../dev/debug-file"),{CliError:S}=require("../errors"),x="src";function P(e){const n=x+"/panels/"+e;return{dir:n,html:n+"/index.html",js:n+"/main.js"}}function q(e,n){return l.join(e,n.split("/").join(l.sep))}function _(e){o.mkdirSync(e,{recursive:!0}),o.readdirSync(e).forEach(n=>o.rmSync(l.join(e,n),{recursive:!0,force:!0}))}function J(e,n,r,t,s){const u=w.webBase(e),a=w.signingPublicKey(e);if(!a&&!t.dev)throw new S("No release signing public key is configured.",{hint:"Set AP_SIGNING_PUBLIC_KEY or run `ap config set signing-public-key <file-or-pem>`. The production key is not yet embedded in this CLI."});return{bundleId:n.settings.bundleId,panelId:r.id,version:t.version,apiBase:t.apiBase||w.apiBase(e,null),publicKey:a,name:n.settings.name||void 0,productUrl:n.settings.listingUrl||u,manageDevicesUrl:u+"/settings/extensions",dev:!!t.dev,runtimeVersion:s}}function y(e){return JSON.stringify(String(e)).replace(/\u2028/g,"\\u2028").replace(/\u2029/g,"\\u2029").replace(/<\/(script)/gi,"<\\/$1")}function M(e){return e.trim()?["(function () {",' var style = document.createElement("style");',' style.setAttribute("data-ap", "bundle");'," style.textContent = "+y(e)+";"," (document.head || document.documentElement).appendChild(style);","}());"].join(`
2
- `):""}function O(e){return e.trim()?`(function () {
1
+ "use strict";const l=require("fs"),u=require("path"),w=require("../config"),{generateManifest:F}=require("../project/manifest"),{bundlePanel:D,assetUrl:E}=require("./bundle"),{concatJsx:k}=require("./jsx"),{loadRuntime:A,concatFiles:x}=require("./runtime"),{copyAssets:B}=require("./assets"),{processIndexHtml:K}=require("./html"),{debugFileXml:O,debugPorts:R}=require("../dev/debug-file"),{CliError:S}=require("../errors"),{projectTargets:J}=require("../targets"),I="src";function q(e){const n=I+"/panels/"+e;return{dir:n,html:n+"/index.html",js:n+"/main.js"}}function P(e,n){return u.join(e,n.split("/").join(u.sep))}function L(e){l.mkdirSync(e,{recursive:!0}),l.readdirSync(e).forEach(n=>l.rmSync(u.join(e,n),{recursive:!0,force:!0}))}function N(e,n,r,s,a){const t=w.webBase(e),o=w.signingPublicKey(e);if(!o&&!s.dev)throw new S("No release signing public key is configured.",{hint:"Set AP_SIGNING_PUBLIC_KEY or run `ap config set signing-public-key <file-or-pem>`. The production key is not yet embedded in this CLI."});return{bundleId:n.settings.bundleId,panelId:r.id,version:s.version,apiBase:s.apiBase||w.apiBase(e,null),publicKey:o,name:n.settings.name||void 0,productUrl:n.settings.listingUrl||t,manageDevicesUrl:t+"/settings/extensions",dev:!!s.dev,runtimeVersion:a}}function y(e){return JSON.stringify(String(e)).replace(/\u2028/g,"\\u2028").replace(/\u2029/g,"\\u2029").replace(/<\/(script)/gi,"<\\/$1")}function _(e){return e.trim()?["(function () {",' var style = document.createElement("style");',' style.setAttribute("data-ap", "bundle");'," style.textContent = "+y(e)+";"," (document.head || document.documentElement).appendChild(style);","}());"].join(`
2
+ `):""}function M(e){return e.trim()?`(function () {
3
3
  document.body.innerHTML = `+y(e)+`;
4
4
  }());`:""}function C(e){return["/* ---- ap dev live reload (dev builds only) ---- */","(function () {"," var BUILD = "+y(e)+";",' var KEY = "ap-dev-reloaded-for";',' if (typeof require !== "function" || !window.AP || !AP.paths) return;',' var fs = require("fs");',' var stamp = require("path").join(AP.paths.extension(), ".ap-dev-build");'," var warned = null;"," var timer = setInterval(function () {"," var id, last = null;",' try { id = String(fs.readFileSync(stamp, "utf8")).trim(); } catch (e) { return; }'," if (!id || id === BUILD) return;"," try { last = window.sessionStorage.getItem(KEY); } catch (e) { last = null; }"," if (last === id) {",' if (warned !== id) { warned = id; console.warn("ap dev: this page is not build " + id + " (two builds overlapped?). Save a file to rebuild; not reloading again for this build."); }'," return;"," }"," try { window.sessionStorage.setItem(KEY, id); } catch (e) { /* reload anyway */ }"," clearInterval(timer);"," window.location.reload();"," }, 400);","}());"].join(`
5
- `)}async function U(e,n,r,t,s,u,a,g){const c=n.root,i=P(r.id),f=q(c,i.html);if(!o.existsSync(f))throw new S("Missing "+i.html+".",{hint:"Create it, or run `ap add panel "+r.id+"`."});const d=E(o.readFileSync(f,"utf8"),i.html,i.js,h=>A(c,n.settings,f,h));if(d.errors.length)throw new S(d.errors.join(`
6
- `));if(g.push.apply(g,d.warnings),!o.existsSync(q(c,i.js)))throw new S("Missing "+i.js+".",{hint:"It starts the panel with AP.boot({ start })."});const p=await D(c,i.js,n.settings),v=J(e,n,r,u,t.version),j=t.files.css.length?I(t.files.css)+`
7
- `:"",b=u.dev?2:0,m=l.join(a,"panels",r.id);return o.mkdirSync(m,{recursive:!0}),o.writeFileSync(l.join(m,"index.html"),d.shell),o.writeFileSync(l.join(m,"main.js"),["/* Built by the AfterPresets CLI. Edit the source files, not this bundle. */","var AP_CONFIG = "+JSON.stringify(v,null,b)+";",s?"var AP_JSX = { type: "+y(s.type)+", code: "+y(s.code)+" };":"","/* ---- styles (imported by "+i.js+") ---- */",M(j+p.css+`
8
- `),"/* ---- markup ("+i.html+") ---- */",O(d.body),"/* ---- @afterpresets/runtime ---- */",I(t.files.js),";","/* ---- developer code ("+i.js+" and its imports) ---- */",p.js,u.liveReload?C(u.buildId):"",""].join(`
9
- `)),{inputs:p.inputs,publicKey:v.publicKey}}function L(e,n,r,t){const s=B(e.root,n.files.jsx);if(!s.files.length&&!n.files.jsx.length)return null;if(r.dev)return{type:"jsx",code:s.source,files:s.files};const a=(r.compileJsx||require("./jsxbin").compileJsxbin)(s.source,{fileName:l.join(t,"jsx","main.jsx"),lineMap:s.lineMap});return{type:"jsxbin",code:String(a).trim(),files:s.files}}async function X(e,n,r){const t=!!r.dev,s=r.version||n.version,u=t?Date.now().toString(36)+"-"+Math.random().toString(36).slice(2,8):null,a=Object.assign({},r,{dev:t,version:s,buildId:u,liveReload:t&&r.liveReload!==!1}),g=[],c=K(e,n.root),i=r.outDir;_(i);const f=L(n,c,a,i),d={};let p=!1;for(const m of n.panels){const h=await U(e,n,m,c,f,a,i,g);d[m.id]={inputs:h.inputs},h.publicKey||(p=!0)}p&&g.push("No signing public key is set; update signature checks cannot run in this dev build.");const v=f?f.files:[];o.mkdirSync(l.join(i,"CSXS"),{recursive:!0}),o.writeFileSync(l.join(i,"CSXS","manifest.xml"),F(n.settings,n.panels,s));const j=k(n.root,i,n.settings),b=N(n.panels,w.projectDebugPort(n.settings));return t&&o.writeFileSync(l.join(i,".debug"),R(b,n.settings.host.app)),a.liveReload&&o.writeFileSync(l.join(i,".ap-dev-build"),u),{outDir:i,version:s,runtimeVersion:c.version,warnings:g,debugPorts:b,files:{panels:d,jsx:v,assets:j}}}function Y(e){return l.join(e.root,"dist",e.settings.bundleId)}function G(e){return l.join(e.root,"dist-dev",e.settings.bundleId)}module.exports={buildProject:X,productionOutDir:Y,devOutDir:G,panelSources:P,SRC_DIR:x,__liveReloadClient:C};
5
+ `)}async function U(e,n,r,s,a,t,o,c){const d=n.root,i=q(r.id),g=P(d,i.html);if(!l.existsSync(g))throw new S("Missing "+i.html+".",{hint:"Create it, or run `ap add panel "+r.id+"`."});const f=K(l.readFileSync(g,"utf8"),i.html,i.js,v=>E(d,n.settings,g,v));if(f.errors.length)throw new S(f.errors.join(`
6
+ `));if(c.push.apply(c,f.warnings),!l.existsSync(P(d,i.js)))throw new S("Missing "+i.js+".",{hint:"It starts the panel with AP.boot({ start })."});const m=await D(d,i.js,n.settings),b=N(e,n,r,t,s.version),j=s.files.css.length?x(s.files.css)+`
7
+ `:"",h=t.dev?2:0,p=u.join(o,"panels",r.id);return l.mkdirSync(p,{recursive:!0}),l.writeFileSync(u.join(p,"index.html"),f.shell),l.writeFileSync(u.join(p,"main.js"),["/* Built by the AfterPresets CLI. Edit the source files, not this bundle. */","var AP_CONFIG = "+JSON.stringify(b,null,h)+";","var AP_JSX = "+Y(a)+";","/* ---- styles (imported by "+i.js+") ---- */",_(j+m.css+`
8
+ `),"/* ---- markup ("+i.html+") ---- */",M(f.body),"/* ---- @afterpresets/runtime ---- */",x(s.files.js),";","/* ---- developer code ("+i.js+" and its imports) ---- */",m.js,t.liveReload?C(t.buildId):"",""].join(`
9
+ `)),{inputs:m.inputs,publicKey:b.publicKey}}function X(e){return"{ type: "+y(e.type)+", code: "+y(e.code)+" }"}function Y(e){return"{ "+Object.keys(e.hosts).map(n=>y(n)+": "+X(e.hosts[n])).join(", ")+" }"}function G(e,n,r,s,a){const t=k(e.root,n.files.jsx,a);if(r.dev)return{type:"jsx",code:t.source,files:t.files};const c=(r.compileJsx||require("./jsxbin").compileJsxbin)(t.source,{fileName:u.join(s,"jsx","main.jsx"),lineMap:t.lineMap});return{type:"jsxbin",code:String(c).trim(),files:t.files}}function H(e,n,r,s){const a={},t=[];return J(e.settings).filter(o=>o.platform==="cep").forEach(o=>{const c=G(e,n,r,s,o.jsxDir);a[o.host]={type:c.type,code:c.code},c.files.forEach(d=>t.indexOf(d)===-1&&t.push(d))}),{hosts:a,files:t.sort()}}async function T(e,n,r){const s=!!r.dev,a=r.version||n.version,t=s?Date.now().toString(36)+"-"+Math.random().toString(36).slice(2,8):null,o=Object.assign({},r,{dev:s,version:a,buildId:t,liveReload:s&&r.liveReload!==!1}),c=[],d=A(e,n.root),i=r.outDir;L(i);const g=H(n,d,o,i),f={};let m=!1;for(const p of n.panels){const v=await U(e,n,p,d,g,o,i,c);f[p.id]={inputs:v.inputs},v.publicKey||(m=!0)}m&&c.push("No signing public key is set; update signature checks cannot run in this dev build.");const b=g.files;l.mkdirSync(u.join(i,"CSXS"),{recursive:!0}),l.writeFileSync(u.join(i,"CSXS","manifest.xml"),F(n.settings,n.panels,a));const j=B(n.root,i,n.settings),h=R(n.panels,w.projectDebugPort(n.settings));return s&&l.writeFileSync(u.join(i,".debug"),O(h,n.settings.hosts.map(p=>p.app))),o.liveReload&&l.writeFileSync(u.join(i,".ap-dev-build"),t),{outDir:i,version:a,runtimeVersion:d.version,warnings:c,debugPorts:h,files:{panels:f,jsx:b,assets:j}}}function V(e){return u.join(e.root,"dist",e.settings.bundleId)}function $(e){return u.join(e.root,"dist-dev",e.settings.bundleId)}module.exports={buildProject:T,productionOutDir:V,devOutDir:$,panelSources:q,SRC_DIR:I,__liveReloadClient:C};
package/src/build/html.js CHANGED
@@ -1,4 +1,4 @@
1
- "use strict";const m={js:"main.js",css:"main.css"},b={js:["main.js","js/main.js"],css:["main.css","css/main.css"]},g=/(\b(?:src|href)\s*=\s*)(["'])([^"']+)\2/gi;function j(t){return!/^(?:[a-z][a-z0-9+.-]*:|\/\/|#)/i.test(t)}function x(t){const s=t.replace(/[?#].*$/,"").replace(/^\.\//,"");return b.js.indexOf(s)!==-1?"js":b.css.indexOf(s)!==-1?"css":/\.(?:js|css)$/i.test(s)?"other":null}const C=/<script\b[^>]*>[\s\S]*?<\/script\s*>/gi,y=/<link\b[^>]*\bhref\s*=\s*(["'])(?:\.\/)?(?:css\/)?main\.css(?:[?#][^"']*)?\1[^>]*>\s*/gi;function I(t){return t.replace(/<!--[\s\S]*?-->/g,"")}function S(t){const s=I(t),r=/<html\b([^>]*)>/i.exec(s),i=/<head\b[^>]*>([\s\S]*?)<\/head\s*>/i.exec(s),e=/<body\b([^>]*)>([\s\S]*?)<\/body\s*>/i.exec(s),h=(i?i[1]:"").replace(y,"").trim();let o=0;const a=[],d=(e?e[2]:s.replace(/<head\b[\s\S]*?<\/head\s*>/i,"").replace(/<\/?(?:html|body|!doctype)[^>]*>/gi,"")).replace(y,"").replace(C,n=>{const c=/\bsrc\s*=\s*(["'])([^"']+)\1/i.exec(n);return c?j(c[2])||a.push(n.trim()):o++,""}).replace(/\n\s*\n/g,`
1
+ "use strict";const m={js:"main.js",css:"main.css"},b={js:["main.js"],css:["main.css"]},g=/(\b(?:src|href)\s*=\s*)(["'])([^"']+)\2/gi;function j(t){return!/^(?:[a-z][a-z0-9+.-]*:|\/\/|#)/i.test(t)}function x(t){const s=t.replace(/[?#].*$/,"").replace(/^\.\//,"");return b.js.indexOf(s)!==-1?"js":b.css.indexOf(s)!==-1?"css":/\.(?:js|css)$/i.test(s)?"other":null}const C=/<script\b[^>]*>[\s\S]*?<\/script\s*>/gi,y=/<link\b[^>]*\bhref\s*=\s*(["'])(?:\.\/)?(?:css\/)?main\.css(?:[?#][^"']*)?\1[^>]*>\s*/gi;function I(t){return t.replace(/<!--[\s\S]*?-->/g,"")}function S(t){const s=I(t),r=/<html\b([^>]*)>/i.exec(s),i=/<head\b[^>]*>([\s\S]*?)<\/head\s*>/i.exec(s),e=/<body\b([^>]*)>([\s\S]*?)<\/body\s*>/i.exec(s),h=(i?i[1]:"").replace(y,"").trim();let o=0;const a=[],d=(e?e[2]:s.replace(/<head\b[\s\S]*?<\/head\s*>/i,"").replace(/<\/?(?:html|body|!doctype)[^>]*>/gi,"")).replace(y,"").replace(C,n=>{const c=/\bsrc\s*=\s*(["'])([^"']+)\1/i.exec(n);return c?j(c[2])||a.push(n.trim()):o++,""}).replace(/\n\s*\n/g,`
2
2
  `).trim();return{shell:["<!doctype html>","<html"+(r?r[1]:' lang="en"')+">","<head>",h?" "+h.replace(/\n\s*/g,`
3
3
  `):' <meta charset="utf-8" />',"</head>","<body"+(e?e[1]:"")+">"].concat(a.map(n=>" "+n)).concat([' <script src="'+m.js+'"></script>',"</body>","</html>",""]).join(`
4
4
  `),body:d,inlineScripts:o}}function L(t,s,r,i){const e=[],h=[],o={js:!1,css:!1},a=t.replace(g,(d,u,n,c)=>{if(!j(c))return d;const l=x(c);if(l==="js"||l==="css")return o[l]=!0,u+n+m[l]+n;if(l==="other")e.push(s+" references "+c+", which is not in the bundle. Import it from "+r+" instead.");else if(i){const f=i(c);if(f.error)e.push(f.error);else return u+n+f.url+n}return d});o.js||e.push(s+' must load the bundle with <script src="main.js"></script>.');const p=S(a);return p.inlineScripts&&e.push(s+" has an inline <script> in <body>. Move that code into "+r+"."),{html:a,shell:p.shell,body:p.body,errors:e,warnings:h}}module.exports={processIndexHtml:L,splitIndexHtml:S,BUILT:m};
package/src/build/jsx.js CHANGED
@@ -1,3 +1,3 @@
1
- "use strict";const o=require("fs"),i=require("path"),a="jsx";function f(e){if(!o.existsSync(e))return[];const n=[];return o.readdirSync(e,{withFileTypes:!0}).forEach(t=>{const r=i.join(e,t.name);t.isDirectory()?n.push.apply(n,f(r)):t.isFile()&&n.push(r)}),n}function y(e){return e.split(i.sep).join("/")}function l(e){return f(i.join(e,a)).map(n=>y(i.relative(e,n))).sort()}function p(e){return l(e).filter(n=>n.toLowerCase().endsWith(".jsx"))}function F(e,n){const t=[],r=[],c=(s,h)=>{h.replace(/^/,"").split(/\r?\n/).forEach((j,x)=>{t.push(j),r.push({file:s,line:x+1})})};n.forEach(s=>c("@afterpresets/runtime/"+i.basename(s),o.readFileSync(s,"utf8")));const u=p(e);return u.forEach(s=>c(s,o.readFileSync(i.join(e,s),"utf8"))),{source:t.join(`
1
+ "use strict";const u=require("fs"),i=require("path"),{TARGETS:D}=require("../targets"),f="jsx",a=D.filter(n=>n.jsxDir).map(n=>n.jsxDir);function p(n){if(!u.existsSync(n))return[];const e=[];return u.readdirSync(n,{withFileTypes:!0}).forEach(t=>{const s=i.join(n,t.name);t.isDirectory()?e.push.apply(e,p(s)):t.isFile()&&e.push(s)}),e}function F(n){return n.split(i.sep).join("/")}function h(n){return p(i.join(n,f)).map(e=>F(i.relative(n,e))).sort()}function j(n){const e=n.split("/");return e.length>2&&a.indexOf(e[1])!==-1?e[1]:null}function x(n,e){return h(n).filter(t=>{if(!t.toLowerCase().endsWith(".jsx"))return!1;if(e===void 0)return!0;const s=j(t);return s===null||s===e})}function m(n,e,t){const s=[],o=[],c=(r,S)=>{S.replace(/^/,"").split(/\r?\n/).forEach((d,y)=>{s.push(d),o.push({file:r,line:y+1})})};e.forEach(r=>c("@afterpresets/runtime/"+i.basename(r),u.readFileSync(r,"utf8")));const l=x(n,t);return l.forEach(r=>c(r,u.readFileSync(i.join(n,r),"utf8"))),{source:s.join(`
2
2
  `)+`
3
- `,files:u,lineMap:r}}module.exports={JSX_DIR:a,jsxFiles:p,jsxDirFiles:l,concatJsx:F};
3
+ `,files:l,lineMap:o}}module.exports={JSX_DIR:f,HOST_JSX_DIRS:a,hostDirOf:j,jsxFiles:x,jsxDirFiles:h,concatJsx:m};
@@ -1,4 +1,4 @@
1
- "use strict";const r=require("fs"),e=require("path"),{CliError:o}=require("../errors");function h(s){try{return e.dirname(require.resolve("@afterpresets/runtime/package.json",{paths:[s]}))}catch{return null}}const j=e.join(__dirname,"..","..","runtime");function d(s,n){return s.runtimeDir?s.runtimeDir:r.existsSync(e.join(j,"runtime-files.json"))?j:n&&h(n)||h(__dirname)}function w(s,n){const i=d(s,n);if(!i)throw new o("The AfterPresets runtime was not found.",{hint:"Run `npm install` in the project, or `ap upgrade`."});const f=JSON.parse(r.readFileSync(e.join(i,"package.json"),"utf8")),p=e.join(i,"runtime-files.json");if(!r.existsSync(p))throw new o("@afterpresets/runtime "+f.version+" has no runtime-files.json at "+i+".",{hint:"Reinstall the CLI with `ap upgrade`."});const t=JSON.parse(r.readFileSync(p,"utf8")),m=Array.isArray(t)?t:t&&Array.isArray(t.files)?t.files:null;if(!m)throw new o("runtime-files.json must be an array of file paths.");const a={js:[],css:[],jsx:[]};return m.forEach(u=>{const c=e.resolve(i,u);if(!r.existsSync(c))throw new o("Runtime file listed in runtime-files.json is missing: "+u);const l=e.extname(u).toLowerCase();if(l===".js")a.js.push(c);else if(l===".css")a.css.push(c);else if(l===".jsx")a.jsx.push(c);else throw new o("runtime-files.json lists an unsupported file type: "+u)}),{dir:i,version:f.version,files:a,docsDir:e.join(i,"docs")}}function y(s){return s.map(n=>"/* "+e.basename(n)+` */
2
- `+r.readFileSync(n,"utf8").replace(/^/,"")).join(`
1
+ "use strict";const i=require("fs"),e=require("path"),{CliError:o}=require("../errors");function d(s){try{return e.dirname(require.resolve("@afterpresets/runtime/package.json",{paths:[s]}))}catch{return null}}const j=e.join(__dirname,"..","..","runtime");function h(s,r){return s.runtimeDir?s.runtimeDir:i.existsSync(e.join(j,"runtime-files.json"))?j:d(__dirname)}function w(s,r){const n=h(s,r);if(!n)throw new o("The AfterPresets runtime was not found.",{hint:"Run `npm install` in the project, or `ap upgrade`."});const f=JSON.parse(i.readFileSync(e.join(n,"package.json"),"utf8")),p=e.join(n,"runtime-files.json");if(!i.existsSync(p))throw new o("@afterpresets/runtime "+f.version+" has no runtime-files.json at "+n+".",{hint:"Reinstall the CLI with `ap upgrade`."});const t=JSON.parse(i.readFileSync(p,"utf8")),m=Array.isArray(t)?t:t&&Array.isArray(t.files)?t.files:null;if(!m)throw new o("runtime-files.json must be an array of file paths.");const a={js:[],css:[],jsx:[]};return m.forEach(u=>{const c=e.resolve(n,u);if(!i.existsSync(c))throw new o("Runtime file listed in runtime-files.json is missing: "+u);const l=e.extname(u).toLowerCase();if(l===".js")a.js.push(c);else if(l===".css")a.css.push(c);else if(l===".jsx")a.jsx.push(c);else throw new o("runtime-files.json lists an unsupported file type: "+u)}),{dir:n,version:f.version,files:a,docsDir:e.join(n,"docs")}}function y(s){return s.map(r=>"/* "+e.basename(r)+` */
2
+ `+i.readFileSync(r,"utf8").replace(/^/,"")).join(`
3
3
  ;
4
- `)}module.exports={findRuntimeDir:d,loadRuntime:w,concatFiles:y};
4
+ `)}module.exports={findRuntimeDir:h,loadRuntime:w,concatFiles:y};