Skip to content
thelabcornerPublic

About

RFC 9562 UUIDs for Adobe ExtendScript ES3

Topics

Resources

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Latest commit

 

History

19 Commits

Folders and files

Repository files navigation

ESUUID: RFC 9562 UUIDs for Adobe ExtendScript (ES3)

ExtendScript UUID = E.S.UUID

UUID v1/v3/v4/v5/v6/v7 generation, parsing, validation, conversion, ESRAND-preferred entropy, and a warned Math.random fallback for Adobe ExtendScript hosts

RFC 9562 Differential Illustrator Adobe: Creative Suite Engine Size License: GPL-3.0-or-later


Part Of The Same Toolkit

Production-grade infrastructure for Adobe ExtendScript.

Runtime Primitives

ESON
Strict RFC 8259 JSON for ExtendScript.

ESB64
Base64 and UTF-8 utilities.

ESARR
ES5+ Array compatibility methods.

ESSTR
String whitespace and trim methods.

ESCHARS
Native bulk byte operations.

ESHTTP
HTTP transport for ExtendScript automation.

ESTIMER
Microsecond timing for ExtendScript automation.

ESRAND
Deterministic random streams and sampling for ExtendScript.

ESUUID
RFC 9562 UUID generation, parsing, and conversion for ExtendScript.

ESENV
Environment and capability detection for ExtendScript.

ESPATH
Deterministic Windows/POSIX path and RFC 8089 file-URI transformations.

ESFS
Synchronous ExtendScript File/Folder I/O with explicit text, BINARY, and replacement semantics.

ESHASH
CRC-32/ISO-HDLC and SHA-256 for byte strings and UTF-8 text.

ESLOG
Structured logging with bounded text and JSONL sinks.

Build & Integration Tools

ESPACK
Self-extracting ExternalObject bundles.

ESMIN
Minification for shipped JSX bundles.

ESABI
Modern ExternalObject ABI declarations for native integrations.

VectorIPC
Bounded local IPC for scripting hosts and native plug-ins.

ESTC
TypeScript-to-ExtendScript build, compatibility, and live-parse tooling.

ESDB
Native state and durable storage for Adobe tooling.

COMTool
Guarded COM, ExtendScript, plug-in, and debugger automation for Adobe desktop apps.

ESsemble
Typed framework, resolver, and composition layer for the ExtendScript toolkit.

Also from the same team: ArcFit.dev, deterministic arc warp for Illustrator.


Table of Contents


Why ESUUID?

ExtendScript is an ES3-era runtime with no standardized UUID API equivalent to modern crypto.randomUUID(). ESUUID provides the RFC 9562 UUID surface directly in ExtendScript syntax with an explicit entropy priority: caller-provided bytes/RNG, then ESRAND, then a warned non-cryptographic Math.random() fallback.

The default Adobe-host facade integrates with ESRAND when it is already installed as $.global.ESRAND. If ESRAND is missing and the caller does not provide entropy, ESUUID falls back to Math.random(), reports entropy: "Math.random-fallback", and emits a one-time warning on the first fallback entropy request.

ESUUID also targets the public API shape developers already know from uuidjs/uuid where that mapping is meaningful in ExtendScript. Differential validation currently covers 3,225 parity checks against [email protected].


Features

  • RFC 9562 UUID v1, v3, v4, v5, v6, and v7 generation.
  • RFC 9562 Appendix A vectors pass 6/6 for v1/v3/v4/v5/v6/v7.
  • parse, stringify, validate, and version match the uuidjs/uuid-style surface.
  • v1ToV6 and v6ToV1 conversions are included and differential-tested.
  • Namespace constants: DNS, URL, OID, and X500.
  • Special constants: NIL and MAX.
  • Explicit byte-array output buffers and offsets for generation and name-based UUIDs.
  • Stateful v1/v6 generation and monotonic v7 sequencing through create().
  • ESRAND-backed default entropy in Adobe hosts when $.global.ESRAND.bytes(count) is available.
  • Caller-injected rng, rand, and now sources for deterministic tests or custom integrations.
  • Warned Math.random() fallback when ESRAND and caller entropy are both unavailable.
  • Same-version global reload preserves the existing facade and stateful v1/v7 generator state.
  • Fresh minified and unminified artifacts are both exercised inside real Illustrator.
  • 55 unit checks, 3,225 differential checks, 75,000 fuzz invariants, and 54/54 standalone live Illustrator checks pass; the ESPACK composition lane separately proves ESRAND -> ESUUID activation with no sibling preload.

