vmlive 1.0.19 → 1.0.20

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vmlive",
3
- "version": "1.0.19",
3
+ "version": "1.0.20",
4
4
  "description": "Local development VM for custom Serverless PaaS",
5
5
  "type": "module",
6
6
  "bin": {
package/src/cli.js CHANGED
@@ -403,9 +403,15 @@ const runDev = async () => {
403
403
  const workspaceId = config.workspaceId || "ws_local";
404
404
  const projectId = config.projectId || "prj_local";
405
405
 
406
+ const configPath = path.join(os.homedir(), '.vm-config.json');
407
+ let jwtToken = process.env.VM_API_TOKEN;
408
+ if (!jwtToken && fs.existsSync(configPath)) {
409
+ jwtToken = JSON.parse(fs.readFileSync(configPath, 'utf-8')).token;
410
+ }
411
+
406
412
  config.functions.forEach(fn => {
407
413
  const relativeTarget = `./${fn.name}-out.mjs`;
408
- fs.writeFileSync(path.join(WORK_DIR, `${fn.name}-shim.mjs`), generateShim(relativeTarget, workspaceId, projectId, fn.name));
414
+ fs.writeFileSync(path.join(WORK_DIR, `${fn.name}-shim.mjs`), generateShim(relativeTarget, workspaceId, projectId, fn.name, jwtToken));
409
415
  });
410
416
 
411
417
  const builder = await esbuild.context({
package/src/shadow-dos.js CHANGED
@@ -7,13 +7,13 @@ export class LocalTaskManagerDO extends DurableObject {
7
7
 
8
8
  async fetch(request) {
9
9
  const url = new URL(request.url);
10
-
10
+
11
11
  if (request.method === "POST" && url.pathname === "/.internal/tasks/schedule") {
12
12
  const body = await request.json();
13
13
  const { functionSlug, executeAt, name, payload, workspaceId, projectId, interval } = body;
14
-
14
+
15
15
  const taskId = interval ? `cron:${functionSlug}:${name}` : crypto.randomUUID();
16
-
16
+
17
17
  const taskRecord = {
18
18
  id: taskId,
19
19
  function_slug: functionSlug,
@@ -30,7 +30,7 @@ export class LocalTaskManagerDO extends DurableObject {
30
30
  await this.ctx.storage.put(taskId, taskRecord);
31
31
  // We set the native Miniflare alarm
32
32
  await this.ctx.storage.setAlarm(executeAt);
33
-
33
+
34
34
  return Response.json({ success: true, id: taskId });
35
35
  }
36
36
  return new Response("Not Found", { status: 404 });
@@ -39,13 +39,13 @@ export class LocalTaskManagerDO extends DurableObject {
39
39
  async alarm() {
40
40
  const now = Date.now();
41
41
  const MapTasks = await this.ctx.storage.list();
42
-
42
+
43
43
  for (const [id, task] of MapTasks) {
44
44
  if (task.execute_at <= now && task.status !== 'completed') {
45
45
  try {
46
46
  // Structurally bypass network by resolving back through Miniflare host headers natively
47
47
  const invokeUrl = `http://127.0.0.1:${this.env.PORT || 8787}/.internal/tasks/dispatch`;
48
-
48
+
49
49
  const res = await fetch(invokeUrl, {
50
50
  method: 'POST',
51
51
  headers: {
@@ -72,7 +72,7 @@ export class LocalTaskManagerDO extends DurableObject {
72
72
  if (unit === 's') addMs = val * 1000;
73
73
  else if (unit === 'm') addMs = val * 60000;
74
74
  else if (unit === 'h') addMs = val * 3600000;
75
-
75
+
76
76
  task.execute_at = now + addMs;
77
77
  await this.ctx.storage.put(id, task);
78
78
  await this.ctx.storage.setAlarm(task.execute_at);
@@ -94,10 +94,10 @@ export class LocalChannelRoomDO extends DurableObject {
94
94
  constructor(ctx, env) {
95
95
  super(ctx, env);
96
96
  }
97
-
97
+
98
98
  async fetch(request) {
99
99
  const url = new URL(request.url);
100
-
100
+
101
101
  if (request.method === "POST" && url.pathname === "/broadcast") {
102
102
  const body = await request.json();
103
103
  const websockets = this.ctx.getWebSockets();
@@ -106,25 +106,25 @@ export class LocalChannelRoomDO extends DurableObject {
106
106
  }
107
107
  return new Response("OK");
108
108
  }
109
-
109
+
110
110
  if (request.headers.get("Upgrade") === "websocket") {
111
111
  const pair = new WebSocketPair();
112
112
  const [client, server] = Object.values(pair);
113
113
  this.ctx.acceptWebSocket(server);
114
114
  return new Response(null, { status: 101, webSocket: client });
115
115
  }
116
-
116
+
117
117
  return new Response("Not Found", { status: 404 });
118
118
  }
119
-
119
+
120
120
  webSocketMessage(ws, message) {
121
121
  this.ctx.getWebSockets().forEach((sock) => {
122
- if (sock !== ws) {
123
- sock.send(message);
124
- }
122
+ if (sock !== ws) {
123
+ sock.send(message);
124
+ }
125
125
  });
126
126
  }
127
-
127
+
128
128
  webSocketClose(ws, code, reason, wasClean) {
129
129
  ws.close(code, reason);
130
130
  }
@@ -1,4 +1,4 @@
1
- export const generateShim = (outFileUrl, workspaceId, projectId, functionSlug) => `
1
+ export const generateShim = (outFileUrl, workspaceId, projectId, functionSlug, jwtToken) => `
2
2
  import * as UserCode from '${outFileUrl}';
3
3
 
4
4
  export default {
@@ -126,8 +126,10 @@ export default {
126
126
  const req = new Request(\`https://rpc.vm.codes/.internal/rpc/\${serviceName.toLowerCase()}/\${method}\`, {
127
127
  method: "POST",
128
128
  headers: {
129
- "Authorization": \`Bearer \${safeEnv.BILLING_TOKEN || 'local'}\`,
130
- "Content-Type": contentType
129
+ "Authorization": "Bearer ${jwtToken || 'local'}",
130
+ "Content-Type": contentType,
131
+ "x-workspace-id": "${workspaceId}",
132
+ "x-project-id": "${projectId}"
131
133
  },
132
134
  body
133
135
  });