@octane-xplat/workshop 0.0.0-nightly.g14544fe

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.
Files changed (67) hide show
  1. package/LICENSE +21 -0
  2. package/MOBILE.md +143 -0
  3. package/README.md +307 -0
  4. package/dist/build/discover.js +404 -0
  5. package/dist/build/macos-node.js +77 -0
  6. package/dist/build/mobile-node.js +96 -0
  7. package/dist/build/mobile-regex.js +40 -0
  8. package/dist/build/node.js +426 -0
  9. package/dist/build/vite-mobile.js +75 -0
  10. package/dist/build/vite.js +230 -0
  11. package/dist/build/windows/preflight.js +83 -0
  12. package/dist/contract.js +50 -0
  13. package/dist/index.js +2 -0
  14. package/package.json +127 -0
  15. package/src/build/discover.ts +585 -0
  16. package/src/build/macos/shell.macos.ts +674 -0
  17. package/src/build/macos-node.ts +98 -0
  18. package/src/build/macos-vite.ts +48 -0
  19. package/src/build/mobile-node.ts +127 -0
  20. package/src/build/mobile-regex.ts +60 -0
  21. package/src/build/node.d.ts +65 -0
  22. package/src/build/node.ts +537 -0
  23. package/src/build/vite-mobile.d.ts +21 -0
  24. package/src/build/vite-mobile.ts +102 -0
  25. package/src/build/vite.d.ts +11 -0
  26. package/src/build/vite.ts +316 -0
  27. package/src/build/windows/preflight.ts +113 -0
  28. package/src/catalog.ts +58 -0
  29. package/src/contract.ts +257 -0
  30. package/src/controls.ts +159 -0
  31. package/src/errors.ts +47 -0
  32. package/src/fixture.ts +158 -0
  33. package/src/index.ts +6 -0
  34. package/src/macos/controller.ts +170 -0
  35. package/src/macos/index.macos.ts +2 -0
  36. package/src/macos/stage.macos.ts +182 -0
  37. package/src/mobile/controller.ts +134 -0
  38. package/src/mobile/entry.mobile.ts +607 -0
  39. package/src/mobile/index.mobile.ts +3 -0
  40. package/src/mobile/mount.mobile.ts +60 -0
  41. package/src/mobile/tree.mobile.tsrx +17 -0
  42. package/src/session.ts +520 -0
  43. package/src/web/entry.web.ts +270 -0
  44. package/src/web/index.web.ts +7 -0
  45. package/src/web/mount.web.ts +86 -0
  46. package/src/web/shell.css +449 -0
  47. package/src/web/shell.web.tsrx +759 -0
  48. package/types/generated/.tsrx-typegen-manifest.json +24 -0
  49. package/types/generated/catalog.d.ts +30 -0
  50. package/types/generated/contract.d.ts +145 -0
  51. package/types/generated/controls.d.ts +28 -0
  52. package/types/generated/errors.d.ts +13 -0
  53. package/types/generated/fixture.d.ts +53 -0
  54. package/types/generated/index.d.ts +6 -0
  55. package/types/generated/macos/controller.d.ts +52 -0
  56. package/types/generated/macos/index.macos.d.ts +2 -0
  57. package/types/generated/macos/stage.macos.d.ts +10 -0
  58. package/types/generated/mobile/controller.d.ts +31 -0
  59. package/types/generated/mobile/entry.mobile.d.ts +22 -0
  60. package/types/generated/mobile/index.mobile.d.ts +3 -0
  61. package/types/generated/mobile/mount.mobile.d.ts +4 -0
  62. package/types/generated/mobile/tree.mobile.d.ts +4 -0
  63. package/types/generated/session.d.ts +84 -0
  64. package/types/generated/web/entry.web.d.ts +53 -0
  65. package/types/generated/web/index.web.d.ts +7 -0
  66. package/types/generated/web/mount.web.d.ts +2 -0
  67. package/types/generated/web/shell.web.d.ts +4 -0
