@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/start.js CHANGED
@@ -31,6 +31,53 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
31
31
  ));
32
32
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
33
33
 
34
+ // ../../node_modules/.pnpm/escape-html@1.0.3/node_modules/escape-html/index.js
35
+ var require_escape_html = __commonJS({
36
+ "../../node_modules/.pnpm/escape-html@1.0.3/node_modules/escape-html/index.js"(exports2, module2) {
37
+ "use strict";
38
+ var matchHtmlRegExp = /["'&<>]/;
39
+ module2.exports = escapeHtml;
40
+ function escapeHtml(string) {
41
+ var str = "" + string;
42
+ var match = matchHtmlRegExp.exec(str);
43
+ if (!match) {
44
+ return str;
45
+ }
46
+ var escape;
47
+ var html = "";
48
+ var index = 0;
49
+ var lastIndex = 0;
50
+ for (index = match.index; index < str.length; index++) {
51
+ switch (str.charCodeAt(index)) {
52
+ case 34:
53
+ escape = "&quot;";
54
+ break;
55
+ case 38:
56
+ escape = "&amp;";
57
+ break;
58
+ case 39:
59
+ escape = "&#39;";
60
+ break;
61
+ case 60:
62
+ escape = "&lt;";
63
+ break;
64
+ case 62:
65
+ escape = "&gt;";
66
+ break;
67
+ default:
68
+ continue;
69
+ }
70
+ if (lastIndex !== index) {
71
+ html += str.substring(lastIndex, index);
72
+ }
73
+ lastIndex = index + 1;
74
+ html += escape;
75
+ }
76
+ return lastIndex !== index ? html + str.substring(lastIndex, index) : html;
77
+ }
78
+ }
79
+ });
80
+
34
81
  // ../../node_modules/.pnpm/lodash@4.17.23/node_modules/lodash/_listCacheClear.js
35
82
  var require_listCacheClear = __commonJS({
36
83
  "../../node_modules/.pnpm/lodash@4.17.23/node_modules/lodash/_listCacheClear.js"(exports2, module2) {
@@ -1655,6 +1702,7 @@ var import_data = require("@arcanejs/react-toolkit/data");
1655
1702
  var import_react_toolkit2 = require("@arcanejs/react-toolkit");
1656
1703
  var import_toolkit = require("@arcanejs/toolkit");
1657
1704
  var import_events = require("events");
1705
+ var import_escape_html = __toESM(require_escape_html(), 1);
1658
1706
  var import_jsx_runtime = require("react/jsx-runtime");
1659
1707
 
1660
1708
  // ../../packages/net-utils/dist/index.js
@@ -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, logger2, toolkit, updateReactState]);
2129
2198
  (0, import_react3.useEffect)(() => {
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
  });
@@ -6205,6 +6284,24 @@ var SIGIL_COLOR = external_exports.enum([
6205
6284
  "gray"
6206
6285
  ]);
6207
6286
 
6287
+ // ../../packages/sigil/dist/shared/config.js
6288
+ var APP_LISTENER_CONFIG = zod_default.object({
6289
+ port: zod_default.union([
6290
+ zod_default.number().int().min(1).max(65535),
6291
+ zod_default.object({
6292
+ from: zod_default.number().int().min(1).max(65535),
6293
+ to: zod_default.number().int().min(1).max(65535)
6294
+ }).refine((data) => data.to >= data.from, {
6295
+ message: '"to" must be greater than or equal to "from"'
6296
+ })
6297
+ ]),
6298
+ interface: zod_default.string().optional()
6299
+ });
6300
+ var ALL_APP_LISTENER_CONFIG = zod_default.record(
6301
+ zod_default.string(),
6302
+ APP_LISTENER_CONFIG
6303
+ );
6304
+
6208
6305
  // src/components/proto.ts
6209
6306
  var NET_UTILS_GENERAL_TARGET_DEFINITION = zod_default.union([
6210
6307
  zod_default.object({
@@ -6285,6 +6382,7 @@ var OUTPUT_CONFIG = zod_default.object({
6285
6382
  link: INPUT_OR_GENERATOR_INSTANCE_ID.nullable()
6286
6383
  });
6287
6384
  var TOOLBOX_CONFIG = zod_default.object({
6385
+ appListener: APP_LISTENER_CONFIG.partial().optional(),
6288
6386
  inputs: zod_default.record(zod_default.string(), INPUT_CONFIG),
6289
6387
  generators: zod_default.record(zod_default.string(), GENERATOR_CONFIG),
6290
6388
  outputs: zod_default.record(zod_default.string(), OUTPUT_CONFIG),
@@ -6318,7 +6416,11 @@ var DEFAULT_PROPS2 = {
6318
6416
  updates: null
6319
6417
  },
6320
6418
  handlers: { children: {} },
6321
- license: ""
6419
+ license: "",
6420
+ network: {
6421
+ envPort: null,
6422
+ defaultPort: -1
6423
+ }
6322
6424
  };
6323
6425
  var ToolboxRoot = class extends import_base2.Base {
6324
6426
  /** @hidden */
@@ -6347,7 +6449,8 @@ var ToolboxRoot = class extends import_base2.Base {
6347
6449
  config: this.props.config,
6348
6450
  state: this.props.state,
6349
6451
  handlers: this.props.handlers,
6350
- license: this.props.license
6452
+ license: this.props.license,
6453
+ network: this.props.network
6351
6454
  };
6352
6455
  }
6353
6456
  /** @hidden */
@@ -6730,9 +6833,27 @@ var createArtnet = (config) => {
6730
6833
  })();
6731
6834
  return connectPromise;
6732
6835
  };
6836
+ const getNextFrameTiming = (mode, timeMillis) => {
6837
+ const timecode = getTimecodeFromMillis(mode, timeMillis);
6838
+ timecode.frame += 1;
6839
+ if (timecode.frame >= TIMECODE_FPS[mode]) {
6840
+ timecode.frame = 0;
6841
+ timecode.seconds += 1;
6842
+ if (timecode.seconds >= 60) {
6843
+ timecode.seconds = 0;
6844
+ timecode.minutes += 1;
6845
+ if (timecode.minutes >= 60) {
6846
+ timecode.minutes = 0;
6847
+ timecode.hours += 1;
6848
+ }
6849
+ }
6850
+ }
6851
+ const nextFrameTimeMillis = getTimeMillisFromTimecode(timecode);
6852
+ return { nextFrameTimeMillis };
6853
+ };
6733
6854
  const sendTimecode = (mode, timeMillis) => {
6734
6855
  if (timeMillis < 0) {
6735
- return Promise.resolve();
6856
+ return Promise.resolve(getNextFrameTiming(mode, timeMillis));
6736
6857
  }
6737
6858
  if (!sendSocket) {
6738
6859
  return Promise.reject(new Error("ArtNet connection has not been opened"));
@@ -6773,7 +6894,7 @@ var createArtnet = (config) => {
6773
6894
  events.emit("error", error);
6774
6895
  reject(error);
6775
6896
  } else {
6776
- resolve();
6897
+ resolve(getNextFrameTiming(mode, timeMillis));
6777
6898
  }
6778
6899
  }
6779
6900
  )
@@ -6786,6 +6907,7 @@ var createArtnet = (config) => {
6786
6907
  };
6787
6908
  return {
6788
6909
  connect,
6910
+ getNextFrameTiming,
6789
6911
  sendTimecode,
6790
6912
  on,
6791
6913
  addListener,
@@ -6866,7 +6988,7 @@ var ArtnetInputConnection = ({
6866
6988
  created.connect().then(() => {
6867
6989
  artnet = created;
6868
6990
  setArtnetInstance(created);
6869
- log.info("ArtNet Timecode output initialized");
6991
+ log.info("ArtNet Timecode input initialized");
6870
6992
  setConnection({ ...connectionConfig, status: "active" });
6871
6993
  }).catch((err) => {
6872
6994
  const error = new Error("Failed to start ArtNet Timecode output");
@@ -14190,12 +14312,30 @@ var ArtnetOutputConnection = ({
14190
14312
  }
14191
14313
  if (timecodeState?.state === "playing" || timecodeState?.state === "lagging") {
14192
14314
  const tcState = timecodeState;
14193
- const interval = setInterval(() => {
14315
+ let timeoutId = null;
14316
+ const sendNextFrame = () => {
14194
14317
  const time = (Date.now() - tcState.effectiveStartTimeMillis) * tcState.speed;
14195
- artnetInstance.sendTimecode(mode, time);
14196
- }, 1e3 / TIMECODE_FPS[mode]);
14318
+ artnetInstance.sendTimecode(mode, time).then(({ nextFrameTimeMillis }) => {
14319
+ const delay = nextFrameTimeMillis - time + 1;
14320
+ timeoutId = setTimeout(sendNextFrame, delay);
14321
+ }).catch(() => {
14322
+ scheduleNextFrame();
14323
+ });
14324
+ };
14325
+ const scheduleNextFrame = () => {
14326
+ const time = (Date.now() - tcState.effectiveStartTimeMillis) * tcState.speed;
14327
+ const { nextFrameTimeMillis } = artnetInstance.getNextFrameTiming(
14328
+ mode,
14329
+ time
14330
+ );
14331
+ const delay = nextFrameTimeMillis - time + 1;
14332
+ timeoutId = setTimeout(sendNextFrame, delay);
14333
+ };
14334
+ scheduleNextFrame();
14197
14335
  return () => {
14198
- clearInterval(interval);
14336
+ if (timeoutId) {
14337
+ clearTimeout(timeoutId);
14338
+ }
14199
14339
  };
14200
14340
  } else if (timecodeState?.state === "stopped") {
14201
14341
  artnetInstance.sendTimecode(mode, timecodeState?.positionMillis ?? 0);
@@ -14449,6 +14589,8 @@ var ClockGenerator = ({
14449
14589
  timecode: {
14450
14590
  metadata: null,
14451
14591
  name: null,
14592
+ errors: [],
14593
+ warnings: [],
14452
14594
  state: {
14453
14595
  accuracyMillis: null,
14454
14596
  smpteMode: null,
@@ -14650,10 +14792,7 @@ var UpdateChecker = ({
14650
14792
 
14651
14793
  // src/env.ts
14652
14794
  var getEnv = (logger2) => {
14653
- const PORT = process.env.PORT ? parseInt(process.env.PORT, 10) : {
14654
- from: 4100,
14655
- to: 4200
14656
- };
14795
+ const PORT = process.env.PORT && parseInt(process.env.PORT, 10) || null;
14657
14796
  let API_BASE_URL;
14658
14797
  try {
14659
14798
  API_BASE_URL = process.env.API_BASE_URL ? new URL(process.env.API_BASE_URL) : new URL("https://arcanewizards.com");
@@ -14671,6 +14810,7 @@ var getEnv = (logger2) => {
14671
14810
 
14672
14811
  // src/app.tsx
14673
14812
  var import_jsx_runtime9 = require("react/jsx-runtime");
14813
+ var DEFAULT_PORT = { from: 4100, to: 4200 };
14674
14814
  var App = ({
14675
14815
  title,
14676
14816
  version: version2,
@@ -14728,14 +14868,16 @@ var App = ({
14728
14868
  [handlers]
14729
14869
  );
14730
14870
  const license = useLicense();
14731
- const appListenerConfig = (0, import_react10.useMemo)(
14732
- () => ({
14733
- default: {
14734
- port: env.PORT
14735
- }
14736
- }),
14737
- [env.PORT]
14738
- );
14871
+ const appListenerConfig = (0, import_react10.useMemo)(() => {
14872
+ const baseConfig = {
14873
+ port: data.appListener?.port ?? DEFAULT_PORT,
14874
+ interface: data.appListener?.interface ?? void 0
14875
+ };
14876
+ if (env.PORT) {
14877
+ baseConfig.port = env.PORT;
14878
+ }
14879
+ return baseConfig;
14880
+ }, [env.PORT, data.appListener]);
14739
14881
  if (!license) {
14740
14882
  return;
14741
14883
  }
@@ -14748,7 +14890,11 @@ var App = ({
14748
14890
  handlers: availableHandlers,
14749
14891
  onUpdateConfig,
14750
14892
  onCallHandler: callHandler,
14751
- license: license.text
14893
+ license: license.text,
14894
+ network: {
14895
+ envPort: env.PORT,
14896
+ defaultPort: DEFAULT_PORT
14897
+ }
14752
14898
  }
14753
14899
  ),
14754
14900
  /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(InputConnections, { state, setState }),
@@ -14800,7 +14946,7 @@ var App = ({
14800
14946
  {
14801
14947
  toolkit,
14802
14948
  setWindowUrl,
14803
- listenerConfig: appListenerConfig
14949
+ listenerConfig: { appListenerConfig }
14804
14950
  }
14805
14951
  )
14806
14952
  ]
@@ -14818,7 +14964,7 @@ var createApp = (props) => {
14818
14964
  };
14819
14965
 
14820
14966
  // package.json
14821
- var version = "0.1.3";
14967
+ var version = "0.1.5";
14822
14968
 
14823
14969
  // src/index.ts
14824
14970
  var runTimecodeToolboxServer = ({
@@ -14883,3 +15029,14 @@ lodash/lodash.js:
14883
15029
  * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
14884
15030
  *)
14885
15031
  */
15032
+ /*! Bundled license information:
15033
+
15034
+ escape-html/index.js:
15035
+ (*!
15036
+ * escape-html
15037
+ * Copyright(c) 2012-2013 TJ Holowaychuk
15038
+ * Copyright(c) 2015 Andreas Lubbe
15039
+ * Copyright(c) 2015 Tiancheng "Timothy" Gu
15040
+ * MIT Licensed
15041
+ *)
15042
+ */