@amerged/ohmyhost-runtime 0.1.11 → 0.1.17

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # @amerged/ohmyhost-runtime
2
2
 
3
- ohmyho.st runtime client, version 0.1.11.
3
+ ohmyho.st runtime client, version 0.1.17.
4
4
 
5
5
  ```sh
6
6
  npm install @amerged/ohmyhost-runtime
package/dist/errors.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export type CustomerRuntimeGatewayErrorCode = "gateway_configuration_invalid" | "gateway_request_invalid" | "gateway_response_invalid" | "gateway_timeout" | "gateway_unavailable" | "mail_credit_insufficient" | "mail_rejected" | "mail_reputation_suspended" | "mail_send_conflict" | "mail_send_limit_exceeded" | "storage_conflict" | "storage_object_not_found" | "storage_quota_exceeded" | "storage_upload_expired" | "storage_upload_rejected" | "unauthorized";
1
+ export type CustomerRuntimeGatewayErrorCode = "gateway_configuration_invalid" | "gateway_request_invalid" | "gateway_response_invalid" | "gateway_timeout" | "gateway_unavailable" | "mail_content_expired" | "mail_attachment_too_large" | "mail_message_not_found" | "mail_credit_insufficient" | "mail_rejected" | "mail_reputation_suspended" | "mail_send_conflict" | "mail_send_limit_exceeded" | "storage_conflict" | "storage_object_not_found" | "storage_quota_exceeded" | "storage_upload_expired" | "storage_upload_rejected" | "unauthorized";
2
2
  export type CustomerRuntimeErrorCode = CustomerRuntimeGatewayErrorCode | "database_query_invalid" | "database_response_invalid" | "database_unavailable" | "scheduled_context_invalid";
3
3
  export declare class CustomerRuntimeError extends Error {
4
4
  readonly code: CustomerRuntimeErrorCode;
@@ -1 +1 @@
1
- {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,+BAA+B,GACvC,+BAA+B,GAC/B,yBAAyB,GACzB,0BAA0B,GAC1B,iBAAiB,GACjB,qBAAqB,GACrB,0BAA0B,GAC1B,eAAe,GACf,2BAA2B,GAC3B,oBAAoB,GACpB,0BAA0B,GAC1B,kBAAkB,GAClB,0BAA0B,GAC1B,wBAAwB,GACxB,wBAAwB,GACxB,yBAAyB,GACzB,cAAc,CAAC;AAEnB,MAAM,MAAM,wBAAwB,GAChC,+BAA+B,GAC/B,wBAAwB,GACxB,2BAA2B,GAC3B,sBAAsB,GACtB,2BAA2B,CAAC;AAEhC,qBAAa,oBAAqB,SAAQ,KAAK;aAE3B,IAAI,EAAE,wBAAwB;aAC9B,SAAS,EAAE,OAAO;gBADlB,IAAI,EAAE,wBAAwB,EAC9B,SAAS,EAAE,OAAO;CAKrC;AAED,gGAAgG;AAChG,qBAAa,qBAAsB,SAAQ,KAAK;aAGX,IAAI,EAAE,MAAM;IAF/C,SAAgB,SAAS,EAAE,OAAO,CAAC;gBAEA,IAAI,EAAE,MAAM;CAMhD;AAED,qBAAa,2BAA4B,SAAQ,oBAAoB;aAGjD,MAAM,EAAE,MAAM,GAAG,IAAI;gBADrC,IAAI,EAAE,+BAA+B,EACrB,MAAM,EAAE,MAAM,GAAG,IAAI,EACrC,SAAS,EAAE,OAAO;CAKrB"}
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,+BAA+B,GACvC,+BAA+B,GAC/B,yBAAyB,GACzB,0BAA0B,GAC1B,iBAAiB,GACjB,qBAAqB,GACrB,sBAAsB,GACtB,2BAA2B,GAC3B,wBAAwB,GACxB,0BAA0B,GAC1B,eAAe,GACf,2BAA2B,GAC3B,oBAAoB,GACpB,0BAA0B,GAC1B,kBAAkB,GAClB,0BAA0B,GAC1B,wBAAwB,GACxB,wBAAwB,GACxB,yBAAyB,GACzB,cAAc,CAAC;AAEnB,MAAM,MAAM,wBAAwB,GAChC,+BAA+B,GAC/B,wBAAwB,GACxB,2BAA2B,GAC3B,sBAAsB,GACtB,2BAA2B,CAAC;AAEhC,qBAAa,oBAAqB,SAAQ,KAAK;aAE3B,IAAI,EAAE,wBAAwB;aAC9B,SAAS,EAAE,OAAO;gBADlB,IAAI,EAAE,wBAAwB,EAC9B,SAAS,EAAE,OAAO;CAKrC;AAED,gGAAgG;AAChG,qBAAa,qBAAsB,SAAQ,KAAK;aAGX,IAAI,EAAE,MAAM;IAF/C,SAAgB,SAAS,EAAE,OAAO,CAAC;gBAEA,IAAI,EAAE,MAAM;CAMhD;AAED,qBAAa,2BAA4B,SAAQ,oBAAoB;aAGjD,MAAM,EAAE,MAAM,GAAG,IAAI;gBADrC,IAAI,EAAE,+BAA+B,EACrB,MAAM,EAAE,MAAM,GAAG,IAAI,EACrC,SAAS,EAAE,OAAO;CAKrB"}
@@ -1 +1 @@
1
- {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAyBA,MAAM,OAAO,oBAAqB,SAAQ,KAAK;IAE3B;IACA;IAFlB,YACkB,IAA8B,EAC9B,SAAkB;QAElC,KAAK,CAAC,IAAI,CAAC,CAAC;QAHI,SAAI,GAAJ,IAAI,CAA0B;QAC9B,cAAS,GAAT,SAAS,CAAS;QAGlC,IAAI,CAAC,IAAI,GAAG,sBAAsB,CAAC;IACrC,CAAC;CACF;AAED,gGAAgG;AAChG,MAAM,OAAO,qBAAsB,SAAQ,KAAK;IAGX;IAFnB,SAAS,CAAU;IAEnC,YAAmC,IAAY;QAC7C,KAAK,CAAC,2BAA2B,CAAC,CAAC;QADF,SAAI,GAAJ,IAAI,CAAQ;QAE7C,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,MAAM,IAAI,SAAS,CAAC,kBAAkB,CAAC,CAAC;QAC1E,IAAI,CAAC,IAAI,GAAG,uBAAuB,CAAC;QACpC,IAAI,CAAC,SAAS,GAAG,IAAI,KAAK,OAAO,IAAI,IAAI,KAAK,OAAO,CAAC;IACxD,CAAC;CACF;AAED,MAAM,OAAO,2BAA4B,SAAQ,oBAAoB;IAGjD;IAFlB,YACE,IAAqC,EACrB,MAAqB,EACrC,SAAkB;QAElB,KAAK,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;QAHP,WAAM,GAAN,MAAM,CAAe;QAIrC,IAAI,CAAC,IAAI,GAAG,6BAA6B,CAAC;IAC5C,CAAC;CACF"}
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AA4BA,MAAM,OAAO,oBAAqB,SAAQ,KAAK;IAE3B;IACA;IAFlB,YACkB,IAA8B,EAC9B,SAAkB;QAElC,KAAK,CAAC,IAAI,CAAC,CAAC;QAHI,SAAI,GAAJ,IAAI,CAA0B;QAC9B,cAAS,GAAT,SAAS,CAAS;QAGlC,IAAI,CAAC,IAAI,GAAG,sBAAsB,CAAC;IACrC,CAAC;CACF;AAED,gGAAgG;AAChG,MAAM,OAAO,qBAAsB,SAAQ,KAAK;IAGX;IAFnB,SAAS,CAAU;IAEnC,YAAmC,IAAY;QAC7C,KAAK,CAAC,2BAA2B,CAAC,CAAC;QADF,SAAI,GAAJ,IAAI,CAAQ;QAE7C,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,MAAM,IAAI,SAAS,CAAC,kBAAkB,CAAC,CAAC;QAC1E,IAAI,CAAC,IAAI,GAAG,uBAAuB,CAAC;QACpC,IAAI,CAAC,SAAS,GAAG,IAAI,KAAK,OAAO,IAAI,IAAI,KAAK,OAAO,CAAC;IACxD,CAAC;CACF;AAED,MAAM,OAAO,2BAA4B,SAAQ,oBAAoB;IAGjD;IAFlB,YACE,IAAqC,EACrB,MAAqB,EACrC,SAAkB;QAElB,KAAK,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;QAHP,WAAM,GAAN,MAAM,CAAe;QAIrC,IAAI,CAAC,IAAI,GAAG,6BAA6B,CAAC;IAC5C,CAAC;CACF"}
package/dist/index.d.ts CHANGED
@@ -3,4 +3,6 @@ export * from "./database.js";
3
3
  export * from "./mail.js";
4
4
  export * from "./storage.js";
5
5
  export type { GatewayConnection } from "./http.js";
6
+ export * from "./mail-webhook.js";
7
+ export * from "./mail-attachments.js";
6
8
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,WAAW,CAAC;AAC1B,cAAc,cAAc,CAAC;AAC7B,YAAY,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,WAAW,CAAC;AAC1B,cAAc,cAAc,CAAC;AAC7B,YAAY,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AACnD,cAAc,mBAAmB,CAAC;AAClC,cAAc,uBAAuB,CAAC"}
package/dist/index.js CHANGED
@@ -2,4 +2,6 @@ export * from "./errors.js";
2
2
  export * from "./database.js";
3
3
  export * from "./mail.js";
4
4
  export * from "./storage.js";
5
+ export * from "./mail-webhook.js";
6
+ export * from "./mail-attachments.js";
5
7
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,WAAW,CAAC;AAC1B,cAAc,cAAc,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,WAAW,CAAC;AAC1B,cAAc,cAAc,CAAC;AAE7B,cAAc,mBAAmB,CAAC;AAClC,cAAc,uBAAuB,CAAC"}
@@ -0,0 +1,8 @@
1
+ import { type GatewayConnection } from "./http.js";
2
+ /** Stream owned attachments through the private mail binding using the environment's runtime key. */
3
+ export declare function createMailAttachmentClient(configuration: GatewayConnection & {
4
+ projectId: string;
5
+ }): {
6
+ download(downloadPath: string): Promise<Response>;
7
+ };
8
+ //# sourceMappingURL=mail-attachments.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mail-attachments.d.ts","sourceRoot":"","sources":["../src/mail-attachments.ts"],"names":[],"mappings":"AAAA,OAAO,EAA+C,KAAK,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAEhG,qGAAqG;AACrG,wBAAgB,0BAA0B,CACxC,aAAa,EAAE,iBAAiB,GAAG;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE;2BAUzB,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC;EA8B1D"}
@@ -0,0 +1,33 @@
1
+ import { validateGatewayConnection, fetchWithTimeout } from "./http.js";
2
+ import { CustomerRuntimeGatewayError } from "./errors.js";
3
+ /** Stream owned attachments through the private mail binding using the environment's runtime key. */
4
+ export function createMailAttachmentClient(configuration) {
5
+ const connection = validateGatewayConnection(configuration);
6
+ if (!/^[0-7][0-9A-HJKMNP-TV-Z]{25}$/u.test(configuration.projectId))
7
+ throw new CustomerRuntimeGatewayError("gateway_configuration_invalid", null, false);
8
+ const pattern = new RegExp(`^/v1/projects/${configuration.projectId}/environments/[0-7][0-9A-HJKMNP-TV-Z]{25}/mail/messages/[0-7][0-9A-HJKMNP-TV-Z]{25}/attachments/[A-Za-z0-9_-]{1,128}$`, "u");
9
+ return {
10
+ async download(downloadPath) {
11
+ if (!pattern.test(downloadPath))
12
+ throw new CustomerRuntimeGatewayError("gateway_request_invalid", null, false);
13
+ const response = await fetchWithTimeout(connection.fetch, new Request(new URL(downloadPath, connection.endpoint), {
14
+ redirect: "manual",
15
+ headers: { authorization: `Bearer ${connection.key}` },
16
+ }), connection.timeoutMilliseconds);
17
+ if (response.status !== 200) {
18
+ await response.body?.cancel();
19
+ throw new CustomerRuntimeGatewayError(response.status === 410
20
+ ? "mail_content_expired"
21
+ : response.status === 413
22
+ ? "mail_attachment_too_large"
23
+ : response.status === 404
24
+ ? "mail_message_not_found"
25
+ : response.status === 401
26
+ ? "unauthorized"
27
+ : "gateway_unavailable", response.status, response.status >= 500);
28
+ }
29
+ return response;
30
+ },
31
+ };
32
+ }
33
+ //# sourceMappingURL=mail-attachments.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mail-attachments.js","sourceRoot":"","sources":["../src/mail-attachments.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,yBAAyB,EAAE,gBAAgB,EAA0B,MAAM,WAAW,CAAC;AAChG,OAAO,EAAE,2BAA2B,EAAE,MAAM,aAAa,CAAC;AAC1D,qGAAqG;AACrG,MAAM,UAAU,0BAA0B,CACxC,aAAwD;IAExD,MAAM,UAAU,GAAG,yBAAyB,CAAC,aAAa,CAAC,CAAC;IAC5D,IAAI,CAAC,gCAAgC,CAAC,IAAI,CAAC,aAAa,CAAC,SAAS,CAAC;QACjE,MAAM,IAAI,2BAA2B,CAAC,+BAA+B,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;IACtF,MAAM,OAAO,GAAG,IAAI,MAAM,CACxB,iBAAiB,aAAa,CAAC,SAAS,uHAAuH,EAC/J,GAAG,CACJ,CAAC;IACF,OAAO;QACL,KAAK,CAAC,QAAQ,CAAC,YAAoB;YACjC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,YAAY,CAAC;gBAC7B,MAAM,IAAI,2BAA2B,CAAC,yBAAyB,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;YAChF,MAAM,QAAQ,GAAG,MAAM,gBAAgB,CACrC,UAAU,CAAC,KAAK,EAChB,IAAI,OAAO,CAAC,IAAI,GAAG,CAAC,YAAY,EAAE,UAAU,CAAC,QAAQ,CAAC,EAAE;gBACtD,QAAQ,EAAE,QAAQ;gBAClB,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,UAAU,CAAC,GAAG,EAAE,EAAE;aACvD,CAAC,EACF,UAAU,CAAC,mBAAmB,CAC/B,CAAC;YACF,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;gBAC5B,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC;gBAC9B,MAAM,IAAI,2BAA2B,CACnC,QAAQ,CAAC,MAAM,KAAK,GAAG;oBACrB,CAAC,CAAC,sBAAsB;oBACxB,CAAC,CAAC,QAAQ,CAAC,MAAM,KAAK,GAAG;wBACvB,CAAC,CAAC,2BAA2B;wBAC7B,CAAC,CAAC,QAAQ,CAAC,MAAM,KAAK,GAAG;4BACvB,CAAC,CAAC,wBAAwB;4BAC1B,CAAC,CAAC,QAAQ,CAAC,MAAM,KAAK,GAAG;gCACvB,CAAC,CAAC,cAAc;gCAChB,CAAC,CAAC,qBAAqB,EAC/B,QAAQ,CAAC,MAAM,EACf,QAAQ,CAAC,MAAM,IAAI,GAAG,CACvB,CAAC;YACJ,CAAC;YACD,OAAO,QAAQ,CAAC;QAClB,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,8 @@
1
+ /** Verify before parsing JSON. Only call this from the application's server-side route. */
2
+ export declare function verifyMailWebhook(input: {
3
+ body: string;
4
+ headers: Headers;
5
+ secret: string;
6
+ now?: Date;
7
+ }): Promise<string>;
8
+ //# sourceMappingURL=mail-webhook.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mail-webhook.d.ts","sourceRoot":"","sources":["../src/mail-webhook.ts"],"names":[],"mappings":"AAAA,2FAA2F;AAC3F,wBAAsB,iBAAiB,CAAC,KAAK,EAAE;IAC7C,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,IAAI,CAAC;CACZ,GAAG,OAAO,CAAC,MAAM,CAAC,CAkClB"}
@@ -0,0 +1,26 @@
1
+ /** Verify before parsing JSON. Only call this from the application's server-side route. */
2
+ export async function verifyMailWebhook(input) {
3
+ const id = input.headers.get("webhook-id"), timestamp = input.headers.get("webhook-timestamp"), signatures = input.headers.get("webhook-signature"), now = input.now ?? new Date();
4
+ if (!id ||
5
+ !/^[A-Za-z0-9_-]{1,256}$/u.test(id) ||
6
+ !timestamp ||
7
+ !/^\d{1,12}$/u.test(timestamp) ||
8
+ !Number.isFinite(now.getTime()) ||
9
+ Math.abs(now.getTime() - Number(timestamp) * 1000) > 300000 ||
10
+ !signatures ||
11
+ signatures.length > 1024 ||
12
+ !/^whsec_[A-Za-z0-9+/]{43}=$/u.test(input.secret))
13
+ throw new Error("Invalid mail webhook signature");
14
+ const bytes = Uint8Array.from(atob(input.secret.slice(6)), (character) => character.charCodeAt(0));
15
+ const key = await crypto.subtle.importKey("raw", bytes, { name: "HMAC", hash: "SHA-256" }, false, ["verify"]);
16
+ const message = new TextEncoder().encode(`${id}.${timestamp}.${input.body}`);
17
+ for (const part of signatures.split(" ")) {
18
+ if (!/^v1,[A-Za-z0-9+/]{43}=$/u.test(part))
19
+ continue;
20
+ const signature = Uint8Array.from(atob(part.slice(3)), (character) => character.charCodeAt(0));
21
+ if (await crypto.subtle.verify("HMAC", key, signature, message))
22
+ return id;
23
+ }
24
+ throw new Error("Invalid mail webhook signature");
25
+ }
26
+ //# sourceMappingURL=mail-webhook.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mail-webhook.js","sourceRoot":"","sources":["../src/mail-webhook.ts"],"names":[],"mappings":"AAAA,2FAA2F;AAC3F,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,KAKvC;IACC,MAAM,EAAE,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,EACxC,SAAS,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,EAClD,UAAU,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,EACnD,GAAG,GAAG,KAAK,CAAC,GAAG,IAAI,IAAI,IAAI,EAAE,CAAC;IAChC,IACE,CAAC,EAAE;QACH,CAAC,yBAAyB,CAAC,IAAI,CAAC,EAAE,CAAC;QACnC,CAAC,SAAS;QACV,CAAC,aAAa,CAAC,IAAI,CAAC,SAAS,CAAC;QAC9B,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;QAC/B,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,MAAM,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC,GAAG,MAAM;QAC3D,CAAC,UAAU;QACX,UAAU,CAAC,MAAM,GAAG,IAAI;QACxB,CAAC,6BAA6B,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC;QAEjD,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;IACpD,MAAM,KAAK,GAAG,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,SAAS,EAAE,EAAE,CACvE,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC,CACxB,CAAC;IACF,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,SAAS,CACvC,KAAK,EACL,KAAK,EACL,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,EACjC,KAAK,EACL,CAAC,QAAQ,CAAC,CACX,CAAC;IACF,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,GAAG,EAAE,IAAI,SAAS,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;IAC7E,KAAK,MAAM,IAAI,IAAI,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;QACzC,IAAI,CAAC,0BAA0B,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,SAAS;QACrD,MAAM,SAAS,GAAG,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;QAC/F,IAAI,MAAM,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,EAAE,SAAS,EAAE,OAAO,CAAC;YAAE,OAAO,EAAE,CAAC;IAC7E,CAAC;IACD,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;AACpD,CAAC"}
package/dist/mail.d.ts CHANGED
@@ -1,10 +1,12 @@
1
1
  import { type GatewayConnection } from "./http.js";
2
2
  export interface TransactionalMailInput {
3
+ readonly from?: string;
4
+ readonly replyTo?: string;
3
5
  readonly idempotencyKey: string;
4
6
  readonly to: string;
5
7
  readonly subject: string;
6
8
  readonly text: string;
7
- readonly html: string;
9
+ readonly html?: string;
8
10
  }
9
11
  export type TransactionalMailResult = {
10
12
  readonly state: "accepted";
@@ -1 +1 @@
1
- {"version":3,"file":"mail.d.ts","sourceRoot":"","sources":["../src/mail.ts"],"names":[],"mappings":"AACA,OAAO,EAKL,KAAK,iBAAiB,EACvB,MAAM,WAAW,CAAC;AAEnB,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,MAAM,uBAAuB,GAC/B;IACE,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;IAC3B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B,GACD;IACE,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC;IAC5B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEN,wBAAgB,6BAA6B,CAC3C,aAAa,EAAE,iBAAiB,GAAG;IAAE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;CAAE;gBAK7C,sBAAsB,GAAG,OAAO,CAAC,uBAAuB,CAAC;GAyC9E"}
1
+ {"version":3,"file":"mail.d.ts","sourceRoot":"","sources":["../src/mail.ts"],"names":[],"mappings":"AACA,OAAO,EAKL,KAAK,iBAAiB,EACvB,MAAM,WAAW,CAAC;AAEnB,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,MAAM,uBAAuB,GAC/B;IACE,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;IAC3B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B,GACD;IACE,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC;IAC5B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEN,wBAAgB,6BAA6B,CAC3C,aAAa,EAAE,iBAAiB,GAAG;IAAE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;CAAE;gBAK7C,sBAAsB,GAAG,OAAO,CAAC,uBAAuB,CAAC;GA2C9E"}
package/dist/mail.js CHANGED
@@ -8,10 +8,12 @@ export function createTransactionalMailClient(configuration) {
8
8
  validateMailInput(input);
9
9
  const response = await postGatewayJson(connection, "/v1/send", {
10
10
  project_id: projectId,
11
+ ...(input.from ? { from: input.from } : {}),
12
+ ...(input.replyTo ? { reply_to: input.replyTo } : {}),
11
13
  to: input.to,
12
14
  subject: input.subject,
13
15
  text: input.text,
14
- html: input.html,
16
+ ...(input.html !== undefined ? { html: input.html } : {}),
15
17
  }, 256 * 1024, input.idempotencyKey);
16
18
  if (response.status !== 202)
17
19
  throwMailError(response.status, response.body);
@@ -38,10 +40,12 @@ export function createTransactionalMailClient(configuration) {
38
40
  }
39
41
  function validateMailInput(input) {
40
42
  if (!validIdempotencyKey(input.idempotencyKey) ||
43
+ (input.from !== undefined && !validEmail(input.from)) ||
44
+ (input.replyTo !== undefined && !validEmail(input.replyTo)) ||
41
45
  !validEmail(input.to) ||
42
46
  !validContent(input.subject, 200, 998, false) ||
43
47
  !validContent(input.text, 65_536, 65_536, true) ||
44
- !validContent(input.html, 131_072, 131_072, true)) {
48
+ (input.html !== undefined && !validContent(input.html, 131_072, 131_072, true))) {
45
49
  throw new CustomerRuntimeGatewayError("gateway_request_invalid", null, false);
46
50
  }
47
51
  }
@@ -54,7 +58,13 @@ function throwMailError(status, body) {
54
58
  if (status === 401 && code === "unauthorized") {
55
59
  throw new CustomerRuntimeGatewayError("unauthorized", status, false);
56
60
  }
57
- if (status === 402 && code === "mail_send_credit_exhausted") {
61
+ if (status === 402 &&
62
+ [
63
+ "mail_send_credit_exhausted",
64
+ "insufficient_organization_credits",
65
+ "paid_plan_required",
66
+ "project_budget_exceeded",
67
+ ].includes(String(code))) {
58
68
  throw new CustomerRuntimeGatewayError("mail_credit_insufficient", status, false);
59
69
  }
60
70
  if (status === 409 && code === "mail_send_conflict") {
package/dist/mail.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"mail.js","sourceRoot":"","sources":["../src/mail.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"mail.js","sourceRoot":"","sources":["../src/mail.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@amerged/ohmyhost-runtime",
3
- "version": "0.1.11",
3
+ "version": "0.1.17",
4
4
  "type": "module",
5
5
  "engines": {
6
6
  "node": ">=22"
@@ -4,6 +4,9 @@ export type CustomerRuntimeGatewayErrorCode =
4
4
  | "gateway_response_invalid"
5
5
  | "gateway_timeout"
6
6
  | "gateway_unavailable"
7
+ | "mail_content_expired"
8
+ | "mail_attachment_too_large"
9
+ | "mail_message_not_found"
7
10
  | "mail_credit_insufficient"
8
11
  | "mail_rejected"
9
12
  | "mail_reputation_suspended"
@@ -3,3 +3,5 @@ export * from "./database.js";
3
3
  export * from "./mail.js";
4
4
  export * from "./storage.js";
5
5
  export type { GatewayConnection } from "./http.js";
6
+ export * from "./mail-webhook.js";
7
+ export * from "./mail-attachments.js";
@@ -0,0 +1,45 @@
1
+ import { validateGatewayConnection, fetchWithTimeout, type GatewayConnection } from "./http.js";
2
+ import { CustomerRuntimeGatewayError } from "./errors.js";
3
+ /** Stream owned attachments through the private mail binding using the environment's runtime key. */
4
+ export function createMailAttachmentClient(
5
+ configuration: GatewayConnection & { projectId: string },
6
+ ) {
7
+ const connection = validateGatewayConnection(configuration);
8
+ if (!/^[0-7][0-9A-HJKMNP-TV-Z]{25}$/u.test(configuration.projectId))
9
+ throw new CustomerRuntimeGatewayError("gateway_configuration_invalid", null, false);
10
+ const pattern = new RegExp(
11
+ `^/v1/projects/${configuration.projectId}/environments/[0-7][0-9A-HJKMNP-TV-Z]{25}/mail/messages/[0-7][0-9A-HJKMNP-TV-Z]{25}/attachments/[A-Za-z0-9_-]{1,128}$`,
12
+ "u",
13
+ );
14
+ return {
15
+ async download(downloadPath: string): Promise<Response> {
16
+ if (!pattern.test(downloadPath))
17
+ throw new CustomerRuntimeGatewayError("gateway_request_invalid", null, false);
18
+ const response = await fetchWithTimeout(
19
+ connection.fetch,
20
+ new Request(new URL(downloadPath, connection.endpoint), {
21
+ redirect: "manual",
22
+ headers: { authorization: `Bearer ${connection.key}` },
23
+ }),
24
+ connection.timeoutMilliseconds,
25
+ );
26
+ if (response.status !== 200) {
27
+ await response.body?.cancel();
28
+ throw new CustomerRuntimeGatewayError(
29
+ response.status === 410
30
+ ? "mail_content_expired"
31
+ : response.status === 413
32
+ ? "mail_attachment_too_large"
33
+ : response.status === 404
34
+ ? "mail_message_not_found"
35
+ : response.status === 401
36
+ ? "unauthorized"
37
+ : "gateway_unavailable",
38
+ response.status,
39
+ response.status >= 500,
40
+ );
41
+ }
42
+ return response;
43
+ },
44
+ };
45
+ }
@@ -0,0 +1,41 @@
1
+ /** Verify before parsing JSON. Only call this from the application's server-side route. */
2
+ export async function verifyMailWebhook(input: {
3
+ body: string;
4
+ headers: Headers;
5
+ secret: string;
6
+ now?: Date;
7
+ }): Promise<string> {
8
+ const id = input.headers.get("webhook-id"),
9
+ timestamp = input.headers.get("webhook-timestamp"),
10
+ signatures = input.headers.get("webhook-signature"),
11
+ now = input.now ?? new Date();
12
+ if (
13
+ !id ||
14
+ !/^[A-Za-z0-9_-]{1,256}$/u.test(id) ||
15
+ !timestamp ||
16
+ !/^\d{1,12}$/u.test(timestamp) ||
17
+ !Number.isFinite(now.getTime()) ||
18
+ Math.abs(now.getTime() - Number(timestamp) * 1000) > 300000 ||
19
+ !signatures ||
20
+ signatures.length > 1024 ||
21
+ !/^whsec_[A-Za-z0-9+/]{43}=$/u.test(input.secret)
22
+ )
23
+ throw new Error("Invalid mail webhook signature");
24
+ const bytes = Uint8Array.from(atob(input.secret.slice(6)), (character) =>
25
+ character.charCodeAt(0),
26
+ );
27
+ const key = await crypto.subtle.importKey(
28
+ "raw",
29
+ bytes,
30
+ { name: "HMAC", hash: "SHA-256" },
31
+ false,
32
+ ["verify"],
33
+ );
34
+ const message = new TextEncoder().encode(`${id}.${timestamp}.${input.body}`);
35
+ for (const part of signatures.split(" ")) {
36
+ if (!/^v1,[A-Za-z0-9+/]{43}=$/u.test(part)) continue;
37
+ const signature = Uint8Array.from(atob(part.slice(3)), (character) => character.charCodeAt(0));
38
+ if (await crypto.subtle.verify("HMAC", key, signature, message)) return id;
39
+ }
40
+ throw new Error("Invalid mail webhook signature");
41
+ }
@@ -8,11 +8,13 @@ import {
8
8
  } from "./http.js";
9
9
 
10
10
  export interface TransactionalMailInput {
11
+ readonly from?: string;
12
+ readonly replyTo?: string;
11
13
  readonly idempotencyKey: string;
12
14
  readonly to: string;
13
15
  readonly subject: string;
14
16
  readonly text: string;
15
- readonly html: string;
17
+ readonly html?: string;
16
18
  }
17
19
 
18
20
  export type TransactionalMailResult =
@@ -39,10 +41,12 @@ export function createTransactionalMailClient(
39
41
  "/v1/send",
40
42
  {
41
43
  project_id: projectId,
44
+ ...(input.from ? { from: input.from } : {}),
45
+ ...(input.replyTo ? { reply_to: input.replyTo } : {}),
42
46
  to: input.to,
43
47
  subject: input.subject,
44
48
  text: input.text,
45
- html: input.html,
49
+ ...(input.html !== undefined ? { html: input.html } : {}),
46
50
  },
47
51
  256 * 1024,
48
52
  input.idempotencyKey,
@@ -78,10 +82,12 @@ export function createTransactionalMailClient(
78
82
  function validateMailInput(input: TransactionalMailInput): void {
79
83
  if (
80
84
  !validIdempotencyKey(input.idempotencyKey) ||
85
+ (input.from !== undefined && !validEmail(input.from)) ||
86
+ (input.replyTo !== undefined && !validEmail(input.replyTo)) ||
81
87
  !validEmail(input.to) ||
82
88
  !validContent(input.subject, 200, 998, false) ||
83
89
  !validContent(input.text, 65_536, 65_536, true) ||
84
- !validContent(input.html, 131_072, 131_072, true)
90
+ (input.html !== undefined && !validContent(input.html, 131_072, 131_072, true))
85
91
  ) {
86
92
  throw new CustomerRuntimeGatewayError("gateway_request_invalid", null, false);
87
93
  }
@@ -98,7 +104,15 @@ function throwMailError(status: number, body: unknown): never {
98
104
  if (status === 401 && code === "unauthorized") {
99
105
  throw new CustomerRuntimeGatewayError("unauthorized", status, false);
100
106
  }
101
- if (status === 402 && code === "mail_send_credit_exhausted") {
107
+ if (
108
+ status === 402 &&
109
+ [
110
+ "mail_send_credit_exhausted",
111
+ "insufficient_organization_credits",
112
+ "paid_plan_required",
113
+ "project_budget_exceeded",
114
+ ].includes(String(code))
115
+ ) {
102
116
  throw new CustomerRuntimeGatewayError("mail_credit_insufficient", status, false);
103
117
  }
104
118
  if (status === 409 && code === "mail_send_conflict") {
@@ -1,20 +0,0 @@
1
- import type { CustomerDatabaseClient } from "./database.js";
2
- import type { createTransactionalMailClient } from "./mail.js";
3
- import type { createPrivateStorageClient } from "./storage.js";
4
- export type ScheduledStorageClient = ReturnType<typeof createPrivateStorageClient>;
5
- export type ScheduledMailClient = ReturnType<typeof createTransactionalMailClient>;
6
- export interface ScheduledFunctionContext {
7
- readonly projectId: string;
8
- readonly environmentId: string;
9
- readonly deploymentId: string;
10
- readonly functionId: string;
11
- readonly scheduledAt: string;
12
- readonly idempotencyKey: string;
13
- readonly signal: AbortSignal;
14
- readonly database: CustomerDatabaseClient;
15
- readonly storage: ScheduledStorageClient;
16
- readonly mail: ScheduledMailClient;
17
- }
18
- export type ScheduledFunctionHandler = (context: ScheduledFunctionContext) => Promise<void>;
19
- export declare function createScheduledFunctionContext(input: ScheduledFunctionContext): ScheduledFunctionContext;
20
- //# sourceMappingURL=scheduled.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"scheduled.d.ts","sourceRoot":"","sources":["../src/scheduled.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAC;AAC5D,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,WAAW,CAAC;AAC/D,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,cAAc,CAAC;AAE/D,MAAM,MAAM,sBAAsB,GAAG,UAAU,CAAC,OAAO,0BAA0B,CAAC,CAAC;AACnF,MAAM,MAAM,mBAAmB,GAAG,UAAU,CAAC,OAAO,6BAA6B,CAAC,CAAC;AAEnF,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAC7B,QAAQ,CAAC,QAAQ,EAAE,sBAAsB,CAAC;IAC1C,QAAQ,CAAC,OAAO,EAAE,sBAAsB,CAAC;IACzC,QAAQ,CAAC,IAAI,EAAE,mBAAmB,CAAC;CACpC;AAED,MAAM,MAAM,wBAAwB,GAAG,CAAC,OAAO,EAAE,wBAAwB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AAE5F,wBAAgB,8BAA8B,CAC5C,KAAK,EAAE,wBAAwB,GAC9B,wBAAwB,CA6C1B"}
package/dist/scheduled.js DELETED
@@ -1,67 +0,0 @@
1
- import { CustomerRuntimeError } from "./errors.js";
2
- export function createScheduledFunctionContext(input) {
3
- if (typeof input !== "object" ||
4
- input === null ||
5
- !validUlid(input.projectId) ||
6
- !validUlid(input.environmentId) ||
7
- !validUlid(input.deploymentId) ||
8
- !/^[a-z][a-z0-9-]{0,62}$/u.test(input.functionId) ||
9
- !validCanonicalTimestamp(input.scheduledAt) ||
10
- !/^[A-Za-z0-9._:-]{1,128}$/u.test(input.idempotencyKey) ||
11
- !(input.signal instanceof AbortSignal) ||
12
- !hasFunctions(input.database, ["query", "transaction"]) ||
13
- !hasFunctions(input.storage, [
14
- "reserveUpload",
15
- "completeUpload",
16
- "createSignedRead",
17
- "deleteObject",
18
- "upload",
19
- ]) ||
20
- !hasFunctions(input.mail, ["send"])) {
21
- throw new CustomerRuntimeError("scheduled_context_invalid", false);
22
- }
23
- const database = bindClient(input.database, ["query", "transaction"]);
24
- const storage = bindClient(input.storage, [
25
- "reserveUpload",
26
- "completeUpload",
27
- "createSignedRead",
28
- "deleteObject",
29
- "upload",
30
- ]);
31
- const mail = bindClient(input.mail, ["send"]);
32
- return Object.freeze({
33
- projectId: input.projectId,
34
- environmentId: input.environmentId,
35
- deploymentId: input.deploymentId,
36
- functionId: input.functionId,
37
- scheduledAt: input.scheduledAt,
38
- idempotencyKey: input.idempotencyKey,
39
- signal: input.signal,
40
- database: database,
41
- storage: storage,
42
- mail: mail,
43
- });
44
- }
45
- function hasFunctions(value, names) {
46
- return (typeof value === "object" &&
47
- value !== null &&
48
- !Array.isArray(value) &&
49
- names.every((name) => typeof value[name] === "function"));
50
- }
51
- function bindClient(value, names) {
52
- return Object.freeze(Object.fromEntries(names.map((name) => {
53
- const method = value[name];
54
- if (typeof method !== "function") {
55
- throw new CustomerRuntimeError("scheduled_context_invalid", false);
56
- }
57
- return [name, method.bind(value)];
58
- })));
59
- }
60
- function validUlid(value) {
61
- return /^[0-9A-HJKMNP-TV-Z]{26}$/u.test(value);
62
- }
63
- function validCanonicalTimestamp(value) {
64
- const timestamp = Date.parse(value);
65
- return Number.isFinite(timestamp) && new Date(timestamp).toISOString() === value;
66
- }
67
- //# sourceMappingURL=scheduled.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"scheduled.js","sourceRoot":"","sources":["../src/scheduled.ts"],"names":[],"mappings":"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"}