@@ -0,0 +1,230 @@
1
+ import { discoverStories, normalizeInclude } from "./discover.js";
2
+ import { existsSync, readFileSync, statSync } from "node:fs";
3
+ import { dirname, join, resolve, sep } from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+ //#region src/build/vite.ts
6
+ /**
7
+ * xplatWorkshop — the workshop dev-server plugin.
8
+ *
9
+ * Emits a virtual catalog module whose metadata comes from static discovery
10
+ * (never module evaluation), a virtual entry that boots the adaptive shell,
11
+ * and a virtual index.html. Story modules stay lazily imported per selection;
12
+ * loaders exist only for stories applicable to the build target, so a
13
+ * platform-specific leaf is never imported into an incompatible bundle.
14
+ */
15
+ var CATALOG_ID = "\0xplat-workshop-catalog";
16
+ var ENTRY_ID = "\0xplat-workshop-entry";
17
+ var STORY_FILE_RE = /\.stories(?:\.(?:web|mobile|ios|android|macos|windows|linux))?\.(?:[cm]?[jt]s|[jt]sx|[jt]srx)$/;
18
+ var TARGET_RESOLUTION = {
19
+ web: {
20
+ conditions: ["web"],
21
+ extensions: [
22
+ ".web.tsrx",
23
+ ".tsrx",
24
+ ".web.tsx",
25
+ ".tsx",
26
+ ".web.ts",
27
+ ".ts",
28
+ ".mts",
29
+ ".ts",
30
+ ".jsx",
31
+ ".js",
32
+ ".json"
33
+ ]
34
+ },
35
+ linux: {
36
+ conditions: ["linux", "web"],
37
+ extensions: [
38
+ ".linux.tsrx",
39
+ ".web.tsrx",
40
+ ".tsrx",
41
+ ".linux.tsx",
42
+ ".web.tsx",
43
+ ".tsx",
44
+ ".linux.ts",
45
+ ".web.ts",
46
+ ".ts",
47
+ ".mts",
48
+ ".ts",
49
+ ".jsx",
50
+ ".js",
51
+ ".json"
52
+ ]
53
+ }
54
+ };
55
+ var fsUrl = (file) => `/@fs/${file.split(sep).join("/")}`;
56
+ function catalogCode(root, config, target) {
57
+ const storiesConfig = config?.stories ?? {};
58
+ const { entries, diagnostics } = discoverStories(root, {
59
+ include: storiesConfig.include,
60
+ exclude: storiesConfig.exclude,
61
+ target
62
+ });
63
+ const include = JSON.stringify(normalizeInclude(storiesConfig.include));
64
+ const loaders = entries.filter((entry) => entry.applicable && diagnostics.length === 0).map((entry) => `\t${JSON.stringify(entry.id)}: (stamp) => stamp === undefined
65
+ \t\t? import(${JSON.stringify(fsUrl(entry.file))})
66
+ \t\t: import(/* @vite-ignore */ ${JSON.stringify(fsUrl(entry.file))} + '?t=' + encodeURIComponent(String(stamp))),`).join("\n");
67
+ return `import { catalogDidUpdate } from '@octane-xplat/workshop/web'
68
+
69
+ export const catalogMeta = ${JSON.stringify(entries)}
70
+ export const diagnostics = ${JSON.stringify(diagnostics)}
71
+ export const includePatterns = ${include}
72
+
73
+ const loaders = {
74
+ ${loaders}
75
+ }
76
+
77
+ export const catalog = catalogMeta.map((entry) =>
78
+ loaders[entry.id] ? { ...entry, load: loaders[entry.id] } : entry,
79
+ )
80
+
81
+ export function loadStory(id, stamp) {
82
+ const entry = catalog.find((item) => item.id === id)
83
+ if (!entry?.load) {
84
+ return Promise.reject(
85
+ new Error(
86
+ entry
87
+ ? 'story "' + id + '" is not supported on this target'
88
+ : 'story "' + id + '" is not in the catalog',
89
+ ),
90
+ )
91
+ }
92
+ return entry.load(stamp)
93
+ }
94
+
95
+ catalogDidUpdate(catalog, diagnostics)
96
+ if (import.meta.hot) {
97
+ import.meta.hot.accept((next) => catalogDidUpdate(next?.catalog ?? catalog, next?.diagnostics ?? diagnostics))
98
+ }
99
+ `;
100
+ }
101
+ function entryCode(config, target, story, packageDir, root) {
102
+ const providerModules = config?.providerModules ?? [];
103
+ const imports = providerModules.map((specifier, index) => {
104
+ const abs = resolve(root, specifier);
105
+ return `import * as __workshopPreset${index} from ${JSON.stringify(fsUrl(abs))}`;
106
+ }).join("\n");
107
+ const providers = providerModules.map((_, index) => `...(__workshopPreset${index}.providers ?? __workshopPreset${index}.default ?? [])`).join(", ");
108
+ const shellCss = fsUrl(join(packageDir, "web", "shell.css"));
109
+ return `import { catalog, loadStory, diagnostics } from ${JSON.stringify(CATALOG_ID)}
110
+ import { startWorkshop } from '@octane-xplat/workshop/web'
111
+ import '@octane-xplat/ui/theme/tokens.css'
112
+ import ${JSON.stringify(shellCss)}
113
+ ${imports}
114
+
115
+ startWorkshop({
116
+ catalog,
117
+ diagnostics,
118
+ loadStory,
119
+ target: ${JSON.stringify(target)},
120
+ initialStoryId: ${JSON.stringify(story ?? null)},
121
+ globalProviders: [${providers}],
122
+ hot: import.meta.hot,
123
+ })
124
+ `;
125
+ }
126
+ var WORKSHOP_HTML = `<!doctype html>
127
+ <html lang="en">
128
+ <head>
129
+ <meta charset="utf-8" />
130
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
131
+ <title>octane-xplat workshop</title>
132
+ <style>html,body{margin:0;height:100%}#workshop-root{height:100%}</style>
133
+ </head>
134
+ <body>
135
+ <div id="workshop-root"></div>
136
+ <script type="module" src="/@id/__x00__xplat-workshop-entry"><\/script>
137
+ </body>
138
+ </html>
139
+ `;
140
+ /**
141
+ * @param {object} [options]
142
+ * @param {string} options.cwd - consumer project root
143
+ * @param {object} [options.config] - resolved workshop.config.* contents
144
+ * @param {string} [options.target] - launch target (DOM hosts: 'web' | 'linux')
145
+ * @param {string} [options.story] - initial stable story id
146
+ */
147
+ function xplatWorkshop(options = {}) {
148
+ const target = options.target ?? "web";
149
+ const story = options.story ?? null;
150
+ const resolution = TARGET_RESOLUTION[target] ?? TARGET_RESOLUTION.web;
151
+ let root = options.cwd ?? process.cwd();
152
+ let config = options.config ?? {};
153
+ return [{
154
+ name: "xplat-workshop-virtual",
155
+ configResolved(resolved) {
156
+ root = options.cwd ?? resolved.root;
157
+ },
158
+ resolveId(id) {
159
+ if (id === CATALOG_ID || id === ENTRY_ID) return id;
160
+ return null;
161
+ },
162
+ load(id) {
163
+ if (id === CATALOG_ID) return catalogCode(root, config, target);
164
+ if (id === ENTRY_ID) return entryCode(config, target, story, dirname(fileURLToPath(import.meta.url)), root);
165
+ return null;
166
+ }
167
+ }, {
168
+ name: "xplat-workshop-shell",
169
+ config() {
170
+ return {
171
+ optimizeDeps: {
172
+ exclude: ["@octane-xplat/workshop"],
173
+ include: ["@octane-xplat/workshop > storybook/preview-api"]
174
+ },
175
+ resolve: { conditions: [...resolution.conditions] }
176
+ };
177
+ },
178
+ configResolved(resolved) {
179
+ const apply = (scope) => {
180
+ scope.resolve.extensions = [...resolution.extensions, ...scope.resolve.extensions.filter((ext) => !resolution.extensions.includes(ext))];
181
+ scope.resolve.conditions = [...resolution.conditions, ...scope.resolve.conditions.filter((cond) => !resolution.conditions.includes(cond))];
182
+ };
183
+ apply(resolved);
184
+ for (const env of Object.values(resolved.environments ?? {})) apply(env);
185
+ },
186
+ hotUpdate: {
187
+ order: "pre",
188
+ handler(ctx) {
189
+ if (this.environment.name !== "client" || !STORY_FILE_RE.test(ctx.file)) return;
190
+ const catalog = this.environment.moduleGraph.getModuleById(CATALOG_ID);
191
+ if (!catalog) return;
192
+ this.environment.moduleGraph.invalidateModule(catalog);
193
+ return [catalog];
194
+ }
195
+ },
196
+ configureServer(s) {
197
+ s.middlewares.use((req, res, next) => {
198
+ const url = (req.url ?? "").split("?")[0];
199
+ if (url === "/" || url === "/index.html") {
200
+ res.statusCode = 200;
201
+ res.setHeader("content-type", "text/html; charset=utf-8");
202
+ res.end(WORKSHOP_HTML);
203
+ return;
204
+ }
205
+ if (url.startsWith("/@workshop-assets/")) return serveAsset(config, root, url, res, next);
206
+ next();
207
+ });
208
+ }
209
+ }];
210
+ }
211
+ function serveAsset(config, root, url, res, next) {
212
+ const assets = config?.assets ?? {};
213
+ const rest = url.slice(18);
214
+ const name = rest.split("/")[0];
215
+ const dir = assets[name] ? resolve(root, assets[name]) : null;
216
+ if (!dir) {
217
+ next();
218
+ return;
219
+ }
220
+ const file = resolve(dir, rest.slice(name.length + 1));
221
+ if (!(file === dir || file.startsWith(dir + sep)) || !existsSync(file) || !statSync(file).isFile()) {
222
+ res.statusCode = 404;
223
+ res.end("not found");
224
+ return;
225
+ }
226
+ res.statusCode = 200;
227
+ res.end(readFileSync(file));
228
+ }
229
+ //#endregion
230
+ export { xplatWorkshop };
@@ -0,0 +1,83 @@
1
+ import { existsSync, readFileSync } from "node:fs";
2
+ import { createRequire } from "node:module";
3
+ import { join } from "node:path";
4
+ import { execFileSync } from "node:child_process";
5
+ //#region src/build/windows/preflight.ts
6
+ /** Read-only Windows setup evidence. Prerequisites never qualify a host. */
7
+ function commandOutput(command, args) {
8
+ try {
9
+ return execFileSync(command, args, {
10
+ encoding: "utf8",
11
+ timeout: 5e3,
12
+ maxBuffer: 65536,
13
+ stdio: [
14
+ "ignore",
15
+ "pipe",
16
+ "pipe"
17
+ ],
18
+ windowsHide: true
19
+ }).trim();
20
+ } catch {
21
+ return null;
22
+ }
23
+ }
24
+ function windowsPreflight(root, { platform = process.platform, run = commandOutput } = {}) {
25
+ const manifest = JSON.parse(readFileSync(join(root, "package.json"), "utf8"));
26
+ const require = createRequire(join(root, "package.json"));
27
+ const installed = (name) => {
28
+ for (const specifier of [`${name}/package.json`, name]) try {
29
+ require.resolve(specifier);
30
+ return true;
31
+ } catch {}
32
+ return false;
33
+ };
34
+ const runtime = manifest.devDependencies?.["@nativescript/windows"] ?? manifest.dependencies?.["@nativescript/windows"];
35
+ const requirements = {
36
+ "Windows host": platform === "win32",
37
+ "nativescript.config": [
38
+ "ts",
39
+ "mts",
40
+ "js",
41
+ "mjs"
42
+ ].some((ext) => existsSync(join(root, `nativescript.config.${ext}`))),
43
+ "App_Resources/Windows/Package.appxmanifest": existsSync(join(root, "App_Resources/Windows/Package.appxmanifest")),
44
+ "@nativescript/windows exact version": typeof runtime === "string" && /^\d+\.\d+\.\d+(?:-[\w.-]+)?(?:\+[\w.-]+)?$/.test(runtime)
45
+ };
46
+ for (const name of [
47
+ "@nativescript/windows",
48
+ "@nativescript/core",
49
+ "@nativescript-community/octane",
50
+ "@nativescript/vite",
51
+ "nativescript",
52
+ "vite"
53
+ ]) requirements[name] = installed(name);
54
+ if (platform === "win32") {
55
+ const sdk = run("dotnet", ["--version"]);
56
+ requirements[".NET SDK >= 10"] = typeof sdk === "string" && /^\d+\.\d+\.\d+/.test(sdk) && Number(sdk.split(".")[0]) >= 10;
57
+ requirements["Developer Mode (development launch)"] = run("powershell", [
58
+ "-NoProfile",
59
+ "-NonInteractive",
60
+ "-Command",
61
+ "(Get-ItemProperty \"HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\AppModelUnlock\" -Name AllowDevelopmentWithoutDevLicense -ErrorAction SilentlyContinue).AllowDevelopmentWithoutDevLicense"
62
+ ])?.trim() === "1";
63
+ }
64
+ return {
65
+ backend: "experimental nativescript/winui",
66
+ executionHost: {
67
+ required: "win32",
68
+ current: platform,
69
+ reachable: platform === "win32"
70
+ },
71
+ qualification: "unverified",
72
+ requirements,
73
+ status: platform !== "win32" ? "remote-host-required" : Object.values(requirements).every(Boolean) ? "unqualified-backend" : "missing-prerequisites",
74
+ note: "Windows workshop mounting, shell and reload are not implemented or host-qualified. " + (platform !== "win32" ? "Run these commands in a Windows checkout; SDK and Developer Mode checks were not run. " : "") + "Prerequisites do not prove renderer compatibility, input, accessibility or lifecycle support. No web fallback is used."
75
+ };
76
+ }
77
+ function windowsLaunchBlocker(report) {
78
+ if (report.status === "remote-host-required") return "Windows workshop requires a real Windows host. Run `xplat workshop doctor` in that host’s checkout. No web fallback is used.";
79
+ const missing = Object.entries(report.requirements).filter(([, ok]) => !ok).map(([name]) => name);
80
+ return (missing.length ? `Windows prerequisites missing: ${missing.join(", ")}. ` : "") + "Windows workshop mounting, shell and reload remain unimplemented and unqualified; launch is blocked. Run `xplat workshop doctor` for setup evidence.";
81
+ }
82
+ //#endregion
83
+ export { windowsLaunchBlocker, windowsPreflight };
@@ -0,0 +1,50 @@
1
+ //#region src/contract.ts
2
+ var WORKSHOP_TARGETS = [
3
+ "web",
4
+ "ios",
5
+ "android",
6
+ "macos",
7
+ "windows",
8
+ "linux"
9
+ ];
10
+ /** Version of the authoring contract — bumped on breaking changes. */
11
+ var WORKSHOP_CONTRACT_VERSION = 1;
12
+ /** Declare a story. Validates cheap authoring rules eagerly. */
13
+ function defineStory(definition) {
14
+ assertLiteralAuthoring(definition);
15
+ return definition;
16
+ }
17
+ function assertLiteralAuthoring(definition) {
18
+ const fail = (message) => {
19
+ throw new Error(`defineStory: ${message}`);
20
+ };
21
+ if (typeof definition?.id !== "string" || !definition.id) fail("a story requires a non-empty string id");
22
+ if (typeof definition.title !== "string" || !definition.title) fail(`story "${definition.id}" requires a non-empty string title`);
23
+ const targets = definition.targets;
24
+ if (!(targets === "all" || Array.isArray(targets) && targets.length > 0 && targets.every((t) => WORKSHOP_TARGETS.includes(t)))) fail(`story "${definition.id}" — targets must be 'all' or a subset of: ${WORKSHOP_TARGETS.join(", ")}`);
25
+ if (typeof definition.component !== "function") fail(`story "${definition.id}" — component must be an Octane component`);
26
+ if (definition.args == null || typeof definition.args !== "object") fail(`story "${definition.id}" — args must be an object`);
27
+ if ("state" in definition && typeof definition.state !== "function") fail(`story "${definition.id}" — state must be a factory function`);
28
+ if ("fixture" in definition && typeof definition.fixture !== "function") fail(`story "${definition.id}" — fixture must be a factory function`);
29
+ if (definition.args && typeof definition.args === "object") {
30
+ for (const key of ["state", "fixture"]) if (key in definition.args) fail(`story "${definition.id}" — args may not declare reserved injected prop "${key}"`);
31
+ }
32
+ if (definition.controls) for (const [key, control] of Object.entries(definition.controls)) {
33
+ if (!control || typeof control !== "object") fail(`story "${definition.id}" — control "${key}" must be an object`);
34
+ const type = control.type;
35
+ if (![
36
+ "boolean",
37
+ "string",
38
+ "number",
39
+ "enum"
40
+ ].includes(type ?? "")) fail(`story "${definition.id}" — control "${key}" has unknown type "${type}" (expected boolean, string, number or enum)`);
41
+ if (type === "enum" && !Array.isArray(control.options)) fail(`story "${definition.id}" — enum control "${key}" requires an options array`);
42
+ if (type === "number" && typeof control.min === "number" && typeof control.max === "number" && control.min > control.max) fail(`story "${definition.id}" — number control "${key}" has min > max`);
43
+ }
44
+ if (definition.providers !== void 0 && !Array.isArray(definition.providers)) fail(`story "${definition.id}" — providers must be an array`);
45
+ }
46
+ function defineWorkshopConfig(config) {
47
+ return config;
48
+ }
49
+ //#endregion
50
+ export { WORKSHOP_CONTRACT_VERSION, WORKSHOP_TARGETS, defineStory, defineWorkshopConfig };
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ import { WORKSHOP_CONTRACT_VERSION, WORKSHOP_TARGETS, defineStory, defineWorkshopConfig } from "./contract.js";
2
+ export { WORKSHOP_CONTRACT_VERSION, WORKSHOP_TARGETS, defineStory, defineWorkshopConfig };
package/package.json ADDED
@@ -0,0 +1,127 @@
1
+ {
2
+ "name": "@octane-xplat/workshop",
3
+ "version": "0.0.0-nightly.g14544fe",
4
+ "description": "Development-only component workshop for Octane Xplat — typed stories, metadata discovery, adaptive shell, lifecycle and warm reload",
5
+ "keywords": [
6
+ "components",
7
+ "cross-platform",
8
+ "dev-tools",
9
+ "octane",
10
+ "stories",
11
+ "storybook",
12
+ "workshop",
13
+ "xplat"
14
+ ],
15
+ "homepage": "https://github.com/octane-xplat/octane-xplat/tree/main/packages/workshop",
16
+ "license": "MIT",
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "https://github.com/octane-xplat/octane-xplat",
20
+ "directory": "packages/workshop"
21
+ },
22
+ "files": [
23
+ "types",
24
+ "dist",
25
+ "src",
26
+ "MOBILE.md",
27
+ "!src/**/*.test.*",
28
+ "!src/**/*.spec.*"
29
+ ],
30
+ "type": "module",
31
+ "exports": {
32
+ ".": {
33
+ "types": "./types/generated/index.d.ts",
34
+ "node": "./dist/index.js",
35
+ "default": "./src/index.ts"
36
+ },
37
+ "./web": {
38
+ "types": "./types/generated/web/index.web.d.ts",
39
+ "default": "./src/web/index.web.ts"
40
+ },
41
+ "./vite": {
42
+ "types": "./src/build/vite.d.ts",
43
+ "default": "./dist/build/vite.js"
44
+ },
45
+ "./node": {
46
+ "types": "./src/build/node.d.ts",
47
+ "default": "./dist/build/node.js"
48
+ },
49
+ "./package.json": "./package.json",
50
+ "./mobile": {
51
+ "types": "./types/generated/mobile/index.mobile.d.ts",
52
+ "default": "./src/mobile/index.mobile.ts"
53
+ },
54
+ "./vite-mobile": {
55
+ "types": "./src/build/vite-mobile.d.ts",
56
+ "default": "./dist/build/vite-mobile.js"
57
+ },
58
+ "./macos": {
59
+ "types": "./types/generated/macos/index.macos.d.ts",
60
+ "default": "./src/macos/index.macos.ts"
61
+ }
62
+ },
63
+ "publishConfig": {
64
+ "access": "public"
65
+ },
66
+ "dependencies": {
67
+ "@babel/core": "7.29.7",
68
+ "@babel/plugin-transform-unicode-property-regex": "7.29.7",
69
+ "@octane-xplat/cli": "0.0.0-nightly.g14544fe",
70
+ "@octane-xplat/platform": "0.0.0-nightly.g14544fe",
71
+ "@octane-xplat/ui": "0.0.0-nightly.g14544fe",
72
+ "storybook": "10.6.1",
73
+ "tinyglobby": "0.2.17"
74
+ },
75
+ "devDependencies": {
76
+ "@nativescript-community/octane": "0.2.5",
77
+ "@nativescript/core": "9.1.3",
78
+ "@nativescript/macos-node-api": "0.4.4-next.2026-08-09-31292056208",
79
+ "@nativescript/types": "9.1.4",
80
+ "@octane-xplat/macos-renderer": "0.0.0-nightly.g14544fe",
81
+ "@octanejs/vite-plugin": "0.1.61",
82
+ "octane": "0.11.0",
83
+ "tsrx-typegen": "0.3.0",
84
+ "typescript": "5.9.3",
85
+ "vite": "8.3.0"
86
+ },
87
+ "peerDependencies": {
88
+ "@nativescript-community/octane": ">=0.2.4 <1",
89
+ "@nativescript/core": ">=9.1.3 <10",
90
+ "@nativescript/macos-node-api": "0.4.4-next.2026-08-09-31292056208",
91
+ "@octane-xplat/macos-renderer": ">=0.14.0 <1",
92
+ "@octanejs/vite-plugin": ">=0.1.61",
93
+ "octane": ">=0.6.3 <1",
94
+ "vite": ">=8"
95
+ },
96
+ "peerDependenciesMeta": {
97
+ "vite": {
98
+ "optional": true
99
+ },
100
+ "@nativescript/core": {
101
+ "optional": true
102
+ },
103
+ "@nativescript-community/octane": {
104
+ "optional": true
105
+ },
106
+ "@octane-xplat/macos-renderer": {
107
+ "optional": true
108
+ },
109
+ "@nativescript/macos-node-api": {
110
+ "optional": true
111
+ }
112
+ },
113
+ "scripts": {
114
+ "typegen": "tsrx-typegen --target workshop",
115
+ "typecheck": "node ../../scripts/typecheck.ts",
116
+ "test": "vitest run && tsrx-tsc --noEmit -p tsconfig.test.json",
117
+ "test:e2e": "pnpm --filter @xplat/workshop-demo test:e2e",
118
+ "test:packed": "pnpm build && node tests/packed-consumer.web.mjs",
119
+ "test:packed:linux": "node tests/packed-consumer.linux.mjs",
120
+ "test:packed:macos": "node tests/packed-consumer.macos.mjs",
121
+ "test:packed:windows": "node tests/packed-windows-preflight.mjs",
122
+ "pack:check": "tsrx-typegen --pack-check",
123
+ "test:types": "tsrx-tsc --noEmit -p tsconfig.test.json",
124
+ "test:packed:mobile": "node tests/packed-consumer.mobile.mjs",
125
+ "build": "vite build"
126
+ }
127
+ }