@ericminassian/platform 0.0.0-stage → 0.1.0

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 (78) hide show
  1. package/dist/app.d.ts +10 -0
  2. package/dist/app.js +23 -0
  3. package/dist/app.js.map +1 -0
  4. package/dist/auth/cookies.d.ts +10 -0
  5. package/dist/auth/cookies.js +37 -0
  6. package/dist/auth/cookies.js.map +1 -0
  7. package/dist/auth/index.d.ts +22 -0
  8. package/dist/auth/index.js +217 -0
  9. package/dist/auth/index.js.map +1 -0
  10. package/dist/auth/pkce.d.ts +16 -0
  11. package/dist/auth/pkce.js +32 -0
  12. package/dist/auth/pkce.js.map +1 -0
  13. package/dist/auth/tokens.d.ts +17 -0
  14. package/dist/auth/tokens.js +142 -0
  15. package/dist/auth/tokens.js.map +1 -0
  16. package/dist/bindings.d.ts +13 -0
  17. package/dist/bindings.js +32 -0
  18. package/dist/bindings.js.map +1 -0
  19. package/dist/clients.d.ts +38 -0
  20. package/dist/clients.js +65 -0
  21. package/dist/clients.js.map +1 -0
  22. package/dist/context.d.ts +31 -0
  23. package/dist/context.js +33 -0
  24. package/dist/context.js.map +1 -0
  25. package/dist/db.d.ts +97 -0
  26. package/dist/db.js +297 -0
  27. package/dist/db.js.map +1 -0
  28. package/dist/events.d.ts +9 -0
  29. package/dist/events.js +28 -0
  30. package/dist/events.js.map +1 -0
  31. package/dist/http.d.ts +14 -0
  32. package/dist/http.js +82 -0
  33. package/dist/http.js.map +1 -0
  34. package/dist/index.d.ts +30 -0
  35. package/dist/index.js +11 -0
  36. package/dist/index.js.map +1 -0
  37. package/dist/queue.d.ts +7 -0
  38. package/dist/queue.js +50 -0
  39. package/dist/queue.js.map +1 -0
  40. package/dist/secrets.d.ts +8 -0
  41. package/dist/secrets.js +42 -0
  42. package/dist/secrets.js.map +1 -0
  43. package/dist/server.d.ts +12 -0
  44. package/dist/server.js +232 -0
  45. package/dist/server.js.map +1 -0
  46. package/dist/storage.d.ts +30 -0
  47. package/dist/storage.js +108 -0
  48. package/dist/storage.js.map +1 -0
  49. package/dist/telemetry.d.ts +42 -0
  50. package/dist/telemetry.js +218 -0
  51. package/dist/telemetry.js.map +1 -0
  52. package/dist/testing.d.ts +31 -0
  53. package/dist/testing.js +54 -0
  54. package/dist/testing.js.map +1 -0
  55. package/dist/worker.d.ts +73 -0
  56. package/dist/worker.js +179 -0
  57. package/dist/worker.js.map +1 -0
  58. package/package.json +58 -3
  59. package/src/app.ts +32 -0
  60. package/src/auth/cookies.ts +39 -0
  61. package/src/auth/index.ts +246 -0
  62. package/src/auth/pkce.ts +43 -0
  63. package/src/auth/tokens.ts +174 -0
  64. package/src/bindings.ts +35 -0
  65. package/src/clients.ts +98 -0
  66. package/src/context.ts +56 -0
  67. package/src/db.ts +380 -0
  68. package/src/events.ts +42 -0
  69. package/src/http.ts +82 -0
  70. package/src/index.ts +40 -0
  71. package/src/queue.ts +67 -0
  72. package/src/secrets.ts +57 -0
  73. package/src/server.ts +274 -0
  74. package/src/storage.ts +143 -0
  75. package/src/telemetry.ts +260 -0
  76. package/src/testing.ts +73 -0
  77. package/src/worker.ts +291 -0
  78. package/README.md +0 -3
