@tokamakdev/tok 0.1.1-beta.82 → 0.1.1-beta.83
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/README.md +5 -1
- package/dist/dev-socket.d.mts +10 -0
- package/dist/dev-socket.mjs +106 -0
- package/dist/events.d.mts +8 -0
- package/dist/events.mjs +7 -0
- package/dist/vite.d.mts +3 -3
- package/dist/vite.mjs +71 -27
- package/package.json +21 -12
package/README.md
CHANGED
|
@@ -12,6 +12,7 @@ npx tok targets
|
|
|
12
12
|
| Entry | Contents |
|
|
13
13
|
| --- | --- |
|
|
14
14
|
| `@tokamakdev/tok` | The `Config` type of the Vite plugin's options |
|
|
15
|
+
| `@tokamakdev/tok/events` | The app's events: `onStart`, `onResume` and `onSuspend` |
|
|
15
16
|
| `@tokamakdev/tok/vite` | The Vite plugin, `tokamak()` |
|
|
16
17
|
| `tok` | The CLI |
|
|
17
18
|
|
|
@@ -28,7 +29,10 @@ export default defineConfig({
|
|
|
28
29
|
});
|
|
29
30
|
```
|
|
30
31
|
|
|
31
|
-
It does nothing unless `tok` runs the build or development command.
|
|
32
|
+
It does nothing unless `tok` runs the build or development command. Then it
|
|
33
|
+
makes the entry Worker import `src/tokamak.ts` and export the entrypoint the
|
|
34
|
+
runtime delivers events through, and in development it delivers the device's
|
|
35
|
+
events to the development Worker through Cloudflare's dev registry.
|
|
32
36
|
|
|
33
37
|
The package installs the `tok` binary for the current machine through an
|
|
34
38
|
optional dependency (`@tokamakdev/tok-darwin-arm64`, `-darwin-x64`,
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** The loopback server the device's dev WebSocket reaches through `tok dev`'s relay. */
|
|
2
|
+
export interface DevSocket {
|
|
3
|
+
readonly port: number;
|
|
4
|
+
close(): Promise<void>;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Listens on a loopback port for dev WebSockets that carry `token`, and delivers each event they
|
|
8
|
+
* carry to `TokamakEvents` in the development Worker `workerName`, replying with its reply.
|
|
9
|
+
*/
|
|
10
|
+
export declare function openDevSocket(workerName: string | undefined, token: string | undefined): Promise<DevSocket>;
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import http from "node:http";
|
|
2
|
+
import { createRequire } from "node:module";
|
|
3
|
+
import { pathToFileURL } from "node:url";
|
|
4
|
+
import { WebSocketServer } from "ws";
|
|
5
|
+
/** The header `tok dev`'s relay forwards with the device's session token. */
|
|
6
|
+
const SESSION_HEADER = "x-tokamak-session";
|
|
7
|
+
/** Calls `TokamakEvents` in the Worker its `TOKAMAK` service binding names, through the dev registry. */
|
|
8
|
+
const CALLER = `export default {
|
|
9
|
+
async fetch(request, env) {
|
|
10
|
+
const { name, event } = await request.json();
|
|
11
|
+
try {
|
|
12
|
+
const { reply } = await env.TOKAMAK.dispatch(name, event);
|
|
13
|
+
return Response.json({ reply: reply ?? null });
|
|
14
|
+
} catch (error) {
|
|
15
|
+
return new Response(error?.stack ?? String(error), { status: 500 });
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
};`;
|
|
19
|
+
/**
|
|
20
|
+
* Listens on a loopback port for dev WebSockets that carry `token`, and delivers each event they
|
|
21
|
+
* carry to `TokamakEvents` in the development Worker `workerName`, replying with its reply.
|
|
22
|
+
*/
|
|
23
|
+
export async function openDevSocket(workerName, token) {
|
|
24
|
+
const worker = new DevWorker(workerName);
|
|
25
|
+
const server = http.createServer((_request, response) => response.writeHead(426).end());
|
|
26
|
+
const sockets = new WebSocketServer({ noServer: true });
|
|
27
|
+
server.on("upgrade", (request, socket, head) => {
|
|
28
|
+
if (!token || request.headers[SESSION_HEADER] !== token) {
|
|
29
|
+
socket.end("HTTP/1.1 401 Unauthorized\r\nConnection: close\r\n\r\n");
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
sockets.handleUpgrade(request, socket, head, (websocket) => serve(websocket, worker));
|
|
33
|
+
});
|
|
34
|
+
await new Promise((resolve, reject) => {
|
|
35
|
+
server.once("error", reject);
|
|
36
|
+
server.listen(0, "127.0.0.1", resolve);
|
|
37
|
+
});
|
|
38
|
+
return {
|
|
39
|
+
port: server.address().port,
|
|
40
|
+
async close() {
|
|
41
|
+
for (const websocket of sockets.clients)
|
|
42
|
+
websocket.terminate();
|
|
43
|
+
server.close();
|
|
44
|
+
await worker.dispose();
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
function serve(websocket, worker) {
|
|
49
|
+
// The device opens another dev WebSocket after this one fails.
|
|
50
|
+
websocket.on("error", () => websocket.terminate());
|
|
51
|
+
websocket.on("message", (data) => {
|
|
52
|
+
const message = parseMessage(String(data));
|
|
53
|
+
if (message?.type !== "event")
|
|
54
|
+
return;
|
|
55
|
+
worker.dispatch(message.name, message.event).then((reply) => websocket.send(JSON.stringify({ type: "reply", id: message.id, reply })), (error) => websocket.send(JSON.stringify({ type: "error", id: message.id, message: String(error) })));
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
function parseMessage(text) {
|
|
59
|
+
try {
|
|
60
|
+
return JSON.parse(text);
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
return undefined;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
/** The development Worker's `TokamakEvents`, called through a Miniflare session started on first use. */
|
|
67
|
+
class DevWorker {
|
|
68
|
+
name;
|
|
69
|
+
#miniflare;
|
|
70
|
+
constructor(name) {
|
|
71
|
+
this.name = name;
|
|
72
|
+
}
|
|
73
|
+
async dispatch(name, event) {
|
|
74
|
+
this.#miniflare ??= this.#start().catch((error) => {
|
|
75
|
+
this.#miniflare = undefined;
|
|
76
|
+
throw error;
|
|
77
|
+
});
|
|
78
|
+
const miniflare = await this.#miniflare;
|
|
79
|
+
const response = await miniflare.dispatchFetch("http://tokamak/", {
|
|
80
|
+
method: "POST",
|
|
81
|
+
body: JSON.stringify({ name, event }),
|
|
82
|
+
});
|
|
83
|
+
if (!response.ok)
|
|
84
|
+
throw new Error(await response.text());
|
|
85
|
+
return (await response.json()).reply;
|
|
86
|
+
}
|
|
87
|
+
async dispose() {
|
|
88
|
+
await (await this.#miniflare?.catch(() => undefined))?.dispose();
|
|
89
|
+
}
|
|
90
|
+
/** A Miniflare session from the Miniflare that Cloudflare's plugin uses. */
|
|
91
|
+
async #start() {
|
|
92
|
+
if (!this.name)
|
|
93
|
+
throw new Error("the Wrangler configuration names no Worker to deliver events to");
|
|
94
|
+
const require = createRequire(import.meta.resolve("@cloudflare/vite-plugin"));
|
|
95
|
+
const module = (await import(pathToFileURL(require.resolve("miniflare")).href));
|
|
96
|
+
const miniflare = new module.Miniflare(module.convertV4MiniflareOptions({
|
|
97
|
+
modules: true,
|
|
98
|
+
script: CALLER,
|
|
99
|
+
compatibilityDate: "2025-01-01",
|
|
100
|
+
serviceBindings: { TOKAMAK: { name: this.name, entrypoint: "TokamakEvents" } },
|
|
101
|
+
unsafeDevRegistryPath: module.getDefaultDevRegistryPath(),
|
|
102
|
+
}));
|
|
103
|
+
await miniflare.ready;
|
|
104
|
+
return miniflare;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** Runs once per runtime start, including when the system starts the app in the background. */
|
|
2
|
+
export declare const onStart: (listener: import("@tokamakdev/plugin/events").Listener<{
|
|
3
|
+
readonly foreground: boolean;
|
|
4
|
+
}, void>) => void;
|
|
5
|
+
/** Runs each time the app moves into the foreground, but not when it starts there. */
|
|
6
|
+
export declare const onResume: (listener: import("@tokamakdev/plugin/events").Listener<Readonly<Record<string, never>>, void>) => void;
|
|
7
|
+
/** Runs each time the app moves out of the foreground. */
|
|
8
|
+
export declare const onSuspend: (listener: import("@tokamakdev/plugin/events").Listener<Readonly<Record<string, never>>, void>) => void;
|
package/dist/events.mjs
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { defineEvent } from "@tokamakdev/plugin/events";
|
|
2
|
+
/** Runs once per runtime start, including when the system starts the app in the background. */
|
|
3
|
+
export const onStart = defineEvent("start");
|
|
4
|
+
/** Runs each time the app moves into the foreground, but not when it starts there. */
|
|
5
|
+
export const onResume = defineEvent("resume");
|
|
6
|
+
/** Runs each time the app moves out of the foreground. */
|
|
7
|
+
export const onSuspend = defineEvent("suspend");
|
package/dist/vite.d.mts
CHANGED
|
@@ -2,9 +2,9 @@ import { type Plugin } from "vite";
|
|
|
2
2
|
import type { Config } from "./index.mjs";
|
|
3
3
|
/**
|
|
4
4
|
* Reports the app's tokamak configuration, and the development server's
|
|
5
|
-
* address, HTTPS certificate and
|
|
6
|
-
* Worker import `module
|
|
7
|
-
* adds no hooks.
|
|
5
|
+
* address, HTTPS certificate, Worker name and dev socket port, to `tok`, and
|
|
6
|
+
* makes the entry Worker import `module` and export `TokamakEvents`. Without
|
|
7
|
+
* `TOKAMAK_VITE_OUTPUT`, which `tok` sets, it adds no hooks.
|
|
8
8
|
*/
|
|
9
9
|
export declare function tokamak({ module, ...config }?: Config & {
|
|
10
10
|
/**
|
package/dist/vite.mjs
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { X509Certificate } from "node:crypto";
|
|
2
2
|
import fs from "node:fs";
|
|
3
3
|
import path from "node:path";
|
|
4
|
-
import {
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { normalizePath, } from "vite";
|
|
6
|
+
import { openDevSocket } from "./dev-socket.mjs";
|
|
5
7
|
/** Modules tried in order when the options name none. */
|
|
6
8
|
const DEFAULT_MODULES = ["src/tokamak.ts", "src/tokamak.js"];
|
|
7
9
|
/** Wrangler configuration files Cloudflare's plugin tries in order. */
|
|
@@ -9,9 +11,9 @@ const WRANGLER_FILES = ["wrangler.jsonc", "wrangler.json", "wrangler.toml"];
|
|
|
9
11
|
const MIDDLEWARE_MODE_ERROR = "Vite is running in middleware mode, so tokamak cannot find the development server's address; tok dev needs Vite's own dev server";
|
|
10
12
|
/**
|
|
11
13
|
* Reports the app's tokamak configuration, and the development server's
|
|
12
|
-
* address, HTTPS certificate and
|
|
13
|
-
* Worker import `module
|
|
14
|
-
* adds no hooks.
|
|
14
|
+
* address, HTTPS certificate, Worker name and dev socket port, to `tok`, and
|
|
15
|
+
* makes the entry Worker import `module` and export `TokamakEvents`. Without
|
|
16
|
+
* `TOKAMAK_VITE_OUTPUT`, which `tok` sets, it adds no hooks.
|
|
15
17
|
*/
|
|
16
18
|
export function tokamak({ module, ...config } = {}) {
|
|
17
19
|
const output = process.env.TOKAMAK_VITE_OUTPUT;
|
|
@@ -19,13 +21,23 @@ export function tokamak({ module, ...config } = {}) {
|
|
|
19
21
|
return [];
|
|
20
22
|
}
|
|
21
23
|
let file;
|
|
24
|
+
const events = import.meta.resolve("@tokamakdev/plugin/events");
|
|
25
|
+
/** The module that defines `TokamakEvents`. */
|
|
26
|
+
const entrypoint = normalizePath(fileURLToPath(new URL("./entrypoint.js", events)));
|
|
27
|
+
/** The module that holds event listeners. */
|
|
28
|
+
const registryFile = normalizePath(fileURLToPath(new URL("./registry.ts", events)));
|
|
22
29
|
/** The module IDs of each entry environment's inputs. */
|
|
23
30
|
const entryIds = new Map();
|
|
24
|
-
/** The entry environments whose input
|
|
25
|
-
const
|
|
31
|
+
/** The entry environments whose input exports `TokamakEvents`. */
|
|
32
|
+
const exporting = new Set();
|
|
26
33
|
return [
|
|
27
34
|
{
|
|
28
35
|
name: "tokamak",
|
|
36
|
+
// Keeps @tokamakdev/plugin out of pre-bundled dependencies, so they
|
|
37
|
+
// share the one module that holds event listeners.
|
|
38
|
+
configEnvironment() {
|
|
39
|
+
return { optimizeDeps: { exclude: ["@tokamakdev/plugin"] } };
|
|
40
|
+
},
|
|
29
41
|
configResolved({ root }) {
|
|
30
42
|
file = findModule(root, module);
|
|
31
43
|
writeJson(output, "config.json", { root, config });
|
|
@@ -40,26 +52,30 @@ export function tokamak({ module, ...config } = {}) {
|
|
|
40
52
|
}
|
|
41
53
|
return;
|
|
42
54
|
}
|
|
43
|
-
const
|
|
44
|
-
httpServer.
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
55
|
+
const worker = await readWorker(server.config.root);
|
|
56
|
+
httpServer.once("listening", () => {
|
|
57
|
+
openDevSocket(worker?.name, process.env.TOKAMAK_SESSION_TOKEN).then((socket) => {
|
|
58
|
+
httpServer.once("close", () => void socket.close());
|
|
59
|
+
const urls = server.resolvedUrls;
|
|
60
|
+
writeJson(output, "server.json", {
|
|
61
|
+
url: urls?.local[0] ?? urls?.network[0],
|
|
62
|
+
workerName: worker?.topLevelName ?? worker?.name,
|
|
63
|
+
certificates: endEntityCertificates(server.config.server.https),
|
|
64
|
+
socketPort: socket.port,
|
|
65
|
+
});
|
|
66
|
+
}, (error) => server.config.logger.error(`tokamak could not open its dev socket: ${String(error)}`));
|
|
51
67
|
});
|
|
52
68
|
},
|
|
53
69
|
async buildApp(builder) {
|
|
54
70
|
const environments = Object.values(builder.environments);
|
|
55
|
-
if (
|
|
56
|
-
throw new Error(
|
|
71
|
+
if (!environments.some((environment) => buildsEntryWorker(environment.config))) {
|
|
72
|
+
throw new Error("no environment builds the entry Worker to export TokamakEvents from");
|
|
57
73
|
}
|
|
58
74
|
},
|
|
59
75
|
},
|
|
60
76
|
{
|
|
61
77
|
name: "tokamak:entry",
|
|
62
|
-
applyToEnvironment: ({ config }) =>
|
|
78
|
+
applyToEnvironment: ({ config }) => buildsEntryWorker(config),
|
|
63
79
|
async transform(code, id) {
|
|
64
80
|
const environment = this.environment;
|
|
65
81
|
const ids = entryIds.get(environment.name) ??
|
|
@@ -68,19 +84,48 @@ export function tokamak({ module, ...config } = {}) {
|
|
|
68
84
|
if (!(await ids).includes(id)) {
|
|
69
85
|
return;
|
|
70
86
|
}
|
|
71
|
-
|
|
87
|
+
exporting.add(environment.name);
|
|
72
88
|
// In Cloudflare's Worker entry, which dev and build both start from,
|
|
73
89
|
// this follows the imports of its polyfills and of the app's entry.
|
|
74
|
-
|
|
90
|
+
const imports = file ? `import ${JSON.stringify(file)};\n` : "";
|
|
91
|
+
return { code: `${code}\n${imports}export { TokamakEvents } from ${JSON.stringify(entrypoint)};\n`, map: null };
|
|
92
|
+
},
|
|
93
|
+
// A module that registers listeners adds them again each time it
|
|
94
|
+
// evaluates, so when an update re-evaluates one, the registry and every
|
|
95
|
+
// module that imports it evaluate again too.
|
|
96
|
+
async hotUpdate({ modules, timestamp }) {
|
|
97
|
+
const graph = this.environment.moduleGraph;
|
|
98
|
+
const registry = graph.getModuleById(registryFile);
|
|
99
|
+
if (!registry) {
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
const entries = (await entryIds.get(this.environment.name)) ?? [];
|
|
103
|
+
const registering = [...withImporters(registry)].filter((module) => !entries.some((id) => id === module.id));
|
|
104
|
+
const updated = new Set(modules.flatMap((changed) => [...withImporters(changed)]));
|
|
105
|
+
if (registering.some((module) => updated.has(module))) {
|
|
106
|
+
graph.invalidateModule(registry, new Set(), timestamp, true);
|
|
107
|
+
}
|
|
75
108
|
},
|
|
76
109
|
generateBundle() {
|
|
77
|
-
if (!
|
|
78
|
-
this.error(`the input of the ${this.environment.name} environment did not
|
|
110
|
+
if (!exporting.has(this.environment.name)) {
|
|
111
|
+
this.error(`the input of the ${this.environment.name} environment did not export TokamakEvents`);
|
|
79
112
|
}
|
|
80
113
|
},
|
|
81
114
|
},
|
|
82
115
|
];
|
|
83
116
|
}
|
|
117
|
+
/** `module` and every module that imports it, directly or through others. */
|
|
118
|
+
function withImporters(module) {
|
|
119
|
+
const found = new Set();
|
|
120
|
+
const pending = [module];
|
|
121
|
+
for (let current = pending.pop(); current; current = pending.pop()) {
|
|
122
|
+
if (!found.has(current)) {
|
|
123
|
+
found.add(current);
|
|
124
|
+
pending.push(...current.importers);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return found;
|
|
128
|
+
}
|
|
84
129
|
/** The module `name` under `root`, or else the first default under `root` that exists. */
|
|
85
130
|
function findModule(root, name) {
|
|
86
131
|
const candidates = (name ? [name] : DEFAULT_MODULES).map((candidate) => normalizePath(path.resolve(root, candidate)));
|
|
@@ -91,18 +136,17 @@ function findModule(root, name) {
|
|
|
91
136
|
return file;
|
|
92
137
|
}
|
|
93
138
|
/**
|
|
94
|
-
* The
|
|
95
|
-
*
|
|
96
|
-
* the
|
|
139
|
+
* The Worker in the Wrangler configuration file in `root`, read as
|
|
140
|
+
* Cloudflare's plugin reads it without `configPath`, in the `CLOUDFLARE_ENV`
|
|
141
|
+
* environment: its name, and its name without the environment's suffix.
|
|
97
142
|
*/
|
|
98
|
-
async function
|
|
143
|
+
async function readWorker(root) {
|
|
99
144
|
const file = WRANGLER_FILES.map((name) => path.join(root, name)).find((candidate) => fs.existsSync(candidate));
|
|
100
145
|
if (!file) {
|
|
101
146
|
return undefined;
|
|
102
147
|
}
|
|
103
148
|
const { unstable_readConfig } = await import("wrangler");
|
|
104
|
-
|
|
105
|
-
return worker.topLevelName ?? worker.name;
|
|
149
|
+
return unstable_readConfig({ config: file, env: process.env.CLOUDFLARE_ENV }, { hideWarnings: true });
|
|
106
150
|
}
|
|
107
151
|
/**
|
|
108
152
|
* The PEM of the end-entity certificate of each chain in `https.cert`, which
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tokamakdev/tok",
|
|
3
|
-
"version": "0.1.1-beta.
|
|
3
|
+
"version": "0.1.1-beta.83",
|
|
4
4
|
"description": "The tokamak CLI, Vite plugin and app API: build native apps from a Cloudflare Workers codebase",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -12,6 +12,10 @@
|
|
|
12
12
|
"types": "./dist/index.d.mts",
|
|
13
13
|
"default": "./dist/index.mjs"
|
|
14
14
|
},
|
|
15
|
+
"./events": {
|
|
16
|
+
"types": "./dist/events.d.mts",
|
|
17
|
+
"default": "./dist/events.mjs"
|
|
18
|
+
},
|
|
15
19
|
"./vite": {
|
|
16
20
|
"types": "./dist/vite.d.mts",
|
|
17
21
|
"default": "./dist/vite.mjs"
|
|
@@ -34,6 +38,10 @@
|
|
|
34
38
|
"engines": {
|
|
35
39
|
"node": ">=18"
|
|
36
40
|
},
|
|
41
|
+
"dependencies": {
|
|
42
|
+
"@tokamakdev/plugin": "0.1.0-beta.83",
|
|
43
|
+
"ws": "^8.22.0"
|
|
44
|
+
},
|
|
37
45
|
"peerDependencies": {
|
|
38
46
|
"@cloudflare/vite-plugin": "^1.54.0",
|
|
39
47
|
"vite": "^7.0.0 || ^8.0.0",
|
|
@@ -50,22 +58,23 @@
|
|
|
50
58
|
"devDependencies": {
|
|
51
59
|
"@cloudflare/vite-plugin": "1.62.5",
|
|
52
60
|
"@types/node": "22.19.15",
|
|
61
|
+
"@types/ws": "8.18.2",
|
|
53
62
|
"typescript": "5.9.3",
|
|
54
63
|
"vite": "8.3.2",
|
|
55
64
|
"wrangler": "4.147.0"
|
|
56
65
|
},
|
|
57
66
|
"optionalDependencies": {
|
|
58
|
-
"@tokamakdev/platform-android-arm64": "0.1.1-beta.
|
|
59
|
-
"@tokamakdev/platform-ios-arm64": "0.1.1-beta.
|
|
60
|
-
"@tokamakdev/platform-ios-simulator-arm64": "0.1.1-beta.
|
|
61
|
-
"@tokamakdev/platform-ios-simulator-x64": "0.1.1-beta.
|
|
62
|
-
"@tokamakdev/platform-macos-arm64": "0.1.1-beta.
|
|
63
|
-
"@tokamakdev/platform-macos-x64": "0.1.1-beta.
|
|
64
|
-
"@tokamakdev/platform-windows-x64": "0.1.1-beta.
|
|
65
|
-
"@tokamakdev/tok-darwin-arm64": "0.1.1-beta.
|
|
66
|
-
"@tokamakdev/tok-darwin-x64": "0.1.1-beta.
|
|
67
|
-
"@tokamakdev/tok-linux-x64": "0.1.1-beta.
|
|
68
|
-
"@tokamakdev/tok-win32-x64": "0.1.1-beta.
|
|
67
|
+
"@tokamakdev/platform-android-arm64": "0.1.1-beta.83",
|
|
68
|
+
"@tokamakdev/platform-ios-arm64": "0.1.1-beta.83",
|
|
69
|
+
"@tokamakdev/platform-ios-simulator-arm64": "0.1.1-beta.83",
|
|
70
|
+
"@tokamakdev/platform-ios-simulator-x64": "0.1.1-beta.83",
|
|
71
|
+
"@tokamakdev/platform-macos-arm64": "0.1.1-beta.83",
|
|
72
|
+
"@tokamakdev/platform-macos-x64": "0.1.1-beta.83",
|
|
73
|
+
"@tokamakdev/platform-windows-x64": "0.1.1-beta.83",
|
|
74
|
+
"@tokamakdev/tok-darwin-arm64": "0.1.1-beta.83",
|
|
75
|
+
"@tokamakdev/tok-darwin-x64": "0.1.1-beta.83",
|
|
76
|
+
"@tokamakdev/tok-linux-x64": "0.1.1-beta.83",
|
|
77
|
+
"@tokamakdev/tok-win32-x64": "0.1.1-beta.83"
|
|
69
78
|
},
|
|
70
79
|
"publishConfig": {
|
|
71
80
|
"access": "public"
|