Which artifact should I use?

Artifact Size Surface Use it when
dist/ESUUID.min.jsx 14,595 bytes Installs $.global.ESUUID Default production ExtendScript script include
dist/ESUUID.jsx 18,746 bytes Installs $.global.ESUUID Readable/debuggable ExtendScript build
dist/vendor-esuuid.min.js 14,595 bytes Installs $.global.ESUUID Vendoring into another generated bundle
dist/vendor-esuuid.js 18,746 bytes Installs $.global.ESUUID Readable vendor input
dist/ESUUID.bundle.min.jsx 57,606 bytes ESPACK v2 activates ESRAND -> ESUUID Dependency-complete production include; no ESRAND preload
dist/ESUUID.bundle.jsx 89,890 bytes Same composed graph, readable Debugging the dependency-complete distribution
dist/ESUUID.facade.jsx 18,833 bytes Loader-free ESUUID library node Input to a larger ESPACK v2 composition
dist/ESUUID.manifest.json 77,143 bytes Exact ESRAND + ESUUID graph/provenance Build/composition input, not a runtime include
dist/esuuid-core.esm.mjs 20,459 bytes ESM exports Node-side tests, differential validation, or tooling

The standalone/vendor artifacts and the ESPACK facade are generated from the same src/jsx-entry.ts entry point. The composed bundle is resolved after those bytes exist: ESPACK reads the ESRAND v2 manifest, solves the dependency, then flattens one loader/control plane followed by ESRAND and ESUUID.

Rule of thumb: use ESUUID.bundle.min.jsx when you want the preferred ESRAND backend without managing sibling load order. Use ESUUID.min.jsx when the host intentionally owns the entropy backend lifecycle or wants the documented Math.random fallback.


Get the Release

Production artifacts ship as GitHub release assets. Grab the immutable builds from the Releases page.

Latest stable Release date Downloads

How it works, in three steps:

  1. Open the Releases page.
  2. Pick the latest stable tag.
  3. Download the asset that matches your use case:
You are... Take this release And this asset
Wanting the preferred ESRAND-backed production include with no sibling preload Latest stable ESUUID.bundle.min.jsx (readable: ESUUID.bundle.jsx)
Managing the entropy backend yourself or intentionally allowing the documented fallback Latest stable ESUUID.min.jsx (readable: ESUUID.jsx)
Composing ESUUID into a larger ESPACK distribution Latest stable ESUUID.facade.jsx + ESUUID.manifest.json
Vendoring ESUUID into another generated artifact Latest stable vendor-esuuid.min.js (readable: vendor-esuuid.js)
Consuming the reference core from Node tooling Latest stable esuuid-core.esm.mjs
Verifying immutable release provenance Latest stable esuuid-v0.2.0.lock.json + SHA256SUMS.txt + the preserved latest-*.json evidence assets

Installation

Use the checked-in ExtendScript build

ESUUID ships generated dist/ artifacts in the repository so a consumer does not need the TypeScript build toolchain just to use the library.

The dependency-complete distribution requires no manual sibling preload:

$.evalFile(File("/path/to/ESUUID.bundle.min.jsx"));

var id = ESUUID.v7();
// ESUUID.capabilities().entropy === "ESRAND"

That one file is an ESPACK v2 composition of ESRAND -> ESUUID. The resolver deduplicates transitive libraries and verifies both activation contracts before the root is considered active.

When using the standalone artifact instead, load ESRAND first when you want the same preferred default entropy backend:

