@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.mjs CHANGED
@@ -34,6 +34,53 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
34
34
  mod
35
35
  ));
36
36
 
37
+ // ../../node_modules/.pnpm/escape-html@1.0.3/node_modules/escape-html/index.js
38
+ var require_escape_html = __commonJS({
39
+ "../../node_modules/.pnpm/escape-html@1.0.3/node_modules/escape-html/index.js"(exports, module) {
40
+ "use strict";
41
+ var matchHtmlRegExp = /["'&<>]/;
42
+ module.exports = escapeHtml;
43
+ function escapeHtml(string) {
44
+ var str = "" + string;
45
+ var match = matchHtmlRegExp.exec(str);
46
+ if (!match) {
47
+ return str;
48
+ }
49
+ var escape;
50
+ var html = "";
51
+ var index = 0;
52
+ var lastIndex = 0;
53
+ for (index = match.index; index < str.length; index++) {
54
+ switch (str.charCodeAt(index)) {
55
+ case 34:
56
+ escape = "&quot;";
57
+ break;
58
+ case 38:
59
+ escape = "&amp;";
60
+ break;
61
+ case 39:
62
+ escape = "&#39;";
63
+ break;
64
+ case 60:
65
+ escape = "&lt;";
66
+ break;
67
+ case 62:
68
+ escape = "&gt;";
69
+ break;
70
+ default:
71
+ continue;
72
+ }
73
+ if (lastIndex !== index) {
74
+ html += str.substring(lastIndex, index);
75
+ }
76
+ lastIndex = index + 1;
77
+ html += escape;
78
+ }
79
+ return lastIndex !== index ? html + str.substring(lastIndex, index) : html;
80
+ }
81
+ }
82
+ });
83
+
37
84
  // ../../node_modules/.pnpm/lodash@4.17.23/node_modules/lodash/_listCacheClear.js
38
85
  var require_listCacheClear = __commonJS({
39
86
  "../../node_modules/.pnpm/lodash@4.17.23/node_modules/lodash/_listCacheClear.js"(exports, module) {
@@ -1644,6 +1691,7 @@ var SIGIL_NAMESPACE = "sigil";
1644
1691
  var isSigilComponentCall = (call, action) => call.namespace === SIGIL_NAMESPACE && call.action === action;
1645
1692
 
1646
1693
  // ../../packages/sigil/dist/index.js
1694
+ var import_escape_html = __toESM(require_escape_html(), 1);
1647
1695
  import { useEffect as useEffect2, useMemo, useState } from "react";
1648
1696
  import {
1649
1697
  BaseParent,
@@ -1862,6 +1910,26 @@ var runSigilApp = ({
1862
1910
  debug: upstreamLogger.debug.bind(upstreamLogger)
1863
1911
  },
1864
1912
  title,
1913
+ htmlPage: (context) => `
1914
+ <html>
1915
+ <head>
1916
+ <title>${(0, import_escape_html.default)(context.title)}</title>
1917
+ <meta charset="utf-8">
1918
+ <meta name="viewport" content="width=device-width, user-scalable=no" />
1919
+ <style type="text/css">
1920
+ @font-face {
1921
+ font-family: 'Material Symbols Outlined';
1922
+ font-style: normal;
1923
+ src: url(${context.coreAssets.materialSymbolsOutlined}) format('woff');
1924
+ }
1925
+ </style>
1926
+ ${context.coreAssets.entrypointCss ? `<link rel="stylesheet" href="${context.coreAssets.entrypointCss}" />` : ""}
1927
+ </head>
1928
+ <body>
1929
+ <div id="root"></div>
1930
+ <script type="text/javascript" src="${context.coreAssets.entrypointJs}"></script>
1931
+ </body>
1932
+ </html>`,
1865
1933
  ...toolkitOptions
1866
1934
  });
1867
1935
  toolkit.start({
@@ -2057,7 +2125,8 @@ var AppListenerManager = ({
2057
2125
  const resolvedConnectionDetails = {
2058
2126
  config,
2059
2127
  host,
2060
- port
2128
+ port,
2129
+ internal: !!config.interface && !!interfaces[config.interface]?.internal
2061
2130
  };
2062
2131
  try {
2063
2132
  const listener = await toolkit.listen({
@@ -2128,11 +2197,21 @@ var AppListenerManager = ({
2128
2197
  }, [appRegistration, listenerConfig, logger, toolkit, updateReactState]);
2129
2198
  useEffect3(() => {
2130
2199
  for (const state of Object.values(listenerState)) {
2200
+ let preferredConnection = null;
2131
2201
  if (state.state === "connected") {
2202
+ if (!preferredConnection) {
2203
+ preferredConnection = state;
2204
+ }
2205
+ if (!preferredConnection.internal && state.internal) {
2206
+ preferredConnection = state;
2207
+ }
2208
+ }
2209
+ if (preferredConnection) {
2132
2210
  setWindowUrl(
2133
- new URL(`http://${state.host ?? "localhost"}:${state.port}/`)
2211
+ new URL(
2212
+ `http://${preferredConnection.host ?? "localhost"}:${preferredConnection.port}/`
2213
+ )
2134
2214
  );
2135
- return;
2136
2215
  }
2137
2216
  }
2138
2217
  });
@@ -6213,6 +6292,24 @@ var SIGIL_COLOR = external_exports.enum([
6213
6292
  "gray"
6214
6293
  ]);
6215
6294
 
6295
+ // ../../packages/sigil/dist/shared/config.js
6296
+ var APP_LISTENER_CONFIG = zod_default.object({
6297
+ port: zod_default.union([
6298
+ zod_default.number().int().min(1).max(65535),
6299
+ zod_default.object({
6300
+ from: zod_default.number().int().min(1).max(65535),
6301
+ to: zod_default.number().int().min(1).max(65535)
6302
+ }).refine((data) => data.to >= data.from, {
6303
+ message: '"to" must be greater than or equal to "from"'
6304
+ })
6305
+ ]),
6306
+ interface: zod_default.string().optional()
6307
+ });
6308
+ var ALL_APP_LISTENER_CONFIG = zod_default.record(
6309
+ zod_default.string(),
6310
+ APP_LISTENER_CONFIG
6311
+ );
6312
+
6216
6313
  // src/components/proto.ts
6217
6314
  var NET_UTILS_GENERAL_TARGET_DEFINITION = zod_default.union([
6218
6315
  zod_default.object({
@@ -6293,6 +6390,7 @@ var OUTPUT_CONFIG = zod_default.object({
6293
6390
  link: INPUT_OR_GENERATOR_INSTANCE_ID.nullable()
6294
6391
  });
6295
6392
  var TOOLBOX_CONFIG = zod_default.object({
6393
+ appListener: APP_LISTENER_CONFIG.partial().optional(),
6296
6394
  inputs: zod_default.record(zod_default.string(), INPUT_CONFIG),
6297
6395
  generators: zod_default.record(zod_default.string(), GENERATOR_CONFIG),
6298
6396
  outputs: zod_default.record(zod_default.string(), OUTPUT_CONFIG),
@@ -6326,7 +6424,11 @@ var DEFAULT_PROPS2 = {
6326
6424
  updates: null
6327
6425
  },
6328
6426
  handlers: { children: {} },
6329
- license: ""
6427
+ license: "",
6428
+ network: {
6429
+ envPort: null,
6430
+ defaultPort: -1
6431
+ }
6330
6432
  };
6331
6433
  var ToolboxRoot = class extends Base {
6332
6434
  /** @hidden */
@@ -6355,7 +6457,8 @@ var ToolboxRoot = class extends Base {
6355
6457
  config: this.props.config,
6356
6458
  state: this.props.state,
6357
6459
  handlers: this.props.handlers,
6358
- license: this.props.license
6460
+ license: this.props.license,
6461
+ network: this.props.network
6359
6462
  };
6360
6463
  }
6361
6464
  /** @hidden */
@@ -6741,9 +6844,27 @@ var createArtnet = (config) => {
6741
6844
  })();
6742
6845
  return connectPromise;
6743
6846
  };
6847
+ const getNextFrameTiming = (mode, timeMillis) => {
6848
+ const timecode = getTimecodeFromMillis(mode, timeMillis);
6849
+ timecode.frame += 1;
6850
+ if (timecode.frame >= TIMECODE_FPS[mode]) {
6851
+ timecode.frame = 0;
6852
+ timecode.seconds += 1;
6853
+ if (timecode.seconds >= 60) {
6854
+ timecode.seconds = 0;
6855
+ timecode.minutes += 1;
6856
+ if (timecode.minutes >= 60) {
6857
+ timecode.minutes = 0;
6858
+ timecode.hours += 1;
6859
+ }
6860
+ }
6861
+ }
6862
+ const nextFrameTimeMillis = getTimeMillisFromTimecode(timecode);
6863
+ return { nextFrameTimeMillis };
6864
+ };
6744
6865
  const sendTimecode = (mode, timeMillis) => {
6745
6866
  if (timeMillis < 0) {
6746
- return Promise.resolve();
6867
+ return Promise.resolve(getNextFrameTiming(mode, timeMillis));
6747
6868
  }
6748
6869
  if (!sendSocket) {
6749
6870
  return Promise.reject(new Error("ArtNet connection has not been opened"));
@@ -6784,7 +6905,7 @@ var createArtnet = (config) => {
6784
6905
  events.emit("error", error);
6785
6906
  reject(error);
6786
6907
  } else {
6787
- resolve();
6908
+ resolve(getNextFrameTiming(mode, timeMillis));
6788
6909
  }
6789
6910
  }
6790
6911
  )
@@ -6797,6 +6918,7 @@ var createArtnet = (config) => {
6797
6918
  };
6798
6919
  return {
6799
6920
  connect,
6921
+ getNextFrameTiming,
6800
6922
  sendTimecode,
6801
6923
  on,
6802
6924
  addListener,
@@ -6877,7 +6999,7 @@ var ArtnetInputConnection = ({
6877
6999
  created.connect().then(() => {
6878
7000
  artnet = created;
6879
7001
  setArtnetInstance(created);
6880
- log.info("ArtNet Timecode output initialized");
7002
+ log.info("ArtNet Timecode input initialized");
6881
7003
  setConnection({ ...connectionConfig, status: "active" });
6882
7004
  }).catch((err) => {
6883
7005
  const error = new Error("Failed to start ArtNet Timecode output");
@@ -14212,12 +14334,30 @@ var ArtnetOutputConnection = ({
14212
14334
  }
14213
14335
  if (timecodeState?.state === "playing" || timecodeState?.state === "lagging") {
14214
14336
  const tcState = timecodeState;
14215
- const interval = setInterval(() => {
14337
+ let timeoutId = null;
14338
+ const sendNextFrame = () => {
14216
14339
  const time = (Date.now() - tcState.effectiveStartTimeMillis) * tcState.speed;
14217
- artnetInstance.sendTimecode(mode, time);
14218
- }, 1e3 / TIMECODE_FPS[mode]);
14340
+ artnetInstance.sendTimecode(mode, time).then(({ nextFrameTimeMillis }) => {
14341
+ const delay = nextFrameTimeMillis - time + 1;
14342
+ timeoutId = setTimeout(sendNextFrame, delay);
14343
+ }).catch(() => {
14344
+ scheduleNextFrame();
14345
+ });
14346
+ };
14347
+ const scheduleNextFrame = () => {
14348
+ const time = (Date.now() - tcState.effectiveStartTimeMillis) * tcState.speed;
14349
+ const { nextFrameTimeMillis } = artnetInstance.getNextFrameTiming(
14350
+ mode,
14351
+ time
14352
+ );
14353
+ const delay = nextFrameTimeMillis - time + 1;
14354
+ timeoutId = setTimeout(sendNextFrame, delay);
14355
+ };
14356
+ scheduleNextFrame();
14219
14357
  return () => {
14220
- clearInterval(interval);
14358
+ if (timeoutId) {
14359
+ clearTimeout(timeoutId);
14360
+ }
14221
14361
  };
14222
14362
  } else if (timecodeState?.state === "stopped") {
14223
14363
  artnetInstance.sendTimecode(mode, timecodeState?.positionMillis ?? 0);
@@ -14476,6 +14616,8 @@ var ClockGenerator = ({
14476
14616
  timecode: {
14477
14617
  metadata: null,
14478
14618
  name: null,
14619
+ errors: [],
14620
+ warnings: [],
14479
14621
  state: {
14480
14622
  accuracyMillis: null,
14481
14623
  smpteMode: null,
@@ -14677,10 +14819,7 @@ var UpdateChecker = ({
14677
14819
 
14678
14820
  // src/env.ts
14679
14821
  var getEnv = (logger) => {
14680
- const PORT = process.env.PORT ? parseInt(process.env.PORT, 10) : {
14681
- from: 4100,
14682
- to: 4200
14683
- };
14822
+ const PORT = process.env.PORT && parseInt(process.env.PORT, 10) || null;
14684
14823
  let API_BASE_URL;
14685
14824
  try {
14686
14825
  API_BASE_URL = process.env.API_BASE_URL ? new URL(process.env.API_BASE_URL) : new URL("https://arcanewizards.com");
@@ -14698,6 +14837,7 @@ var getEnv = (logger) => {
14698
14837
 
14699
14838
  // src/app.tsx
14700
14839
  import { Fragment as Fragment4, jsx as jsx9, jsxs as jsxs2 } from "react/jsx-runtime";
14840
+ var DEFAULT_PORT = { from: 4100, to: 4200 };
14701
14841
  var App = ({
14702
14842
  title,
14703
14843
  version: version2,
@@ -14755,14 +14895,16 @@ var App = ({
14755
14895
  [handlers]
14756
14896
  );
14757
14897
  const license = useLicense();
14758
- const appListenerConfig = useMemo6(
14759
- () => ({
14760
- default: {
14761
- port: env.PORT
14762
- }
14763
- }),
14764
- [env.PORT]
14765
- );
14898
+ const appListenerConfig = useMemo6(() => {
14899
+ const baseConfig = {
14900
+ port: data.appListener?.port ?? DEFAULT_PORT,
14901
+ interface: data.appListener?.interface ?? void 0
14902
+ };
14903
+ if (env.PORT) {
14904
+ baseConfig.port = env.PORT;
14905
+ }
14906
+ return baseConfig;
14907
+ }, [env.PORT, data.appListener]);
14766
14908
  if (!license) {
14767
14909
  return;
14768
14910
  }
@@ -14775,7 +14917,11 @@ var App = ({
14775
14917
  handlers: availableHandlers,
14776
14918
  onUpdateConfig,
14777
14919
  onCallHandler: callHandler,
14778
- license: license.text
14920
+ license: license.text,
14921
+ network: {
14922
+ envPort: env.PORT,
14923
+ defaultPort: DEFAULT_PORT
14924
+ }
14779
14925
  }
14780
14926
  ),
14781
14927
  /* @__PURE__ */ jsx9(InputConnections, { state, setState }),
@@ -14827,7 +14973,7 @@ var App = ({
14827
14973
  {
14828
14974
  toolkit,
14829
14975
  setWindowUrl,
14830
- listenerConfig: appListenerConfig
14976
+ listenerConfig: { appListenerConfig }
14831
14977
  }
14832
14978
  )
14833
14979
  ]
@@ -14845,7 +14991,7 @@ var createApp = (props) => {
14845
14991
  };
14846
14992
 
14847
14993
  // package.json
14848
- var version = "0.1.3";
14994
+ var version = "0.1.5";
14849
14995
 
14850
14996
  // src/urls.ts
14851
14997
  var urls_exports = {};
@@ -14918,3 +15064,14 @@ lodash/lodash.js:
14918
15064
  * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
14919
15065
  *)
14920
15066
  */
15067
+ /*! Bundled license information:
15068
+
15069
+ escape-html/index.js:
15070
+ (*!
15071
+ * escape-html
15072
+ * Copyright(c) 2012-2013 TJ Holowaychuk
15073
+ * Copyright(c) 2015 Andreas Lubbe
15074
+ * Copyright(c) 2015 Tiancheng "Timothy" Gu
15075
+ * MIT Licensed
15076
+ *)
15077
+ */