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.
- package/package.json +2 -2
- package/runtime/docs/cep/host-after-effects.md +57 -0
- package/runtime/docs/cep/host-premiere.md +84 -0
- package/runtime/docs/{host.md → cep/host.md} +34 -16
- package/runtime/docs/{README.md → common/README.md} +9 -7
- package/runtime/docs/{assets.md → common/assets.md} +16 -2
- package/runtime/docs/{licensing.md → common/licensing.md} +1 -1
- package/runtime/docs/{panels.md → common/panels.md} +5 -5
- package/runtime/docs/{storage.md → common/storage.md} +5 -5
- package/runtime/docs/{updates.md → common/updates.md} +1 -1
- package/runtime/package.json +1 -1
- package/runtime/src/host.js +1 -1
- package/runtime/src/updates.js +1 -1
- package/src/build/build.js +7 -7
- package/src/build/html.js +1 -1
- package/src/build/jsx.js +2 -2
- package/src/build/runtime.js +3 -3
- package/src/check/check.js +3 -3
- package/src/check/types.js +2 -2
- package/src/cli.js +5 -5
- package/src/commands/add.js +8 -3
- package/src/commands/check.js +3 -3
- package/src/commands/dev.js +2 -2
- package/src/commands/docs.js +1 -1
- package/src/commands/init.js +12 -3
- package/src/config.js +1 -1
- package/src/dev/cep-link.js +1 -1
- package/src/dev/debug-file.js +5 -5
- package/src/mcp/extendscript.js +9 -7
- package/src/mcp/panels.js +1 -1
- package/src/mcp/server.js +2 -2
- package/src/mcp/tools/host.js +1 -1
- package/src/mcp/tools/panel.js +4 -4
- package/src/mcp/tools/project.js +15 -15
- package/src/project/add-panel.js +1 -1
- package/src/project/docs.js +3 -1
- package/src/project/manifest.js +3 -2
- package/src/project/project.js +2 -2
- package/src/project/template.js +4 -1
- package/src/prompt.js +1 -1
- package/src/release/installers.js +4 -4
- package/src/release/package.js +1 -1
- package/src/release/publish.js +1 -1
- package/src/targets.js +1 -0
- package/src/user-config.js +2 -2
- package/template/{AGENTS.md → cep/AGENTS.md} +23 -22
- package/template/{README.md → cep/README.md} +9 -9
- package/template/{docs → cep/docs}/initial_setup.md +4 -4
- package/template/{src → cep/src}/features/home/home.html +4 -4
- package/template/{src → cep/src}/features/home/home.js +10 -11
- package/template/{src → cep/src}/shared/lib/host-theme.js +3 -3
- package/template/{src → cep/src}/shared/lib/view.js +1 -1
- package/template/{src → cep/src}/shared/ui/tokens.css +1 -1
- package/template/hosts/aeft/AGENTS.host.md +10 -0
- package/template/hosts/aeft/jsx/aeft/home.jsx +16 -0
- package/template/hosts/ppro/AGENTS.host.md +15 -0
- package/template/hosts/ppro/jsx/ppro/home.jsx +20 -0
- package/vendor/afterpresets-additions/AfterEffects.d.ts +291 -0
- package/vendor/afterpresets-additions/Premiere.d.ts +179 -0
- package/vendor/types-for-adobe/Premiere/24.0/index.d.ts +2567 -0
- package/vendor/types-for-adobe/README.md +8 -4
- package/template/jsx/home.jsx +0 -17
- /package/runtime/docs/{boot.md → common/boot.md} +0 -0
- /package/template/{.mcp.json → cep/.mcp.json} +0 -0
- /package/template/{gitignore → cep/gitignore} +0 -0
- /package/template/{package.json → cep/package.json} +0 -0
- /package/template/{src → cep/src}/features/home/home.css +0 -0
- /package/template/{src → cep/src}/features/license-screen/license-screen.css +0 -0
- /package/template/{src → cep/src}/features/license-screen/license-screen.html +0 -0
- /package/template/{src → cep/src}/features/license-screen/license-screen.js +0 -0
- /package/template/{src → cep/src}/features/update-screen/update-screen.css +0 -0
- /package/template/{src → cep/src}/features/update-screen/update-screen.html +0 -0
- /package/template/{src → cep/src}/features/update-screen/update-screen.js +0 -0
- /package/template/{src → cep/src}/panels/main/index.html +0 -0
- /package/template/{src → cep/src}/panels/main/main.js +0 -0
- /package/template/{src → cep/src}/shared/lib/dom.js +0 -0
- /package/template/{src → cep/src}/shared/lib/markdown.js +0 -0
- /package/template/{src → cep/src}/shared/ui/base.css +0 -0
- /package/template/{src → cep/src}/shared/ui/button.css +0 -0
- /package/template/{src → cep/src}/shared/ui/card.css +0 -0
- /package/template/{src → cep/src}/shared/ui/field.css +0 -0
- /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.
|
|
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.
|
|
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
|
|
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
|
|
6
|
+
# Calling the app (ExtendScript)
|
|
7
7
|
|
|
8
|
-
Panel code runs in a browser. Anything that touches
|
|
9
|
-
|
|
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
|
-
|
|
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.
|
|
42
|
-
|
|
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
|
|
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,
|
|
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
|
|
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
|
|
110
|
-
changes
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
16
|
-
| `modal` | A dialog that blocks
|
|
17
|
-
| `invisible` | No window; starts with
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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` |
|
|
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
|
package/runtime/package.json
CHANGED
package/runtime/src/host.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
(function(
|
|
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);
|
package/runtime/src/updates.js
CHANGED
|
@@ -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,
|
|
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);
|
package/src/build/build.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
"use strict";const
|
|
2
|
-
`):""}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,
|
|
6
|
-
`));if(
|
|
7
|
-
`:"",
|
|
8
|
-
`),"/* ---- markup ("+i.html+") ---- */",
|
|
9
|
-
`)),{inputs:
|
|
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"
|
|
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
|
|
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:
|
|
3
|
+
`,files:l,lineMap:o}}module.exports={JSX_DIR:f,HOST_JSX_DIRS:a,hostDirOf:j,jsxFiles:x,jsxDirFiles:h,concatJsx:m};
|
package/src/build/runtime.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";const
|
|
2
|
-
`+
|
|
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:
|
|
4
|
+
`)}module.exports={findRuntimeDir:h,loadRuntime:w,concatFiles:y};
|