$.evalFile(File("/path/to/vendor-esrand.js"));
$.evalFile(File("/path/to/ESUUID.min.jsx"));

var id = ESUUID.v7();

ESRAND is available at thelabcorner/es-rand.

The package-level ESRAND peer remains marked optional because the standalone facade intentionally supports a fallback. That host-time fallback is separate from the shipped ESUUID.bundle*.jsx contract, where ESRAND is a required composed dependency.

Build from source

Requirements:

  • Node.js 20 or newer.
  • Python 3 for the conservative ExtendScript minifier.
  • HTTPS access to the pinned public ESTC source archive.
git clone https://github.com/thelabcorner/es-uuid.git
cd es-uuid
npm ci
npm run build

The build uses the pinned ESTC source archive installed by npm ci by default. Inside the wider toolkit workspace, set ESUUID_USE_WORKSPACE_ESTC=1 to opt into the sibling ../extendscript-toolchain checkout.

Run without ESRAND

ESUUID can load without ESRAND. If you call a random UUID method without supplying entropy, the Adobe facade falls back to Math.random(), emits a one-time warning, and continues:

$.evalFile(File("/path/to/ESUUID.min.jsx"));

var id = ESUUID.v4(); // works, warns once that Math.random() is being used

For deterministic or stronger externally-supplied entropy, inject a source:

$.evalFile(File("/path/to/ESUUID.min.jsx"));

var uuid = ESUUID.create({
  rng: function () {
    return [
      0x91, 0x91, 0x08, 0xf7,
      0x52, 0xd1, 0x33, 0x20,
      0x5b, 0xac, 0xf8, 0x47,
      0xdb, 0x41, 0x48, 0xa8
    ];
  }
});

var id = uuid.v4();

Quick Start

// ESRAND should already be installed on $.global.
$.evalFile(File("/path/to/ESUUID.min.jsx"));

var randomId = ESUUID.v4();
var orderedId = ESUUID.v7();

var stableNameId = ESUUID.v5(
  "www.example.com",
  ESUUID.DNS
);

var bytes = ESUUID.parse(randomId);
var roundTrip = ESUUID.stringify(bytes);

if (!ESUUID.validate(roundTrip)) {
  throw new Error("invalid UUID");
}

$.writeln("v4: " + randomId);
$.writeln("v7: " + orderedId);
$.writeln("v5: " + stableNameId);

API Reference

Constants

Name Value / purpose
ESUUID.VERSION Library version, currently 0.2.0
ESUUID.NIL 00000000-0000-0000-0000-000000000000
ESUUID.MAX ffffffff-ffff-ffff-ffff-ffffffffffff
ESUUID.DNS RFC namespace UUID for DNS names
ESUUID.URL RFC namespace UUID for URLs
ESUUID.OID RFC namespace UUID for ISO OIDs
ESUUID.X500 RFC namespace UUID for X.500 DNs

Random and time-based UUIDs

ESUUID.v1(options);
ESUUID.v4(options);
ESUUID.v6(options);
ESUUID.v7(options);

Generation methods return a canonical UUID string by default. Pass a byte-array output buffer and optional offset to write 16 bytes into an existing array:

var out = new Array(32);
ESUUID.v4({ random: random16 }, out, 8);

Relevant options:

Option Methods Contract
random v1/v4/v6/v7 Byte array with at least 16 bytes; the first 16 are consumed
rng v1/v4/v6/v7 Function returning at least 16 byte values
msecs v1/v6/v7 Explicit millisecond timestamp
nsecs v1/v6 100 ns sub-millisecond counter
clockseq v1/v6 Explicit 14-bit clock sequence
node v1/v6 Explicit 6-byte node identifier
seq v7 Explicit unsigned 32-bit sequence

Name-based UUIDs

ESUUID.v3(value, namespace);
ESUUID.v5(value, namespace);

value may be a string or byte-like object. namespace may be a UUID string or exactly 16 bytes.

The standard namespace constants are also attached to ESUUID.v3 and ESUUID.v5:

