lakebed 0.0.17 → 0.0.19
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 +51 -34
- package/package.json +1 -1
- package/src/anonymous-server.js +365 -8
- package/src/anonymous.js +244 -2
- package/src/auth.js +2 -3
- package/src/cli.js +319 -51
- package/src/client.d.ts +0 -1
- package/src/client.js +2 -2
- package/src/server.d.ts +49 -1
- package/src/server.js +53 -0
- package/src/source-runtime-worker.js +114 -1
- package/src/source-runtime.js +27 -0
- package/src/version.js +1 -1
|
@@ -312,6 +312,103 @@ function createBrokeredResponse(response) {
|
|
|
312
312
|
};
|
|
313
313
|
}
|
|
314
314
|
|
|
315
|
+
function endpointBodyToBase64(body) {
|
|
316
|
+
if (body === undefined || body === null) {
|
|
317
|
+
return "";
|
|
318
|
+
}
|
|
319
|
+
if (typeof body === "string") {
|
|
320
|
+
return nodeBuffer.from(body, "utf8").toString("base64");
|
|
321
|
+
}
|
|
322
|
+
if (body instanceof ArrayBuffer) {
|
|
323
|
+
return nodeBuffer.from(body).toString("base64");
|
|
324
|
+
}
|
|
325
|
+
if (ArrayBuffer.isView(body)) {
|
|
326
|
+
return nodeBuffer.from(body.buffer, body.byteOffset, body.byteLength).toString("base64");
|
|
327
|
+
}
|
|
328
|
+
return nodeBuffer.from(JSON.stringify(body ?? null), "utf8").toString("base64");
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
function endpointStatus(status, fallback = 200) {
|
|
332
|
+
const parsed = Number(status);
|
|
333
|
+
return Number.isInteger(parsed) && parsed >= 100 && parsed <= 599 ? parsed : fallback;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
async function normalizeEndpointResponse(result) {
|
|
337
|
+
if (result === undefined || result === null) {
|
|
338
|
+
return { bodyBase64: "", headers: {}, status: 204 };
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
if (
|
|
342
|
+
result &&
|
|
343
|
+
typeof result === "object" &&
|
|
344
|
+
result.kind !== "response" &&
|
|
345
|
+
typeof result.arrayBuffer === "function" &&
|
|
346
|
+
typeof result.status === "number"
|
|
347
|
+
) {
|
|
348
|
+
const body = nodeBuffer.from(await result.arrayBuffer());
|
|
349
|
+
return {
|
|
350
|
+
bodyBase64: body.toString("base64"),
|
|
351
|
+
headers: headersToObject(result.headers),
|
|
352
|
+
status: endpointStatus(result.status)
|
|
353
|
+
};
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
if (isPlainObject(result) && result.kind === "response") {
|
|
357
|
+
return {
|
|
358
|
+
bodyBase64: endpointBodyToBase64(result.body),
|
|
359
|
+
headers: headersToObject(result.headers),
|
|
360
|
+
status: endpointStatus(result.status)
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
if (typeof result === "string") {
|
|
365
|
+
return {
|
|
366
|
+
bodyBase64: endpointBodyToBase64(result),
|
|
367
|
+
headers: { "Content-Type": "text/plain; charset=utf-8" },
|
|
368
|
+
status: 200
|
|
369
|
+
};
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
return {
|
|
373
|
+
bodyBase64: endpointBodyToBase64(result),
|
|
374
|
+
headers: { "Content-Type": "application/json; charset=utf-8" },
|
|
375
|
+
status: 200
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
function createEndpointRequest(request) {
|
|
380
|
+
const url = new URL(request.url ?? request.path ?? "/", "http://lakebed.local");
|
|
381
|
+
const body = nodeBuffer.from(request.bodyBase64 ?? "", "base64");
|
|
382
|
+
const headers = new Map(Object.entries(headersToObject(request.headers)).map(([key, value]) => [key.toLowerCase(), String(value)]));
|
|
383
|
+
|
|
384
|
+
return {
|
|
385
|
+
headers: {
|
|
386
|
+
entries() {
|
|
387
|
+
return headers.entries();
|
|
388
|
+
},
|
|
389
|
+
get(name) {
|
|
390
|
+
return headers.get(String(name).toLowerCase()) ?? null;
|
|
391
|
+
},
|
|
392
|
+
has(name) {
|
|
393
|
+
return headers.has(String(name).toLowerCase());
|
|
394
|
+
}
|
|
395
|
+
},
|
|
396
|
+
method: String(request.method ?? "GET").toUpperCase(),
|
|
397
|
+
path: request.path ?? url.pathname,
|
|
398
|
+
query: new URLSearchParams(url.searchParams),
|
|
399
|
+
url: url.href,
|
|
400
|
+
async bytes() {
|
|
401
|
+
return new Uint8Array(body);
|
|
402
|
+
},
|
|
403
|
+
async json() {
|
|
404
|
+
return JSON.parse(body.toString("utf8"));
|
|
405
|
+
},
|
|
406
|
+
async text() {
|
|
407
|
+
return body.toString("utf8");
|
|
408
|
+
}
|
|
409
|
+
};
|
|
410
|
+
}
|
|
411
|
+
|
|
315
412
|
function brokeredFetch(input, init = {}) {
|
|
316
413
|
if (!allowBrokeredFetch) {
|
|
317
414
|
return Promise.reject(new Error("Outbound fetch is disabled for anonymous deploys."));
|
|
@@ -389,7 +486,8 @@ function sendError(error) {
|
|
|
389
486
|
sendToParent?.({
|
|
390
487
|
error: {
|
|
391
488
|
message: error instanceof Error ? error.message : String(error),
|
|
392
|
-
name: error instanceof Error ? error.name : "Error"
|
|
489
|
+
name: error instanceof Error ? error.name : "Error",
|
|
490
|
+
stack: error instanceof Error ? error.stack : undefined
|
|
393
491
|
},
|
|
394
492
|
ok: false,
|
|
395
493
|
type: "source-runtime.result"
|
|
@@ -429,6 +527,21 @@ async function runSource(request) {
|
|
|
429
527
|
return;
|
|
430
528
|
}
|
|
431
529
|
|
|
530
|
+
if (request.op === "endpoint") {
|
|
531
|
+
const definition = app.endpoints?.[request.name];
|
|
532
|
+
const handler = definition?.handler ?? definition;
|
|
533
|
+
if (typeof handler !== "function") {
|
|
534
|
+
throw new Error(`Unknown endpoint: ${request.name}`);
|
|
535
|
+
}
|
|
536
|
+
const result = await handler(source.ctx, createEndpointRequest(request.endpointRequest ?? {}));
|
|
537
|
+
const response = await normalizeEndpointResponse(result);
|
|
538
|
+
sendResult({
|
|
539
|
+
operations: jsonSafe(source.operations),
|
|
540
|
+
response: jsonSafe(response)
|
|
541
|
+
});
|
|
542
|
+
return;
|
|
543
|
+
}
|
|
544
|
+
|
|
432
545
|
throw new Error(`Unsupported source operation: ${request.op}`);
|
|
433
546
|
}
|
|
434
547
|
|
package/src/source-runtime.js
CHANGED
|
@@ -493,6 +493,9 @@ async function brokeredFetch(request, options) {
|
|
|
493
493
|
function workerError(payload) {
|
|
494
494
|
const error = new Error(payload?.message ?? "Source runtime failed.");
|
|
495
495
|
error.name = payload?.name ?? "SourceRuntimeError";
|
|
496
|
+
if (payload?.stack) {
|
|
497
|
+
error.stack = payload.stack;
|
|
498
|
+
}
|
|
496
499
|
return error;
|
|
497
500
|
}
|
|
498
501
|
|
|
@@ -557,6 +560,29 @@ export class ChildProcessSourceRuntime {
|
|
|
557
560
|
}, mutationTransactionOptions(limits));
|
|
558
561
|
}
|
|
559
562
|
|
|
563
|
+
async executeEndpoint({ artifact, auth, deployId, limits = DEFAULT_ANONYMOUS_LIMITS, name, request, state }) {
|
|
564
|
+
return state.transaction(deployId, async (tx) => {
|
|
565
|
+
const snapshot = await snapshotSourceState({ artifact, deployId, state: tx });
|
|
566
|
+
const response = await this.runWorker({
|
|
567
|
+
allowFetch: artifact.deployTarget === "claimed-source",
|
|
568
|
+
artifact,
|
|
569
|
+
auth,
|
|
570
|
+
endpointRequest: request,
|
|
571
|
+
env: snapshot.env,
|
|
572
|
+
name,
|
|
573
|
+
op: "endpoint",
|
|
574
|
+
rows: snapshot.rows
|
|
575
|
+
});
|
|
576
|
+
await applySourceOperations({
|
|
577
|
+
artifact,
|
|
578
|
+
deployId,
|
|
579
|
+
operations: response.operations ?? [],
|
|
580
|
+
tx
|
|
581
|
+
});
|
|
582
|
+
return response.response ?? { bodyBase64: "", headers: {}, status: 204 };
|
|
583
|
+
}, mutationTransactionOptions(limits));
|
|
584
|
+
}
|
|
585
|
+
|
|
560
586
|
runWorker(request) {
|
|
561
587
|
return new Promise((resolveRun, rejectRun) => {
|
|
562
588
|
const child = fork(this.workerPath, [], {
|
|
@@ -603,6 +629,7 @@ export class ChildProcessSourceRuntime {
|
|
|
603
629
|
if (message.ok) {
|
|
604
630
|
finish(resolveRun, {
|
|
605
631
|
operations: message.operations,
|
|
632
|
+
response: message.response,
|
|
606
633
|
result: message.result
|
|
607
634
|
});
|
|
608
635
|
} else {
|
package/src/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const LAKEBED_VERSION = "0.0.
|
|
1
|
+
export const LAKEBED_VERSION = "0.0.19";
|