@arcanewizards/timecode-toolbox 0.1.3 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -30,6 +30,53 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
30
30
  ));
31
31
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
32
32
 
33
+ // ../../node_modules/.pnpm/escape-html@1.0.3/node_modules/escape-html/index.js
34
+ var require_escape_html = __commonJS({
35
+ "../../node_modules/.pnpm/escape-html@1.0.3/node_modules/escape-html/index.js"(exports2, module2) {
36
+ "use strict";
37
+ var matchHtmlRegExp = /["'&<>]/;
38
+ module2.exports = escapeHtml;
39
+ function escapeHtml(string) {
40
+ var str = "" + string;
41
+ var match = matchHtmlRegExp.exec(str);
42
+ if (!match) {
43
+ return str;
44
+ }
45
+ var escape;
46
+ var html = "";
47
+ var index = 0;
48
+ var lastIndex = 0;
49
+ for (index = match.index; index < str.length; index++) {
50
+ switch (str.charCodeAt(index)) {
51
+ case 34:
52
+ escape = "&quot;";
53
+ break;
54
+ case 38:
55
+ escape = "&amp;";
56
+ break;
57
+ case 39:
58
+ escape = "&#39;";
59
+ break;
60
+ case 60:
61
+ escape = "&lt;";
62
+ break;
63
+ case 62:
64
+ escape = "&gt;";
65
+ break;
66
+ default:
67
+ continue;
68
+ }
69
+ if (lastIndex !== index) {
70
+ html += str.substring(lastIndex, index);
71
+ }
72
+ lastIndex = index + 1;
73
+ html += escape;
74
+ }
75
+ return lastIndex !== index ? html + str.substring(lastIndex, index) : html;
76
+ }
77
+ }
78
+ });
79
+
33
80
  // ../../node_modules/.pnpm/lodash@4.17.23/node_modules/lodash/_listCacheClear.js
34
81
  var require_listCacheClear = __commonJS({
35
82
  "../../node_modules/.pnpm/lodash@4.17.23/node_modules/lodash/_listCacheClear.js"(exports2, module2) {
@@ -1654,6 +1701,7 @@ var import_data = require("@arcanejs/react-toolkit/data");
1654
1701
  var import_react_toolkit2 = require("@arcanejs/react-toolkit");
1655
1702
  var import_toolkit = require("@arcanejs/toolkit");
1656
1703
  var import_events = require("events");
1704
+ var import_escape_html = __toESM(require_escape_html(), 1);
1657
1705
  var import_jsx_runtime = require("react/jsx-runtime");
1658
1706
 
1659
1707
  // ../../packages/net-utils/dist/index.js
@@ -1861,6 +1909,26 @@ var runSigilApp = ({
1861
1909
  debug: upstreamLogger.debug.bind(upstreamLogger)
1862
1910
  },
1863
1911
  title,
1912
+ htmlPage: (context) => `
1913
+ <html>
1914
+ <head>
1915
+ <title>${(0, import_escape_html.default)(context.title)}</title>
1916
+ <meta charset="utf-8">
1917
+ <meta name="viewport" content="width=device-width, user-scalable=no" />
1918
+ <style type="text/css">
1919
+ @font-face {
1920
+ font-family: 'Material Symbols Outlined';
1921
+ font-style: normal;
1922
+ src: url(${context.coreAssets.materialSymbolsOutlined}) format('woff');
1923
+ }
1924
+ </style>
1925
+ ${context.coreAssets.entrypointCss ? `<link rel="stylesheet" href="${context.coreAssets.entrypointCss}" />` : ""}
1926
+ </head>
1927
+ <body>
1928
+ <div id="root"></div>
1929
+ <script type="text/javascript" src="${context.coreAssets.entrypointJs}"></script>
1930
+ </body>
1931
+ </html>`,
1864
1932
  ...toolkitOptions
1865
1933
  });
1866
1934
  toolkit.start({
@@ -2056,7 +2124,8 @@ var AppListenerManager = ({
2056
2124
  const resolvedConnectionDetails = {
2057
2125
  config,
2058
2126
  host,
2059
- port
2127
+ port,
2128
+ internal: !!config.interface && !!interfaces[config.interface]?.internal
2060
2129
  };
2061
2130
  try {
2062
2131
  const listener = await toolkit.listen({
@@ -2127,11 +2196,21 @@ var AppListenerManager = ({
2127
2196
  }, [appRegistration, listenerConfig, logger, toolkit, updateReactState]);
2128
2197
  (0, import_react3.useEffect)(() => {
2129
2198
  for (const state of Object.values(listenerState)) {
2199
+ let preferredConnection = null;
2130
2200
  if (state.state === "connected") {
2201
+ if (!preferredConnection) {
2202
+ preferredConnection = state;
2203
+ }
2204
+ if (!preferredConnection.internal && state.internal) {
2205
+ preferredConnection = state;
2206
+ }
2207
+ }
2208
+ if (preferredConnection) {
2131
2209
  setWindowUrl(
2132
- new URL(`http://${state.host ?? "localhost"}:${state.port}/`)
2210
+ new URL(
2211
+ `http://${preferredConnection.host ?? "localhost"}:${preferredConnection.port}/`
2212
+ )
2133
2213
  );
2134
- return;
2135
2214
  }
2136
2215
  }
2137
2216
  });
@@ -6204,6 +6283,24 @@ var SIGIL_COLOR = external_exports.enum([
6204
6283
  "gray"
6205
6284
  ]);
6206
6285
 
6286
+ // ../../packages/sigil/dist/shared/config.js
6287
+ var APP_LISTENER_CONFIG = zod_default.object({
6288
+ port: zod_default.union([
6289
+ zod_default.number().int().min(1).max(65535),
6290
+ zod_default.object({
6291
+ from: zod_default.number().int().min(1).max(65535),
6292
+ to: zod_default.number().int().min(1).max(65535)
6293
+ }).refine((data) => data.to >= data.from, {
6294
+ message: '"to" must be greater than or equal to "from"'
6295
+ })
6296
+ ]),
6297
+ interface: zod_default.string().optional()
6298
+ });
6299
+ var ALL_APP_LISTENER_CONFIG = zod_default.record(
6300
+ zod_default.string(),
6301
+ APP_LISTENER_CONFIG
6302
+ );
6303
+
6207
6304
  // src/components/proto.ts
6208
6305
  var NET_UTILS_GENERAL_TARGET_DEFINITION = zod_default.union([
6209
6306
  zod_default.object({
@@ -6284,6 +6381,7 @@ var OUTPUT_CONFIG = zod_default.object({
6284
6381
  link: INPUT_OR_GENERATOR_INSTANCE_ID.nullable()
6285
6382
  });
6286
6383
  var TOOLBOX_CONFIG = zod_default.object({
6384
+ appListener: APP_LISTENER_CONFIG.partial().optional(),
6287
6385
  inputs: zod_default.record(zod_default.string(), INPUT_CONFIG),
6288
6386
  generators: zod_default.record(zod_default.string(), GENERATOR_CONFIG),
6289
6387
  outputs: zod_default.record(zod_default.string(), OUTPUT_CONFIG),
@@ -6317,7 +6415,11 @@ var DEFAULT_PROPS2 = {
6317
6415
  updates: null
6318
6416
  },
6319
6417
  handlers: { children: {} },
6320
- license: ""
6418
+ license: "",
6419
+ network: {
6420
+ envPort: null,
6421
+ defaultPort: -1
6422
+ }
6321
6423
  };
6322
6424
  var ToolboxRoot = class extends import_base2.Base {
6323
6425
  /** @hidden */
@@ -6346,7 +6448,8 @@ var ToolboxRoot = class extends import_base2.Base {
6346
6448
  config: this.props.config,
6347
6449
  state: this.props.state,
6348
6450
  handlers: this.props.handlers,
6349
- license: this.props.license
6451
+ license: this.props.license,
6452
+ network: this.props.network
6350
6453
  };
6351
6454
  }
6352
6455
  /** @hidden */
@@ -6729,9 +6832,27 @@ var createArtnet = (config) => {
6729
6832
  })();
6730
6833
  return connectPromise;
6731
6834
  };
6835
+ const getNextFrameTiming = (mode, timeMillis) => {
6836
+ const timecode = getTimecodeFromMillis(mode, timeMillis);
6837
+ timecode.frame += 1;
6838
+ if (timecode.frame >= TIMECODE_FPS[mode]) {
6839
+ timecode.frame = 0;
6840
+ timecode.seconds += 1;
6841
+ if (timecode.seconds >= 60) {
6842
+ timecode.seconds = 0;
6843
+ timecode.minutes += 1;
6844
+ if (timecode.minutes >= 60) {
6845
+ timecode.minutes = 0;
6846
+ timecode.hours += 1;
6847
+ }
6848
+ }
6849
+ }
6850
+ const nextFrameTimeMillis = getTimeMillisFromTimecode(timecode);
6851
+ return { nextFrameTimeMillis };
6852
+ };
6732
6853
  const sendTimecode = (mode, timeMillis) => {
6733
6854
  if (timeMillis < 0) {
6734
- return Promise.resolve();
6855
+ return Promise.resolve(getNextFrameTiming(mode, timeMillis));
6735
6856
  }
6736
6857
  if (!sendSocket) {
6737
6858
  return Promise.reject(new Error("ArtNet connection has not been opened"));
@@ -6772,7 +6893,7 @@ var createArtnet = (config) => {
6772
6893
  events.emit("error", error);
6773
6894
  reject(error);
6774
6895
  } else {
6775
- resolve();
6896
+ resolve(getNextFrameTiming(mode, timeMillis));
6776
6897
  }
6777
6898
  }
6778
6899
  )
@@ -6785,6 +6906,7 @@ var createArtnet = (config) => {
6785
6906
  };
6786
6907
  return {
6787
6908
  connect,
6909
+ getNextFrameTiming,
6788
6910
  sendTimecode,
6789
6911
  on,
6790
6912
  addListener,
@@ -6865,7 +6987,7 @@ var ArtnetInputConnection = ({
6865
6987
  created.connect().then(() => {
6866
6988
  artnet = created;
6867
6989
  setArtnetInstance(created);
6868
- log.info("ArtNet Timecode output initialized");
6990
+ log.info("ArtNet Timecode input initialized");
6869
6991
  setConnection({ ...connectionConfig, status: "active" });
6870
6992
  }).catch((err) => {
6871
6993
  const error = new Error("Failed to start ArtNet Timecode output");
@@ -14189,12 +14311,30 @@ var ArtnetOutputConnection = ({
14189
14311
  }
14190
14312
  if (timecodeState?.state === "playing" || timecodeState?.state === "lagging") {
14191
14313
  const tcState = timecodeState;
14192
- const interval = setInterval(() => {
14314
+ let timeoutId = null;
14315
+ const sendNextFrame = () => {
14193
14316
  const time = (Date.now() - tcState.effectiveStartTimeMillis) * tcState.speed;
14194
- artnetInstance.sendTimecode(mode, time);
14195
- }, 1e3 / TIMECODE_FPS[mode]);
14317
+ artnetInstance.sendTimecode(mode, time).then(({ nextFrameTimeMillis }) => {
14318
+ const delay = nextFrameTimeMillis - time + 1;
14319
+ timeoutId = setTimeout(sendNextFrame, delay);
14320
+ }).catch(() => {
14321
+ scheduleNextFrame();
14322
+ });
14323
+ };
14324
+ const scheduleNextFrame = () => {
14325
+ const time = (Date.now() - tcState.effectiveStartTimeMillis) * tcState.speed;
14326
+ const { nextFrameTimeMillis } = artnetInstance.getNextFrameTiming(
14327
+ mode,
14328
+ time
14329
+ );
14330
+ const delay = nextFrameTimeMillis - time + 1;
14331
+ timeoutId = setTimeout(sendNextFrame, delay);
14332
+ };
14333
+ scheduleNextFrame();
14196
14334
  return () => {
14197
- clearInterval(interval);
14335
+ if (timeoutId) {
14336
+ clearTimeout(timeoutId);
14337
+ }
14198
14338
  };
14199
14339
  } else if (timecodeState?.state === "stopped") {
14200
14340
  artnetInstance.sendTimecode(mode, timecodeState?.positionMillis ?? 0);
@@ -14448,6 +14588,8 @@ var ClockGenerator = ({
14448
14588
  timecode: {
14449
14589
  metadata: null,
14450
14590
  name: null,
14591
+ errors: [],
14592
+ warnings: [],
14451
14593
  state: {
14452
14594
  accuracyMillis: null,
14453
14595
  smpteMode: null,
@@ -14649,10 +14791,7 @@ var UpdateChecker = ({
14649
14791
 
14650
14792
  // src/env.ts
14651
14793
  var getEnv = (logger) => {
14652
- const PORT = process.env.PORT ? parseInt(process.env.PORT, 10) : {
14653
- from: 4100,
14654
- to: 4200
14655
- };
14794
+ const PORT = process.env.PORT && parseInt(process.env.PORT, 10) || null;
14656
14795
  let API_BASE_URL;
14657
14796
  try {
14658
14797
  API_BASE_URL = process.env.API_BASE_URL ? new URL(process.env.API_BASE_URL) : new URL("https://arcanewizards.com");
@@ -14670,6 +14809,7 @@ var getEnv = (logger) => {
14670
14809
 
14671
14810
  // src/app.tsx
14672
14811
  var import_jsx_runtime9 = require("react/jsx-runtime");
14812
+ var DEFAULT_PORT = { from: 4100, to: 4200 };
14673
14813
  var App = ({
14674
14814
  title,
14675
14815
  version: version2,
@@ -14727,14 +14867,16 @@ var App = ({
14727
14867
  [handlers]
14728
14868
  );
14729
14869
  const license = useLicense();
14730
- const appListenerConfig = (0, import_react10.useMemo)(
14731
- () => ({
14732
- default: {
14733
- port: env.PORT
14734
- }
14735
- }),
14736
- [env.PORT]
14737
- );
14870
+ const appListenerConfig = (0, import_react10.useMemo)(() => {
14871
+ const baseConfig = {
14872
+ port: data.appListener?.port ?? DEFAULT_PORT,
14873
+ interface: data.appListener?.interface ?? void 0
14874
+ };
14875
+ if (env.PORT) {
14876
+ baseConfig.port = env.PORT;
14877
+ }
14878
+ return baseConfig;
14879
+ }, [env.PORT, data.appListener]);
14738
14880
  if (!license) {
14739
14881
  return;
14740
14882
  }
@@ -14747,7 +14889,11 @@ var App = ({
14747
14889
  handlers: availableHandlers,
14748
14890
  onUpdateConfig,
14749
14891
  onCallHandler: callHandler,
14750
- license: license.text
14892
+ license: license.text,
14893
+ network: {
14894
+ envPort: env.PORT,
14895
+ defaultPort: DEFAULT_PORT
14896
+ }
14751
14897
  }
14752
14898
  ),
14753
14899
  /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(InputConnections, { state, setState }),
@@ -14799,7 +14945,7 @@ var App = ({
14799
14945
  {
14800
14946
  toolkit,
14801
14947
  setWindowUrl,
14802
- listenerConfig: appListenerConfig
14948
+ listenerConfig: { appListenerConfig }
14803
14949
  }
14804
14950
  )
14805
14951
  ]
@@ -14817,7 +14963,7 @@ var createApp = (props) => {
14817
14963
  };
14818
14964
 
14819
14965
  // package.json
14820
- var version = "0.1.3";
14966
+ var version = "0.1.5";
14821
14967
 
14822
14968
  // src/urls.ts
14823
14969
  var urls_exports = {};
@@ -14891,3 +15037,14 @@ lodash/lodash.js:
14891
15037
  * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
14892
15038
  *)
14893
15039
  */
15040
+ /*! Bundled license information:
15041
+
15042
+ escape-html/index.js:
15043
+ (*!
15044
+ * escape-html
15045
+ * Copyright(c) 2012-2013 TJ Holowaychuk
15046
+ * Copyright(c) 2015 Andreas Lubbe
15047
+ * Copyright(c) 2015 Tiancheng "Timothy" Gu
15048
+ * MIT Licensed
15049
+ *)
15050
+ */