var a = ESUUID.v3("www.example.com", ESUUID.v3.DNS);
var b = ESUUID.v5("www.example.com", ESUUID.v5.DNS);

Parsing and validation

var bytes = ESUUID.parse("919108f7-52d1-4320-9bac-f847db4148a8");
var text = ESUUID.stringify(bytes);

ESUUID.validate(text); // true
ESUUID.version(text);  // 4

stringify(bytes, offset) reads exactly 16 bytes beginning at offset.

v1/v6 conversion

var v6 = ESUUID.v1ToV6(v1);
var v1Again = ESUUID.v6ToV1(v6);

The conversion helpers reject valid UUIDs of the wrong source version instead of silently reinterpreting them.

Stateful generators

var ids = ESUUID.create({
  now: function () {
    return new Date().getTime();
  }
});

var a = ids.v7();
var b = ids.v7();

create() returns a stateful generator exposing v1, v4, v6, and v7. In the Adobe-host facade, a custom now function still inherits the installed ESRAND backend unless the caller explicitly supplies rng or rand.

Capability reporting

var caps = ESUUID.capabilities();

With ESRAND installed:

standard:      RFC 9562
engine:        ExtendScript ES3
entropy:       ESRAND
cryptographic: false

Without ESRAND, entropy reports Math.random-fallback. That state is deliberately non-cryptographic and the first actual fallback entropy request emits a warning.


Validation

Current 0.2.0 validation on the public-reproducible build:

Check Command Result
TypeScript npm run typecheck pass
ExtendScript build + ES3 grammar checks npm run build 4/4 ExtendScript artifacts pass ESTC acorn-ecma3 checks
Unit suite npm test 55/55 checks
Differential parity npm run differential 3,225/3,225 checks vs. [email protected]
Seeded invariants npm run fuzz 75,000/75,000 checks
Live Illustrator npm run live-verify -- --pipe <runtime> 54/54 checks on Illustrator 30.6.0 / ExtendScript 4.5.6
Live host benchmark npm run live-benchmark -- --pipe <runtime> --rounds 3 9/9 benchmark lanes completed, 0 rejected samples

The differential oracle is uuidjs/uuid, version 14.0.2. The live check runs the actual generated ESUUID.jsx and ESUUID.min.jsx artifacts through COM Tool V2 script.runFile, and dogfoods the real sibling ESRAND distribution.

Machine-readable live evidence is committed under evidence/.


Spec Conformance

ESUUID targets RFC 9562, Universally Unique IDentifiers (UUIDs).

RFC 9562 Appendix A vector Result
UUIDv1 pass
UUIDv3 pass
UUIDv4 pass
UUIDv5 pass
UUIDv6 pass
UUIDv7 pass

The same unit suite also covers NIL/MAX handling, RFC variant validation, UUIDv8 recognition, v1/v6 conversion, output-buffer boundaries, sequence limits, and monotonic state behavior.

Name-based UUIDs use an ES3-compatible MD5 implementation for v3 and SHA-1 implementation for v5 as required by the UUID versions. No uuidjs runtime code is vendored.


Performance

Measured live on Adobe Illustrator 30.6.0 / ExtendScript 4.5.6 using the ESTIMER vendor engine lane through COM Tool V2.

Protocol: one benchmark lane per script.runFile; ESTIMER prime; 5 warmups; 9 measured samples per lane; 3 rounds; batch-normalized per-operation values. The table reports the median across the three round summaries, with the observed minimum and p95 envelope recorded by the benchmark harness.

Lane Median us/op Min us/op p95 us/op Median ops/s
v4, ESRAND entropy 47.012 44.760 50.284 21,271
v4, Math.random fallback 51.336 50.836 62.608 19,480
v4, explicit bytes 37.354 35.704 45.692 26,771
v7, ESRAND entropy 53.700 51.688 66.676 18,622
v7, Math.random fallback 61.684 59.100 64.576 16,212
v7, explicit bytes 45.654 43.342 51.730 21,904
parse 135.185 123.230 149.374 7,397
stringify 95.471 88.325 97.147 10,474
v5 1,016.220 915.400 1,190.840 984