package/dist/http.js ADDED
@@ -0,0 +1,82 @@
1
+ import { createServer } from 'node:http';
2
+ import { Readable } from 'node:stream';
3
+ export function toRequest(req, signal) {
4
+ const host = req.headers.host ?? 'localhost';
5
+ const url = new URL(req.url ?? '/', `http://${host}`);
6
+ const headers = new Headers();
7
+ for (let i = 0; i < req.rawHeaders.length; i += 2) {
8
+ const k = req.rawHeaders[i];
9
+ const v = req.rawHeaders[i + 1];
10
+ if (k.startsWith(':'))
11
+ continue;
12
+ headers.append(k, v);
13
+ }
14
+ const method = req.method ?? 'GET';
15
+ const hasBody = method !== 'GET' && method !== 'HEAD';
16
+ return new Request(url, {
17
+ method,
18
+ headers,
19
+ ...(hasBody ? { body: Readable.toWeb(req), duplex: 'half' } : {}),
20
+ ...(signal ? { signal } : {}),
21
+ });
22
+ }
23
+ export async function writeResponse(res, response) {
24
+ const headers = {};
25
+ response.headers.forEach((value, key) => {
26
+ if (key === 'set-cookie')
27
+ return;
28
+ headers[key] = value;
29
+ });
30
+ const cookies = response.headers.getSetCookie();
31
+ if (cookies.length)
32
+ headers['set-cookie'] = cookies;
33
+ res.writeHead(response.status, response.statusText || undefined, headers);
34
+ if (!response.body) {
35
+ res.end();
36
+ return;
37
+ }
38
+ const reader = response.body.getReader();
39
+ try {
40
+ for (;;) {
41
+ const { done, value } = await reader.read();
42
+ if (done)
43
+ break;
44
+ if (!res.write(value))
45
+ await new Promise((r) => res.once('drain', r));
46
+ }
47
+ }
48
+ finally {
49
+ res.end();
50
+ }
51
+ }
52
+ export function createNodeServer(fetchFn) {
53
+ return createServer((req, res) => {
54
+ const controller = new AbortController();
55
+ res.once('close', () => {
56
+ if (!res.writableFinished)
57
+ controller.abort();
58
+ });
59
+ fetchFn(toRequest(req, controller.signal))
60
+ .then((response) => writeResponse(res, response))
61
+ .catch((e) => {
62
+ if (!res.headersSent) {
63
+ res.writeHead(500, { 'content-type': 'application/json' });
64
+ res.end(JSON.stringify({ error: { code: 'internal', message: String(e?.message ?? e) } }));
65
+ }
66
+ else
67
+ res.destroy(e);
68
+ });
69
+ });
70
+ }
71
+ /** Parse `host:port` (IPv6 in brackets allowed). */
72
+ export function parseEndpoint(endpoint) {
73
+ const i = endpoint.lastIndexOf(':');
74
+ if (i <= 0)
75
+ throw new Error(`Invalid listen endpoint "${endpoint}" (expected host:port)`);
76
+ const host = endpoint.slice(0, i).replace(/^\[|\]$/g, '');
77
+ const port = Number(endpoint.slice(i + 1));
78
+ if (!Number.isInteger(port) || port < 0 || port > 65535)
79
+ throw new Error(`Invalid port in "${endpoint}"`);
80
+ return { host, port };
81
+ }
82
+ //# sourceMappingURL=http.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.js","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * @ericminassian/platform — the only thing app code imports. Cloud-neutral
3
+ * interfaces backed by AWS (DynamoDB, SQS, EventBridge, S3, SSM, Cognito)
4
+ * through bindings the engine injects. Under `plat dev` the same code talks to
5
+ * the AWS Emulator, so there is exactly one implementation.
6
+ *
7
+ * CONTRACT: these exports are documented in templates/app/AGENTS.md and used
8
+ * by every app. Keep signatures stable.
9
+ */
10
+ export type { PlatformUser } from '@ericminassian/platform-core';
11
+ export { type AppInfo, app } from './app.ts';
12
+ export { type Auth, auth } from './auth/index.ts';
13
+ export { setRoute } from './context.ts';
14
+ export { type Collection, type CollectionOptions, type Db, db, type KeyValue, type Page, type QueryOptions, } from './db.ts';
15
+ export { type Events, events } from './events.ts';
16
+ export { type Queue, queue } from './queue.ts';
17
+ export { type Secrets, secrets } from './secrets.ts';
18
+ export { type Store, type StoredObject, storage } from './storage.ts';
19
+ export { log, metrics } from './telemetry.ts';
20
+ export { invokeJob } from './worker.ts';
21
+ export interface Metrics {
22
+ count(name: string, n?: number): void;
23
+ value(name: string, value: number, unit?: string): void;
24
+ }
25
+ export interface Logger {
26
+ debug(msg: string, fields?: Record<string, unknown>): void;
27
+ info(msg: string, fields?: Record<string, unknown>): void;
28
+ warn(msg: string, fields?: Record<string, unknown>): void;
29
+ error(msg: string, fields?: Record<string, unknown> | unknown): void;
30
+ }
package/dist/index.js ADDED
@@ -0,0 +1,11 @@
1
+ export { app } from './app.js';
2
+ export { auth } from './auth/index.js';
3
+ export { setRoute } from './context.js';
4
+ export { db, } from './db.js';
5
+ export { events } from './events.js';
6
+ export { queue } from './queue.js';
7
+ export { secrets } from './secrets.js';
8
+ export { storage } from './storage.js';
9
+ export { log, metrics } from './telemetry.js';
10
+ export { invokeJob } from './worker.js';
11
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAUA,OAAO,EAAgB,GAAG,EAAE,MAAM,UAAU,CAAC;AAC7C,OAAO,EAAa,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AACxC,OAAO,EAIL,EAAE,GAIH,MAAM,SAAS,CAAC;AACjB,OAAO,EAAe,MAAM,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAc,KAAK,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,EAAgB,OAAO,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,EAAiC,OAAO,EAAE,MAAM,cAAc,CAAC;AACtE,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,7 @@
1
+ export interface Queue<T> {
2
+ send(body: T, opts?: {
3
+ delaySeconds?: number;
4
+ }): Promise<void>;
5
+ sendBatch(bodies: T[]): Promise<void>;
6
+ }
7
+ export declare function queue<T = unknown>(name: string): Queue<T>;
package/dist/queue.js ADDED
@@ -0,0 +1,50 @@
1
+ import { getBindings } from './bindings.js';
2
+ import { client } from './clients.js';
3
+ import { currentTrace } from './context.js';
4
+ import { span } from './telemetry.js';
5
+ function queueUrl(name) {
6
+ const queues = getBindings().queues;
7
+ const q = queues[name];
8
+ if (!q) {
9
+ const declared = Object.keys(queues);
10
+ throw new Error(`Unknown queue "${name}". Declared queues: ${declared.length ? declared.join(', ') : '(none)'} — add it under "queues" in platform.json.`);
11
+ }
12
+ return q.url;
13
+ }
14
+ function traceAttribute(trace) {
15
+ return { trace: { DataType: 'String', StringValue: trace } };
16
+ }
17
+ export function queue(name) {
18
+ return {
19
+ send: (body, opts) => span('queue.send', name, async () => {
20
+ const { SendMessageCommand } = await import('@aws-sdk/client-sqs');
21
+ await (await client('sqs')).send(new SendMessageCommand({
22
+ QueueUrl: queueUrl(name),
23
+ MessageBody: JSON.stringify(body),
24
+ MessageAttributes: traceAttribute(currentTrace()),
25
+ ...(opts?.delaySeconds !== undefined ? { DelaySeconds: opts.delaySeconds } : {}),
26
+ }));
27
+ }),
28
+ sendBatch: (bodies) => span('queue.send', name, async () => {
29
+ const url = queueUrl(name);
30
+ const trace = currentTrace();
31
+ const { SendMessageBatchCommand } = await import('@aws-sdk/client-sqs');
32
+ const sqs = await client('sqs');
33
+ for (let i = 0; i < bodies.length; i += 10) {
34
+ const chunk = bodies.slice(i, i + 10);
35
+ const out = await sqs.send(new SendMessageBatchCommand({
36
+ QueueUrl: url,
37
+ Entries: chunk.map((b, j) => ({
38
+ Id: String(i + j),
39
+ MessageBody: JSON.stringify(b),
40
+ MessageAttributes: traceAttribute(trace),
41
+ })),
42
+ }));
43
+ if (out.Failed?.length) {
44
+ throw new Error(`queue "${name}": ${out.Failed.length} message(s) failed: ${out.Failed[0]?.Message ?? out.Failed[0]?.Code}`);
45
+ }
46
+ }
47
+ }),
48
+ };
49
+ }
50
+ //# sourceMappingURL=queue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"queue.js","sourceRoot":"","sources":["../src/queue.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ export interface Secrets {
2
+ /** Throws if missing. Stage value wins over the app-wide shared value. Cached ~5 min. */
3
+ get(name: string): Promise<string>;
4
+ getOptional(name: string): Promise<string | undefined>;
5
+ }
6
+ export declare const secrets: Secrets;
7
+ /** Drop cached values (tests). */
8
+ export declare function clearSecretsCache(): void;
@@ -0,0 +1,42 @@
1
+ import { getBindings } from './bindings.js';
2
+ import { client } from './clients.js';
3
+ import { span } from './telemetry.js';
4
+ const TTL_MS = 5 * 60 * 1000;
5
+ const cache = new Map();
6
+ async function read(path) {
7
+ try {
8
+ const { GetParameterCommand } = await import('@aws-sdk/client-ssm');
9
+ const out = await (await client('ssm')).send(new GetParameterCommand({ Name: path, WithDecryption: true }));
10
+ return out.Parameter?.Value;
11
+ }
12
+ catch (e) {
13
+ if (e?.name === 'ParameterNotFound')
14
+ return undefined;
15
+ throw e;
16
+ }
17
+ }
18
+ async function lookup(name) {
19
+ const hit = cache.get(name);
20
+ if (hit && Date.now() - hit.at < TTL_MS)
21
+ return hit.value;
22
+ const { secrets } = getBindings();
23
+ const value = await span('secrets.get', name, async () => (await read(`${secrets.path}${name}`)) ?? read(`${secrets.sharedPath}${name}`));
24
+ cache.set(name, { value, at: Date.now() });
25
+ return value;
26
+ }
27
+ export const secrets = {
28
+ async get(name) {
29
+ const v = await lookup(name);
30
+ if (v === undefined) {
31
+ const b = getBindings();
32
+ throw new Error(`Secret ${name} is not set. Run: plat secrets set ${b.app} ${name} --stage ${b.stage} (or without --stage for all stages)`);
33
+ }
34
+ return v;
35
+ },
36
+ getOptional: (name) => lookup(name),
37
+ };
38
+ /** Drop cached values (tests). */
39
+ export function clearSecretsCache() {
40
+ cache.clear();
41
+ }
42
+ //# sourceMappingURL=secrets.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"secrets.js","sourceRoot":"","sources":["../src/secrets.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACtC,OAAO,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAQtC,MAAM,MAAM,GAAG,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;AAC7B,MAAM,KAAK,GAAG,IAAI,GAAG,EAAqD,CAAC;AAE3E,KAAK,UAAU,IAAI,CAAC,IAAY;IAC9B,IAAI,CAAC;QACH,MAAM,EAAE,mBAAmB,EAAE,GAAG,MAAM,MAAM,CAAC,qBAAqB,CAAC,CAAC;QACpE,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAC1C,IAAI,mBAAmB,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,CAAC,CAC9D,CAAC;QACF,OAAO,GAAG,CAAC,SAAS,EAAE,KAAK,CAAC;IAC9B,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,IAAK,CAAuB,EAAE,IAAI,KAAK,mBAAmB;YAAE,OAAO,SAAS,CAAC;QAC7E,MAAM,CAAC,CAAC;IACV,CAAC;AACH,CAAC;AAED,KAAK,UAAU,MAAM,CAAC,IAAY;IAChC,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC5B,IAAI,GAAG,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,GAAG,CAAC,EAAE,GAAG,MAAM;QAAE,OAAO,GAAG,CAAC,KAAK,CAAC;IAC1D,MAAM,EAAE,OAAO,EAAE,GAAG,WAAW,EAAE,CAAC;IAClC,MAAM,KAAK,GAAG,MAAM,IAAI,CACtB,aAAa,EACb,IAAI,EACJ,KAAK,IAAI,EAAE,CAAC,CAAC,MAAM,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,GAAG,IAAI,EAAE,CAAC,CAAC,IAAI,IAAI,CAAC,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,EAAE,CAAC,CAC3F,CAAC;IACF,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IAC3C,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,CAAC,MAAM,OAAO,GAAY;IAC9B,KAAK,CAAC,GAAG,CAAC,IAAI;QACZ,MAAM,CAAC,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,CAAC;QAC7B,IAAI,CAAC,KAAK,SAAS,EAAE,CAAC;YACpB,MAAM,CAAC,GAAG,WAAW,EAAE,CAAC;YACxB,MAAM,IAAI,KAAK,CACb,UAAU,IAAI,sCAAsC,CAAC,CAAC,GAAG,IAAI,IAAI,YAAY,CAAC,CAAC,KAAK,uCAAuC,CAC5H,CAAC;QACJ,CAAC;QACD,OAAO,CAAC,CAAC;IACX,CAAC;IACD,WAAW,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC;CACpC,CAAC;AAEF,kCAAkC;AAClC,MAAM,UAAU,iBAAiB;IAC/B,KAAK,CAAC,KAAK,EAAE,CAAC;AAChB,CAAC"}
@@ -0,0 +1,12 @@
1
+ /** Anything with a web-standard fetch: a Hono app, `{ fetch }`, or a bare function. */
2
+ export type FetchHandlerLike = {
3
+ fetch(request: Request, ...rest: unknown[]): Response | Promise<Response>;
4
+ } | ((request: Request) => Response | Promise<Response>);
5
+ /** The wrapped fetch (platform routes + instrumentation), without listening. Useful in tests. */
6
+ export declare function createPlatformFetch(handler: FetchHandlerLike): (request: Request) => Promise<Response>;
7
+ /** `/api/todos/42` → `/api/todos/:id` (used when the framework's route pattern is unknown). */
8
+ export declare function normalizePath(path: string): string;
9
+ /** Start the HTTP server. Resolves once listening. */
10
+ export declare function startServer(handler: FetchHandlerLike): Promise<{
11
+ close(): Promise<void>;
12
+ }>;
package/dist/server.js ADDED
@@ -0,0 +1,232 @@
1
+ /**
2
+ * Web Function entry wrapper. `plat build` generates:
3
+ *
4
+ * import handler from '<app>/src/server.ts';
5
+ * import { startServer } from '@ericminassian/platform/server';
6
+ * startServer(handler);
7
+ *
8
+ * and bundles it to `index.mjs`. startServer listens on
9
+ * `AWS_LAMBDA_HTTP_ENDPOINT` (Web Function contract; `plat dev` sets it too),
10
+ * adds `/__platform/*` routes (health, auth), auto-instruments every request
11
+ * (telemetry `req`/`err`/`span` lines, traces) and maps `x-platform-host` to
12
+ * the public URL the app sees.
13
+ *
14
+ * CONTRACT: used by the CLI build. Keep stable.
15
+ */
16
+ import { fingerprint, HEALTH_PATH, HOST_HEADER, PLATFORM_PATH_PREFIX, TRACE_HEADER, } from '@ericminassian/platform-core';
17
+ import { authGate, handleAuthRoute } from './auth/index.js';
18
+ import { getBindings, tryBindings } from './bindings.js';
19
+ import { currentContext, newContext, parseTraceparent, runWithContext } from './context.js';
20
+ import { createNodeServer, parseEndpoint } from './http.js';
21
+ import { emit, emitError, installConsoleCapture, installFetchInstrumentation, toError } from './telemetry.js';
22
+ let cold = true;
23
+ /** The wrapped fetch (platform routes + instrumentation), without listening. Useful in tests. */
24
+ export function createPlatformFetch(handler) {
25
+ const appFetch = typeof handler === 'function'
26
+ ? handler
27
+ : (req) => handler.fetch(req);
28
+ const matchRoute = routeMatcher(handler);
29
+ instrumentHonoErrors(handler);
30
+ return async (incoming) => {
31
+ const t0 = performance.now();
32
+ const trace = incoming.headers.get(TRACE_HEADER) ?? parseTraceparent(incoming.headers.get('traceparent'));
33
+ const ctx = newContext(trace);
34
+ const wasCold = cold;
35
+ cold = false;
36
+ return runWithContext(ctx, async () => {
37
+ const request = publicRequest(incoming);
38
+ const url = new URL(request.url);
39
+ let response;
40
+ let errorEmitted = false;
41
+ try {
42
+ if (url.pathname.startsWith(PLATFORM_PATH_PREFIX)) {
43
+ response = await platformRoute(request);
44
+ }
45
+ else {
46
+ response = (await authGate(request)) ?? (await appFetch(request));
47
+ }
48
+ }
49
+ catch (e) {
50
+ if (e instanceof Response)
51
+ response = e;
52
+ else {
53
+ emitError(e, 'http', { route: ctx.route ?? matchRoute(request.method, url.pathname) });
54
+ errorEmitted = true;
55
+ response = Response.json({ error: { code: 'internal', message: 'Internal Server Error', trace: ctx.trace } }, { status: 500 });
56
+ }
57
+ }
58
+ response = finalize(response, ctx.trace, ctx.cookies);
59
+ const route = ctx.route ?? matchRoute(request.method, url.pathname);
60
+ if (response.status >= 500 && !errorEmitted) {
61
+ if (ctx.error !== undefined)
62
+ emitError(ctx.error, 'http', { route });
63
+ else {
64
+ const e = new Error(`HTTP ${response.status} ${request.method} ${route}`);
65
+ e.name = 'HttpError';
66
+ emitError(e, 'http', { route });
67
+ }
68
+ }
69
+ emit('req', {
70
+ method: request.method,
71
+ route,
72
+ path: url.pathname,
73
+ status: response.status,
74
+ dur: Math.round((performance.now() - t0) * 10) / 10,
75
+ ...(lengthOf(response) !== undefined ? { bytes: lengthOf(response) } : {}),
76
+ ...(incoming.headers.get('cloudfront-viewer-country')
77
+ ? { country: incoming.headers.get('cloudfront-viewer-country') }
78
+ : {}),
79
+ ...(ctx.user ? { user: fingerprint([ctx.user.id]) } : {}),
80
+ ...(wasCold ? { cold: true } : {}),
81
+ span: ctx.span,
82
+ });
83
+ return response;
84
+ });
85
+ };
86
+ }
87
+ /** Rewrite the request onto the app's public origin (scheme/port from bindings, host from the router). */
88
+ function publicRequest(incoming) {
89
+ const b = tryBindings();
90
+ if (!b)
91
+ return incoming;
92
+ const inUrl = new URL(incoming.url);
93
+ const origin = new URL(b.url);
94
+ const forwarded = incoming.headers.get(HOST_HEADER);
95
+ if (forwarded && /^[a-z0-9.-]+$/i.test(forwarded.replace(/:\d+$/, '')))
96
+ origin.hostname = forwarded.replace(/:\d+$/, '');
97
+ const target = `${origin.origin}${inUrl.pathname}${inUrl.search}`;
98
+ if (target === incoming.url)
99
+ return incoming;
100
+ const hasBody = incoming.method !== 'GET' && incoming.method !== 'HEAD';
101
+ return new Request(target, {
102
+ method: incoming.method,
103
+ headers: incoming.headers,
104
+ signal: incoming.signal,
105
+ redirect: incoming.redirect,
106
+ ...(hasBody ? { body: incoming.body, duplex: 'half' } : {}),
107
+ });
108
+ }
109
+ async function platformRoute(request) {
110
+ const url = new URL(request.url);
111
+ if (url.pathname === HEALTH_PATH) {
112
+ const b = getBindings();
113
+ return Response.json({ ok: true, app: b.app, stage: b.stage, revision: b.revision }, { headers: { 'cache-control': 'no-store' } });
114
+ }
115
+ const authResponse = await handleAuthRoute(request);
116
+ if (authResponse)
117
+ return authResponse;
118
+ return Response.json({ error: { code: 'not_found', message: 'Not found' } }, { status: 404 });
119
+ }
120
+ function finalize(response, trace, cookies) {
121
+ const headers = new Headers(response.headers);
122
+ headers.set(TRACE_HEADER, trace);
123
+ if (!headers.has('cache-control'))
124
+ headers.set('cache-control', 'private, no-store');
125
+ for (const c of cookies)
126
+ headers.append('set-cookie', c);
127
+ return new Response(response.body, { status: response.status, statusText: response.statusText, headers });
128
+ }
129
+ function lengthOf(r) {
130
+ const v = r.headers.get('content-length');
131
+ return v ? Number(v) : undefined;
132
+ }
133
+ /**
134
+ * Hono catches handler errors itself (default: plain-text 500). Hook its
135
+ * onError so errors reach telemetry with their real stack, and so apps using
136
+ * the default handler get the platform's JSON 500 with a trace id. A custom
137
+ * onError the app installed keeps control of the response.
138
+ */
139
+ function instrumentHonoErrors(handler) {
140
+ const h = handler;
141
+ if (typeof h.onError !== 'function' || h.__platform)
142
+ return;
143
+ const prev = h.errorHandler;
144
+ const prevIsDefault = typeof prev !== 'function' ||
145
+ prev.name === 'errorHandler' ||
146
+ String(prev).includes('Internal Server Error');
147
+ h.onError((err, c) => {
148
+ if (err && typeof err.getResponse === 'function') {
149
+ return prev ? prev(err, c) : err.getResponse();
150
+ }
151
+ const ctx = currentContext();
152
+ if (ctx)
153
+ ctx.error = err;
154
+ if (prev && !prevIsDefault)
155
+ return prev(err, c);
156
+ throw err;
157
+ });
158
+ h.__platform = true;
159
+ }
160
+ // ---------------------------------------------------------------- route patterns
161
+ const ID_SEGMENT = /^(\d+|[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}|[0-9a-f]{12,}|[0-9a-hjkmnp-tv-z]{26}|(?=[A-Za-z0-9_-]*\d)[A-Za-z0-9_-]{16,})$/i;
162
+ /** `/api/todos/42` → `/api/todos/:id` (used when the framework's route pattern is unknown). */
163
+ export function normalizePath(path) {
164
+ return path
165
+ .split('/')
166
+ .map((seg) => (seg && ID_SEGMENT.test(seg) ? ':id' : seg))
167
+ .join('/');
168
+ }
169
+ /** Hono apps expose `routes`; match against them to recover the route pattern. */
170
+ function routeMatcher(handler) {
171
+ const routes = handler.routes;
172
+ if (!Array.isArray(routes))
173
+ return (_m, path) => normalizePath(path);
174
+ let compiled;
175
+ return (method, path) => {
176
+ compiled ??= routes
177
+ .filter((r) => r.method !== 'ALL' && typeof r.path === 'string' && !/^\/?\*?$/.test(r.path))
178
+ .map((r) => ({ method: r.method, path: r.path, re: patternToRegex(r.path) }));
179
+ const hit = compiled.find((r) => (r.method === method || (method === 'HEAD' && r.method === 'GET')) && r.re.test(path));
180
+ return hit ? hit.path : normalizePath(path);
181
+ };
182
+ }
183
+ function patternToRegex(pattern) {
184
+ const body = pattern
185
+ .split('/')
186
+ .map((seg) => {
187
+ if (seg === '*')
188
+ return '.*';
189
+ if (seg.startsWith(':')) {
190
+ const custom = /\{(.+)\}/.exec(seg);
191
+ const optional = seg.endsWith('?');
192
+ const part = custom ? `(?:${custom[1]})` : '[^/]+';
193
+ return optional ? `?(?:${part})?` : part;
194
+ }
195
+ return seg.replace(/[.+?^${}()|[\]\\]/g, '\\$&').replace(/\\\*/g, '.*');
196
+ })
197
+ .join('/');
198
+ return new RegExp(`^${body}/?$`);
199
+ }
200
+ // ---------------------------------------------------------------- server
201
+ /** Start the HTTP server. Resolves once listening. */
202
+ export async function startServer(handler) {
203
+ installConsoleCapture();
204
+ installFetchInstrumentation();
205
+ const endpoint = process.env.AWS_LAMBDA_HTTP_ENDPOINT ??
206
+ (process.env.PORT ? `127.0.0.1:${process.env.PORT}` : '127.0.0.1:8080');
207
+ const { host, port } = parseEndpoint(endpoint);
208
+ const server = createNodeServer(createPlatformFetch(handler));
209
+ server.keepAliveTimeout = 65_000;
210
+ await new Promise((resolve, reject) => {
211
+ server.once('error', reject);
212
+ server.listen(port, host, () => {
213
+ server.off('error', reject);
214
+ resolve();
215
+ });
216
+ });
217
+ emit('env', { event: 'start', runtime: 'web', initMs: Math.round(performance.now()) });
218
+ const close = () => new Promise((resolve) => {
219
+ server.close(() => resolve());
220
+ server.closeIdleConnections?.();
221
+ });
222
+ process.once('SIGTERM', () => {
223
+ emit('env', { event: 'stop', runtime: 'web' });
224
+ // Web Functions allow ~1 s for cleanup after SIGTERM.
225
+ const force = setTimeout(() => process.exit(0), 900);
226
+ force.unref();
227
+ close().then(() => process.exit(0));
228
+ });
229
+ process.on('unhandledRejection', (reason) => emitError(toError(reason), 'unhandled'));
230
+ return { close };
231
+ }
232
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ export interface StoredObject {
2
+ key: string;
3
+ size: number;
4
+ lastModified?: Date;
5
+ }
6
+ export interface Store {
7
+ put(key: string, body: Uint8Array | string, opts?: {
8
+ contentType?: string;
9
+ }): Promise<void>;
10
+ get(key: string): Promise<Uint8Array | undefined>;
11
+ getText(key: string): Promise<string | undefined>;
12
+ delete(key: string): Promise<void>;
13
+ list(prefix?: string, opts?: {
14
+ cursor?: string;
15
+ limit?: number;
16
+ }): Promise<{
17
+ objects: StoredObject[];
18
+ cursor?: string;
19
+ }>;
20
+ /** Browser-direct upload URL (HTTP PUT). */
21
+ uploadUrl(key: string, opts?: {
22
+ contentType?: string;
23
+ expiresInSeconds?: number;
24
+ }): Promise<string>;
25
+ downloadUrl(key: string, opts?: {
26
+ expiresInSeconds?: number;
27
+ filename?: string;
28
+ }): Promise<string>;
29
+ }
30
+ export declare function storage(name: string): Store;