├── .env.production
├── .github
└── workflows
│ └── main.yml
├── .gitignore
├── .npmrc
├── .prettierrc
├── .vscode
└── settings.json
├── LICENSE
├── README.md
├── cep.config.ts
├── create-bolt-cep
├── .gitattributes
├── .gitignore
├── .vscode
│ └── settings.json
├── LICENSE
├── README.md
├── package.json
├── src
│ └── index.ts
├── tsconfig.json
└── yarn.lock
├── package.json
├── package.react.jsonc
├── package.svelte.jsonc
├── package.vue.jsonc
├── src
├── js
│ ├── assets
│ │ ├── adobe.svg
│ │ ├── bolt-cep-react.png
│ │ ├── bolt-cep-vue.png
│ │ ├── bolt-cep.svg
│ │ ├── built-with-bolt-cep.png
│ │ ├── built-with-bolt-cep
│ │ │ ├── Built_With_BOLT_CEP_Logo_Black_V01.png
│ │ │ ├── Built_With_BOLT_CEP_Logo_Black_V01.svg
│ │ │ ├── Built_With_BOLT_CEP_Logo_White_V01.png
│ │ │ └── Built_With_BOLT_CEP_Logo_White_V01.svg
│ │ ├── create-bolt-cep--demo.gif
│ │ ├── node-js.svg
│ │ ├── react.svg
│ │ ├── sass.svg
│ │ ├── svelte.svg
│ │ ├── typescript.svg
│ │ ├── vite.svg
│ │ └── vue.svg
│ ├── favicon.svg
│ ├── global.d.ts
│ ├── index.scss
│ ├── lib
│ │ ├── cep
│ │ │ ├── .gitattributes
│ │ │ ├── cep-types.d.ts
│ │ │ ├── cep_engine_extensions.js
│ │ │ ├── csinterface.d.ts
│ │ │ ├── csinterface.js
│ │ │ ├── es-types
│ │ │ │ └── index.ts
│ │ │ ├── node.ts
│ │ │ ├── vulcan.d.ts
│ │ │ └── vulcan.js
│ │ └── utils
│ │ │ ├── aeft.ts
│ │ │ ├── bolt.ts
│ │ │ ├── cep.ts
│ │ │ ├── init-cep.ts
│ │ │ └── ppro.ts
│ ├── main
│ │ ├── env.d.ts
│ │ ├── index-react.tsx
│ │ ├── index-svelte.ts
│ │ ├── index-vue.ts
│ │ ├── index.html
│ │ ├── main.scss
│ │ ├── main.svelte
│ │ ├── main.tsx
│ │ ├── main.vue
│ │ └── vite-env.d.ts
│ ├── variables.scss
│ └── vite-env.d.ts
├── jsx
│ ├── aeft
│ │ ├── aeft-utils.ts
│ │ ├── aeft.ts
│ │ └── tsconfig.json
│ ├── ame
│ │ ├── ame.ts
│ │ └── tsconfig.json
│ ├── anim
│ │ ├── anim.ts
│ │ └── tsconfig.json
│ ├── audt
│ │ ├── audt.ts
│ │ └── tsconfig.json
│ ├── global.d.ts
│ ├── idsn
│ │ ├── idsn.ts
│ │ └── tsconfig.json
│ ├── ilst
│ │ ├── ilst.ts
│ │ └── tsconfig.json
│ ├── index.ts
│ ├── kbrg
│ │ ├── kbrg.ts
│ │ └── tsconfig.json
│ ├── lib
│ │ ├── .gitattributes
│ │ └── json2.js
│ ├── phxs
│ │ ├── phxs-utils.ts
│ │ ├── phxs.ts
│ │ └── tsconfig.json
│ ├── ppro
│ │ ├── ppro-utils.ts
│ │ ├── ppro.ts
│ │ └── tsconfig.json
│ ├── tsconfig.json
│ └── utils
│ │ ├── samples.ts
│ │ └── utils.ts
└── shared
│ ├── shared.ts
│ └── universals.d.ts
├── tsconfig-build.json
├── tsconfig.json
├── tsconfig.react.json
├── tsconfig.svelte.json
├── tsconfig.vue.json
├── vite-cep-plugin
├── .gitignore
├── LICENSE
├── README.md
├── package.json
├── scripts
│ ├── copy-files.js
│ └── copy-files.ts
├── src
│ ├── bin
│ │ ├── ZXPSignCmd
│ │ └── ZXPSignCmd.exe
│ ├── cep-config.ts
│ ├── copy-node.ts
│ ├── index.ts
│ ├── lib
│ │ ├── lib.ts
│ │ ├── node-built-ins.ts
│ │ ├── require-js.js
│ │ └── zxp.ts
│ └── templates
│ │ ├── debug-template.ts
│ │ ├── dev-html-template.ts
│ │ ├── extension-template.ts
│ │ ├── manifest-template.ts
│ │ └── menu-html-template.ts
├── tsconfig.json
└── yarn.lock
├── vite.config.ts
├── vite.es.config.ts
└── yarn.lock
/.env.production:
--------------------------------------------------------------------------------
1 | NODE_ENV=production
--------------------------------------------------------------------------------
/.github/workflows/main.yml:
--------------------------------------------------------------------------------
1 | name: ZXP Release
2 |
3 | on:
4 | push:
5 | tags:
6 | - "*.*.*"
7 |
8 | permissions:
9 | contents: write
10 |
11 | jobs:
12 | build:
13 | runs-on: windows-latest
14 |
15 | strategy:
16 | matrix:
17 | node-version: [18.x]
18 | steps:
19 | - uses: actions/checkout@v2
20 | - name: Use Node.js ${{ matrix.node-version }}
21 | uses: actions/setup-node@v2
22 | with:
23 | node-version: ${{ matrix.node-version }}
24 | - run: npm i --legacy-peer-deps
25 | - run: npm run zxp
26 |
27 | - name: GitHub Release
28 | uses: softprops/action-gh-release@v1
29 | if: startsWith(github.ref, 'refs/tags/')
30 | env:
31 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
32 | SOURCE_NAME: ${{ steps.extract_names.outputs.SOURCE_NAME }}
33 | SOURCE_BRANCH: ${{ steps.extract_names.outputs.SOURCE_BRANCH }}
34 | SOURCE_TAG: ${{ steps.extract_names.outputs.SOURCE_TAG }}
35 | with:
36 | files: "./dist/zxp/*"
37 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .DS_Store
3 | dist
4 | dist-ssr
5 | *.local
6 | dist
7 | yarn-error.log
8 | .media
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
1 | legacy-peer-deps=true
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "overrides": [
3 | {
4 | "files": [
5 | "*.jsonc",
6 | "devcontainer.json",
7 | "jsconfig.json",
8 | "language-configuration.json",
9 | "tsconfig.json"
10 | ],
11 | "options": {
12 | "trailingComma": "none"
13 | }
14 | }
15 | ]
16 | }
17 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "prettier.tabWidth": 2,
3 | "prettier.useTabs": false,
4 | "prettier.printWidth": 80
5 | }
6 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) Hyper Brew LLC
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | A lightning-fast boilerplate for building Adobe CEP Extensions in React, Vue, or Svelte built on Vite + TypeScript + Sass
4 |
5 | 
6 | [](https://github.com/hyperbrew/bolt-cep/blob/master/LICENSE)
7 | [](https://discord.gg/PC3EvvuRbc)
8 |
9 | ## Features
10 |
11 | - Lightning Fast Hot Module Replacement (HMR)
12 | - Write Modern ES6 in both the JavaScript and ExtendScript layers
13 | - Type-safe ExtendScript with Types-for-Adobe
14 | - End-to-End Type Safety with evalTS()
15 | - Easily configure in cep.config.ts
16 | - Setup for single or multi-panel extensions
17 | - Comes with multi-host-app configuration
18 | - Optimized Build Size
19 | - Easy Publish to ZXP for Distribution
20 | - Easy Package to ZIP archive with sidecar assets
21 | - GitHub Actions ready-to-go for ZXP Releases
22 |
23 | _Full Blog Post:_ https://hyperbrew.co/blog/bolt-cep-build-extensions-faster/
24 |
25 | ### Compatibility
26 |
27 | - [Adobe CC Apps](https://www.adobe.com/creativecloud/desktop-app.html) version 2022 or later
28 | - Windows & Mac Intel
29 | - Mac Arm64 (M1-M4) require special setup ([more details](#misc-troubleshooting))
30 |
31 | ---
32 |
33 | ## Backers
34 |
35 | Huge thanks to our backers who have made this project possible!
36 |
37 |
38 |
39 |
40 | If you're interested in supporting this open-source project, please [contact the Hyper Brew team](https://hyperbrew.co/contact/).
41 |
42 | ---
43 |
44 | ## Tools Built with Bolt CEP
45 |
46 | Tools like Rubberhose 3, Klutz GPT, Brevity, and more are powered by Bolt CEP! Check out the full library of tools built with Bolt CEP:
47 |
48 | [Built with Bolt CEP](https://hyperbrew.co/resources/bolt-cep/)
49 |
50 |
51 |
52 | ---
53 |
54 | ## Support
55 |
56 | ### Free Support 🙌
57 |
58 | If you have questions with getting started using Bolt CEP, feel free to ask and discuss in our free Discord community [Discord Community](https://discord.gg/PC3EvvuRbc).
59 |
60 | ### Paid Priority Support 🥇
61 |
62 | If your team is interested in paid consulting or development with Bolt CEP, please [contact the Hyper Brew team](https://hyperbrew.co/contact/). More info on our [Adobe Plugin Development & Consulting Services](https://hyperbrew.co/landings/boost-development)
63 |
64 | ---
65 |
66 | ## Can I use Bolt CEP in my free or commercial project?
67 |
68 | Yes! Bolt CEP is **100% free and open source**, being released under the MIT license with no attribution required. This means you are free to use it in your free or commercial projects.
69 |
70 | We would greatly appreciate it if you could provide a link back to this tool's info page in your product's site or about page:
71 |
72 | Bolt CEP Info Page Link: https://hyperbrew.co/resources/bolt-cep
73 |
74 | **Built with Bolt CEP** button graphics:
75 |
76 | **PNG Files**
77 |
78 |
86 |
87 | **SVG Files**
88 |
89 |
96 |
97 | ## Prerequisites
98 |
99 | - [Node.js 18](https://nodejs.org/en/) or later
100 | - Package manager either
101 | - NPM (comes with Node.js)
102 | - [Yarn](https://classic.yarnpkg.com/lang/en/docs/install/) ( ensure by running `yarn set version classic` )
103 | - [PNPM](https://pnpm.io/installation) ( ensure by running `pnpm --version` )
104 |
105 | ## Quick Start
106 |
107 |
108 |
109 | Create your new Bolt CEP project (follow CLI prompts)
110 |
111 | - yarn - `yarn create bolt-cep`
112 | - npm - `npx create-bolt-cep`
113 | - pnpm - `pnpm create-bolt-cep`
114 |
115 | Change directory to the new project
116 |
117 | - `cd project`
118 |
119 | Install Dependencies (if not already done by create command)
120 |
121 | - yarn - `yarn`
122 | - npm - `npm i`
123 | - pnpm - `pnpm i`
124 |
125 | **⚠️ Enable PlayerDebugMode**
126 |
127 | - Adobe CEP's PlayerDebugMode must be enabled on your machine to test `yarn build` or `yarn dev` builds. Only an installed ZXP with `yarn zxp` will work without PlayerDebugMode enabled.
128 | - Enable this easily with the [aescripts ZXP Installer](https://aescripts.com/learn/zxp-installer/) > Settings > Debug > Enable Debugging
129 | - Or enable manually per OS by following the CEP Cookbook Instructions: [Adobe CEP 12 Cookbook](https://github.com/Adobe-CEP/CEP-Resources/blob/master/CEP_12.x/Documentation/CEP%2012%20HTML%20Extension%20Cookbook.md#debugging-unsigned-extensions)
130 |
131 | Build the extension (must run before `dev`, can also run after for panel to work statically without the process) Symlink is created to extensions folder.
132 |
133 | - yarn `yarn build`
134 | - npm `npm run build`
135 | - pnpm `pnpm build`
136 |
137 | Run the extension in HMR Hot-reload mode for rapid development. Both JS and ExtendScript folders re-build on changes.
138 | Viewable in browser via localhost:3000/panel/ (see [Panel Structure](#cep-panel-structure) to set up multiple panels)
139 |
140 | - yarn `yarn dev`
141 | - npm `npm run dev`
142 | - pnpm `pnpm dev`
143 |
144 | Build & Package the extension as a ZXP for delivery to the `dist/zxp` folder (install with [aescripts ZXP Installer](https://aescripts.com/learn/zxp-installer/) or another ZXP installer)
145 |
146 | - yarn `yarn zxp`
147 | - npm `npm run zxp`
148 | - pnpm `pnpm zxp`
149 |
150 | Bundles your packaged zxp file and specified assets from `copyZipAssets` to a zip archive in the `./zip` folder
151 |
152 | - yarn `yarn zip`
153 | - npm `npm run zip`
154 | - pnpm `pnpm zip`
155 |
156 | ---
157 |
158 | ## Config
159 |
160 | Update your CEP build and package settings in `cep.config.ts` safely typed
161 |
162 | Start building your app per framework in:
163 |
164 | - `src/js/main/main.tsx`
165 | - `src/js/main/main.vue`
166 | - `src/js/main/main.svelte`
167 |
168 | Write ExtendScript code in `src/jsx/main.ts`
169 |
170 | ---
171 |
172 | ## CEP Panel Structure
173 |
174 | Each panel is treated as it's own page, with shared code for efficiency. The Boilerplate currently comes with 2 panels, `main` and `settings`. These are configured in the `cep.config.ts`.
175 |
176 | Each panel can be edited in their respective folders:
177 |
178 | ```
179 | src
180 | └─ js
181 | ├─ main
182 | │ ├─ index.html
183 | | └─ index.tsx
184 | └─ settings
185 | ├─ index.html
186 | └─ index.tsx
187 | ```
188 |
189 | To add panels, add an item to the panels object in `cep.config.ts`, and duplicate the folder structure and adjust as needed.
190 |
191 | ---
192 |
193 | ## ExtendScript
194 |
195 | ExtendScript can be written in ES6 and will be compiled down to a single ES3 file for compatibility.
196 |
197 | JSON 2 is included by default, and any external JS libraries added with the include directive will be bundled as well:
198 |
199 | ```js
200 | // @include './lib/library.js'
201 | ```
202 |
203 | App-specific code is split into modules for type-safe development by the application's name as seen in the `index.ts`.
204 |
205 | ```
206 | aftereffects >> aeft/aeft.ts
207 | illustrator >> ilst/ilst.ts
208 | animate >> anim/anim.ts
209 | ```
210 |
211 | Write your app-specific functions in each of these separate modules, and they will be required per each application.
212 |
213 | To add support for additional host apps:
214 |
215 | - Add additional app module files (aeft.ts, anim.ts, etc).
216 | - Extend the main `switch()` in `scr/jsx/index.ts` with your additional.
217 | - Add the host to your `cep.config.ts` file.
218 |
219 | ---
220 |
221 | ## Calling ExtendScript from CEP JavaScript
222 |
223 | All ExtendScript function are appended to your panel's namespace in the background to avoid namespace clashes when using `evalTS()` and `evalES()`.
224 |
225 | We have now introduced a new and improved end-to-end type-safe way to interact with ExtendScript from CEP using `evalTS()`. This function dynamically infers types from
226 | ExtendScript functions and handles both stringifying and parsing of the results so your developer interaction can be as simple as possible.
227 |
228 | As demonstrated in `main.tsx`, your ExtendScript functions can be called with `evalTS()` by passing the name of the function, followed by the arguments.
229 |
230 | CEP
231 |
232 | ```js
233 | evalTS("myFunc", "test").then((res) => {
234 | console.log(res);
235 | });
236 |
237 | evalTS("myFuncObj", { height: 90, width: 100 }).then((res) => {
238 | console.log(res.x);
239 | console.log(res.y);
240 | });
241 | ```
242 |
243 | ExtendScript
244 |
245 | ```js
246 | export const myFunc = (str: string) => {
247 | return str;
248 | };
249 |
250 | export const myFuncObj = (obj: { height: number, width: number }) => {
251 | return {
252 | y: obj.height,
253 | x: obj.width,
254 | };
255 | };
256 | ```
257 |
258 | For any existing Bolt CEP projects, rest assured that the legacy `evalES()` function remains in place as usual as demonstrated in `main.tsx`.
259 |
260 | ```js
261 | evalES(`helloWorld("${csi.getApplicationID()}")`);
262 | ```
263 |
264 | You will also want to use this function for calling ExtendScript functions in the global scope directly, by passing `true` to the second parameter:
265 |
266 | ```js
267 | evalES(
268 | `alert("Hello from ExtendScript :: " + app.appName + " " + app.version)`,
269 | true,
270 | );
271 | ```
272 |
273 | ---
274 |
275 | ## Calling CEP JavaScript from ExtendScript
276 |
277 | For certain situations such as hooking into event listeners or sending updates during long functions, it makes sense to trigger events from the ExtendScript environment to the JavaScript environment. This can be done with `listenTS()` and `dispatchTS()`.
278 |
279 | Using this method accounts for:
280 |
281 | - Setting up a scoped listener on the JS side for the CSEvent
282 | - Setting up PlugPlug CSEvent event on ExtendScript side
283 | - Ensuring End-to-End Type-Safety for the event
284 |
285 | ### 1. Declare the Event Type in EventTS in shared/universals.ts
286 |
287 | ```js
288 | export type EventTS = {
289 | myCustomEvent: {
290 | oneValue: string,
291 | anotherValue: number,
292 | },
293 | // [... other events]
294 | };
295 | ```
296 |
297 | ### 2. Listen in CEP JavaScript
298 |
299 | ```js
300 | import { listenTS } from "../lib/utils/bolt";
301 |
302 | listenTS("myCustomEvent", (data) => {
303 | console.log("oneValue is", data.oneValue);
304 | console.log("anotherValue is", data.anotherValue);
305 | });
306 | ```
307 |
308 | ### 3. Dispatch in ExtendScript
309 |
310 | ```js
311 | import { dispatchTS } from "../utils/utils";
312 |
313 | dispatchTS("myCustomEvent", { oneValue: "name", anotherValue: 20 });
314 | ```
315 |
316 | Alternatively, `dispatchTS()` can also be used in the same way from the CEP side to trigger events within or between CEP panels, just ensure you're importing the dispatchTS() function from the correct file within the `js` folder.
317 |
318 | ```js
319 | import { dispatchTS } from "../lib/utils/bolt";
320 |
321 | dispatchTS("myCustomEvent", { oneValue: "name", anotherValue: 20 });
322 | ```
323 |
324 | ---
325 |
326 | ## GitHub Actions ZXP Releases
327 |
328 | This repo comes with a configured GitHub Action workflow to build a ZXP and add to the releases each time a git tag is added.
329 |
330 | ```
331 | git tag 1.0.0
332 | git push origin --tags
333 | ```
334 |
335 | Then your new build will be available under GitHub Releases. For more info, see the [YML config](.github\workflows\main.yml)
336 |
337 | ---
338 |
339 | ---
340 |
341 | ## Copy Assets
342 |
343 | If you have assets that you would like copied without being affected by the bundler, you can add the optional `copyAssets:[]` array inside your cep.config.ts to include files or entire folders.
344 |
345 | ```js
346 | copyAssets: ["public", "custom/my.jsx"],
347 | ```
348 |
349 | **Example:**
350 |
351 | Files placed in `src/public` will be copied to `dist/public` with config set to `copyAssets: ["public"]`.
352 |
353 | ---
354 |
355 | ---
356 |
357 | ## Copy Zip Assets
358 |
359 | If you have assets that you would like copied with your zxp into a zip archive for delivery, you can add the optional `copyZipAssets:[]` array inside your cep.config.ts to include files or entire folders. A folder ending in "/\*" will copy the contents without the folder structure into the zip destination.
360 |
361 | ```js
362 | copyZipAssets: ["instructions/*", "icons"],
363 | ```
364 |
365 | ---
366 |
367 | ## Custom Ponyfills
368 |
369 | Unlike Polyfills which modify the global prototype, Ponyfills replace functionality with custom methods. Built-in Ponyfills include:
370 |
371 | - Object.freeze()
372 | - Array.isArray()
373 |
374 | You can add your own Ponyfils by passing them into the `jsxPonyfill()` function in `vite.es.config.ts`:
375 |
376 | ```js
377 | jsxPonyfill([
378 | {
379 | find: "Array.isArray",
380 | replace: "__isArray",
381 | inject: `function __isArray(arr) { try { return arr instanceof Array; } catch (e) { return false; } };`,
382 | },
383 | ]);
384 | ```
385 |
386 | If you have a common Ponyfill you feel should be built-in, create a ticket and we'll look into it.
387 |
388 | ---
389 |
390 | ## ExtendScript Scope
391 |
392 | This boilerplate is flavored for a single JSX object attached to helper object `$` for all your panels to prevent pollution in the global namespace. If you prefer to include your own raw JSX, include it in the Copy Assets object (above), and add the optional scriptPath object to your cep.config.ts file.
393 |
394 | ```js
395 | panels: [
396 | {
397 | name: "main",
398 | scriptPath: "custom/index.jsx",
399 | [...]
400 | },
401 | {
402 | name: "settings",
403 | scriptPath: "custom/settings.jsx",
404 | [...]
405 | },
406 | ],
407 | copyAssets: ["custom"],
408 | ```
409 |
410 | ---
411 |
412 | ## Troubleshooting Modules
413 |
414 | Node.js Built-in modules can be imported from the `src/js/lib/node.ts` file.
415 |
416 | ```js
417 | import { os, path, fs } from "../lib/node";
418 | ```
419 |
420 | To use 3rd party libraries, first attempt to use with the standard import syntax.
421 |
422 | ```js
423 | import { FaBolt } from "react-icons/fa";
424 | ```
425 |
426 | If the import syntax fails (typically with modules that use the Node.js runtime) you can resort to the Node.js `require()` syntax,
427 |
428 | ```js
429 | const unzipper = require("unzipper");
430 | ```
431 |
432 | The build system will detect any non-built-in Node.js modules using `require()` and copy them to the output `node_modules` folder, but if a package is missed, you can add it explicitly to the `installModules:[]` array inside your `cep.config.ts` file.
433 |
434 | ```js
435 | installModules: ["unzipper"],
436 | ```
437 |
438 | Also if they're Node.js-specific modules, it's best to place the requires inside functions so they are only required at runtime and don't break your panel when previewing in the browser.
439 |
440 | ---
441 |
442 | ## A Note on Routers
443 |
444 | If you would like to set up a routing system like react-router, be aware that you'll have to make adjustments for CEP. React Router for instance bases the router path off of `window.location.pathname` which in the browser resolves to the page:
445 |
446 | `/main/index.html`
447 |
448 | yet in CEP context resolves to the full system path:
449 |
450 | `file:///C:/Users/Username/AppData/Roaming/Adobe/CEP/extensions/com.bolt.cep/main/index.html`
451 |
452 | To solve this, you'll need to adjust the router basename for each context, here is one way of accomplishing that with the panel named `main`:
453 |
454 | ```js
455 | const posix = (str: string) => str.replace(/\\/g, "/");
456 |
457 | const cepBasename = window.cep_node
458 | ? `${posix(window.cep_node.global.__dirname)}/`
459 | : "/main/";
460 |
461 | ReactDOM.render(
462 |
463 | [...]
464 | ,
465 | document.getElementById("app")
466 | );
467 | ```
468 |
469 | ## Misc Troubleshooting
470 |
471 | **React Spectrum won't allow certain UI items to be clicked on MacOS**:
472 |
473 | There is an ongoing bug with React Spectrum and other UI libraries on MacOS with clicking elements. To resolve this issue, run the helper function `enableSpectrum()` to resolve this issue on Mac.
474 |
475 | `main.ts`
476 |
477 | ```js
478 | import { initBolt, enableSpectrum } from "../lib/utils/bolt";
479 |
480 | enableSpectrum();
481 | initBolt();
482 | ```
483 |
484 | Additionally, some users have reported that adding the following CEF Flag will resolve the issue as well:
485 |
486 | `cep.config.ts`
487 |
488 | ```js
489 | ...
490 | parameters: [
491 | ...
492 | '--disable-site-isolation-trials'
493 | ],
494 | ...
495 | ```
496 |
497 | **ZXPSignCmd Fails on Mac or Windows**:
498 |
499 | 4/18/2025 ZXPSignCmd broke on Windows across the board and on MacOS for most TSA services. ( [more info](https://community.adobe.com/t5/premiere-pro-bugs/zxpsigncmd-sign-process-is-broken-segmentation-fault/idc-p/15276912#M49107) )
500 |
501 | 4/30/2025 Adobe fixed the issues for Windows and MacOS, and we have included the updated ZXPSignCmd for both OS's in the latest release of `vite-cep-plugin@1.2.9`.
502 |
503 | To use the latest in your existing Bolt CEP project, run `yarn add vite-cep-plugin`, and make sure your `zxp.tsa` settings in `cep.config.ts` match the [latest format](./cep.config.ts).
504 |
505 | **Build Issues on Mac Arm64 Apple Silicon Machines (M1/M2/M3)**
506 |
507 | 5/13/2025 - jsxbin is now natively supported on Apple Silicon machines. More info here: [Setup ExtendScript Dev for Apple Silicon Macs](https://hyperbrew.co/blog/adobe-extendscript-support-for-apple-silicon/)
508 |
509 | **Update a Bolt CEP Project** To update an existing Bolt CEP project to the the latest version, create a new Bolt CEP project with the same framework (React, Vue, Svelte), then compare and update the following files:
510 |
511 | 1. `package.json` - Update all dependencies and scripts ( `vite-cep-plugin` - usually contains the most frequent updates )
512 | 2. `vite.config.ts` - Unless you've modified the vite config yourself, you can just copy the contents of the latest into yours.
513 | 3. `vite.es.config.ts` - Like the previous config, unless you've modified it yourself, you can just copy the contents of the latest into yours.
514 | 4. `cep.config.ts` - Check if any new properties have been added that don't exist in your config.
515 | 5. `src/js/lib` - Update this entire folder.
516 | 6. `src/jsx/index.ts` - Check if any new properties have been added that don't exist in your config.
517 | 7. `src/shared/universals.d.ts` - Check if any new properties have been added that don't exist in your config.
518 |
519 | **ZXPSignCmd Permissions issues on Mac**:
520 |
521 | Previously, you would need to fix the permissions of ZXPSignCmd by running the following command in the terminal, however this is now automated since `vite-cep-plugin@1.1.15`. If you still experience problems other reasons you can manually fix the executable as follows:
522 |
523 | If you're getting permissions errors running ZXPSignCmd on the latest Mac releases, try a fresh clone. If that does't work, reset permissions for ZXPSignCmd by opening the directory `node_modules/vite-cep-plugin/lib/bin` and running `chmod 700 ./ZXPSignCmd`.
524 |
--------------------------------------------------------------------------------
/cep.config.ts:
--------------------------------------------------------------------------------
1 | import { CEP_Config } from "vite-cep-plugin";
2 | import { version } from "./package.json";
3 |
4 | const config: CEP_Config = {
5 | version,
6 | id: "com.bolt.cep", // BOLT_ID_REPLACE
7 | displayName: "Bolt CEP", // BOLT_DISPLAYNAME_REPLACE
8 | symlink: "local",
9 | port: 3000,
10 | servePort: 5000,
11 | startingDebugPort: 8860,
12 | extensionManifestVersion: 6.0,
13 | requiredRuntimeVersion: 9.0,
14 | hosts: [
15 | { name: "AEFT", version: "[0.0,99.9]" }, // BOLT_AEFT_ONLY
16 | { name: "AME", version: "[0.0,99.9]" }, // BOLT_AME_ONLY
17 | { name: "FLPR", version: "[0.0,99.9]" }, // BOLT_ANIM_ONLY
18 | { name: "AUDT", version: "[0.0,99.9]" }, // BOLT_AUDT_ONLY
19 | { name: "IDSN", version: "[0.0,99.9]" }, // BOLT_IDSN_ONLY
20 | { name: "ILST", version: "[0.0,99.9]" }, // BOLT_ILST_ONLY
21 | { name: "KBRG", version: "[0.0,99.9]" }, // BOLT_KBRG_ONLY
22 | { name: "PHXS", version: "[0.0,99.9]" }, // BOLT_PHXS_ONLY
23 | { name: "PPRO", version: "[0.0,99.9]" }, // BOLT_PPRO_ONLY
24 | ],
25 |
26 | type: "Panel",
27 | iconDarkNormal: "./src/assets/light-icon.png",
28 | iconNormal: "./src/assets/dark-icon.png",
29 | iconDarkNormalRollOver: "./src/assets/light-icon.png",
30 | iconNormalRollOver: "./src/assets/dark-icon.png",
31 | parameters: ["--v=0", "--enable-nodejs", "--mixed-context"],
32 | width: 500,
33 | height: 550,
34 |
35 | panels: [
36 | {
37 | mainPath: "./main/index.html",
38 | name: "main",
39 | panelDisplayName: "Bolt CEP", // BOLT_DISPLAYNAME_REPLACE
40 | autoVisible: true,
41 | width: 600,
42 | height: 650,
43 | },
44 | ],
45 | build: {
46 | jsxBin: "off",
47 | sourceMap: true,
48 | },
49 | zxp: {
50 | country: "US",
51 | province: "CA",
52 | org: "Company",
53 | password: "password",
54 | tsa: [
55 | "http://timestamp.digicert.com/", // Windows Only
56 | "http://timestamp.apple.com/ts01", // MacOS Only
57 | ],
58 | allowSkipTSA: false,
59 | sourceMap: false,
60 | jsxBin: "off",
61 | },
62 | installModules: [],
63 | copyAssets: [],
64 | copyZipAssets: [],
65 | };
66 | export default config;
67 |
--------------------------------------------------------------------------------
/create-bolt-cep/.gitattributes:
--------------------------------------------------------------------------------
1 | *.ts linguist-language=TypeScript
--------------------------------------------------------------------------------
/create-bolt-cep/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | dist
3 | test*
4 | .DS_Store
5 | yarn-error.log
6 | .test*
--------------------------------------------------------------------------------
/create-bolt-cep/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "prettier.tabWidth": 2,
3 | "prettier.useTabs": false,
4 | "prettier.printWidth": 80
5 | }
6 |
--------------------------------------------------------------------------------
/create-bolt-cep/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) Hyper Brew LLC
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/create-bolt-cep/README.md:
--------------------------------------------------------------------------------
1 | # Create Bolt CEP
2 |
3 | 
4 | [](https://github.com/hyperbrew/create-bolt-cep/blob/master/LICENSE)
5 | [](https://discord.gg/PC3EvvuRbc)
6 |
7 | Generate a new CEP Extension from the Bolt CEP boilerplate
8 |
9 | https://github.com/hyperbrew/bolt-cep
10 |
11 | Usage Examples:
12 |
13 | `yarn create bolt-cep`
14 |
--------------------------------------------------------------------------------
/create-bolt-cep/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "create-bolt-cep",
3 | "version": "2.0.2",
4 | "license": "MIT",
5 | "bin": {
6 | "create-bolt-cep": "dist/index.js"
7 | },
8 | "files": [
9 | "dist/*"
10 | ],
11 | "main": "dist/index.js",
12 | "engines": {
13 | "node": ">=16.0.0"
14 | },
15 | "scripts": {
16 | "build": "tsc",
17 | "dev": "tsc --watch",
18 | "prepare": "npm run build",
19 | "publish": "npm publish --access public",
20 | "start": "node dist/index.js",
21 | "test": "node scripts/test.js"
22 | },
23 | "repository": {
24 | "type": "git",
25 | "url": "git+https://github.com/hyper-brew/bolt-cep.git",
26 | "directory": "packages/create-vite"
27 | },
28 | "bugs": {
29 | "url": "https://github.com/hyper-brew/bolt-cep/issues"
30 | },
31 | "dependencies": {
32 | "bolt-cep": "^2.0.0",
33 | "meta-bolt": "^0.0.15"
34 | },
35 | "devDependencies": {}
36 | }
37 |
--------------------------------------------------------------------------------
/create-bolt-cep/src/index.ts:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | import { main } from "meta-bolt";
4 | import type { BoltInitData, ArgOpt } from "meta-bolt";
5 |
6 | export const frameworkOptions: ArgOpt[] = [
7 | {
8 | value: "svelte",
9 | label: "Svelte",
10 | files: [
11 | "src/js/main/index-svelte.ts",
12 | "src/js/main/main.svelte",
13 | "src/js/main/vite-env.d.ts",
14 | "package.svelte.jsonc",
15 | "tsconfig.svelte.json",
16 | ],
17 | },
18 | {
19 | value: "react",
20 | label: "React",
21 | files: [
22 | "src/js/main/index-react.tsx",
23 | "src/js/main/main.tsx",
24 | "package.react.jsonc",
25 | "tsconfig.react.json",
26 | ],
27 | },
28 | {
29 | value: "vue",
30 | label: "Vue",
31 | files: [
32 | "src/js/main/index-vue.ts",
33 | "src/js/main/main.vue",
34 | "src/js/main/env.d.ts",
35 | "package.vue.jsonc",
36 | "tsconfig.vue.json",
37 | ],
38 | },
39 | ];
40 |
41 | export const appOptions: ArgOpt[] = [
42 | { value: "aeft", label: "After Effects", files: ["src/jsx/aeft"] },
43 | { value: "ppro", label: "Premiere Pro", files: ["src/jsx/ppro"] },
44 | { value: "phxs", label: "Photoshop", files: ["src/jsx/phxs"] },
45 | { value: "ilst", label: "Illustrator", files: ["src/jsx/ilst"] },
46 | { value: "idsn", label: "InDesign", files: ["src/jsx/idsn"] },
47 | { value: "anim", label: "Animate", files: ["src/jsx/anim"] },
48 | { value: "ame", label: "Media Encoder", files: ["src/jsx/ame"] },
49 | { value: "kbrg", label: "Bridge", files: ["src/jsx/kbrg"] },
50 | { value: "audt", label: "Audition", files: ["src/jsx/audt"] },
51 | ];
52 |
53 | const initData: BoltInitData = {
54 | intro: {
55 | name: "create-bolt-cep",
56 | prettyName: "Bolt CEP",
57 | },
58 | base: {
59 | module: "bolt-cep",
60 | createDirName: __dirname,
61 | globalIncludes: [
62 | "*",
63 | "src/**/*",
64 | ".github/**/*",
65 | ".gitignore",
66 | ".npmrc",
67 | ".prettierrc",
68 | ".env.example",
69 | ],
70 | globalExcludes: [".env", "yarn-error.log", "package.json", "tsconfig.json"],
71 | fileRenames: [
72 | ["package.svelte.jsonc", "package.json"],
73 | ["package.react.jsonc", "package.json"],
74 | ["package.vue.jsonc", "package.json"],
75 |
76 | ["tsconfig.svelte.json", "tsconfig.json"],
77 | ["tsconfig.react.json", "tsconfig.json"],
78 | ["tsconfig.vue.json", "tsconfig.json"],
79 |
80 | [".npmignore", ".gitignore"],
81 | ],
82 | },
83 | argsTemplate: [
84 | {
85 | name: "folder",
86 | type: "folder",
87 | message: "Where do you want to create your project?",
88 | initialValue: "./",
89 | required: true,
90 | validator: (input: string) => {
91 | if (input.length < 3) return `Value is required!`;
92 | },
93 | describe: "Name of the folder for the new Adobe extension ",
94 | },
95 | {
96 | name: "displayName",
97 | type: "string",
98 | message: "Choose a unique Display Name for your extension:",
99 | initialValue: "Bolt CEP",
100 | required: true,
101 | validator: (input: string) => {
102 | if (input.length < 1) return `Value is required!`;
103 | },
104 | describe: "Panel's display name",
105 | alias: "n",
106 | },
107 | {
108 | name: "id",
109 | type: "string",
110 | message: "Choose a unique ID for your extension:",
111 | initialValue: "com.bolt.cep",
112 | required: true,
113 | validator: (input: string) => {
114 | if (input.length < 1) return `Value is required!`;
115 | },
116 | describe: "Unique ID for your extension (e.g. com.bolt.cep)",
117 | alias: "i",
118 | },
119 | {
120 | name: "framework",
121 | type: "select",
122 | message: "Select framework:",
123 | alias: "f",
124 | describe: "Select a Framework for your extension:",
125 | options: frameworkOptions,
126 | required: true,
127 | },
128 | {
129 | name: "apps",
130 | type: "multiselect",
131 | message: "Select app:",
132 | alias: "a",
133 | describe: "Select app(s) for your extension:",
134 | options: appOptions,
135 | validator: (input: string[]) => {
136 | if (input.length < 1) return `At Least One value Required!`;
137 | },
138 | required: true,
139 | },
140 | {
141 | name: "installDeps",
142 | type: "boolean",
143 | message: "Install dependencies?",
144 | initialValue: true,
145 | required: true,
146 | alias: "d",
147 | describe: "Install dependencies (default: false)",
148 | },
149 | {
150 | name: "sampleCode",
151 | type: "boolean",
152 | message: "Keep Sample Code Snippets?",
153 | initialValue: true,
154 | required: true,
155 | alias: "s",
156 | describe: "Keep Sample Code (default: true)",
157 | },
158 | ],
159 | };
160 |
161 | //* if not using as a module, run immediately
162 | console.log("BOLT_MODULEONLY", process.env.BOLT_MODULEONLY);
163 | if (!process.env.BOLT_MODULEONLY) main(initData);
164 |
--------------------------------------------------------------------------------
/create-bolt-cep/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es2021",
4 | "module": "commonjs",
5 | "declaration": true,
6 | "strict": true,
7 | "allowJs": true,
8 | "skipLibCheck": true,
9 | "newLine": "lf",
10 | "outDir": "dist"
11 | },
12 | "files": ["src/index.ts"],
13 | "exclude": ["node_modules"]
14 | }
15 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "bolt-cep",
3 | "version": "2.0.0",
4 | "scripts": {
5 | "dev": "vite",
6 | "watch": "tsc && vite build --watch true",
7 | "build": "rimraf dist/* && tsc -p \"tsconfig-build.json\" && vite build --watch false",
8 | "zxp": "rimraf dist/* && tsc -p \"tsconfig-build.json\" && cross-env ZXP_PACKAGE=true vite build --watch false",
9 | "zip": "rimraf dist/* && tsc -p \"tsconfig-build.json\" && cross-env ZIP_PACKAGE=true vite build --watch false",
10 | "serve": "cross-env SERVE_PANEL=true vite preview",
11 | "symlink": "cross-env BOLT_ACTION=symlink vite",
12 | "delsymlink": "cross-env BOLT_ACTION=delsymlink vite",
13 | "dep": "cross-env BOLT_ACTION=dependencyCheck vite"
14 | },
15 | "dependencies": {
16 | "react": "^18.2.0",
17 | "react-dom": "^18.2.0",
18 | "ts-node": "^10.9.1",
19 | "vue": "^3.2.45"
20 | },
21 | "devDependencies": {
22 | "source-map": "^0.7.4",
23 | "@babel/core": "^7.19.0",
24 | "@babel/plugin-proposal-class-properties": "^7.16.0",
25 | "@babel/plugin-proposal-object-rest-spread": "^7.16.0",
26 | "@babel/plugin-syntax-dynamic-import": "^7.8.3",
27 | "@babel/plugin-transform-runtime": "^7.16.4",
28 | "@babel/preset-env": "^7.19.0",
29 | "@babel/preset-react": "^7.16.0",
30 | "@babel/preset-typescript": "^7.16.0",
31 | "@babel/runtime": "^7.16.3",
32 | "@rollup/plugin-babel": "^5.3.1",
33 | "@rollup/plugin-commonjs": "^21.0.2",
34 | "@rollup/plugin-image": "^2.1.1",
35 | "@rollup/plugin-json": "^4.1.0",
36 | "@rollup/plugin-node-resolve": "^13.1.3",
37 | "@rollup/plugin-replace": "^4.0.0",
38 | "@sveltejs/vite-plugin-svelte": "^1.2.0",
39 | "@tsconfig/svelte": "^3.0.0",
40 | "@types/fs-extra": "^9.0.13",
41 | "@types/node": "^16.11.7",
42 | "@types/react": "^18.0.24",
43 | "@types/react-dom": "^18.0.8",
44 | "@types/trusted-types": "^2.0.2",
45 | "@vitejs/plugin-react": "^3.0.1",
46 | "@vitejs/plugin-vue": "^4.0.0",
47 | "babel-plugin-react-require": "^3.1.3",
48 | "babel-plugin-transform-scss": "^1.1.0",
49 | "babel-preset-env": "^1.7.0",
50 | "core-js": "3",
51 | "cross-env": "^7.0.3",
52 | "fs-extra": "^10.0.0",
53 | "rimraf": "^3.0.2",
54 | "rollup": "^2.79.2",
55 | "rollup-plugin-multi-input": "^1.3.1",
56 | "rollup-plugin-node-copy": "^1.0.4",
57 | "rollup-plugin-scss": "^3.0.0",
58 | "sass": "^1.43.4",
59 | "svelte": "^4.2.19",
60 | "svelte-check": "^2.9.2",
61 | "svelte-preprocess": "^4.10.7",
62 | "types-for-adobe": "^7.2.3",
63 | "types-for-adobe-extras": "^0.0.9",
64 | "typescript": "^4.6.4",
65 | "vite": "^5.4.19",
66 | "vite-cep-plugin": "^2.0.0"
67 | },
68 | "resolutions": {
69 | "typescript": "4.6.4"
70 | },
71 | "main": "index.js",
72 | "license": "MIT",
73 | "files": [
74 | "package.json",
75 | "package.react.jsonc",
76 | "package.svelte.jsonc",
77 | "package.vue.jsonc",
78 | "src/**/*",
79 | ".github/**/*",
80 | ".vscode/**/*",
81 | ".env.production",
82 | "tsconfig.json",
83 | "tsconfig.react.json",
84 | "tsconfig.svelte.json",
85 | "tsconfig.vue.json",
86 | "tsconfig-build.json",
87 | "README.md",
88 | "cep.config.ts",
89 | "vite.config.ts",
90 | "vite.es.config.ts",
91 | "yarn.lock",
92 | ".npmrc",
93 | ".gitignore"
94 | ]
95 | }
96 |
--------------------------------------------------------------------------------
/package.react.jsonc:
--------------------------------------------------------------------------------
1 | {
2 | "name": "bolt-cep", // BOLT_ID_REPLACE
3 | "private": true,
4 | "version": "0.0.1",
5 | "scripts": {
6 | "dev": "vite",
7 | "watch": "tsc && vite build --watch true",
8 | "build": "rimraf dist/* && tsc -p \"tsconfig-build.json\" && vite build --watch false",
9 | "zxp": "rimraf dist/* && tsc -p \"tsconfig-build.json\" && cross-env ZXP_PACKAGE=true vite build --watch false",
10 | "zip": "rimraf dist/* && tsc -p \"tsconfig-build.json\" && cross-env ZIP_PACKAGE=true vite build --watch false",
11 | "serve": "cross-env SERVE_PANEL=true vite preview",
12 | "symlink": "cross-env BOLT_ACTION=symlink vite",
13 | "delsymlink": "cross-env BOLT_ACTION=delsymlink vite"
14 | },
15 | "dependencies": {
16 | "react": "^18.2.0",
17 | "react-dom": "^18.2.0"
18 | },
19 | "devDependencies": {
20 | "source-map": "^0.7.4",
21 | "@babel/core": "^7.19.0",
22 | "@babel/plugin-proposal-class-properties": "^7.16.0",
23 | "@babel/plugin-proposal-object-rest-spread": "^7.16.0",
24 | "@babel/plugin-syntax-dynamic-import": "^7.8.3",
25 | "@babel/plugin-transform-runtime": "^7.16.4",
26 | "@babel/preset-env": "^7.19.0",
27 | "@babel/preset-react": "^7.16.0",
28 | "@babel/preset-typescript": "^7.16.0",
29 | "@babel/runtime": "^7.16.3",
30 | "@rollup/plugin-babel": "^5.3.1",
31 | "@rollup/plugin-commonjs": "^21.0.2",
32 | "@rollup/plugin-image": "^2.1.1",
33 | "@rollup/plugin-json": "^4.1.0",
34 | "@rollup/plugin-node-resolve": "^13.1.3",
35 | "@rollup/plugin-replace": "^4.0.0",
36 | "@types/fs-extra": "^9.0.13",
37 | "@types/node": "^16.11.7",
38 | "@types/react": "^18.0.24",
39 | "@types/react-dom": "^18.0.8",
40 | "@types/trusted-types": "^2.0.2",
41 | "@vitejs/plugin-react": "^3.0.1",
42 | "babel-plugin-react-require": "^3.1.3",
43 | "babel-plugin-transform-scss": "^1.1.0",
44 | "babel-preset-env": "^1.7.0",
45 | "core-js": "3",
46 | "cross-env": "^7.0.3",
47 | "fs-extra": "^10.0.0",
48 | "rimraf": "^3.0.2",
49 | "rollup": "^2.79.2",
50 | "rollup-plugin-multi-input": "^1.3.1",
51 | "rollup-plugin-node-copy": "^1.0.4",
52 | "rollup-plugin-scss": "^3.0.0",
53 | "sass": "^1.43.4",
54 | "types-for-adobe": "^7.2.3",
55 | "types-for-adobe-extras": "^0.0.9",
56 | "typescript": "^4.6.4",
57 | "vite": "^5.4.19",
58 | "vite-cep-plugin": "^2.0.0"
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/package.svelte.jsonc:
--------------------------------------------------------------------------------
1 | {
2 | "name": "bolt-cep", // BOLT_ID_REPLACE
3 | "private": true,
4 | "version": "0.0.1",
5 | "scripts": {
6 | "dev": "vite",
7 | "watch": "tsc && vite build --watch true",
8 | "build": "rimraf dist/* && tsc -p \"tsconfig-build.json\" && vite build --watch false",
9 | "zxp": "rimraf dist/* && tsc -p \"tsconfig-build.json\" && cross-env ZXP_PACKAGE=true vite build --watch false",
10 | "zip": "rimraf dist/* && tsc -p \"tsconfig-build.json\" && cross-env ZIP_PACKAGE=true vite build --watch false",
11 | "serve": "cross-env SERVE_PANEL=true vite preview",
12 | "symlink": "cross-env BOLT_ACTION=symlink vite",
13 | "delsymlink": "cross-env BOLT_ACTION=delsymlink vite"
14 | },
15 | "dependencies": {},
16 | "devDependencies": {
17 | "source-map": "^0.7.4",
18 | "@babel/core": "^7.19.0",
19 | "@babel/plugin-proposal-class-properties": "^7.16.0",
20 | "@babel/plugin-proposal-object-rest-spread": "^7.16.0",
21 | "@babel/plugin-syntax-dynamic-import": "^7.8.3",
22 | "@babel/plugin-transform-runtime": "^7.16.4",
23 | "@babel/preset-env": "^7.19.0",
24 | "@babel/preset-typescript": "^7.16.0",
25 | "@babel/runtime": "^7.16.3",
26 | "@rollup/plugin-babel": "^5.3.1",
27 | "@rollup/plugin-commonjs": "^21.0.2",
28 | "@rollup/plugin-image": "^2.1.1",
29 | "@rollup/plugin-json": "^4.1.0",
30 | "@rollup/plugin-node-resolve": "^13.1.3",
31 | "@rollup/plugin-replace": "^4.0.0",
32 | "@sveltejs/vite-plugin-svelte": "^1.2.0",
33 | "@tsconfig/svelte": "^3.0.0",
34 | "@types/fs-extra": "^9.0.13",
35 | "@types/node": "^16.11.7",
36 | "@types/trusted-types": "^2.0.2",
37 | "babel-plugin-transform-scss": "^1.1.0",
38 | "babel-preset-env": "^1.7.0",
39 | "core-js": "3",
40 | "cross-env": "^7.0.3",
41 | "fs-extra": "^10.0.0",
42 | "rimraf": "^3.0.2",
43 | "rollup": "^2.79.2",
44 | "rollup-plugin-multi-input": "^1.3.1",
45 | "rollup-plugin-node-copy": "^1.0.4",
46 | "rollup-plugin-scss": "^3.0.0",
47 | "sass": "^1.43.4",
48 | "svelte": "^4.2.19",
49 | "svelte-check": "^2.9.2",
50 | "svelte-preprocess": "^4.10.7",
51 | "types-for-adobe": "^7.2.3",
52 | "types-for-adobe-extras": "^0.0.9",
53 | "typescript": "^4.6.4",
54 | "vite": "^5.4.19",
55 | "vite-cep-plugin": "^2.0.0"
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/package.vue.jsonc:
--------------------------------------------------------------------------------
1 | {
2 | "name": "bolt-cep", // BOLT_ID_REPLACE
3 | "private": true,
4 | "version": "0.0.1",
5 | "scripts": {
6 | "dev": "vite",
7 | "watch": "tsc && vite build --watch true",
8 | "build": "rimraf dist/* && tsc -p \"tsconfig-build.json\" && vite build --watch false",
9 | "zxp": "rimraf dist/* && tsc -p \"tsconfig-build.json\" && cross-env ZXP_PACKAGE=true vite build --watch false",
10 | "zip": "rimraf dist/* && tsc -p \"tsconfig-build.json\" && cross-env ZIP_PACKAGE=true vite build --watch false",
11 | "serve": "cross-env SERVE_PANEL=true vite preview",
12 | "symlink": "cross-env BOLT_ACTION=symlink vite",
13 | "delsymlink": "cross-env BOLT_ACTION=delsymlink vite"
14 | },
15 | "dependencies": {
16 | "vue": "^3.2.45"
17 | },
18 | "devDependencies": {
19 | "source-map": "^0.7.4",
20 | "@babel/core": "^7.19.0",
21 | "@babel/plugin-proposal-class-properties": "^7.16.0",
22 | "@babel/plugin-proposal-object-rest-spread": "^7.16.0",
23 | "@babel/plugin-syntax-dynamic-import": "^7.8.3",
24 | "@babel/plugin-transform-runtime": "^7.16.4",
25 | "@babel/preset-env": "^7.19.0",
26 | "@babel/preset-typescript": "^7.16.0",
27 | "@babel/runtime": "^7.16.3",
28 | "@rollup/plugin-babel": "^5.3.1",
29 | "@rollup/plugin-commonjs": "^21.0.2",
30 | "@rollup/plugin-image": "^2.1.1",
31 | "@rollup/plugin-json": "^4.1.0",
32 | "@rollup/plugin-node-resolve": "^13.1.3",
33 | "@rollup/plugin-replace": "^4.0.0",
34 | "@types/fs-extra": "^9.0.13",
35 | "@types/node": "^16.11.7",
36 | "@types/trusted-types": "^2.0.2",
37 | "@vitejs/plugin-vue": "^4.0.0",
38 | "babel-plugin-transform-scss": "^1.1.0",
39 | "babel-preset-env": "^1.7.0",
40 | "core-js": "3",
41 | "cross-env": "^7.0.3",
42 | "fs-extra": "^10.0.0",
43 | "rimraf": "^3.0.2",
44 | "rollup": "^2.79.2",
45 | "rollup-plugin-multi-input": "^1.3.1",
46 | "rollup-plugin-node-copy": "^1.0.4",
47 | "rollup-plugin-scss": "^3.0.0",
48 | "sass": "^1.43.4",
49 | "types-for-adobe": "^7.2.3",
50 | "types-for-adobe-extras": "^0.0.9",
51 | "typescript": "^4.6.4",
52 | "vite": "^5.4.19",
53 | "vite-cep-plugin": "^2.0.0"
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/js/assets/adobe.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/js/assets/bolt-cep-react.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hyperbrew/bolt-cep/e23b2d0408a5962c3041ac0926feed86704f76bb/src/js/assets/bolt-cep-react.png
--------------------------------------------------------------------------------
/src/js/assets/bolt-cep-vue.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hyperbrew/bolt-cep/e23b2d0408a5962c3041ac0926feed86704f76bb/src/js/assets/bolt-cep-vue.png
--------------------------------------------------------------------------------
/src/js/assets/bolt-cep.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
--------------------------------------------------------------------------------
/src/js/assets/built-with-bolt-cep.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hyperbrew/bolt-cep/e23b2d0408a5962c3041ac0926feed86704f76bb/src/js/assets/built-with-bolt-cep.png
--------------------------------------------------------------------------------
/src/js/assets/built-with-bolt-cep/Built_With_BOLT_CEP_Logo_Black_V01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hyperbrew/bolt-cep/e23b2d0408a5962c3041ac0926feed86704f76bb/src/js/assets/built-with-bolt-cep/Built_With_BOLT_CEP_Logo_Black_V01.png
--------------------------------------------------------------------------------
/src/js/assets/built-with-bolt-cep/Built_With_BOLT_CEP_Logo_Black_V01.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
77 |
--------------------------------------------------------------------------------
/src/js/assets/built-with-bolt-cep/Built_With_BOLT_CEP_Logo_White_V01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hyperbrew/bolt-cep/e23b2d0408a5962c3041ac0926feed86704f76bb/src/js/assets/built-with-bolt-cep/Built_With_BOLT_CEP_Logo_White_V01.png
--------------------------------------------------------------------------------
/src/js/assets/built-with-bolt-cep/Built_With_BOLT_CEP_Logo_White_V01.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
79 |
--------------------------------------------------------------------------------
/src/js/assets/create-bolt-cep--demo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hyperbrew/bolt-cep/e23b2d0408a5962c3041ac0926feed86704f76bb/src/js/assets/create-bolt-cep--demo.gif
--------------------------------------------------------------------------------
/src/js/assets/node-js.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/js/assets/react.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
37 |
--------------------------------------------------------------------------------
/src/js/assets/sass.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
46 |
--------------------------------------------------------------------------------
/src/js/assets/svelte.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/src/js/assets/typescript.svg:
--------------------------------------------------------------------------------
1 |
2 |
7 |
--------------------------------------------------------------------------------
/src/js/assets/vite.svg:
--------------------------------------------------------------------------------
1 |
16 |
--------------------------------------------------------------------------------
/src/js/assets/vue.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/src/js/favicon.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/js/global.d.ts:
--------------------------------------------------------------------------------
1 | import { cep_node, cep, __adobe_cep__ } from "./lib/cep-types";
2 |
3 | declare module "*.png";
4 | declare module "*.gif";
5 | declare module "*.jpg";
6 | declare module "*.svg";
7 |
8 | declare global {
9 | interface Window {
10 | cep_node: cep_node;
11 | cep: cep;
12 | __adobe_cep__: __adobe_cep__;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/js/index.scss:
--------------------------------------------------------------------------------
1 | @use "./variables.scss" as *;
2 |
3 | body {
4 | margin: 0;
5 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
6 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
7 | sans-serif;
8 | -webkit-font-smoothing: antialiased;
9 | -moz-osx-font-smoothing: grayscale;
10 | }
11 |
12 | code {
13 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
14 | monospace;
15 | }
16 |
17 | .app {
18 | background-color: #282c34;
19 | text-align: center;
20 | }
21 |
22 | .app-header {
23 | min-height: 100vh;
24 | display: flex;
25 | flex-direction: column;
26 | align-items: center;
27 | justify-content: center;
28 | font-size: 1rem;
29 | color: white;
30 | }
31 |
32 | .app-link {
33 | color: white;
34 | }
35 |
36 | button {
37 | font-size: 0.8rem;
38 | background-color: $darker;
39 | padding: 0.2rem 0.5rem;
40 | text-align: center;
41 | vertical-align: middle;
42 | border-radius: 5px;
43 | color: white;
44 | border: none;
45 | outline: none;
46 | user-select: none;
47 | }
48 |
49 | button:hover {
50 | background-color: $active;
51 | }
52 |
53 | button:active {
54 | background-color: $active;
55 | }
56 |
57 | label {
58 | color: $font;
59 | }
60 |
61 | .button-group {
62 | display: flex;
63 | gap: 0.5rem;
64 | }
65 |
66 | .stack-icons {
67 | display: flex;
68 | margin: 2rem 0rem 2rem 0rem;
69 | font-size: 2.5rem;
70 |
71 | > div {
72 | display: flex;
73 | flex-direction: column;
74 | text-align: center;
75 | justify-content: center;
76 | font-size: 1rem;
77 | margin: 0rem 1rem 0rem 1rem;
78 | }
79 |
80 | img {
81 | margin: auto;
82 | display: block;
83 | height: 3rem;
84 | width: 3rem;
85 | }
86 | }
87 |
88 | .icon {
89 | width: 350px;
90 | height: 150px;
91 | }
92 |
93 | .icon-button {
94 | width: 20px;
95 | height: 20px;
96 | }
97 |
98 | ::-webkit-scrollbar {
99 | width: 10px;
100 | -webkit-appearance: always;
101 | }
102 |
103 | ::-webkit-scrollbar-track {
104 | background: $darkest;
105 | padding: 2.25em 1.6875em;
106 | }
107 |
108 | ::-webkit-scrollbar-thumb {
109 | background: $darker;
110 | border-radius: 5px;
111 | }
112 |
113 | ::-webkit-scrollbar-thumb:hover {
114 | background: $dark;
115 | }
116 |
--------------------------------------------------------------------------------
/src/js/lib/cep/.gitattributes:
--------------------------------------------------------------------------------
1 | *.js linguist-detectable=false
--------------------------------------------------------------------------------
/src/js/lib/cep/cep-types.d.ts:
--------------------------------------------------------------------------------
1 | export declare interface cep_node {
2 | global: any;
3 | process: any;
4 | buffer: any;
5 | require: any;
6 | }
7 | export declare interface cep {
8 | encoding: {
9 | Base64: "Base64" | string;
10 | UTF8: "UTF-8" | string;
11 | convertion: {
12 | utf8_to_b64: (...params: any) => {};
13 | b64_to_utf8: (...params: any) => {};
14 | binary_to_b64: (...params: any) => {};
15 | b64_to_binary: (...params: any) => {};
16 | ascii_to_b64: (...params: any) => {};
17 | };
18 | };
19 | fs: {
20 | ERR_CANT_READ: number;
21 | ERR_CANT_WRITE: number;
22 | ERR_FILE_EXISTS: number;
23 | ERR_INVALID_PARAMS: number;
24 | ERR_NOT_DIRECTORY: number;
25 | ERR_NOT_FILE: number;
26 | ERR_NOT_FOUND: number;
27 | ERR_OUT_OF_SPACE: number;
28 | ERR_UNKNOWN: number;
29 | ERR_UNSUPPORTED_ENCODING: number;
30 | NO_ERROR: number;
31 | chmod: (...params: any) => {};
32 | deleteFile: (...params: any) => {};
33 | makedir: (...params: any) => {};
34 | readFile: (...params: any) => {};
35 | readdir: (...params: any) => {};
36 | rename: (...params: any) => {};
37 | showOpenDialog: (...params: any) => {};
38 | showOpenDialogEx: (...params: any) => {};
39 | showSaveDialogEx: (...params: any) => {};
40 | stat: (...params: any) => {};
41 | writeFile: (...params: any) => {};
42 | };
43 | process: {
44 | ERR_EXCEED_MAX_NUM_PROCESS: number;
45 | createProcess: (...params: any) => {};
46 | getWorkingDirectory: (...params: any) => {};
47 | isRunning: (...params: any) => {};
48 | onquit: (...params: any) => {};
49 | stderr: (...params: any) => {};
50 | stdin: (...params: any) => {};
51 | stdout: (...params: any) => {};
52 | terminate: (...params: any) => {};
53 | waitfor: (...params: any) => {};
54 | };
55 | util: {
56 | DEPRECATED_API: number;
57 | ERR_INVALID_URL: number;
58 | openURLInDefaultBrowser: (...params: any) => {};
59 | registerExtensionUnloadCallback: (...params: any) => {};
60 | storeProxyCredentials: (...params: any) => {};
61 | };
62 | }
63 |
64 | export interface __adobe_cep__ {
65 | addEventListener: (...params: any) => {};
66 | analyticsLogging: (...params: any) => {};
67 | autoThemeColorChange: (...params: any) => {};
68 | closeExtension: (...params: any) => {};
69 | dispatchEvent: (...params: any) => {};
70 | dumpInstallationInfo: (...params: any) => {};
71 | evalScript: (...params: any) => {};
72 | getCurrentApiVersion: (...params: any) => {};
73 | getCurrentImsUserId: (...params: any) => {};
74 | getExtensionId: (...params: any) => {};
75 | getExtensions: (...params: any) => {};
76 | getHostCapabilities: (...params: any) => {};
77 | getHostEnvironment: (...params: any) => {};
78 | getMonitorScaleFactor: (...params: any) => {};
79 | getNetworkPreferences: (...params: any) => {};
80 | getScaleFactor: (...params: any) => {};
81 | getSystemPath: (...params: any) => {};
82 | imsConnect: (...params: any) => {};
83 | imsDisconnect: (...params: any) => {};
84 | imsFetchAccessToken: (...params: any) => {};
85 | imsFetchAccounts: (...params: any) => {};
86 | imsSetProxyCredentials: (...params: any) => {};
87 | initResourceBundle: (...params: any) => {};
88 | invokeAsync: (...params: any) => {};
89 | invokeSync: (...params: any) => {};
90 | nglImsFetchAccessToken: (...params: any) => {};
91 | nglImsFetchProfile: (...params: any) => {};
92 | registerInvalidCertificateCallback: (...params: any) => {};
93 | registerKeyEventsInterest: (...params: any) => {};
94 | removeEventListener: (...params: any) => {};
95 | requestOpenExtension: (...params: any) => {};
96 | resizeContent: (...params: any) => {};
97 | setScaleFactorChangedHandler: (...params: any) => {};
98 | showAAM: (...params: any) => {};
99 | }
100 |
--------------------------------------------------------------------------------
/src/js/lib/cep/es-types/index.ts:
--------------------------------------------------------------------------------
1 | export type Scripts = {
2 | [key: string]: (...ags: any) => any;
3 | };
4 |
--------------------------------------------------------------------------------
/src/js/lib/cep/node.ts:
--------------------------------------------------------------------------------
1 | // Abstracted built-in Node.js Modules
2 |
3 | //@ts-ignore
4 | export const crypto = (
5 | typeof window.cep !== "undefined" ? require("crypto") : {}
6 | ) as typeof import("crypto");
7 | export const assert = (
8 | typeof window.cep !== "undefined" ? require("assert") : {}
9 | ) as typeof import("assert");
10 | export const buffer = (
11 | typeof window.cep !== "undefined" ? require("buffer") : {}
12 | ) as typeof import("buffer");
13 | export const child_process = (
14 | typeof window.cep !== "undefined" ? require("child_process") : {}
15 | ) as typeof import("child_process");
16 | export const cluster = (
17 | typeof window.cep !== "undefined" ? require("cluster") : {}
18 | ) as typeof import("cluster");
19 | export const dgram = (
20 | typeof window.cep !== "undefined" ? require("dgram") : {}
21 | ) as typeof import("dgram");
22 | export const dns = (
23 | typeof window.cep !== "undefined" ? require("dns") : {}
24 | ) as typeof import("dns");
25 | export const domain = (
26 | typeof window.cep !== "undefined" ? require("domain") : {}
27 | ) as typeof import("domain");
28 | export const events = (
29 | typeof window.cep !== "undefined" ? require("events") : {}
30 | ) as typeof import("events");
31 | export const fs = (
32 | typeof window.cep !== "undefined" ? require("fs") : {}
33 | ) as typeof import("fs");
34 | export const http = (
35 | typeof window.cep !== "undefined" ? require("http") : {}
36 | ) as typeof import("http");
37 | export const https = (
38 | typeof window.cep !== "undefined" ? require("https") : {}
39 | ) as typeof import("https");
40 | export const net = (
41 | typeof window.cep !== "undefined" ? require("net") : {}
42 | ) as typeof import("net");
43 | export const os = (
44 | typeof window.cep !== "undefined" ? require("os") : {}
45 | ) as typeof import("os");
46 | export const path = (
47 | typeof window.cep !== "undefined" ? require("path") : {}
48 | ) as typeof import("path");
49 | export const punycode = (
50 | typeof window.cep !== "undefined" ? require("punycode") : {}
51 | ) as typeof import("punycode");
52 | export const querystring = (
53 | typeof window.cep !== "undefined" ? require("querystring") : {}
54 | ) as typeof import("querystring");
55 | export const readline = (
56 | typeof window.cep !== "undefined" ? require("readline") : {}
57 | ) as typeof import("readline");
58 | export const stream = (
59 | typeof window.cep !== "undefined" ? require("stream") : {}
60 | ) as typeof import("stream");
61 | export const string_decoder = (
62 | typeof window.cep !== "undefined" ? require("string_decoder") : {}
63 | ) as typeof import("string_decoder");
64 | export const timers = (
65 | typeof window.cep !== "undefined" ? require("timers") : {}
66 | ) as typeof import("timers");
67 | export const tls = (
68 | typeof window.cep !== "undefined" ? require("tls") : {}
69 | ) as typeof import("tls");
70 | export const tty = (
71 | typeof window.cep !== "undefined" ? require("tty") : {}
72 | ) as typeof import("tty");
73 | export const url = (
74 | typeof window.cep !== "undefined" ? require("url") : {}
75 | ) as typeof import("url");
76 | export const util = (
77 | typeof window.cep !== "undefined" ? require("util") : {}
78 | ) as typeof import("util");
79 | export const v8 = (
80 | typeof window.cep !== "undefined" ? require("v8") : {}
81 | ) as typeof import("v8");
82 | export const vm = (
83 | typeof window.cep !== "undefined" ? require("vm") : {}
84 | ) as typeof import("vm");
85 | export const zlib = (
86 | typeof window.cep !== "undefined" ? require("zlib") : {}
87 | ) as typeof import("zlib");
88 |
--------------------------------------------------------------------------------
/src/js/lib/cep/vulcan.d.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Vulcan
3 |
4 | The singleton instance, VulcanInterface, provides an interface
5 | to the Vulcan. Allows you to launch CC applications
6 | and discover information about them.
7 | */
8 | export default class Vulcan {
9 | constructor();
10 |
11 | /**
12 | * Gets all available application SAPCode-Specifiers on the local machine.
13 | *
14 | * Vulcan Control New 6.x APIs, and Deprecating older Vulcan Control APIs.
15 | * Changes : New getTargetSpecifiersEx returns productSAPCodeSpecifiers
16 | *
17 | * @return The array of all available application SAPCode-Specifiers.
18 | */
19 | getTargetSpecifiersEx(): any;
20 |
21 | /**
22 | * Launches a CC application on the local machine, if it is not already running.
23 | *
24 | * Vulcan Control New 6.x APIs, and Deprecating older Vulcan Control APIs.
25 | * Changes : New launchAppEx uses productSAPCodeSpecifiers
26 | *
27 | * @param productSAPCodeSpecifier The application specifier; for example "ILST-25.2.3", "ILST-25", "ILST-25.2.3-en_US" and "ILST. Refer to `Documentation/CEP 11.1 HTML Extension Cookbook.md#applications-integrated-with-cep` for product SAPCode.
28 | * @param focus True to launch in foreground, or false to launch in the background.
29 | * @param cmdLine Optional, command-line parameters to supply to the launch command.
30 | * @return True if the app can be launched, false otherwise.
31 | */
32 | launchAppEx(
33 | productSAPCodeSpecifier: string,
34 | focus: boolean,
35 | cmdLine?: string,
36 | ): boolean;
37 |
38 | /**
39 | * Checks whether a CC application is running on the local machine.
40 | *
41 | * Vulcan Control New 6.x APIs, and Deprecating older Vulcan Control APIs.
42 | * Changes : New isAppRunningEx uses productSAPCodeSpecifiers
43 | *
44 | * @param productSAPCodeSpecifier The application specifier; for example "ILST-25.2.3", "ILST-25", "ILST-25.2.3-en_US" and "ILST. Refer to `Documentation/CEP 11.1 HTML Extension Cookbook.md#applications-integrated-with-cep` for product SAPCode.
45 | * @return True if the app is running, false otherwise.
46 | */
47 | isAppRunningEx(productSAPCodeSpecifier: string): boolean;
48 |
49 | /**
50 | * Checks whether a CC application is installed on the local machine.
51 | *
52 | * Vulcan Control New 6.x APIs, and Deprecating older Vulcan Control APIs.
53 | * Changes : New isAppInstalledEx uses productSAPCodeSpecifiers
54 | *
55 | * @param productSAPCodeSpecifier The application specifier; for example "ILST-25.2.3", "ILST-25", "ILST-25.2.3-en_US" and "ILST. Refer to `Documentation/CEP 11.1 HTML Extension Cookbook.md#applications-integrated-with-cep` for product SAPCode.
56 | * @return True if the app is installed, false otherwise.
57 | */
58 | isAppInstalledEx(productSAPCodeSpecifier: string): any;
59 |
60 | /**s
61 | * Retrieves the local install path of a CC application.
62 | *
63 | * Vulcan Control New 6.x APIs, and Deprecating older Vulcan Control APIs.
64 | * Changes : New getAppPathEx uses productSAPCodeSpecifiers
65 | *
66 | * @param productSAPCodeSpecifier The application specifier; for example "ILST-25.2.3", "ILST-25", "ILST-25.2.3-en_US" and "ILST. Refer to `Documentation/CEP 11.1 HTML Extension Cookbook.md#applications-integrated-with-cep` for product SAPCode.
67 | * @return The path string if the application is found, "" otherwise.
68 | */
69 | getAppPathEx(): any;
70 |
71 | // OLD FUNCTIONS
72 | // OLD FUNCTIONS
73 | // OLD FUNCTIONS
74 | // OLD FUNCTIONS
75 |
76 | /**
77 | * Gets all available application specifiers on the local machine.
78 | * @returns The array of all available application specifiers.
79 | */
80 | getTargetSpecifiers(): any;
81 | /**
82 | * Launches a CC application on the local machine, if it is not already running.
83 | * @param targetSpecifier - The application specifier; for example "indesign".
84 |
85 | Note: In Windows 7 64-bit or Windows 8 64-bit system, some target applications (like Photoshop and Illustrator) have both 32-bit version
86 | and 64-bit version. Therefore, we need to specify the version by this parameter with "photoshop-70.032" or "photoshop-70.064". If you
87 | installed Photoshop 32-bit and 64-bit on one Windows 64-bit system and invoke this interface with parameter "photoshop-70.032", you may
88 | receive wrong result.
89 | The specifiers for Illustrator is "illustrator-17.032", "illustrator-17.064", "illustrator-17" and "illustrator".
90 |
91 | In other platforms there is no such issue, so we can use "photoshop" or "photoshop-70" as specifier.
92 | * @param focus - True to launch in foreground, or false to launch in the background.
93 | * @param cmdLine - Optional, command-line parameters to supply to the launch command.
94 | * @returns True if the app can be launched, false otherwise.
95 | */
96 | launchApp(targetSpecifier: any, focus: any, cmdLine: any): any;
97 | /**
98 | * Checks whether a CC application is running on the local machine.
99 | * @param targetSpecifier - The application specifier; for example "indesign".
100 |
101 | Note: In Windows 7 64-bit or Windows 8 64-bit system, some target applications (like Photoshop and Illustrator) have both 32-bit version
102 | and 64-bit version. Therefore, we need to specify the version by this parameter with "photoshop-70.032" or "photoshop-70.064". If you
103 | installed Photoshop 32-bit and 64-bit on one Windows 64-bit system and invoke this interface with parameter "photoshop-70.032", you may
104 | receive wrong result.
105 | The specifiers for Illustrator is "illustrator-17.032", "illustrator-17.064", "illustrator-17" and "illustrator".
106 |
107 | In other platforms there is no such issue, so we can use "photoshop" or "photoshop-70" as specifier.
108 | * @returns True if the app is running, false otherwise.
109 | */
110 | isAppRunning(targetSpecifier: any): any;
111 | /**
112 | * Checks whether a CC application is installed on the local machine.
113 | * @param targetSpecifier - The application specifier; for example "indesign".
114 |
115 | Note: In Windows 7 64-bit or Windows 8 64-bit system, some target applications (like Photoshop and Illustrator) have both 32-bit version
116 | and 64-bit version. Therefore, we need to specify the version by this parameter with "photoshop-70.032" or "photoshop-70.064". If you
117 | installed Photoshop 32-bit and 64-bit on one Windows 64-bit system and invoke this interface with parameter "photoshop-70.032", you may
118 | receive wrong result.
119 | The specifiers for Illustrator is "illustrator-17.032", "illustrator-17.064", "illustrator-17" and "illustrator".
120 |
121 | In other platforms there is no such issue, so we can use "photoshop" or "photoshop-70" as specifier.
122 | * @returns True if the app is installed, false otherwise.
123 | */
124 | isAppInstalled(targetSpecifier: any): any;
125 | /**
126 | * Retrieves the local install path of a CC application.
127 | * @param targetSpecifier - The application specifier; for example "indesign".
128 |
129 | Note: In Windows 7 64-bit or Windows 8 64-bit system, some target applications (like Photoshop and Illustrator) have both 32-bit version
130 | and 64-bit version. Therefore, we need to specify the version by this parameter with "photoshop-70.032" or "photoshop-70.064". If you
131 | installed Photoshop 32-bit and 64-bit on one Windows 64-bit system and invoke this interface with parameter "photoshop-70.032", you may
132 | receive wrong result.
133 | The specifiers for Illustrator is "illustrator-17.032", "illustrator-17.064", "illustrator-17" and "illustrator".
134 |
135 | In other platforms there is no such issue, so we can use "photoshop" or "photoshop-70" as specifier.
136 | * @returns The path string if the application is found, "" otherwise.
137 | */
138 | getAppPath(targetSpecifier: any): any;
139 | /**
140 | * Registers a message listener callback function for a Vulcan message.
141 | * @param type - The message type.
142 | * @param callback - The callback function that handles the message.
143 | Takes one argument, the message object.
144 | * @param obj - Optional, the object containing the callback method, if any.
145 | Default is null.
146 | */
147 | addMessageListener(type: any, callback: any, obj: any): void;
148 | /**
149 | * Removes a registered message listener callback function for a Vulcan message.
150 | * @param type - The message type.
151 | * @param callback - The callback function that was registered.
152 | Takes one argument, the message object.
153 | * @param obj - Optional, the object containing the callback method, if any.
154 | Default is null.
155 | */
156 | removeMessageListener(type: any, callback: any, obj: any): void;
157 | /**
158 | * Dispatches a Vulcan message.
159 | * @param vulcanMessage - The message object.
160 | */
161 | dispatchMessage(vulcanMessage: any): void;
162 | /**
163 | * Retrieves the message payload of a Vulcan message for the registered message listener callback function.
164 | * @param vulcanMessage - The message object.
165 | * @returns A string containing the message payload.
166 | */
167 | getPayload(vulcanMessage: any): any;
168 | /**
169 | * Gets all available endpoints of the running Vulcan-enabled applications.
170 |
171 | Since 7.0.0
172 | * @returns The array of all available endpoints.
173 | An example endpoint string:
174 |
175 | PHXS
176 | 16.1.0
177 |
178 | */
179 | getEndPoints(): any;
180 | /**
181 | * Gets the endpoint for itself.
182 |
183 | Since 7.0.0
184 | * @returns The endpoint string for itself.
185 | */
186 | getSelfEndPoint(): any;
187 | }
188 |
189 | /**
190 | * Singleton instance of Vulcan
191 | */
192 | declare var VulcanInterface: any;
193 |
194 | /**
195 | * VulcanMessage
196 | Message type for sending messages between host applications.
197 | A message of this type can be sent to the designated destination
198 | when appId and appVersion are provided and valid. Otherwise,
199 | the message is broadcast to all running Vulcan-enabled applications.
200 |
201 | To send a message between extensions running within one
202 | application, use the CSEvent
type in CSInterface.js.
203 | * @param type - The message type.
204 | * @param appId - The peer appId.
205 | * @param appVersion - The peer appVersion.
206 | */
207 | export declare class VulcanMessage {
208 | static TYPE_PREFIX: string;
209 | static SCOPE_SUITE: string;
210 | static DEFAULT_APP_ID: string;
211 | static DEFAULT_APP_VERSION: string;
212 | static DEFAULT_DATA: string;
213 | static dataTemplate: string;
214 | static payloadTemplate: string;
215 | constructor(type: any, appId: any, appVersion: any);
216 | /**
217 | * Initializes this message instance.
218 | * @param message - A \c message instance to use for initialization.
219 | */
220 | initialize(message: any): void;
221 | /**
222 | * Retrieves the message data.
223 | * @returns A data string in XML format.
224 | */
225 | xmlData(): any;
226 | /**
227 | * Sets the message payload of this message.
228 | * @param payload - A string containing the message payload.
229 | */
230 | setPayload(payload: any): void;
231 | /**
232 | * Retrieves the message payload of this message.
233 | * @returns A string containing the message payload.
234 | */
235 | getPayload(): any;
236 | /**
237 | * Converts the properties of this instance to a string.
238 | * @returns The string version of this instance.
239 | */
240 | toString(): any;
241 | }
242 |
243 | /**
244 | * Retrieves the content of an XML element.
245 | * @param xmlStr - The XML string.
246 | * @param key - The name of the tag.
247 | * @returns The content of the tag, or the empty string
248 | if such tag is not found or the tag has no content.
249 | */
250 | declare function GetValueByKey(xmlStr: any, key: any): any;
251 |
252 | /**
253 | * Reports whether required parameters are valid.
254 | * @returns True if all required parameters are valid,
255 | false if any of the required parameters are invalid.
256 | */
257 | declare function requiredParamsValid(): any;
258 |
259 | /**
260 | * Reports whether a string has a given prefix.
261 | * @param str - The target string.
262 | * @param prefix - The specific prefix string.
263 | * @returns True if the string has the prefix, false if not.
264 | */
265 | declare function strStartsWith(str: any, prefix: any): any;
266 |
--------------------------------------------------------------------------------
/src/js/lib/utils/aeft.ts:
--------------------------------------------------------------------------------
1 | import { fs, path } from "../cep/node";
2 | import { csi } from "./bolt";
3 |
4 | const getLatestFile = (dir: string, suffix: string): string | null => {
5 | const getModified = (filePath: string) =>
6 | fs.statSync(filePath).mtime.valueOf();
7 | let latestFile: string | null = null;
8 | fs.readdirSync(dir)
9 | .filter((file) => file.includes(suffix))
10 | .map((file) => {
11 | if (
12 | latestFile === null ||
13 | getModified(path.join(dir, file)) >
14 | getModified(path.join(dir, latestFile))
15 | ) {
16 | latestFile = file;
17 | }
18 | });
19 | return latestFile;
20 | };
21 |
22 | export const getPrefsDir = (): string => {
23 | const appVersion = csi.getHostEnvironment().appVersion;
24 | const { platform, env } = window.cep_node.process;
25 | const mainDir =
26 | platform == "darwin"
27 | ? `${env.HOME}/Library/Preferences`
28 | : env.APPDATA || "";
29 | const prefsDir = path.join(
30 | mainDir,
31 | "Adobe",
32 | "After Effects",
33 | parseFloat(appVersion).toFixed(1).toString()
34 | );
35 | return prefsDir;
36 | };
37 |
38 | export const getOutputModules = (): string[] => {
39 | const prefsDir = getPrefsDir();
40 | const prefsSuffix = "indep-output.txt";
41 | const outputPref = getLatestFile(prefsDir, prefsSuffix);
42 | if (outputPref) {
43 | const txt = fs.readFileSync(path.join(prefsDir, outputPref), {
44 | encoding: "utf-8",
45 | });
46 | const matches = txt.match(
47 | /\"Output Module Spec Strings Name .* = \".*.\"/g
48 | );
49 | if (matches) {
50 | let outputModules: string[] = [];
51 | matches.map((line) => {
52 | const str = line.split("=").pop()?.trim().replace(/"/g, "");
53 | if (str && !str.includes("_HIDDEN X-Factor")) {
54 | outputModules.push(str);
55 | }
56 | });
57 | return outputModules;
58 | }
59 | }
60 | return [];
61 | };
62 |
63 | export const getRenderSettingsList = (): string[] => {
64 | const prefsDir = getPrefsDir();
65 | const prefsSuffix = "indep-render.txt";
66 | const renderPref = getLatestFile(prefsDir, prefsSuffix);
67 | if (renderPref) {
68 | const txt = fs.readFileSync(path.join(prefsDir, renderPref), {
69 | encoding: "utf-8",
70 | });
71 | const lines = txt.match(/[^\r\n]+/g);
72 | if (lines) {
73 | const firstLine = lines.findIndex((line) =>
74 | line.includes("Render Settings List")
75 | );
76 | const lastLine = lines.findIndex((line) =>
77 | line.includes("Still Frame RS Index")
78 | );
79 | const settingBlock = lines
80 | .slice(firstLine, lastLine)
81 | .join("")
82 | .trim()
83 | .replace(/^.*\=/g, "")
84 | .replace(/\t/g, "")
85 | .replace(/\\/g, "")
86 | .replace(/\"\"/g, "");
87 | let renderSettings: string[] = [];
88 | settingBlock.match(/\".*?\"/g)?.map((str) => {
89 | if (str && !str.includes("_HIDDEN X-Factor")) {
90 | renderSettings.push(str.replace(/\"/g, ""));
91 | }
92 | });
93 | return renderSettings;
94 | }
95 | }
96 | return [];
97 | };
98 |
--------------------------------------------------------------------------------
/src/js/lib/utils/bolt.ts:
--------------------------------------------------------------------------------
1 | import CSInterface, { CSEvent } from "../cep/csinterface";
2 | import Vulcan, { VulcanMessage } from "../cep/vulcan";
3 | import { ns } from "../../../shared/shared";
4 | import { fs } from "../cep/node";
5 |
6 | export const csi = new CSInterface();
7 | export const vulcan = new Vulcan();
8 |
9 | // jsx utils
10 |
11 | /**
12 | * @function EvalES
13 | * Evaluates a string in ExtendScript scoped to the project's namespace
14 | * Optionally, pass true to the isGlobal param to avoid scoping
15 | *
16 | * @param script The script as a string to be evaluated
17 | * @param isGlobal Optional. Defaults to false,
18 | *
19 | * @return String Result.
20 | */
21 |
22 | export const evalES = (script: string, isGlobal = false): Promise => {
23 | return new Promise(function (resolve, reject) {
24 | const pre = isGlobal
25 | ? ""
26 | : `var host = typeof $ !== 'undefined' ? $ : window; host["${ns}"].`;
27 | const fullString = pre + script;
28 | csi.evalScript(
29 | "try{" + fullString + "}catch(e){alert(e);}",
30 | (res: string) => {
31 | resolve(res);
32 | }
33 | );
34 | });
35 | };
36 |
37 | import type { Scripts } from "@esTypes/index";
38 | import type { EventTS } from "../../../shared/universals";
39 | import { initializeCEP } from "./init-cep";
40 |
41 | type ArgTypes = F extends (...args: infer A) => any
42 | ? A
43 | : never;
44 | type ReturnType = F extends (...args: infer A) => infer B
45 | ? B
46 | : never;
47 |
48 | /**
49 | * @description End-to-end type-safe ExtendScript evaluation with error handling
50 | * Call ExtendScript functions from CEP with type-safe parameters and return types.
51 | * Any ExtendScript errors are captured and logged to the CEP console for tracing
52 | *
53 | * @param functionName The name of the function to be evaluated.
54 | * @param args the list of arguments taken by the function.
55 | *
56 | * @return Promise resolving to function native return type.
57 | *
58 | * @example
59 | * // CEP
60 | * evalTS("myFunc", 60, 'test').then((res) => {
61 | * console.log(res.word);
62 | * });
63 | *
64 | * // ExtendScript
65 | * export const myFunc = (num: number, word: string) => {
66 | * return { num, word };
67 | * }
68 | *
69 | */
70 |
71 | export const evalTS = <
72 | Key extends string & keyof Scripts,
73 | Func extends Function & Scripts[Key]
74 | >(
75 | functionName: Key,
76 | ...args: ArgTypes
77 | ): Promise> => {
78 | return new Promise(function (resolve, reject) {
79 | const formattedArgs = args
80 | .map((arg) => {
81 | console.log(JSON.stringify(arg));
82 | return `${JSON.stringify(arg)}`;
83 | })
84 | .join(",");
85 | csi.evalScript(
86 | `try{
87 | var host = typeof $ !== 'undefined' ? $ : window;
88 | var res = host["${ns}"].${functionName}(${formattedArgs});
89 | JSON.stringify(res);
90 | }catch(e){
91 | e.fileName = new File(e.fileName).fsName;
92 | JSON.stringify(e);
93 | }`,
94 | (res: string) => {
95 | try {
96 | //@ts-ignore
97 | if (res === "undefined") return resolve();
98 | const parsed = JSON.parse(res);
99 | if (
100 | typeof parsed.name === "string" &&
101 | (parsed.name).toLowerCase().includes("error")
102 | ) {
103 | console.error(parsed.message);
104 | reject(parsed);
105 | } else {
106 | resolve(parsed);
107 | }
108 | } catch (error) {
109 | reject(res);
110 | }
111 | }
112 | );
113 | });
114 | };
115 |
116 | export const evalFile = (file: string) => {
117 | return evalES(
118 | "typeof $ !== 'undefined' ? $.evalFile(\"" +
119 | file +
120 | '") : fl.runScript(FLfile.platformPathToURI("' +
121 | file +
122 | '"));',
123 | true
124 | );
125 | };
126 |
127 | /**
128 | * @function listenTS End-to-end Type-Safe ExtendScript to JavaScript Events
129 | * Uses the PlugPlug ExternalObject to trigger events in CEP panels
130 | * Function comes scoped to the panel's namespace to avoid conflicts
131 | * Simply declare your event name and value in the shared/universals.ts file
132 | * Listen for events with listenTS() in your CEP panel
133 | * Trigger those events with dispatchTS() ExtendScript
134 | * @param event The event name to listen for (defined in EventTS in shared/universals.ts)
135 | * @param callback The callback function to be executed when the event is triggered
136 | * @param isLocal Whether to scope the event to the panel's namespace. Defaults to true
137 | *
138 | * @example
139 | *
140 | * // 1. Declare Type in EventTS in shared/universals.ts
141 | * export type EventTS = {
142 | * 'myCustomEvent': {
143 | * name: string;
144 | * value: number;
145 | * }
146 | * // [... other events]
147 | * };
148 | *
149 | * // 2. Listen in CEP
150 | * listenTS("myCustomEvent", (data) => {
151 | * console.log("name is", data.name);
152 | * console.log("value is", data.value);
153 | * });
154 | *
155 | * // 3. Dispatch in ExtendScript
156 | * dispatchTS("myCustomEvent", { name: "name", value: 20 });
157 | *
158 | */
159 | export const listenTS = (
160 | event: Key,
161 | callback: (data: EventTS[Key]) => void,
162 | isLocal = true
163 | ) => {
164 | const fullEvent = isLocal ? `${ns}.${event}` : event;
165 | const csi = new CSInterface();
166 | // console.log(`listening to ${fullEvent}`);
167 | const thisCallback = (e: { data: EventTS[Key] }) => {
168 | callback(e.data);
169 | };
170 |
171 | // remove any existing listeners
172 | csi.removeEventListener(fullEvent, thisCallback, null);
173 | // add the event listener
174 | csi.addEventListener(fullEvent, thisCallback);
175 | };
176 |
177 | /**
178 | * @function dispatchTS Displatches an event within or between CEP panels with Type-Safety
179 | * See listenTS() in the CEP panel for more info
180 | * @param event The event name to listen for (defined in EventTS in shared/universals.ts)
181 | * @param callback The callback function to be executed when the event is triggered
182 | * @param scope The scope of the event. Defaults to "APPLICATION"
183 | * @param appId The application ID. Defaults to the current application
184 | * @param id The extension ID. Defaults to the current extension
185 | * @param isLocal Whether to scope the event to the panel's namespace. Defaults to true
186 | */
187 | export const dispatchTS = (
188 | event: Key,
189 | data: EventTS[Key],
190 | scope = "APPLICATION",
191 | appId = csi.getApplicationID() as string,
192 | id = csi.getExtensionID() as string,
193 | isLocal = true
194 | ) => {
195 | const fullEvent = isLocal ? `${ns}.${event}` : event;
196 | // console.log(`dispatching ${fullEvent}`);
197 | const csEvent = new CSEvent(fullEvent, scope, appId, id);
198 | csEvent.data = data;
199 | csi.dispatchEvent(csEvent);
200 | };
201 |
202 | // js utils
203 |
204 | export const initBolt = (log = true) => {
205 | if (window.cep) {
206 | const extRoot = csi.getSystemPath("extension");
207 | const jsxSrc = `${extRoot}/jsx/index.js`;
208 | const jsxBinSrc = `${extRoot}/jsx/index.jsxbin`;
209 | if (fs.existsSync(jsxSrc)) {
210 | if (log) console.log(jsxSrc);
211 | evalFile(jsxSrc);
212 | } else if (fs.existsSync(jsxBinSrc)) {
213 | if (log) console.log(jsxBinSrc);
214 | evalFile(jsxBinSrc);
215 | }
216 | initializeCEP();
217 | }
218 | };
219 |
220 | export const posix = (str: string) => str.replace(/\\/g, "/");
221 |
222 | export const openLinkInBrowser = (url: string) => {
223 | if (window.cep) {
224 | csi.openURLInDefaultBrowser(url);
225 | } else {
226 | location.href = url;
227 | }
228 | };
229 |
230 | export const getAppBackgroundColor = () => {
231 | const { green, blue, red } = JSON.parse(
232 | window.__adobe_cep__.getHostEnvironment() as string
233 | ).appSkinInfo.panelBackgroundColor.color;
234 | return {
235 | rgb: {
236 | r: red,
237 | g: green,
238 | b: blue,
239 | },
240 | hex: `#${red.toString(16)}${green.toString(16)}${blue.toString(16)}`,
241 | };
242 | };
243 |
244 | export const subscribeBackgroundColor = (callback: (color: string) => void) => {
245 | const getColor = () => {
246 | const newColor = getAppBackgroundColor();
247 | console.log("BG Color Updated: ", { rgb: newColor.rgb });
248 | const { r, g, b } = newColor.rgb;
249 | return `rgb(${r}, ${g}, ${b})`;
250 | };
251 | // get current color
252 | callback(getColor());
253 | // listen for changes
254 | csi.addEventListener(
255 | "com.adobe.csxs.events.ThemeColorChanged",
256 | () => callback(getColor()),
257 | {}
258 | );
259 | };
260 |
261 | // vulcan
262 |
263 | declare type IVulcanMessageObject = {
264 | event: string;
265 | callbackID?: string;
266 | data?: string | null;
267 | payload?: object;
268 | };
269 |
270 | export const vulcanSend = (id: string, msgObj: IVulcanMessageObject) => {
271 | const msg = new VulcanMessage(VulcanMessage.TYPE_PREFIX + id, null, null);
272 | const msgStr = JSON.stringify(msgObj);
273 | msg.setPayload(msgStr);
274 | vulcan.dispatchMessage(msg);
275 | };
276 |
277 | export const vulcanListen = (id: string, callback: Function) => {
278 | vulcan.addMessageListener(
279 | VulcanMessage.TYPE_PREFIX + id,
280 | (res: any) => {
281 | var msgStr = vulcan.getPayload(res);
282 | const msgObj = JSON.parse(msgStr);
283 | callback(msgObj);
284 | },
285 | null
286 | );
287 | };
288 |
289 | export const isAppRunning = (targetSpecifier: string) => {
290 | const { major, minor, micro } = csi.getCurrentApiVersion();
291 | const version = parseFloat(`${major}.${minor}`);
292 | if (version >= 11.2) {
293 | return vulcan.isAppRunningEx(targetSpecifier.toUpperCase());
294 | } else {
295 | return vulcan.isAppRunning(targetSpecifier);
296 | }
297 | };
298 |
299 | interface IOpenDialogResult {
300 | data: string[];
301 | }
302 | export const selectFolder = (
303 | dir: string,
304 | msg: string,
305 | callback: (res: string) => void
306 | ) => {
307 | const result = (
308 | window.cep.fs.showOpenDialogEx || window.cep.fs.showOpenDialog
309 | )(false, true, msg, dir) as IOpenDialogResult;
310 | if (result.data?.length > 0) {
311 | const folder = decodeURIComponent(result.data[0].replace("file://", ""));
312 | callback(folder);
313 | }
314 | };
315 |
316 | export const selectFile = (
317 | dir: string,
318 | msg: string,
319 | callback: (res: string) => void
320 | ) => {
321 | const result = (
322 | window.cep.fs.showOpenDialogEx || window.cep.fs.showOpenDialog
323 | )(false, false, msg, dir) as IOpenDialogResult;
324 | if (result.data?.length > 0) {
325 | const folder = decodeURIComponent(result.data[0].replace("file://", ""));
326 | callback(folder);
327 | }
328 | };
329 |
330 | /**
331 | * @function enableSpectrum fixes an issue with React Spectrum and PointerEvents on MacOS
332 | * Run once at the start of your app to fix this issue
333 | */
334 |
335 | export const enableSpectrum = () => {
336 | if (window.PointerEvent) {
337 | //@ts-ignore
338 | delete window.PointerEvent;
339 | }
340 | };
341 |
--------------------------------------------------------------------------------
/src/js/lib/utils/cep.ts:
--------------------------------------------------------------------------------
1 | import { os } from "../cep/node";
2 | import { csi } from "./bolt";
3 |
4 | /**
5 | * Register all possible keyboard shortcuts on Mac and Windows for you CEP Panel
6 | * Warning: Note that certain keys will not work per OS regardless of registration
7 | */
8 |
9 | export const keyRegisterOverride = () => {
10 | //@ts-ignore
11 | const platform = navigator.platform.substring(0, 3);
12 | let maxKey = 0;
13 | if (platform === "Mac") maxKey = 126; // Mac Max Key Code
14 | else if (platform === "Win") maxKey = 222; // HTML Max Key Code
15 | let allKeys: {
16 | keyCode: number;
17 | ctrlKey: boolean;
18 | altKey: boolean;
19 | shiftKey: boolean;
20 | metaKey: boolean;
21 | }[] = [];
22 | for (let k = 0; k <= maxKey; k++) {
23 | for (let j = 0; j <= 15; j++) {
24 | const guide = (j >>> 0).toString(2).padStart(4, "0");
25 | allKeys.push({
26 | keyCode: k,
27 | ctrlKey: guide[0] === "1",
28 | altKey: guide[1] === "1",
29 | shiftKey: guide[2] === "1",
30 | metaKey: guide[3] === "1",
31 | });
32 | }
33 | }
34 | const keyRes = csi.registerKeyEventsInterest(JSON.stringify(allKeys));
35 | console.log("Key Events Registered Completed: " + keyRes);
36 | };
37 |
38 | export const textCepPatch = (e: KeyboardEvent) => {
39 | const isMac = os.platform() === "darwin";
40 | if (!isMac) return; // Only needed on MacOS, Windows handles this natively
41 |
42 | // console.log("keyup", e);
43 |
44 | const isShiftKey = e.shiftKey;
45 | const input = e.target as HTMLTextAreaElement | HTMLInputElement;
46 | const start = input.selectionStart;
47 | let end = input.selectionEnd;
48 |
49 | const selectionExists = start !== null && end !== null && start !== end;
50 |
51 | if (start === null || end === null) return;
52 |
53 | if (e.key === "ArrowLeft") {
54 | if (start === 0) return; // Prevents going to -1
55 | if (isShiftKey) {
56 | input.setSelectionRange(start - 1, end);
57 | } else {
58 | input.setSelectionRange(start - 1, start - 1);
59 | }
60 | } else if (e.key === "ArrowRight") {
61 | if (end === input.value.length) return; // Prevents going to start
62 | if (isShiftKey) {
63 | input.setSelectionRange(start, end + 1);
64 | } else {
65 | input.setSelectionRange(end + 1, end + 1);
66 | }
67 | }
68 | };
69 |
70 | /**
71 | * Prevents the user from dropping files or URLs onto the panel and navigating away
72 | */
73 |
74 | export const dropDisable = () => {
75 | window.addEventListener("dragover", (e) => e.preventDefault(), false);
76 | window.addEventListener("drop", (e) => e.preventDefault(), false);
77 | };
78 |
--------------------------------------------------------------------------------
/src/js/lib/utils/init-cep.ts:
--------------------------------------------------------------------------------
1 | import { company, displayName, version } from "../../../shared/shared";
2 | import { dispatchTS, openLinkInBrowser } from "./bolt";
3 | import { keyRegisterOverride, dropDisable } from "./cep";
4 |
5 | const buildFlyoutMenu = () => {
6 | const menu = ``;
12 |
13 | interface FlyoutMenuEvent {
14 | data:
15 | | {
16 | menuId: string;
17 | }
18 | | string;
19 | }
20 | const flyoutHandler = (event: FlyoutMenuEvent) => {
21 | let menuId;
22 | if (typeof event.data === "string") {
23 | try {
24 | //? On build the events come in garbled string which requires some replacing and then parsing to get the data
25 | menuId = JSON.parse(
26 | event.data.replace(/\$/g, "").replace(/\=2/g, ":")
27 | ).menuId;
28 | } catch (e) {
29 | console.error(e);
30 | }
31 | } else {
32 | menuId = event.data.menuId;
33 | }
34 | if (menuId === "website") {
35 | // openLinkInBrowser(homePage);
36 | } else if (menuId === "info") {
37 | // openLinkInBrowser(productPage);
38 | } else if (menuId === "refresh") {
39 | location.reload();
40 | }
41 | };
42 |
43 | window.__adobe_cep__.invokeSync("setPanelFlyoutMenu", menu);
44 | window.__adobe_cep__.addEventListener(
45 | "com.adobe.csxs.events.flyoutMenuClicked",
46 | flyoutHandler
47 | );
48 | };
49 |
50 | const buildContextMenu = () => {
51 | console.log("buildContextMenu");
52 | const menuObj = {
53 | menu: [
54 | {
55 | label: "Reload",
56 | enabled: true,
57 | checked: false,
58 | checkable: false,
59 | id: "c-0",
60 | callback: () => {
61 | location.reload();
62 | },
63 | },
64 | {
65 | label: "Force Reload",
66 | enabled: true,
67 | checked: false,
68 | checkable: false,
69 | id: "c-1",
70 | callback: () => {
71 | process.abort();
72 | },
73 | },
74 | ],
75 | };
76 | window.__adobe_cep__.invokeAsync(
77 | "setContextMenuByJSON",
78 | JSON.stringify(menuObj),
79 | (e: string) => {
80 | menuObj.menu.find((m) => m.id === e)?.callback();
81 | }
82 | );
83 | };
84 |
85 | export const initializeCEP = () => {
86 | buildFlyoutMenu();
87 | buildContextMenu();
88 | // keyRegisterOverride(); // Capture all Key Events Possible (many limitations on MacOS)
89 | dropDisable(); // to prevent drop files on panel and taking over
90 | };
91 |
--------------------------------------------------------------------------------
/src/js/lib/utils/ppro.ts:
--------------------------------------------------------------------------------
1 | import { fs, os, path } from "../cep/node";
2 | import { csi } from "./bolt";
3 |
4 | const readDirSafe = (dir: string) =>
5 | fs.existsSync(dir) ? fs.readdirSync(dir) : [];
6 |
7 | export const getAllLuts = (): { creative: string[]; technical: string[] } => {
8 | const isWin = os.platform() === "win32";
9 |
10 | const appPath = path.dirname(csi.getSystemPath("hostApplication"));
11 | const appLutsDir = path.join(
12 | isWin ? appPath : path.dirname(appPath),
13 | "Lumetri",
14 | "LUTs"
15 | );
16 |
17 | const winLocal = path.join(
18 | os.homedir(),
19 | "AppData",
20 | "Roaming",
21 | "Adobe",
22 | "Common",
23 | "LUTs"
24 | );
25 | const winGlobal = path.join("C:", "Program Files", "Adobe", "Common", "LUTs");
26 | const macLocal = path.join(
27 | os.homedir(),
28 | "Library",
29 | "Application Support",
30 | "Adobe",
31 | "Common",
32 | "LUTs"
33 | );
34 | const macGlobal = path.join(
35 | "Library",
36 | "Application Support",
37 | "Adobe",
38 | "Common",
39 | "LUTs"
40 | );
41 |
42 | const appCreative = path.join(appLutsDir, "Creative");
43 | const appTechnical = path.join(appLutsDir, "Technical");
44 | const localCreative = isWin
45 | ? path.join(winLocal, "Creative")
46 | : path.join(macLocal, "Creative");
47 | const localTechnical = isWin
48 | ? path.join(winLocal, "Technical")
49 | : path.join(macLocal, "Technical");
50 | const globalCreative = isWin
51 | ? path.join(winGlobal, "Creative")
52 | : path.join(macGlobal, "Creative");
53 | const globalTechnical = isWin
54 | ? path.join(winGlobal, "Technical")
55 | : path.join(macGlobal, "Technical");
56 |
57 | const appCreativeLuts = readDirSafe(appCreative);
58 | const appTechnicalLuts = readDirSafe(appTechnical);
59 |
60 | const localCreativeLuts = readDirSafe(localCreative);
61 | const localTechnicalLuts = readDirSafe(localTechnical);
62 | const globalCreativeLuts = readDirSafe(globalCreative);
63 | const globalTechnicalLuts = readDirSafe(globalTechnical);
64 | const creative = [
65 | ...appCreativeLuts,
66 | ...localCreativeLuts,
67 | ...globalCreativeLuts,
68 | ]
69 | .sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()))
70 | .map((lut) => path.basename(lut, path.extname(lut)));
71 | const technical = [
72 | ...appTechnicalLuts,
73 | ...localTechnicalLuts,
74 | ...globalTechnicalLuts,
75 | ]
76 | .sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()))
77 | .map((lut) => path.basename(lut, path.extname(lut)));
78 |
79 | return { creative, technical };
80 | };
81 |
82 | export const allowedImportFiles: string[] = [
83 | "264",
84 | "3g2",
85 | "3gp",
86 | "3gpp",
87 | "aac",
88 | "aaf",
89 | "ac3",
90 | "ai",
91 | "aif",
92 | "aiff",
93 | "ari",
94 | "asf",
95 | "asnd",
96 | "asx",
97 | "avc",
98 | "avi",
99 | "bmp",
100 | "bwf",
101 | "cin",
102 | "cine",
103 | "crm",
104 | "dfxp",
105 | "dib",
106 | "dif",
107 | "dng",
108 | "dpx",
109 | "dv",
110 | "eps",
111 | "exr",
112 | "f4v",
113 | "f4v",
114 | "fli",
115 | "gif",
116 | "icb",
117 | "ico",
118 | "jfif",
119 | "jpe",
120 | "jpeg",
121 | "jpg",
122 | "m15",
123 | "m1a",
124 | "m1s",
125 | "m1v",
126 | "m2a",
127 | "m2p",
128 | "m2t",
129 | "m2ts",
130 | "m2v",
131 | "m4a",
132 | "m4v",
133 | "m75",
134 | "mcc",
135 | "m0d",
136 | "mov",
137 | "mp2",
138 | "mp3",
139 | "mp4",
140 | "mpa",
141 | "mpe",
142 | "mpeg",
143 | "mpg",
144 | "mpg4",
145 | "mpm",
146 | "mpv",
147 | "mts",
148 | "mxf",
149 | "mxv",
150 | "mxr",
151 | "pct",
152 | "pict",
153 | "png",
154 | "prt",
155 | "ptl",
156 | "qt",
157 | "r3d",
158 | "rle",
159 | "rmf",
160 | "scc",
161 | "srt",
162 | "stl",
163 | "sxr",
164 | "tga",
165 | "tif",
166 | "tiff",
167 | "ts",
168 | "vda",
169 | "vob",
170 | "vst",
171 | "wav",
172 | "wma",
173 | "wmv",
174 | "psd",
175 | ];
176 |
--------------------------------------------------------------------------------
/src/js/main/env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | declare module "*.vue" {
4 | import type { DefineComponent } from "vue";
5 | // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types
6 | const component: DefineComponent<{}, {}, any>;
7 | export default component;
8 | }
9 |
--------------------------------------------------------------------------------
/src/js/main/index-react.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom/client";
3 | import { initBolt } from "../lib/utils/bolt";
4 | import "../index.scss";
5 | import { App } from "./main";
6 |
7 | initBolt();
8 |
9 | ReactDOM.createRoot(document.getElementById("app") as HTMLElement).render(
10 |
11 |
12 |
13 | );
14 |
--------------------------------------------------------------------------------
/src/js/main/index-svelte.ts:
--------------------------------------------------------------------------------
1 | import App from "./main.svelte";
2 | import { initBolt } from "../lib/utils/bolt";
3 |
4 | initBolt();
5 |
6 | const app = new App({
7 | target: document.getElementById("app") as Element,
8 | });
9 |
10 | export default app;
11 |
--------------------------------------------------------------------------------
/src/js/main/index-vue.ts:
--------------------------------------------------------------------------------
1 | import { createApp } from "vue";
2 | import App from "./main.vue";
3 | import { initBolt } from "../lib/utils/bolt";
4 |
5 | initBolt();
6 |
7 | createApp(App).mount("#app");
8 |
--------------------------------------------------------------------------------
/src/js/main/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Bolt CEP
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/src/js/main/main.scss:
--------------------------------------------------------------------------------
1 | @use "../variables.scss" as *;
2 |
--------------------------------------------------------------------------------
/src/js/main/main.svelte:
--------------------------------------------------------------------------------
1 |
70 |
71 |
72 |
129 |
130 |
131 |
134 |
--------------------------------------------------------------------------------
/src/js/main/main.tsx:
--------------------------------------------------------------------------------
1 | import { useEffect, useState } from "react";
2 | import { os, path } from "../lib/cep/node";
3 | import {
4 | csi,
5 | evalES,
6 | openLinkInBrowser,
7 | subscribeBackgroundColor,
8 | evalTS,
9 | } from "../lib/utils/bolt";
10 | import "./main.scss";
11 |
12 | // BOLT_SAMPLECODE_START
13 | import reactLogo from "../assets/react.svg";
14 | import viteLogo from "../assets/vite.svg";
15 | import tsLogo from "../assets/typescript.svg";
16 | import sassLogo from "../assets/sass.svg";
17 | import nodeJs from "../assets/node-js.svg";
18 | import adobe from "../assets/adobe.svg";
19 | import bolt from "../assets/bolt-cep.svg";
20 | // BOLT_SAMPLECODE_END
21 |
22 | export const App = () => {
23 | const [bgColor, setBgColor] = useState("#282c34");
24 | // BOLT_SAMPLECODE_START
25 | const [count, setCount] = useState(0);
26 |
27 | //* Demonstration of Traditional string eval-based ExtendScript Interaction
28 | const jsxTest = () => {
29 | console.log(evalES(`helloWorld("${csi.getApplicationID()}")`));
30 | };
31 |
32 | //* Demonstration of End-to-End Type-safe ExtendScript Interaction
33 | const jsxTestTS = () => {
34 | evalTS("helloStr", "test").then((res) => {
35 | console.log(res);
36 | });
37 | evalTS("helloNum", 1000).then((res) => {
38 | console.log(typeof res, res);
39 | });
40 | evalTS("helloArrayStr", ["ddddd", "aaaaaa", "zzzzzzz"]).then((res) => {
41 | console.log(typeof res, res);
42 | });
43 | evalTS("helloObj", { height: 90, width: 100 }).then((res) => {
44 | console.log(typeof res, res);
45 | console.log(res.x);
46 | console.log(res.y);
47 | });
48 | evalTS("helloVoid").then(() => {
49 | console.log("function returning void complete");
50 | });
51 | evalTS("helloError", "test").catch((e) => {
52 | console.log("there was an error", e);
53 | });
54 | };
55 |
56 | const nodeTest = () => {
57 | alert(
58 | `Node.js ${process.version}\nPlatform: ${
59 | os.platform
60 | }\nFolder: ${path.basename(window.cep_node.global.__dirname)}`
61 | );
62 | };
63 | // BOLT_SAMPLECODE_END
64 |
65 | useEffect(() => {
66 | if (window.cep) {
67 | subscribeBackgroundColor(setBgColor);
68 | }
69 | }, []);
70 |
71 | return (
72 |
73 |
74 | {/* BOLT_SAMPLECODE_START */}
75 |
76 |
77 |
78 |

79 | Vite
80 |
81 | +
82 |
83 |

84 | React
85 |
86 | +
87 |
88 |

89 | TypeScript
90 |
91 | +
92 |
93 |

94 | Sass
95 |
96 |
97 |
98 |
101 |
104 |
107 |
108 |
109 |
110 | Edit main.tsx
and save to test HMR updates.
111 |
112 |
113 |
121 | {" | "}
122 |
128 | {" | "}
129 |
137 |
138 | {/* BOLT_SAMPLECODE_END */}
139 |
140 |
141 | );
142 | };
143 |
--------------------------------------------------------------------------------
/src/js/main/main.vue:
--------------------------------------------------------------------------------
1 |
62 |
63 |
64 |
65 |
124 |
125 |
126 |
127 |
130 |
--------------------------------------------------------------------------------
/src/js/main/vite-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 | ///
3 |
--------------------------------------------------------------------------------
/src/js/variables.scss:
--------------------------------------------------------------------------------
1 | $darkest: #222222;
2 | $darker: #333333;
3 | $dark: #444444;
4 | $font: #bbbbbb;
5 | $highlight: #aaaaaa;
6 |
7 | $primary: #88715a;
8 | $secondary: #4a3928;
9 |
10 | $active: #20639b;
11 | $changed: #3caea3;
12 | $warning: #f6d55c;
13 | $error: #ed553b;
14 |
--------------------------------------------------------------------------------
/src/js/vite-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/src/jsx/aeft/aeft-utils.ts:
--------------------------------------------------------------------------------
1 | export const forEachLayer = (
2 | comp: CompItem,
3 | callback: (item: Layer, index: number) => void
4 | ) => {
5 | const len = comp.numLayers;
6 | for (let i = 1; i < len + 1; i++) {
7 | callback(comp.layers[i], i);
8 | }
9 | };
10 |
11 | export const forEachComp = (
12 | folder: FolderItem | Project,
13 | callback: (item: CompItem, index: number) => void
14 | ) => {
15 | const len = folder.numItems;
16 | let comps: CompItem[] = [];
17 | for (let i = 1; i < len + 1; i++) {
18 | const item = folder.items[i];
19 | if (item instanceof CompItem) {
20 | comps.push(item);
21 | }
22 | }
23 | for (let i = 0; i < comps.length; i++) {
24 | let comp = comps[i];
25 | callback(comp, i);
26 | }
27 | };
28 |
29 | export const compFromFootage = (item: FootageItem): CompItem => {
30 | return app.project.items.addComp(
31 | item.name,
32 | item.width,
33 | item.height,
34 | item.pixelAspect,
35 | item.duration,
36 | item.frameRate
37 | );
38 | };
39 |
40 | export const getProjectDir = () => {
41 | app.project.file;
42 | if (app.project.file !== null) {
43 | return app.project.file.parent;
44 | } else {
45 | return "";
46 | }
47 | };
48 |
49 | export const getActiveComp = () => {
50 | if (app.project.activeItem instanceof CompItem === false) {
51 | app.activeViewer?.setActive();
52 | }
53 | return app.project.activeItem as CompItem;
54 | };
55 |
56 | // Project Item Helpers
57 |
58 | export const getItemByName = (parent: FolderItem, name: string) => {
59 | for (var i = 0; i < parent.numItems; i++) {
60 | const item = parent.items[i + 1];
61 | if (item.name === name) {
62 | return item;
63 | }
64 | }
65 | };
66 |
67 | // Metadata helpers
68 |
69 | export const setAeMetadata = (propName: string, propValue: any) => {
70 | if (ExternalObject.AdobeXMPScript === undefined) {
71 | ExternalObject.AdobeXMPScript = new ExternalObject("lib:AdobeXMPScript");
72 | }
73 | if (!app.project || !ExternalObject.AdobeXMPScript || !XMPMeta) return;
74 | const prefix = "xmp:";
75 | const uri = XMPMeta.getNamespaceURI(prefix);
76 | const newPropName = prefix + propName;
77 | let metadata = new XMPMeta(app.project.xmpPacket);
78 | metadata.setProperty(uri, newPropName, propValue.toString());
79 | app.project.xmpPacket = metadata.serialize();
80 | };
81 |
82 | export const getAeMetadata = (propName: string) => {
83 | if (ExternalObject.AdobeXMPScript === undefined) {
84 | ExternalObject.AdobeXMPScript = new ExternalObject("lib:AdobeXMPScript");
85 | }
86 | if (!app.project || !ExternalObject.AdobeXMPScript || !XMPMeta) return;
87 | const prefix = "xmp:";
88 | const uri = XMPMeta.getNamespaceURI(prefix);
89 | const newPropName = prefix + propName;
90 | const metadata = new XMPMeta(app.project.xmpPacket);
91 | return metadata.getProperty(uri, newPropName);
92 | };
93 |
--------------------------------------------------------------------------------
/src/jsx/aeft/aeft.ts:
--------------------------------------------------------------------------------
1 | import {
2 | helloVoid,
3 | helloError,
4 | helloStr,
5 | helloNum,
6 | helloArrayStr,
7 | helloObj,
8 | } from "../utils/samples";
9 | export { helloError, helloStr, helloNum, helloArrayStr, helloObj, helloVoid };
10 | import { dispatchTS } from "../utils/utils";
11 |
12 | export const helloWorld = () => {
13 | alert("Hello from After Effects!");
14 | app.project.activeItem;
15 | };
16 |
--------------------------------------------------------------------------------
/src/jsx/aeft/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es3",
4 | "noLib": true,
5 | "strict": true,
6 | "types": [
7 | "../global",
8 | "../../../node_modules/types-for-adobe/AfterEffects/22.0",
9 | "../../../node_modules/types-for-adobe/shared/PlugPlugExternalObject",
10 | "../../../node_modules/types-for-adobe/shared/XMPScript"
11 | ]
12 | },
13 | "include": ["./**/*"]
14 | }
15 |
--------------------------------------------------------------------------------
/src/jsx/ame/ame.ts:
--------------------------------------------------------------------------------
1 | import {
2 | helloVoid,
3 | helloError,
4 | helloStr,
5 | helloNum,
6 | helloArrayStr,
7 | helloObj,
8 | } from "../utils/samples";
9 | export { helloError, helloStr, helloNum, helloArrayStr, helloObj, helloVoid };
10 | import { dispatchTS } from "../utils/utils";
11 |
12 | export const helloWorld = () => {
13 | alert("Hello from Media Encoder");
14 | };
15 |
--------------------------------------------------------------------------------
/src/jsx/ame/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es3",
4 | "noLib": true,
5 | "strict": true,
6 | "types": [
7 | "../global",
8 | "../../../node_modules/types-for-adobe/shared/global"
9 | ]
10 | },
11 | "include": ["./**/*"]
12 | }
13 |
--------------------------------------------------------------------------------
/src/jsx/anim/anim.ts:
--------------------------------------------------------------------------------
1 | import {
2 | helloVoid,
3 | helloError,
4 | helloStr,
5 | helloNum,
6 | helloArrayStr,
7 | helloObj,
8 | } from "../utils/samples";
9 | export { helloError, helloStr, helloNum, helloArrayStr, helloObj, helloVoid };
10 | import { dispatchTS } from "../utils/utils";
11 |
12 | export const helloWorld = () => {
13 | alert("Hello from Animate");
14 | document.path;
15 | };
16 |
--------------------------------------------------------------------------------
/src/jsx/anim/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es3",
4 | "noLib": true,
5 | "strict": true,
6 | "types": ["../global", "../../../node_modules/types-for-adobe/Animate/22.0"]
7 | },
8 | "include": ["./**/*"]
9 | }
10 |
--------------------------------------------------------------------------------
/src/jsx/audt/audt.ts:
--------------------------------------------------------------------------------
1 | import {
2 | helloVoid,
3 | helloError,
4 | helloStr,
5 | helloNum,
6 | helloArrayStr,
7 | helloObj,
8 | } from "../utils/samples";
9 | export { helloError, helloStr, helloNum, helloArrayStr, helloObj, helloVoid };
10 | import { dispatchTS } from "../utils/utils";
11 |
12 | export const helloWorld = () => {
13 | alert("Hello from Audtion");
14 | };
15 |
--------------------------------------------------------------------------------
/src/jsx/audt/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es3",
4 | "noLib": true,
5 | "strict": true,
6 | "types": [
7 | "../global",
8 | "../../../node_modules/types-for-adobe/Audition/2018"
9 | ]
10 | },
11 | "include": ["./**/*"]
12 | }
13 |
--------------------------------------------------------------------------------
/src/jsx/global.d.ts:
--------------------------------------------------------------------------------
1 | //@ts-ignore
2 | declare var JSON: {
3 | stringify(object: object): string;
4 | parse(string: string): object;
5 | };
6 |
--------------------------------------------------------------------------------
/src/jsx/idsn/idsn.ts:
--------------------------------------------------------------------------------
1 | import {
2 | helloVoid,
3 | helloError,
4 | helloStr,
5 | helloNum,
6 | helloArrayStr,
7 | helloObj,
8 | } from "../utils/samples";
9 | export { helloError, helloStr, helloNum, helloArrayStr, helloObj, helloVoid };
10 | import { dispatchTS } from "../utils/utils";
11 |
12 | export const helloWorld = () => {
13 | alert("Hello from InDesign");
14 | };
15 |
--------------------------------------------------------------------------------
/src/jsx/idsn/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es3",
4 | "noLib": true,
5 | "strict": true,
6 | "types": [
7 | "../global",
8 | "../../../node_modules/types-for-adobe/InDesign/2021"
9 | ]
10 | },
11 | "include": ["./**/*"]
12 | }
13 |
--------------------------------------------------------------------------------
/src/jsx/ilst/ilst.ts:
--------------------------------------------------------------------------------
1 | import {
2 | helloVoid,
3 | helloError,
4 | helloStr,
5 | helloNum,
6 | helloArrayStr,
7 | helloObj,
8 | } from "../utils/samples";
9 | export { helloError, helloStr, helloNum, helloArrayStr, helloObj, helloVoid };
10 | import { dispatchTS } from "../utils/utils";
11 |
12 | export const helloWorld = () => {
13 | alert("Hello from Illustrator");
14 | };
15 |
--------------------------------------------------------------------------------
/src/jsx/ilst/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es3",
4 | "noLib": true,
5 | "strict": true,
6 | "types": [
7 | "../global",
8 | "../../../node_modules/types-for-adobe/Illustrator/2015.3",
9 | "../../../node_modules/types-for-adobe/shared/PlugPlugExternalObject"
10 | ]
11 | },
12 | "include": ["./**/*"]
13 | }
14 |
--------------------------------------------------------------------------------
/src/jsx/index.ts:
--------------------------------------------------------------------------------
1 | // @include './lib/json2.js'
2 |
3 | import { ns } from "../shared/shared";
4 |
5 | import * as aeft from "./aeft/aeft"; // BOLT_AEFT_ONLY
6 | import * as ame from "./ame/ame"; // BOLT_AME_ONLY
7 | import * as anim from "./anim/anim"; // BOLT_ANIM_ONLY
8 | import * as audt from "./audt/audt"; // BOLT_AUDT_ONLY
9 | import * as idsn from "./idsn/idsn"; // BOLT_IDSN_ONLY
10 | import * as ilst from "./ilst/ilst"; // BOLT_ILST_ONLY
11 | import * as kbrg from "./kbrg/kbrg"; // BOLT_KBRG_ONLY
12 | import * as phxs from "./phxs/phxs"; // BOLT_PHXS_ONLY
13 | import * as ppro from "./ppro/ppro"; // BOLT_PPRO_ONLY
14 |
15 | //@ts-ignore
16 | const host = typeof $ !== "undefined" ? $ : window;
17 |
18 | // A safe way to get the app name since some versions of Adobe Apps broken BridgeTalk in various places (e.g. After Effects 24-25)
19 | // in that case we have to do various checks per app to deterimine the app name
20 |
21 | const getAppNameSafely = (): ApplicationName | "unknown" => {
22 | const compare = (a: string, b: string) => {
23 | return a.toLowerCase().indexOf(b.toLowerCase()) > -1;
24 | };
25 | const exists = (a: any) => typeof a !== "undefined";
26 | const isBridgeTalkWorking =
27 | typeof BridgeTalk !== "undefined" &&
28 | typeof BridgeTalk.appName !== "undefined";
29 |
30 | if (isBridgeTalkWorking) {
31 | return BridgeTalk.appName;
32 | } else if (app) {
33 | //@ts-ignore
34 | if (exists(app.name)) {
35 | //@ts-ignore
36 | const name: string = app.name;
37 | if (compare(name, "photoshop")) return "photoshop";
38 | if (compare(name, "illustrator")) return "illustrator";
39 | if (compare(name, "audition")) return "audition";
40 | if (compare(name, "bridge")) return "bridge";
41 | if (compare(name, "indesign")) return "indesign";
42 | }
43 | //@ts-ignore
44 | if (exists(app.appName)) {
45 | //@ts-ignore
46 | const appName: string = app.appName;
47 | if (compare(appName, "after effects")) return "aftereffects";
48 | if (compare(appName, "animate")) return "animate";
49 | }
50 | //@ts-ignore
51 | if (exists(app.path)) {
52 | //@ts-ignore
53 | const path = app.path;
54 | if (compare(path, "premiere")) return "premierepro";
55 | }
56 | //@ts-ignore
57 | if (exists(app.getEncoderHost) && exists(AMEFrontendEvent)) {
58 | return "ame";
59 | }
60 | }
61 | return "unknown";
62 | };
63 |
64 | switch (getAppNameSafely()) {
65 | // BOLT_AEFT_START
66 | case "aftereffects":
67 | case "aftereffectsbeta":
68 | host[ns] = aeft;
69 | break;
70 | // BOLT_AEFT_END
71 |
72 | // BOLT_AME_START
73 | case "ame":
74 | case "amebeta":
75 | host[ns] = ame;
76 | break;
77 | // BOLT_AME_END
78 |
79 | // BOLT_ANIM_START
80 | case "animate":
81 | case "animatebeta":
82 | host[ns] = anim;
83 | break;
84 | // BOLT_ANIM_END
85 |
86 | // BOLT_AUDT_START
87 | case "audition":
88 | case "auditionbeta":
89 | host[ns] = audt;
90 | break;
91 | // BOLT_AUDT_END
92 |
93 | // BOLT_IDSN_START
94 | case "indesign":
95 | case "indesignbeta":
96 | host[ns] = idsn;
97 | break;
98 | // BOLT_IDSN_END
99 |
100 | // BOLT_ILST_START
101 | case "illustrator":
102 | case "illustratorbeta":
103 | host[ns] = ilst;
104 | break;
105 | // BOLT_ILST_END
106 |
107 | // BOLT_KBRG_START
108 | case "bridge":
109 | case "bridgebeta":
110 | host[ns] = kbrg;
111 | break;
112 | // BOLT_KBRG_END
113 |
114 | // BOLT_PHXS_START
115 | case "photoshop":
116 | case "photoshopbeta":
117 | host[ns] = phxs;
118 | break;
119 | // BOLT_PHXS_END
120 |
121 | // BOLT_PPRO_START
122 | case "premierepro":
123 | case "premiereprobeta":
124 | host[ns] = ppro;
125 | break;
126 | // BOLT_PPRO_END
127 | }
128 |
129 | const empty = {};
130 | // prettier-ignore
131 | export type Scripts = typeof empty
132 | & typeof aeft // BOLT_AEFT_ONLY
133 | & typeof ame // BOLT_AME_ONLY
134 | & typeof anim // BOLT_ANIM_ONLY
135 | & typeof audt // BOLT_AUDT_ONLY
136 | & typeof idsn // BOLT_IDSN_ONLY
137 | & typeof ilst // BOLT_ILST_ONLY
138 | & typeof kbrg // BOLT_KBRG_ONLY
139 | & typeof phxs // BOLT_PHXS_ONLY
140 | & typeof ppro // BOLT_PPRO_ONLY
141 | ;
142 |
143 | // https://extendscript.docsforadobe.dev/interapplication-communication/bridgetalk-class.html?highlight=bridgetalk#appname
144 | type ApplicationName =
145 | | "aftereffects"
146 | | "aftereffectsbeta"
147 | | "ame"
148 | | "amebeta"
149 | | "audition"
150 | | "auditionbeta"
151 | | "animate"
152 | | "animatebeta"
153 | | "bridge"
154 | | "bridgebeta"
155 | // | "flash"
156 | | "illustrator"
157 | | "illustratorbeta"
158 | | "indesign"
159 | | "indesignbeta"
160 | // | "indesignserver"
161 | | "photoshop"
162 | | "photoshopbeta"
163 | | "premierepro"
164 | | "premiereprobeta";
165 |
--------------------------------------------------------------------------------
/src/jsx/kbrg/kbrg.ts:
--------------------------------------------------------------------------------
1 | import {
2 | helloVoid,
3 | helloError,
4 | helloStr,
5 | helloNum,
6 | helloArrayStr,
7 | helloObj,
8 | } from "../utils/samples";
9 | export { helloError, helloStr, helloNum, helloArrayStr, helloObj, helloVoid };
10 | import { dispatchTS } from "../utils/utils";
11 |
12 | export const helloWorld = () => {
13 | alert("Hello from Bridge");
14 | };
15 |
--------------------------------------------------------------------------------
/src/jsx/kbrg/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es3",
4 | "noLib": true,
5 | "strict": true,
6 | "types": [
7 | "../global",
8 | "../../../node_modules/types-for-adobe/shared/global"
9 | ]
10 | },
11 | "include": ["./**/*"]
12 | }
13 |
--------------------------------------------------------------------------------
/src/jsx/lib/.gitattributes:
--------------------------------------------------------------------------------
1 | *.js linguist-detectable=false
--------------------------------------------------------------------------------
/src/jsx/lib/json2.js:
--------------------------------------------------------------------------------
1 | "object"!=typeof JSON&&(JSON={}),function(){"use strict";var rx_one=/^[\],:{}\s]*$/,rx_two=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,rx_three=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,rx_four=/(?:^|:|,)(?:\s*\[)+/g,rx_escapable=/[\\\"\u0000-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,rx_dangerous=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,gap,indent,meta,rep;function f(t){return t<10?"0"+t:t}function this_value(){return this.valueOf()}function quote(t){return rx_escapable.lastIndex=0,rx_escapable.test(t)?'"'+t.replace(rx_escapable,function(t){var e=meta[t];return"string"==typeof e?e:"\\u"+("0000"+t.charCodeAt(0).toString(16)).slice(-4)})+'"':'"'+t+'"'}function str(t,e){var r,n,o,u,f,a=gap,i=e[t];switch(i&&"object"==typeof i&&"function"==typeof i.toJSON&&(i=i.toJSON(t)),"function"==typeof rep&&(i=rep.call(e,t,i)),typeof i){case"string":return quote(i);case"number":return isFinite(i)?String(i):"null";case"boolean":case"null":return String(i);case"object":if(!i)return"null";if(gap+=indent,f=[],"[object Array]"===Object.prototype.toString.apply(i)){for(u=i.length,r=0;r app.activeDocument?.path.fsName;
2 |
3 | export const getDocumentPath = () => app.activeDocument?.fullName.fsName;
4 |
5 | export const getDocumentName = () => app.activeDocument?.name;
6 |
--------------------------------------------------------------------------------
/src/jsx/phxs/phxs.ts:
--------------------------------------------------------------------------------
1 | import {
2 | helloVoid,
3 | helloError,
4 | helloStr,
5 | helloNum,
6 | helloArrayStr,
7 | helloObj,
8 | } from "../utils/samples";
9 | export { helloError, helloStr, helloNum, helloArrayStr, helloObj, helloVoid };
10 | import { dispatchTS } from "../utils/utils";
11 |
12 | export const helloWorld = () => {
13 | alert("Hello from Photoshop");
14 | };
15 |
--------------------------------------------------------------------------------
/src/jsx/phxs/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es3",
4 | "noLib": true,
5 | "strict": true,
6 | "types": [
7 | "../global",
8 | "../../../node_modules/types-for-adobe/Photoshop/2015.5",
9 | "../../../node_modules/types-for-adobe/shared/PlugPlugExternalObject"
10 | ]
11 | },
12 | "include": ["./**/*"]
13 | }
14 |
--------------------------------------------------------------------------------
/src/jsx/ppro/ppro-utils.ts:
--------------------------------------------------------------------------------
1 | // ProjectItem Helpers
2 |
3 | export const forEachChild = (
4 | item: ProjectItem,
5 | callback: (item: ProjectItem) => void
6 | ) => {
7 | const len = item.children.numItems;
8 | for (let i = 0; i < len; i++) {
9 | callback(item.children[i]);
10 | }
11 | };
12 |
13 | export const deleteItem = (item: ProjectItem) => {
14 | if (item.type === 2 /* BIN */) {
15 | item.deleteBin();
16 | } else {
17 | const tmpBin = app.project.rootItem.createBin("tmp");
18 | item.moveBin(tmpBin);
19 | tmpBin.deleteBin();
20 | }
21 | };
22 |
23 | export const getChildByName = (item: ProjectItem, name: string) => {
24 | for (let i = 0; i < item.children.numItems; i++) {
25 | const child = item.children[i];
26 | if (child.name === name) {
27 | return child;
28 | }
29 | }
30 | };
31 |
32 | export const getChildByNodeId = (item: ProjectItem, nodeId: string) => {
33 | for (let i = 0; i < item.children.numItems; i++) {
34 | const child = item.children[i];
35 | if (child.nodeId === nodeId) {
36 | return child;
37 | }
38 | }
39 | };
40 |
41 | export const getChildFromTreePath = (project: Project, treePath: string) => {
42 | const elements = treePath.split("\\"); // first item is blank, second is root
43 | let projectItem: ProjectItem | undefined = project.rootItem;
44 | for (let i = 2; i < elements.length; i++) {
45 | const item = elements[i];
46 | projectItem = getChildByName(projectItem, item);
47 | if (!projectItem) return null;
48 | }
49 | return projectItem;
50 | };
51 |
52 | export const getDescendantByNodeId = (
53 | item: ProjectItem,
54 | nodeId: string
55 | ): ProjectItem | undefined => {
56 | for (let i = 0; i < item.children.numItems; i++) {
57 | const child = item.children[i];
58 | if (child.nodeId === nodeId) {
59 | return child;
60 | } else if (child.type === 2 /* BIN */) {
61 | const found = getDescendantByNodeId(child, nodeId);
62 | if (found) return found;
63 | }
64 | }
65 | };
66 |
67 | export const getParentItem = (item: ProjectItem) => {
68 | const dir = item.treePath.split("\\");
69 | if (dir.length < 2) {
70 | return app.project.rootItem;
71 | }
72 | let current = app.project.rootItem;
73 | for (let i = 2; i < dir.length - 1; i++) {
74 | const name = dir[i];
75 | const next = getChildByName(current, name);
76 | if (next) {
77 | current = next;
78 | }
79 | }
80 | return current;
81 | };
82 |
83 | export const findItemByPath = (
84 | item: ProjectItem,
85 | path: string
86 | ): ProjectItem | undefined => {
87 | const len = item.children.numItems;
88 | for (let i = 0; i < len; i++) {
89 | const child = item.children[i];
90 | if (child.children && child.children.numItems > 0) {
91 | const res = findItemByPath(child, path);
92 | if (res) {
93 | return res;
94 | }
95 | } else if (child.getMediaPath() === path) {
96 | return child;
97 | }
98 | }
99 | };
100 |
101 | // Sequence Helpers
102 |
103 | export const getSequenceFromProjectItem = (item: ProjectItem) => {
104 | for (let i = 0; i < app.project.sequences.numSequences; i++) {
105 | const seq = app.project.sequences[i];
106 | if (seq.projectItem.nodeId === item.nodeId) {
107 | return seq;
108 | }
109 | }
110 | };
111 |
112 | export const getSequenceLengthInFrames = (seq: Sequence) => {
113 | const settings = seq.getSettings();
114 | const end = seq.end;
115 | const fps = settings.videoFrameRate.ticks;
116 | const frames = parseInt(end) / parseInt(fps);
117 | return frames;
118 | };
119 |
120 | export const forEachVideoTrack = (
121 | sequence: Sequence,
122 | callback: (track: Track, index: number) => void,
123 | reverse?: boolean
124 | ) => {
125 | const num = sequence.videoTracks.numTracks;
126 | if (reverse) {
127 | for (let i = num - 1; i > -1; i--) {
128 | callback(sequence.videoTracks[i], i);
129 | }
130 | } else {
131 | for (let i = 0; i < num; i++) {
132 | callback(sequence.videoTracks[i], i);
133 | }
134 | }
135 | };
136 |
137 | export const forEachAudioTrack = (
138 | sequence: Sequence,
139 | callback: (track: Track, index: number) => void,
140 | reverse?: boolean
141 | ) => {
142 | const num = sequence.audioTracks.numTracks;
143 | if (reverse) {
144 | for (let i = num - 1; i > -1; i--) {
145 | callback(sequence.audioTracks[i], i);
146 | }
147 | } else {
148 | for (let i = 0; i < num; i++) {
149 | callback(sequence.audioTracks[i], i);
150 | }
151 | }
152 | };
153 |
154 | export const forEachClip = (
155 | track: Track,
156 | callback: (clip: TrackItem, index: number) => void,
157 | reverse?: boolean
158 | ) => {
159 | const num = track.clips.numItems;
160 | if (reverse) {
161 | for (let i = num - 1; i > -1; i--) {
162 | callback(track.clips[i], i);
163 | }
164 | } else {
165 | for (let i = 0; i < num; i++) {
166 | callback(track.clips[i], i);
167 | }
168 | }
169 | };
170 |
171 | // Time Helpers
172 |
173 | export const addTime = (a: Time, b: Time) => {
174 | const ticks = parseInt(a.ticks) + parseInt(b.ticks);
175 | let time = new Time();
176 | time.ticks = ticks.toString();
177 | return time;
178 | };
179 |
180 | export const subtractTime = (a: Time, b: Time) => {
181 | const ticks = parseInt(a.ticks) - parseInt(b.ticks);
182 | let time = new Time();
183 | time.ticks = ticks.toString();
184 | return time;
185 | };
186 | export const multiplyTime = (a: Time, factor: number) => {
187 | const ticks = parseInt(a.ticks) * factor;
188 | let time = new Time();
189 | time.ticks = ticks.toString();
190 | return time;
191 | };
192 | export const divideTime = (a: Time, factor: number) => {
193 | const ticks = parseInt(a.ticks) / factor;
194 | let time = new Time();
195 | time.ticks = ticks.toString();
196 | return time;
197 | };
198 |
199 | export const ticksToTime = (ticks: string) => {
200 | let time = new Time();
201 | time.ticks = ticks;
202 | return time;
203 | };
204 |
205 | const fpsTicksTable: { [key: number]: number } = {
206 | 23.976: 10594584000,
207 | 24: 10584000000,
208 | 25: 10160640000,
209 | 29.97: 8475667200,
210 | 30: 8467200000,
211 | 50: 5080320000,
212 | 59.94: 4237833600,
213 | 60: 4233600000,
214 | };
215 |
216 | export const getItemFrameRate = (item: ProjectItem) => {
217 | if (item.isSequence()) {
218 | const sequence = getSequenceFromProjectItem(item);
219 | if (sequence) {
220 | return 1 / sequence.getSettings().videoFrameRate.seconds;
221 | }
222 | } else {
223 | const key = "Column.Intrinsic.MediaTimebase";
224 | const mediaTimeBase = getPrMetadata(item, [key]);
225 | return parseFloat(mediaTimeBase[key]);
226 | }
227 | };
228 |
229 | export const getItemDuration = (item: ProjectItem) => {
230 | const key = "Column.Intrinsic.MediaDuration";
231 | const res = getPrMetadata(item, [key]);
232 | return parseFloat(res[key]);
233 | };
234 |
235 | export const getFPSTime = (fps: number) => {
236 | let time = new Time();
237 | let ticks = fpsTicksTable[fps];
238 | if (!ticks) return false;
239 | time.ticks = ticks.toString();
240 | return time;
241 | };
242 |
243 | export const ticksToFrames = (ticks: string, timebase: string) => {
244 | const timebaseNum = parseInt(timebase);
245 | return parseInt(ticks) / timebaseNum;
246 | };
247 |
248 | export const timecodeToSeconds = (timecode: string, frameRate: number) => {
249 | const segments = timecode.split(":");
250 | const hours = parseInt(segments[0]);
251 | const minutes = parseInt(segments[1]);
252 | const seconds = parseInt(segments[2]);
253 | const frames = parseInt(segments[3]);
254 | return hours * 3600 + minutes * 60 + seconds + frames / frameRate;
255 | };
256 |
257 | export const timecodeToTicks = (timecode: string, frameRate: number) => {
258 | const segments = timecode.split(":");
259 | const hours = parseInt(segments[0]);
260 | const minutes = parseInt(segments[1]);
261 | const seconds = parseInt(segments[2]);
262 | const frames = parseInt(segments[3]);
263 | const totalSeconds =
264 | hours * 3600 + minutes * 60 + seconds + frames / frameRate;
265 | const ticks = totalSeconds * 10000000; // 1 second = 10,000,000 ticks
266 | return Math.round(ticks);
267 | };
268 |
269 | export const secondsToTime = (seconds: number) => {
270 | let time = new Time();
271 | time.seconds = seconds;
272 | return time;
273 | };
274 |
275 | export const getTimecode = (
276 | t: Time,
277 | frameRateTime: Time,
278 | videoDisplayFormat: number
279 | ) => {
280 | const timecode = t.getFormatted(frameRateTime, videoDisplayFormat) as string;
281 | return timecode;
282 | };
283 |
284 | export const getTimecodeFromSequence = (t: Time, sequence: Sequence) => {
285 | return getTimecode(
286 | t,
287 | sequence.getSettings().videoFrameRate,
288 | sequence.getSettings().videoDisplayFormat
289 | );
290 | };
291 |
292 | // QE DOM Methods
293 |
294 | export const qeGetClipAt = (track: Track, index: number) => {
295 | let curClipIndex = -1;
296 | for (let i = 0; i < track.numItems; i++) {
297 | const item = track.getItemAt(i);
298 | //@ts-ignore
299 | const type = item.type as "Empty" | "Clip";
300 | if (type === "Clip") {
301 | curClipIndex++;
302 | if (curClipIndex === index) {
303 | return item;
304 | }
305 | }
306 | }
307 | };
308 |
309 | // QE DOM doesn't understand some format, so this function so we convert to compatible ones
310 | export const qeSafeTimeDisplayFormat = (timeDisplayFormat: number) => {
311 | const conversionTable: {
312 | [key: number]: number;
313 | } = {
314 | 998: 110, // 23.89 > 23.976
315 | };
316 | const match = conversionTable[timeDisplayFormat];
317 | return match ? match : timeDisplayFormat;
318 | };
319 |
320 | // Metadata Helpers
321 |
322 | export const getPrMetadata = (projectItem: ProjectItem, fields: string[]) => {
323 | let PProMetaURI = "http://ns.adobe.com/premierePrivateProjectMetaData/1.0/";
324 | if (ExternalObject.AdobeXMPScript === undefined) {
325 | ExternalObject.AdobeXMPScript = new ExternalObject("lib:AdobeXMPScript");
326 | }
327 | if (!app.isDocumentOpen() || !ExternalObject.AdobeXMPScript || !XMPMeta) {
328 | return {};
329 | }
330 | let xmp = new XMPMeta(projectItem.getProjectMetadata());
331 | let result: {
332 | [key: string]: string;
333 | } = {};
334 | for (let i = 0; i < fields.length; i++) {
335 | if (xmp.doesPropertyExist(PProMetaURI, fields[i])) {
336 | result[fields[i]] = xmp.getProperty(PProMetaURI, fields[i]).value;
337 | }
338 | }
339 | return result;
340 | };
341 |
342 | export const setPrMetadata = (
343 | projectItem: ProjectItem,
344 | data: {
345 | fieldName: string;
346 | fieldId: string;
347 | value: string;
348 | }[]
349 | ) => {
350 | let PProMetaURI = "http://ns.adobe.com/premierePrivateProjectMetaData/1.0/";
351 | if (ExternalObject.AdobeXMPScript === undefined) {
352 | ExternalObject.AdobeXMPScript = new ExternalObject("lib:AdobeXMPScript");
353 | }
354 | if (!app.isDocumentOpen() || !ExternalObject.AdobeXMPScript || !XMPMeta) {
355 | return {};
356 | }
357 | let xmp = new XMPMeta(projectItem.getProjectMetadata());
358 | for (var i = 0; i < data.length; i++) {
359 | let item = data[i];
360 | var successfullyAdded = app.project.addPropertyToProjectMetadataSchema(
361 | item.fieldName,
362 | item.fieldId,
363 | 2
364 | );
365 | }
366 | var array = [];
367 | for (var i = 0; i < data.length; i++) {
368 | let item = data[i];
369 | xmp.setProperty(PProMetaURI, item.fieldName, item.value);
370 | array.push(item.fieldName);
371 | }
372 | var str = xmp.serialize();
373 | projectItem.setProjectMetadata(str, array);
374 | };
375 |
376 | export const removePrMetadata = (
377 | projectItem: ProjectItem,
378 | fields: string[]
379 | ) => {
380 | let PProMetaURI = "http://ns.adobe.com/premierePrivateProjectMetaData/1.0/";
381 | if (ExternalObject.AdobeXMPScript === undefined) {
382 | ExternalObject.AdobeXMPScript = new ExternalObject("lib:AdobeXMPScript");
383 | }
384 | if (!app.isDocumentOpen() || !ExternalObject.AdobeXMPScript || !XMPMeta) {
385 | return {};
386 | }
387 | let xmp = new XMPMeta(projectItem.getProjectMetadata());
388 | var array = [];
389 | for (var i = 0; i < fields.length; i++) {
390 | xmp.deleteProperty(PProMetaURI, fields[i]);
391 | array.push(fields[i]);
392 | }
393 | var str = xmp.serialize();
394 | projectItem.setProjectMetadata(str, array);
395 | };
396 |
397 | // Motion Graphics Template ( MOGRT ) Helpers
398 |
399 | export const fillMogrtText = (
400 | clip: TrackItem,
401 | propName: string,
402 | text: string
403 | ) => {
404 | const mgt = clip.getMGTComponent();
405 | const prop = mgt.properties.getParamForDisplayName(propName);
406 | if (prop) {
407 | const valueStr = prop.getValue();
408 | let value = JSON.parse(valueStr) as any;
409 | value.textEditValue = text;
410 | prop.setValue(JSON.stringify(value), true);
411 | }
412 | };
413 |
414 | // Audio Conversions
415 |
416 | export const dbToDec = (x: number) => Math.pow(10, (x - 15) / 20);
417 |
418 | export const decToDb = (x: number) => 20 * Math.log(x) * Math.LOG10E + 15;
419 |
--------------------------------------------------------------------------------
/src/jsx/ppro/ppro.ts:
--------------------------------------------------------------------------------
1 | import {
2 | helloVoid,
3 | helloError,
4 | helloStr,
5 | helloNum,
6 | helloArrayStr,
7 | helloObj,
8 | } from "../utils/samples";
9 | export { helloError, helloStr, helloNum, helloArrayStr, helloObj, helloVoid };
10 | import { dispatchTS } from "../utils/utils";
11 |
12 | export const qeDomFunction = () => {
13 | if (typeof qe === "undefined") {
14 | app.enableQE();
15 | }
16 | if (qe) {
17 | qe.name;
18 | qe.project.getVideoEffectByName("test");
19 | }
20 | };
21 |
22 | export const helloWorld = () => {
23 | alert("Hello from Premiere Pro.");
24 | };
25 |
--------------------------------------------------------------------------------
/src/jsx/ppro/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es3",
4 | "noLib": true,
5 | "strict": true,
6 | "types": [
7 | "../global",
8 | "../../../node_modules/types-for-adobe/Premiere/24.0",
9 | "../../../node_modules/types-for-adobe-extras/Premiere/12.0/qeDom",
10 | "../../../node_modules/types-for-adobe/shared/PlugPlugExternalObject"
11 | ]
12 | },
13 | "include": ["./**/*"]
14 | }
15 |
--------------------------------------------------------------------------------
/src/jsx/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es3",
4 | "noLib": true,
5 | "strict": true,
6 | "types": [
7 | "./global",
8 | "../../node_modules/types-for-adobe/shared/global",
9 | "../../node_modules/types-for-adobe/shared/PlugPlugExternalObject"
10 | ]
11 | },
12 | "include": ["./**/*"]
13 | }
14 |
--------------------------------------------------------------------------------
/src/jsx/utils/samples.ts:
--------------------------------------------------------------------------------
1 | export const helloVoid = (): void => {
2 | alert("test");
3 | };
4 | export const helloError = (str: string) => {
5 | // Intentional Error for Error Handling Demonstration
6 | //@ts-ignore
7 | throw new Error(`We're throwing an error`);
8 | };
9 |
10 | export const helloStr = (str: string) => {
11 | alert(`ExtendScript received a string: ${str}`);
12 | return str;
13 | };
14 | export const helloNum = (n: number) => {
15 | alert(`ExtendScript received a number: ${n.toString()}`);
16 | return n;
17 | };
18 | export const helloArrayStr = (arr: string[]) => {
19 | alert(
20 | `ExtendScript received an array of ${arr.length} strings: ${arr.toString()}`
21 | );
22 | return arr;
23 | };
24 | export const helloObj = (obj: { height: number; width: number }) => {
25 | alert(`ExtendScript received an object: ${JSON.stringify(obj)}`);
26 | return {
27 | y: obj.height,
28 | x: obj.width,
29 | };
30 | };
31 |
--------------------------------------------------------------------------------
/src/jsx/utils/utils.ts:
--------------------------------------------------------------------------------
1 | import type { EventTS } from "../../shared/universals";
2 | import { ns } from "../../shared/shared";
3 |
4 | /**
5 | * @function dispatchTS Displatches an event to the CEP panel with Type-Safety
6 | * See listenTS() in the CEP panel for more info
7 | * @param event The event name to listen for (defined in EventTS in shared/universals.ts)
8 | * @param callback The callback function to be executed when the event is triggered
9 | */
10 | export const dispatchTS = (
11 | event: Key,
12 | data: EventTS[Key]
13 | ) => {
14 | if (new ExternalObject("lib:PlugPlugExternalObject")) {
15 | var eventObj = new CSXSEvent();
16 | eventObj.type = `${ns}.${event}`;
17 | eventObj.data = JSON.stringify(data);
18 | eventObj.dispatch();
19 | }
20 | };
21 |
22 | export const forEach = (
23 | arr: T[],
24 | callback: (item: T, i: number) => void
25 | ): void => {
26 | for (let i = 0; i < arr.length; i++) {
27 | callback(arr[i], i);
28 | }
29 | };
30 |
31 | export const map = (
32 | arr: T[],
33 | callback: (item: T, i: number) => any
34 | ): T[] => {
35 | let res = [];
36 | for (let i = 0; i < arr.length; i++) {
37 | res.push(callback(arr[i], i));
38 | }
39 | return res;
40 | };
41 |
42 | export const filter = (
43 | arr: T[],
44 | func: (item: T, i: number) => boolean
45 | ): T[] => {
46 | let res = [];
47 | for (let i = 0; i < arr.length; i++) {
48 | if (func(arr[i], i)) {
49 | res.push(arr[i]);
50 | }
51 | }
52 | return res;
53 | };
54 |
55 | export const includes = (arr: T[], value: string | number) => {
56 | for (let i = 0; i < arr.length; i++) {
57 | const element = arr[i];
58 | if (element === value) {
59 | return true;
60 | }
61 | }
62 | return false;
63 | };
64 |
65 | export const indexOf = (arr: T[], value: string | number) => {
66 | for (let i = 0; i < arr.length; i++) {
67 | const element = arr[i];
68 | if (element === value) {
69 | return i;
70 | }
71 | }
72 | return -1;
73 | };
74 |
75 | // Joins paths
76 | export const join = (...args: string[]) => {
77 | const sep = $.os === "Windows" ? "\\" : "/";
78 | const len = args.length;
79 | let res = args[0];
80 | for (let i = 1; i < len; i++) {
81 | res = res + sep + args[i];
82 | }
83 | return res;
84 | };
85 |
--------------------------------------------------------------------------------
/src/shared/shared.ts:
--------------------------------------------------------------------------------
1 | import config from "../../cep.config";
2 | export const ns = config.id;
3 | export const company = config.zxp.org;
4 | export const displayName = config.displayName;
5 | export const version = config.version;
6 |
--------------------------------------------------------------------------------
/src/shared/universals.d.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * @description Declare event types for listening with listenTS() and dispatching with dispatchTS()
3 | */
4 | export type EventTS = {
5 | myCustomEvent: {
6 | oneValue: string;
7 | anotherValue: number;
8 | };
9 | };
10 |
--------------------------------------------------------------------------------
/tsconfig-build.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.json",
3 | "compilerOptions": {
4 | "noImplicitAny": false,
5 | "paths": {
6 | "@esTypes/*": ["./src/js/lib/cep/es-types"]
7 | }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ESNext",
4 | "useDefineForClassFields": true,
5 | "lib": ["DOM", "DOM.Iterable", "ESNext"],
6 | "allowJs": false,
7 | "skipLibCheck": true,
8 | "esModuleInterop": false,
9 | "allowSyntheticDefaultImports": true,
10 | "strict": true,
11 | "forceConsistentCasingInFileNames": true,
12 | "module": "ESNext",
13 | "moduleResolution": "Node",
14 | "resolveJsonModule": true,
15 | "isolatedModules": false,
16 | "noEmit": true,
17 | "jsx": "react-jsx",
18 | "paths": {
19 | "@esTypes/*": ["./src/jsx"]
20 | }
21 | },
22 | "include": ["./src"],
23 | "exclude": [
24 | "./src/jsx",
25 | "./src/js/template-*",
26 | "node_modules/@types/react/index.d.ts"
27 | ]
28 | }
29 |
--------------------------------------------------------------------------------
/tsconfig.react.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ESNext",
4 | "useDefineForClassFields": true,
5 | "lib": ["DOM", "DOM.Iterable", "ESNext"],
6 | "allowJs": false,
7 | "skipLibCheck": true,
8 | "esModuleInterop": false,
9 | "allowSyntheticDefaultImports": true,
10 | "strict": true,
11 | "forceConsistentCasingInFileNames": true,
12 | "module": "ESNext",
13 | "moduleResolution": "Node",
14 | "resolveJsonModule": true,
15 | "isolatedModules": true,
16 | "noEmit": true,
17 | "jsx": "react-jsx",
18 | "paths": {
19 | "@esTypes/*": ["./src/jsx"]
20 | }
21 | },
22 | "include": ["./src"],
23 | "exclude": ["./src/jsx"]
24 | }
25 |
--------------------------------------------------------------------------------
/tsconfig.svelte.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ESNext",
4 | "useDefineForClassFields": true,
5 | "lib": ["DOM", "DOM.Iterable", "ESNext"],
6 | "allowJs": false,
7 | "skipLibCheck": true,
8 | "esModuleInterop": false,
9 | "allowSyntheticDefaultImports": true,
10 | "strict": true,
11 | "forceConsistentCasingInFileNames": true,
12 | "module": "ESNext",
13 | "moduleResolution": "Node",
14 | "resolveJsonModule": true,
15 | "isolatedModules": true,
16 | "noEmit": true,
17 | "jsx": "preserve",
18 | "paths": {
19 | "@esTypes/*": ["./src/jsx"]
20 | }
21 | },
22 | "include": ["./src"],
23 | "exclude": ["./src/jsx"]
24 | }
25 |
--------------------------------------------------------------------------------
/tsconfig.vue.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ESNext",
4 | "useDefineForClassFields": true,
5 | "lib": ["DOM", "DOM.Iterable", "ESNext"],
6 | "allowJs": false,
7 | "skipLibCheck": true,
8 | "esModuleInterop": false,
9 | "allowSyntheticDefaultImports": true,
10 | "strict": true,
11 | "forceConsistentCasingInFileNames": true,
12 | "module": "ESNext",
13 | "moduleResolution": "Node",
14 | "resolveJsonModule": true,
15 | "isolatedModules": false,
16 | "noEmit": true,
17 | "jsx": "preserve",
18 | "paths": {
19 | "@esTypes/*": ["./src/jsx"]
20 | }
21 | },
22 | "include": ["./src"],
23 | "exclude": ["./src/jsx"]
24 | }
25 |
--------------------------------------------------------------------------------
/vite-cep-plugin/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | *.p12
3 | /lib
4 | yarn-error.log
5 | *.DS_Store
--------------------------------------------------------------------------------
/vite-cep-plugin/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) Hyper Brew LLC
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/vite-cep-plugin/README.md:
--------------------------------------------------------------------------------
1 | # Vite CEP Plugin
2 |
3 | 
4 | [](https://github.com/hyperbrew/vite-cep-plugin/blob/master/LICENSE)
5 | [](https://discord.gg/PC3EvvuRbc)
6 |
7 | A plugin for bundling Adobe CEP Extension panels with the Vite.js bundler.
8 |
9 | Intented to be used with the `Bolt CEP` bolierplate: https://github.com/hyperbrew/bolt-cep
10 |
11 | Install or update with `yarn add vite-cep-plugin`
12 |
--------------------------------------------------------------------------------
/vite-cep-plugin/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vite-cep-plugin",
3 | "version": "2.0.0",
4 | "description": "A Vite Plugin for building Adobe CEP Extension Panels",
5 | "main": "lib/index.js",
6 | "types": "lib/index.d.ts",
7 | "repository": {
8 | "type": "git",
9 | "url": "https://github.com/hyperbrew/bolt-cep.git"
10 | },
11 | "homepage": "https://github.com/hyperbrew/bolt-cep",
12 | "license": "MIT",
13 | "scripts": {
14 | "build": "tsc && node scripts/copy-files.js",
15 | "prepare": "npm run build",
16 | "publish": "npm publish --access public",
17 | "publish-beta": "npm publish --access public --tag beta"
18 | },
19 | "devDependencies": {
20 | "@types/fs-extra": "^9.0.13",
21 | "@types/ws": "^8.2.2",
22 | "ts-node": "^10.4.0",
23 | "typescript": "^4.6.4",
24 | "vite": "^4.0.5"
25 | },
26 | "dependencies": {
27 | "@types/archiver": "^5.3.1",
28 | "archiver": "^5.3.1",
29 | "fs-extra": "^10.0.0",
30 | "jszip": "^3.10.1",
31 | "magic-string": "^0.25.7",
32 | "meta-bolt": "^0.0.15",
33 | "prettify-xml": "^1.2.0"
34 | },
35 | "optionalDependencies": {
36 | "jsxbin": "^2.3.0"
37 | },
38 | "files": [
39 | "lib/**/*"
40 | ]
41 | }
42 |
--------------------------------------------------------------------------------
/vite-cep-plugin/scripts/copy-files.js:
--------------------------------------------------------------------------------
1 | var fs = require("fs-extra");
2 | var path = require("path");
3 | var src = path.join(process.cwd(), "src", "bin");
4 | var dst = path.join(process.cwd(), "lib", "bin");
5 | fs.ensureDirSync(dst);
6 | fs.copySync(src, dst);
7 |
--------------------------------------------------------------------------------
/vite-cep-plugin/scripts/copy-files.ts:
--------------------------------------------------------------------------------
1 | //@ts-nocheck
2 | import * as fs from "fs-extra";
3 | import * as path from "path";
4 |
5 | const src = path.join(process.cwd(), "src", "bin");
6 | const dst = path.join(process.cwd(), "lib", "bin");
7 | fs.ensureDirSync(dst);
8 | fs.copySync(src, dst);
9 |
--------------------------------------------------------------------------------
/vite-cep-plugin/src/bin/ZXPSignCmd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hyperbrew/bolt-cep/e23b2d0408a5962c3041ac0926feed86704f76bb/vite-cep-plugin/src/bin/ZXPSignCmd
--------------------------------------------------------------------------------
/vite-cep-plugin/src/bin/ZXPSignCmd.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hyperbrew/bolt-cep/e23b2d0408a5962c3041ac0926feed86704f76bb/vite-cep-plugin/src/bin/ZXPSignCmd.exe
--------------------------------------------------------------------------------
/vite-cep-plugin/src/cep-config.ts:
--------------------------------------------------------------------------------
1 | // For more details on Manifest Preferences see:
2 | // https://github.com/Adobe-CEP/CEP-Resources/blob/master/CEP_11.x/Documentation/CEP%2011.1%20HTML%20Extension%20Cookbook.md
3 |
4 | type CEP_Host_Name =
5 | | "PHSP"
6 | | "PHXS"
7 | | "IDSN"
8 | | "AICY"
9 | | "ILST"
10 | | "PPRO"
11 | | "PRLD"
12 | | "AEFT"
13 | | "FLPR"
14 | | "AUDT"
15 | | "DRWV"
16 | | "KBRG"
17 | | "AME"
18 | | "MUSE"
19 | | "LTRM"
20 | | "DEMO"
21 | | "BRDG"
22 | | "RUSH";
23 |
24 | type CEP_Host = {
25 | name: CEP_Host_Name;
26 | version: string;
27 | };
28 |
29 | export type JSXBIN_MODE = "off" | "copy" | "replace";
30 |
31 | type CEF_Command =
32 | | "--enable-media-stream"
33 | | "--enable-speech-input"
34 | | "--enable-file-cookies"
35 | | "--enable-nodejs"
36 | | "--persist-session-cookies"
37 | | "--disable-image-loading"
38 | | "--disable-javascript-open-windows"
39 | | "--disable-javascript-close-windows"
40 | | "--disable-javascript-access-clipboard"
41 | | "--disable-site-isolation-trials"
42 | | "--enable-caret-browsing"
43 | | "--proxy-auto-detect"
44 | | "--user-agent"
45 | | "--disable-application-cache"
46 | | "--disable-pinch"
47 | | "--mixed-context"
48 | | "--allow-file-access"
49 | | "--allow-file-access-from-files"
50 | | "--disable-popup-blocking"
51 | | "--aggressive-cache-discard"
52 | | "--winhttp-proxy-resolver"
53 | | "--v=0"
54 | | "--v=1"
55 | | "--v=2"
56 | | "--v=3"
57 | | "--v=4"
58 | | "--v=5";
59 |
60 | type CEP_Panel_Type =
61 | | "Panel"
62 | | "ModalDialog"
63 | | "Modeless"
64 | | "Custom"
65 | | "Embedded";
66 |
67 | export interface CEP_Panel {
68 | mainPath: string;
69 | name: string;
70 | panelDisplayName?: string | null;
71 | autoVisible: boolean;
72 | width?: number;
73 | height?: number;
74 | maxWidth?: number;
75 | maxHeight?: number;
76 | minWidth?: number;
77 | minHeight?: number;
78 | scriptPath?: string;
79 | host?: string;
80 | type?: CEP_Panel_Type;
81 | id?: string;
82 | iconDarkNormal?: string;
83 | iconNormal?: string;
84 | iconDarkNormalRollOver?: string;
85 | iconNormalRollOver?: string;
86 | parameters?: CEF_Command[];
87 | startOnEvents?: string[];
88 | }
89 |
90 | export interface CEP_Extended_Panel extends CEP_Panel {
91 | id: string;
92 | parameters: CEF_Command[];
93 | type: CEP_Panel_Type;
94 | }
95 |
96 | export interface CEP_Config {
97 | port: number;
98 | servePort: number;
99 | symlink: "local" | "global";
100 | startingDebugPort: number;
101 | version: string;
102 | id: string;
103 | displayName: string;
104 | extensionManifestVersion: number;
105 | requiredRuntimeVersion: number;
106 | hosts: CEP_Host[];
107 | type: CEP_Panel_Type;
108 | iconDarkNormal?: string;
109 | iconNormal?: string;
110 | iconDarkNormalRollOver?: string;
111 | iconNormalRollOver?: string;
112 | parameters: CEF_Command[];
113 | scriptPath?: string;
114 | width?: number;
115 | height?: number;
116 | maxWidth?: number;
117 | maxHeight?: number;
118 | minWidth?: number;
119 | minHeight?: number;
120 | standalone?: boolean;
121 |
122 | panels: CEP_Panel[];
123 |
124 | build?: {
125 | sourceMap?: boolean;
126 | jsxBin?: JSXBIN_MODE;
127 | };
128 | zxp: {
129 | country: string;
130 | province: string;
131 | org: string;
132 | password: string;
133 | tsa?: string | string[];
134 | allowSkipTSA?: boolean;
135 | sourceMap?: boolean;
136 | jsxBin?: JSXBIN_MODE;
137 | };
138 | installModules?: string[];
139 | copyAssets?: string[];
140 | copyZipAssets?: string[];
141 | }
142 |
143 | export interface CEP_Config_Extended extends CEP_Config {
144 | panels: CEP_Extended_Panel[];
145 | }
146 |
--------------------------------------------------------------------------------
/vite-cep-plugin/src/copy-node.ts:
--------------------------------------------------------------------------------
1 | import * as path from "path";
2 | import * as fs from "fs-extra";
3 |
4 | export const unique = (array: any) => {
5 | return array.filter((v: string, i: number, a: string) => a.indexOf(v) === i);
6 | };
7 |
8 | interface NodeSolveArgs {
9 | src: string;
10 | pkg: string;
11 | keepDevDependencies: boolean;
12 | }
13 |
14 | const nodeSolve = ({ src, pkg, keepDevDependencies }: NodeSolveArgs) => {
15 | let allDependencies = [pkg];
16 | const fullPath = path.join(src, "node_modules", pkg);
17 | // console.log(`getting pkgs for ${fullPath}`);
18 | const pkgJson = path.join(fullPath, "package.json");
19 | if (fs.existsSync(pkgJson)) {
20 | const raw = fs.readFileSync(pkgJson, { encoding: "utf-8" });
21 | const json = JSON.parse(raw);
22 | let { dependencies, devDependencies } = json;
23 | const depList = dependencies ? Object.keys(dependencies) : [];
24 | const devDepList = devDependencies ? Object.keys(devDependencies) : [];
25 | const resDepList = keepDevDependencies
26 | ? depList.concat(devDepList)
27 | : depList;
28 | if (resDepList.length > 0) {
29 | allDependencies = allDependencies.concat(resDepList);
30 | resDepList.map((name) => {
31 | allDependencies = allDependencies.concat(
32 | nodeSolve({ src, pkg: name, keepDevDependencies })
33 | );
34 | });
35 | }
36 | }
37 | return allDependencies || [];
38 | };
39 |
40 | interface CopyModulesArgs {
41 | packages: string[];
42 | src: string;
43 | dest: string;
44 | symlink: boolean;
45 | }
46 |
47 | export const copyModules = ({
48 | packages,
49 | src,
50 | dest,
51 | symlink,
52 | }: CopyModulesArgs) => {
53 | const allPkg = packages.flatMap((pkg) =>
54 | nodeSolve({ src, pkg, keepDevDependencies: false })
55 | );
56 | const uniqePkg = unique(allPkg);
57 | console.log(
58 | `Copying ${packages.length} Node Module(s) (${
59 | uniqePkg.length
60 | } Dependencies) : ${packages.join(",")}`
61 | );
62 | fs.ensureDirSync(path.join(dest, "node_modules"));
63 | uniqePkg.map((pkg: string) => {
64 | const fullSrcPath = path.join(process.cwd(), src, "node_modules", pkg);
65 | const fullDstPath = path.join(process.cwd(), dest, "node_modules", pkg);
66 | fs.ensureDirSync(path.dirname(fullDstPath));
67 | if (!symlink) {
68 | fs.copySync(fullSrcPath, fullDstPath, {dereference: true});
69 | } else {
70 | fs.ensureSymlink(fullSrcPath, fullDstPath, "dir");
71 | }
72 | });
73 | };
74 |
75 | interface CopyFilesArgs {
76 | src: string;
77 | dest: string;
78 | assets: string[];
79 | }
80 |
81 | export const copyFiles = ({ src, dest, assets }: CopyFilesArgs) => {
82 | console.log(`Copying ${assets.length} Assets`);
83 | // fs.ensureDirSync(path.join(dest, "node_modules"));
84 | assets.map((asset: string) => {
85 | const fullSrcPath = path.join(src, asset);
86 | if (asset.indexOf("/*") === asset.length - 2) {
87 | // flatten folder
88 | const folder = asset.substring(0, asset.length - 2);
89 | const files = fs.readdirSync(path.join(src, folder));
90 |
91 | files.map((file) => {
92 | const fullSrcPath = path.join(src, folder, file);
93 | const fullDstPath = path.join(dest, file);
94 | console.log(`COPY ${fullSrcPath} to ${fullDstPath}`);
95 | fs.ensureDirSync(path.dirname(fullDstPath));
96 | fs.copySync(fullSrcPath, fullDstPath);
97 | });
98 | } else {
99 | const fullDstPath = path.join(dest, asset);
100 | console.log(`COPY ${fullSrcPath} to ${fullDstPath}`);
101 | fs.ensureDirSync(path.dirname(fullDstPath));
102 | fs.copySync(fullSrcPath, fullDstPath);
103 | }
104 | });
105 | };
106 |
107 | const rollupNodeCopyPlugin = ({
108 | packages,
109 | src,
110 | dest,
111 | symlink,
112 | }: CopyModulesArgs) => {
113 | return {
114 | name: "copy-node-modules",
115 | buildEnd: async () => {
116 | copyModules({ packages, src, dest, symlink });
117 | },
118 | };
119 | };
120 |
121 | export default rollupNodeCopyPlugin;
122 |
--------------------------------------------------------------------------------
/vite-cep-plugin/src/lib/lib.ts:
--------------------------------------------------------------------------------
1 | export const fixAssetPathJS = (code: string) => {
2 | code = code.replace(/\=\"\.\/assets/g, `="../assets`);
3 | code = code.replace(/\=\"\/assets/g, `="../assets`);
4 | code = code.replace(/\(\"\.\/assets/g, `("../assets`);
5 | code = code.replace(/\(\"\/assets/g, `("../assets`);
6 | return code;
7 | };
8 |
9 | export const fixAssetPathCSS = (code: string) => {
10 | code = code.replace(/\(\.\/assets/g, `(../assets`);
11 | code = code.replace(/\(\/assets/g, `(./`);
12 | return code;
13 | };
14 |
15 | export const fixAssetPathHTML = (code: string) => {
16 | code = code.replace(/\=\"\/assets/g, `="../assets`);
17 | return code;
18 | };
19 |
20 | export const removeModuleTags = (code: string) => {
21 | code = code.replace(/\/g, "");
22 | code = code.replace(/\
18 |
19 |
20 |
21 |
22 |
25 |
26 |