The Math.random lanes measure steady-state fallback generation after the one-time warning has already been emitted during warmup. These are host-engine measurements, not Node throughput estimates. Re-run npm run live-benchmark on the target Adobe host before using them as a capacity estimate for a different machine or application.

A separate Node microbenchmark exists under tests/benchmark.mjs for development regression checks.


Security Model

ESUUID is a pure JavaScript/ExtendScript UUID implementation. It does not open sockets, write files, load native code, or evaluate caller-provided source.

ESUUID does not claim cryptographic entropy. ESUUID.capabilities().cryptographic is deliberately false. The default Adobe-host random source is ESRAND, which is designed for deterministic random infrastructure rather than cryptographic key generation.

Consequences:

  • Do not use ESUUID-generated UUIDs as passwords, bearer tokens, API secrets, session secrets, or cryptographic nonces.
  • UUIDv3 uses MD5 and UUIDv5 uses SHA-1 because those hash functions are part of the specified UUID version algorithms. Their presence is not a recommendation to use MD5/SHA-1 for general-purpose security.
  • If ESRAND and caller entropy are both missing, ESUUID falls back to Math.random(), emits a one-time warning, and reports entropy: "Math.random-fallback".
  • The Math.random() fallback is non-cryptographic and may be predictable; inject a CSPRNG-backed source for security-sensitive identifiers.
  • Caller-supplied entropy is trusted as supplied. ESUUID validates byte shape and bounds, not randomness quality.

For ordinary identifiers, deterministic fixtures, namespace UUIDs, and time-ordered UUIDs inside ExtendScript automation, the entropy contract is explicit and inspectable.


Compatibility

Target Status
Adobe Illustrator 30.6.0 54/54 live checks pass
ExtendScript 4.5.6 live verified
ExtendScript ES3 grammar 4/4 generated artifacts pass ESTC acorn-ecma3 checks
Other Adobe ExtendScript hosts ES3-compatible build; not yet separately live-certified
Node.js Node 20+ for build/test tooling and ESM differential harness
Windows live COM Tool V2 verification performed on Windows
macOS generated ES3 code is host-neutral; live COM verification is Windows-only

The runtime library itself does not depend on Node.js. Node is only used for build, test, differential, and evidence tooling.


Engine quirks that shaped the design

All live observations in this section were verified on Illustrator 30.6.0 / ExtendScript 4.5.6 unless stated otherwise.

Bitwise composition cannot assume modern parser/minifier behavior

The implementation isolates compound 32-bit bitwise composition behind simple helper operations. This is intentional: ExtendScript's bitwise/operator parsing behavior can diverge from assumptions made by modern JavaScript optimization passes. The shipped minified and unminified builds are therefore both checked as ES3 and executed live.

Reloading a global library can destroy monotonic state

A naive $.evalFile() reload would replace the facade and reset the state used by v1/v7 generators. The live suite explicitly verifies that re-evaluating the same compatible ESUUID version preserves the existing facade identity and that a v7 generated after reload remains ordered after the pre-reload value.

Entropy availability can change during a host session

A script may load ESUUID before ESRAND and install ESRAND later. ESUUID therefore distinguishes ESRAND from Math.random-fallback capability state. Re-evaluating ESUUID after ESRAND becomes available upgrades the facade instead of preserving a stale fallback backend.

Minified output must be tested as a separate runtime artifact

Static parsing is necessary but insufficient for ExtendScript. The live suite clears the existing global facade before loading ESUUID.min.jsx, preventing the reload-preservation path from masking a minifier regression. The minified artifact then runs RFC vectors and ESRAND-backed generation independently.


Development

Portable Node-only validation:

npm ci
npm run verify:portable

Full ExtendScript build and offline validation:

npm run verify

Individual gates:

npm run typecheck
npm run build
npm test
npm run differential
npm run fuzz
npm run benchmark
npm run pack:smoke
npm run evidence:check

Maintainer live gates require a running COM Tool V2 runtime with an Illustrator target:

npm run live-verify -- --pipe <runtime-pipe>
npm run live-benchmark -- --pipe <runtime-pipe> --rounds 3
npm run release:gate -- --pipe <runtime-pipe> --target <target-id>

npm run release:gate runs the portable/full verification, the exact 54-check live Illustrator contract, a clean packed-tarball install/rebuild, the evidence/document synchronization gate, and the release manifest/checksum generator. The live benchmark is intentionally separate because its evidence remains valid only while its recorded ESUUID/ESRAND/ESTIMER artifact hashes match the current bytes.

The V2 harness prefers the stable per-user COM Tool V2 install at %LOCALAPPDATA%\Programs\ComToolV2\current\ComTool.Cli.exe, falls back to the toolkit workspace Release CLI when present, and accepts COMTOOL_V2_CLI / --cli as an explicit override. If another COM Tool runtime owns Illustrator, live gates wait safely for up to 60 seconds by default without stealing the lease; set COMTOOL_V2_LEASE_WAIT_MS or --lease-wait-ms to change that bound.

npm run build uses the pinned public ESTC dependency installed by npm ci by default. Set ESUUID_USE_WORKSPACE_ESTC=1 to opt into the sibling toolkit ESTC checkout, ESUUID_ESTC to override the ESTC entry point, or ESUUID_PYTHON to select a Python executable. Standalone live validation can point at external sibling artifacts with ESUUID_ESRAND_VENDOR; live benchmarking additionally accepts ESUUID_ESTIMER_VENDOR.


Repository layout

es-uuid/
├─ src/
│  ├─ core.ts                  RFC 9562 algorithms and stateful generators
│  ├─ index.ts                 ESM public exports
│  ├─ jsx-entry.ts             ExtendScript global facade
│  ├─ types.ts                 public TypeScript contracts
│  └─ globals.d.ts             ExtendScript build globals
├─ dist/                       checked-in generated artifacts
├─ tests/
│  ├─ esuuid-test.mjs          unit and RFC vectors
│  ├─ differential.mjs         [email protected] parity
│  ├─ fuzz.mjs                 seeded invariants
│  ├─ benchmark.mjs            Node regression microbenchmark
│  ├─ esuuid-live-probe.jsx    real-host verification probe
│  └─ live-verify.mjs          COM Tool V2 live gate
├─ bench/
│  ├─ live-bench.jsx           ESTIMER host benchmark probe
│  └─ run-live-bench.mjs       benchmark orchestrator
├─ tooling/
│  ├─ comtool-v2.mjs           live-gate transport helper
│  ├─ check-evidence.mjs        artifact/evidence/docs consistency gate
│  ├─ pack-smoke.mjs            clean tarball rebuild + byte parity
│  ├─ release-gate.mjs          end-to-end release orchestrator
│  ├─ release-manifest.mjs      hashes + immutable release lock
│  └─ minifier/                pinned conservative JSX minifier pipeline
├─ evidence/
│  ├─ latest-live-verify.json
│  ├─ latest-live-benchmark.json
│  └─ latest-pack-reproducibility.json
├─ release/
│  ├─ esuuid-v0.2.0.lock.json
│  └─ SHA256SUMS.txt
├─ esuuid-build.mjs
├─ extendscript.estc.config.mjs
├─ extendscript.vendor.estc.config.mjs
└─ package.json

Credits

  • RFC 9562, the UUID specification.
  • uuidjs/uuid, used as the differential API/behavior oracle for mappings that make sense in ExtendScript.
  • docsforadobe, for ExtendScript and Adobe scripting references.
  • ESTC, the TypeScript-to-ExtendScript build and ES3 compatibility toolchain.
  • ESRAND, the default Adobe-host entropy backend used by ESUUID.

See ATTRIBUTION.md for the compatibility baseline and licensing notes.


License

GPL-3.0-or-later. See LICENSE.


ESUUID: RFC 9562 UUID infrastructure for Adobe ExtendScript ES3.

About

RFC 9562 UUIDs for Adobe ExtendScript ES3

Topics

Resources

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages