@q32/core 0.1.1

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 (93) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +60 -0
  3. package/dist/ai.d.ts +26 -0
  4. package/dist/ai.d.ts.map +1 -0
  5. package/dist/ai.js +16 -0
  6. package/dist/ai.js.map +1 -0
  7. package/dist/api.d.ts +25 -0
  8. package/dist/api.d.ts.map +1 -0
  9. package/dist/api.js +66 -0
  10. package/dist/api.js.map +1 -0
  11. package/dist/billing.d.ts +21 -0
  12. package/dist/billing.d.ts.map +1 -0
  13. package/dist/billing.js +18 -0
  14. package/dist/billing.js.map +1 -0
  15. package/dist/cloudflare.d.ts +12 -0
  16. package/dist/cloudflare.d.ts.map +1 -0
  17. package/dist/cloudflare.js +25 -0
  18. package/dist/cloudflare.js.map +1 -0
  19. package/dist/crypto.d.ts +10 -0
  20. package/dist/crypto.d.ts.map +1 -0
  21. package/dist/crypto.js +42 -0
  22. package/dist/crypto.js.map +1 -0
  23. package/dist/d1.d.ts +34 -0
  24. package/dist/d1.d.ts.map +1 -0
  25. package/dist/d1.js +44 -0
  26. package/dist/d1.js.map +1 -0
  27. package/dist/email.d.ts +33 -0
  28. package/dist/email.d.ts.map +1 -0
  29. package/dist/email.js +16 -0
  30. package/dist/email.js.map +1 -0
  31. package/dist/env.d.ts +11 -0
  32. package/dist/env.d.ts.map +1 -0
  33. package/dist/env.js +55 -0
  34. package/dist/env.js.map +1 -0
  35. package/dist/http.d.ts +14 -0
  36. package/dist/http.d.ts.map +1 -0
  37. package/dist/http.js +53 -0
  38. package/dist/http.js.map +1 -0
  39. package/dist/ids.d.ts +7 -0
  40. package/dist/ids.d.ts.map +1 -0
  41. package/dist/ids.js +35 -0
  42. package/dist/ids.js.map +1 -0
  43. package/dist/index.d.ts +22 -0
  44. package/dist/index.d.ts.map +1 -0
  45. package/dist/index.js +22 -0
  46. package/dist/index.js.map +1 -0
  47. package/dist/jobs.d.ts +52 -0
  48. package/dist/jobs.d.ts.map +1 -0
  49. package/dist/jobs.js +195 -0
  50. package/dist/jobs.js.map +1 -0
  51. package/dist/mcp.d.ts +18 -0
  52. package/dist/mcp.d.ts.map +1 -0
  53. package/dist/mcp.js +33 -0
  54. package/dist/mcp.js.map +1 -0
  55. package/dist/oauth.d.ts +17 -0
  56. package/dist/oauth.d.ts.map +1 -0
  57. package/dist/oauth.js +33 -0
  58. package/dist/oauth.js.map +1 -0
  59. package/dist/ops-events.d.ts +25 -0
  60. package/dist/ops-events.d.ts.map +1 -0
  61. package/dist/ops-events.js +43 -0
  62. package/dist/ops-events.js.map +1 -0
  63. package/dist/pg.d.ts +27 -0
  64. package/dist/pg.d.ts.map +1 -0
  65. package/dist/pg.js +51 -0
  66. package/dist/pg.js.map +1 -0
  67. package/dist/r2-json.d.ts +8 -0
  68. package/dist/r2-json.d.ts.map +1 -0
  69. package/dist/r2-json.js +21 -0
  70. package/dist/r2-json.js.map +1 -0
  71. package/dist/rate-limit.d.ts +19 -0
  72. package/dist/rate-limit.d.ts.map +1 -0
  73. package/dist/rate-limit.js +48 -0
  74. package/dist/rate-limit.js.map +1 -0
  75. package/dist/seo.d.ts +23 -0
  76. package/dist/seo.d.ts.map +1 -0
  77. package/dist/seo.js +60 -0
  78. package/dist/seo.js.map +1 -0
  79. package/dist/session.d.ts +11 -0
  80. package/dist/session.d.ts.map +1 -0
  81. package/dist/session.js +55 -0
  82. package/dist/session.js.map +1 -0
  83. package/dist/testing.d.ts +25 -0
  84. package/dist/testing.d.ts.map +1 -0
  85. package/dist/testing.js +94 -0
  86. package/dist/testing.js.map +1 -0
  87. package/dist/time.d.ts +5 -0
  88. package/dist/time.d.ts.map +1 -0
  89. package/dist/time.js +17 -0
  90. package/dist/time.js.map +1 -0
  91. package/docs/evaluation.md +74 -0
  92. package/docs/goal-audit.md +28 -0
  93. package/package.json +129 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Q32 LLC
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,60 @@
1
+ # @q32/core
2
+
3
+ Shared TypeScript primitives for Q32 Cloudflare Worker projects.
4
+
5
+ The first release focuses on common infrastructure repeated across Q32 apps:
6
+
7
+ - AI provider contracts and JSON extraction helpers
8
+ - API operation registries
9
+ - billing plan/status primitives
10
+ - Cloudflare binding guards
11
+ - environment parsing
12
+ - email provider contracts and address helpers
13
+ - IDs, tokens, and signed session cookies
14
+ - HTTP JSON/error helpers
15
+ - D1-like database types and migration runner
16
+ - D1-backed jobs
17
+ - `ops_events`
18
+ - Postgres migration helpers
19
+ - R2 JSON artifacts
20
+ - SEO sitemap, robots, and metadata helpers
21
+ - test helpers for Worker queues, R2, and JSON responses
22
+ - OAuth/MCP discovery metadata
23
+ - D1 rate limiting
24
+ - WebCrypto JSON encryption
25
+
26
+ ## Install
27
+
28
+ ```bash
29
+ pnpm add @q32/core
30
+ ```
31
+
32
+ ## Development
33
+
34
+ ```bash
35
+ pnpm install
36
+ pnpm test
37
+ pnpm build
38
+ ```
39
+
40
+ ## Release
41
+
42
+ Publishing is handled by the `Release` GitHub Actions workflow when a GitHub release is published. Configure an npm automation token as the repository secret `NPM_TOKEN` before the first release.
43
+
44
+ ## Modules
45
+
46
+ ```ts
47
+ import {
48
+ D1JobStore,
49
+ D1_JOBS_SCHEMA,
50
+ appUrl,
51
+ createId,
52
+ jsonResponse,
53
+ oauthAuthorizationServerMetadata,
54
+ renderSitemapXml,
55
+ recordOpsEvent,
56
+ signSession,
57
+ } from "@q32/core";
58
+ ```
59
+
60
+ See [docs/evaluation.md](docs/evaluation.md) for the project-inventory replacement matrix.
package/dist/ai.d.ts ADDED
@@ -0,0 +1,26 @@
1
+ export type AiMessage = {
2
+ role: "system" | "user" | "assistant" | "tool";
3
+ content: string;
4
+ };
5
+ export type AiJsonRequest = {
6
+ model: string;
7
+ messages: AiMessage[];
8
+ responseName?: string;
9
+ temperature?: number;
10
+ };
11
+ export type AiJsonProvider = {
12
+ generateJson<T>(request: AiJsonRequest): Promise<T>;
13
+ };
14
+ export type AiUsage = {
15
+ inputTokens?: number;
16
+ outputTokens?: number;
17
+ totalTokens?: number;
18
+ };
19
+ export type AiResult<T> = {
20
+ value: T;
21
+ usage?: AiUsage;
22
+ providerMetadata?: Record<string, unknown>;
23
+ };
24
+ export declare function systemUserMessages(system: string, user: string): AiMessage[];
25
+ export declare function extractJsonObject(text: string): unknown;
26
+ //# sourceMappingURL=ai.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai.d.ts","sourceRoot":"","sources":["../src/ai.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,SAAS,GAAG;IACtB,IAAI,EAAE,QAAQ,GAAG,MAAM,GAAG,WAAW,GAAG,MAAM,CAAC;IAC/C,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,SAAS,EAAE,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,YAAY,CAAC,CAAC,EAAE,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;CACrD,CAAC;AAEF,MAAM,MAAM,OAAO,GAAG;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,QAAQ,CAAC,CAAC,IAAI;IACxB,KAAK,EAAE,CAAC,CAAC;IACT,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC5C,CAAC;AAEF,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,EAAE,CAK5E;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAMvD"}
package/dist/ai.js ADDED
@@ -0,0 +1,16 @@
1
+ export function systemUserMessages(system, user) {
2
+ return [
3
+ { role: "system", content: system },
4
+ { role: "user", content: user },
5
+ ];
6
+ }
7
+ export function extractJsonObject(text) {
8
+ const trimmed = text.trim();
9
+ if (trimmed.startsWith("{") && trimmed.endsWith("}"))
10
+ return JSON.parse(trimmed);
11
+ const fenced = trimmed.match(/```(?:json)?\s*([\s\S]*?)```/i);
12
+ if (fenced)
13
+ return JSON.parse(fenced[1].trim());
14
+ throw new Error("No JSON object found in model output.");
15
+ }
16
+ //# sourceMappingURL=ai.js.map
package/dist/ai.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai.js","sourceRoot":"","sources":["../src/ai.ts"],"names":[],"mappings":"AA4BA,MAAM,UAAU,kBAAkB,CAAC,MAAc,EAAE,IAAY;IAC7D,OAAO;QACL,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE;QACnC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE;KAChC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;IAC5B,IAAI,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACjF,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,+BAA+B,CAAC,CAAC;IAC9D,IAAI,MAAM;QAAE,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IAChD,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;AAC3D,CAAC"}
package/dist/api.d.ts ADDED
@@ -0,0 +1,25 @@
1
+ export type ApiMethod = "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
2
+ export interface SchemaLike<T = unknown> {
3
+ parse(value: unknown): T;
4
+ }
5
+ export type ApiOperationSpec<TInput = unknown> = {
6
+ name: string;
7
+ title: string;
8
+ description: string;
9
+ method: ApiMethod;
10
+ path: string;
11
+ scope?: string;
12
+ inputSchema?: SchemaLike<TInput>;
13
+ openapi?: boolean;
14
+ };
15
+ export type ApiOperation<TContext, TInput = unknown, TOutput = unknown> = ApiOperationSpec<TInput> & {
16
+ handler: (context: TContext, input: TInput) => Promise<TOutput> | TOutput;
17
+ };
18
+ export type ApiOperationRegistry<TContext> = Record<string, ApiOperation<TContext, unknown, unknown>>;
19
+ export declare function defineApiOperation<TContext, TInput = unknown, TOutput = unknown>(operation: ApiOperation<TContext, TInput, TOutput>): ApiOperation<TContext, TInput, TOutput>;
20
+ export declare function defineApiRegistry<TContext, TRegistry extends ApiOperationRegistry<TContext>>(registry: TRegistry): TRegistry;
21
+ export declare function dispatchApiOperation<TContext>(registry: ApiOperationRegistry<TContext>, name: string, context: TContext, input: unknown): Promise<unknown>;
22
+ export declare function operationPathParameters(path: string): string[];
23
+ export declare function interpolateOperationPath(path: string, input: Record<string, unknown>): string;
24
+ export declare function openApiPathsForRegistry<TContext>(registry: ApiOperationRegistry<TContext>): Record<string, Record<string, Record<string, unknown>>>;
25
+ //# sourceMappingURL=api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,SAAS,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,OAAO,GAAG,QAAQ,CAAC;AAEpE,MAAM,WAAW,UAAU,CAAC,CAAC,GAAG,OAAO;IACrC,KAAK,CAAC,KAAK,EAAE,OAAO,GAAG,CAAC,CAAC;CAC1B;AAED,MAAM,MAAM,gBAAgB,CAAC,MAAM,GAAG,OAAO,IAAI;IAC/C,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,SAAS,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC;IACjC,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,EAAE,OAAO,GAAG,OAAO,IAAI,gBAAgB,CAAC,MAAM,CAAC,GAAG;IACnG,OAAO,EAAE,CAAC,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;CAC3E,CAAC;AAEF,MAAM,MAAM,oBAAoB,CAAC,QAAQ,IAAI,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,QAAQ,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;AAEtG,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,EAAE,OAAO,GAAG,OAAO,EAC9E,SAAS,EAAE,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,GACjD,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,CAEzC;AAED,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,SAAS,SAAS,oBAAoB,CAAC,QAAQ,CAAC,EAC1F,QAAQ,EAAE,SAAS,GAClB,SAAS,CAQX;AAED,wBAAsB,oBAAoB,CAAC,QAAQ,EACjD,QAAQ,EAAE,oBAAoB,CAAC,QAAQ,CAAC,EACxC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,QAAQ,EACjB,KAAK,EAAE,OAAO,GACb,OAAO,CAAC,OAAO,CAAC,CAKlB;AAED,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAI9D;AAED,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAQ7F;AAED,wBAAgB,uBAAuB,CAAC,QAAQ,EAC9C,QAAQ,EAAE,oBAAoB,CAAC,QAAQ,CAAC,GACvC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CA0BzD"}
package/dist/api.js ADDED
@@ -0,0 +1,66 @@
1
+ import { HttpError } from "./http.js";
2
+ export function defineApiOperation(operation) {
3
+ return operation;
4
+ }
5
+ export function defineApiRegistry(registry) {
6
+ const names = new Set();
7
+ for (const [key, operation] of Object.entries(registry)) {
8
+ if (operation.name !== key)
9
+ throw new Error(`API operation key/name mismatch: ${key} != ${operation.name}`);
10
+ if (names.has(operation.name))
11
+ throw new Error(`Duplicate API operation name: ${operation.name}`);
12
+ names.add(operation.name);
13
+ }
14
+ return registry;
15
+ }
16
+ export async function dispatchApiOperation(registry, name, context, input) {
17
+ const operation = registry[name];
18
+ if (!operation)
19
+ throw new HttpError(404, `Unknown API operation: ${name}`, "unknown_operation");
20
+ const parsed = operation.inputSchema ? operation.inputSchema.parse(input) : input;
21
+ return operation.handler(context, parsed);
22
+ }
23
+ export function operationPathParameters(path) {
24
+ const params = new Set();
25
+ for (const match of path.matchAll(/\{([A-Za-z_][A-Za-z0-9_]*)\}/g))
26
+ params.add(match[1]);
27
+ return [...params];
28
+ }
29
+ export function interpolateOperationPath(path, input) {
30
+ return path.replace(/\{([A-Za-z_][A-Za-z0-9_]*)\}/g, (_, key) => {
31
+ const value = input[key];
32
+ if (value === undefined || value === null || value === "") {
33
+ throw new HttpError(400, `Missing path parameter: ${key}`, "missing_path_parameter");
34
+ }
35
+ return encodeURIComponent(String(value));
36
+ });
37
+ }
38
+ export function openApiPathsForRegistry(registry) {
39
+ const paths = {};
40
+ for (const operation of Object.values(registry)) {
41
+ if (operation.openapi === false)
42
+ continue;
43
+ const path = operation.path.replace(/\{([A-Za-z_][A-Za-z0-9_]*)\}/g, "{$1}");
44
+ const method = operation.method.toLowerCase();
45
+ paths[path] ??= {};
46
+ paths[path][method] = {
47
+ operationId: operation.name,
48
+ summary: operation.title,
49
+ description: operation.description,
50
+ security: operation.scope ? [{ bearerAuth: [operation.scope] }] : undefined,
51
+ parameters: operationPathParameters(operation.path).map((name) => ({
52
+ name,
53
+ in: "path",
54
+ required: true,
55
+ schema: { type: "string" },
56
+ })),
57
+ responses: {
58
+ "200": {
59
+ description: "OK",
60
+ },
61
+ },
62
+ };
63
+ }
64
+ return paths;
65
+ }
66
+ //# sourceMappingURL=api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ export type BillingPlan = {
2
+ id: string;
3
+ name: string;
4
+ rank: number;
5
+ stripePriceId?: string;
6
+ limits?: Record<string, number>;
7
+ };
8
+ export type SubscriptionStatus = "trialing" | "active" | "past_due" | "canceled" | "unpaid" | "incomplete" | "incomplete_expired" | "paused";
9
+ export type BillingCustomer = {
10
+ customerId: string;
11
+ email?: string;
12
+ planId?: string;
13
+ stripeCustomerId?: string;
14
+ stripeSubscriptionId?: string;
15
+ subscriptionStatus?: SubscriptionStatus;
16
+ };
17
+ export declare function planAtLeast(plans: BillingPlan[], actualPlanId: string | null | undefined, requiredPlanId: string): boolean;
18
+ export declare function activeSubscriptionStatuses(): SubscriptionStatus[];
19
+ export declare function isActiveSubscriptionStatus(status: SubscriptionStatus | null | undefined): boolean;
20
+ export declare function stripeEventAlreadyProcessedMessage(eventId: string): string;
21
+ //# sourceMappingURL=billing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"billing.d.ts","sourceRoot":"","sources":["../src/billing.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,WAAW,GAAG;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACjC,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAC1B,UAAU,GACV,QAAQ,GACR,UAAU,GACV,UAAU,GACV,QAAQ,GACR,YAAY,GACZ,oBAAoB,GACpB,QAAQ,CAAC;AAEb,MAAM,MAAM,eAAe,GAAG;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,kBAAkB,CAAC,EAAE,kBAAkB,CAAC;CACzC,CAAC;AAEF,wBAAgB,WAAW,CAAC,KAAK,EAAE,WAAW,EAAE,EAAE,YAAY,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAAE,cAAc,EAAE,MAAM,GAAG,OAAO,CAM1H;AAED,wBAAgB,0BAA0B,IAAI,kBAAkB,EAAE,CAEjE;AAED,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,kBAAkB,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAEjG;AAED,wBAAgB,kCAAkC,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAE1E"}
@@ -0,0 +1,18 @@
1
+ export function planAtLeast(plans, actualPlanId, requiredPlanId) {
2
+ const byId = new Map(plans.map((plan) => [plan.id, plan]));
3
+ const actual = actualPlanId ? byId.get(actualPlanId) : undefined;
4
+ const required = byId.get(requiredPlanId);
5
+ if (!actual || !required)
6
+ return false;
7
+ return actual.rank >= required.rank;
8
+ }
9
+ export function activeSubscriptionStatuses() {
10
+ return ["trialing", "active"];
11
+ }
12
+ export function isActiveSubscriptionStatus(status) {
13
+ return status === "trialing" || status === "active";
14
+ }
15
+ export function stripeEventAlreadyProcessedMessage(eventId) {
16
+ return `Stripe event already processed: ${eventId}`;
17
+ }
18
+ //# sourceMappingURL=billing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"billing.js","sourceRoot":"","sources":["../src/billing.ts"],"names":[],"mappings":"AA2BA,MAAM,UAAU,WAAW,CAAC,KAAoB,EAAE,YAAuC,EAAE,cAAsB;IAC/G,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;IAC3D,MAAM,MAAM,GAAG,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IACjE,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IAC1C,IAAI,CAAC,MAAM,IAAI,CAAC,QAAQ;QAAE,OAAO,KAAK,CAAC;IACvC,OAAO,MAAM,CAAC,IAAI,IAAI,QAAQ,CAAC,IAAI,CAAC;AACtC,CAAC;AAED,MAAM,UAAU,0BAA0B;IACxC,OAAO,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;AAChC,CAAC;AAED,MAAM,UAAU,0BAA0B,CAAC,MAA6C;IACtF,OAAO,MAAM,KAAK,UAAU,IAAI,MAAM,KAAK,QAAQ,CAAC;AACtD,CAAC;AAED,MAAM,UAAU,kCAAkC,CAAC,OAAe;IAChE,OAAO,mCAAmC,OAAO,EAAE,CAAC;AACtD,CAAC"}
@@ -0,0 +1,12 @@
1
+ export type WorkerQueueMessage<T = unknown> = {
2
+ jobId: string;
3
+ payload?: T;
4
+ };
5
+ export type DurableObjectIdLike = {
6
+ toString(): string;
7
+ };
8
+ export declare function requireD1(env: Record<string, unknown>, binding?: string): D1Database;
9
+ export declare function requireR2(env: Record<string, unknown>, binding: string): R2Bucket;
10
+ export declare function requireQueue<T = unknown>(env: Record<string, unknown>, binding: string): Queue<T>;
11
+ export declare function isCloudflareScheduledEvent(value: unknown): value is ScheduledEvent;
12
+ //# sourceMappingURL=cloudflare.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloudflare.d.ts","sourceRoot":"","sources":["../src/cloudflare.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,kBAAkB,CAAC,CAAC,GAAG,OAAO,IAAI;IAC5C,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,CAAC,CAAC;CACb,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,QAAQ,IAAI,MAAM,CAAC;CACpB,CAAC;AAEF,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,SAAO,GAAG,UAAU,CAMlF;AAED,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,EAAE,MAAM,GAAG,QAAQ,CAMjF;AAED,wBAAgB,YAAY,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,EAAE,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,CAMjG;AAED,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,cAAc,CAElF"}
@@ -0,0 +1,25 @@
1
+ export function requireD1(env, binding = "DB") {
2
+ const db = env[binding];
3
+ if (!db || typeof db !== "object" || typeof db.prepare !== "function") {
4
+ throw new Error(`Missing D1 binding: ${binding}`);
5
+ }
6
+ return db;
7
+ }
8
+ export function requireR2(env, binding) {
9
+ const bucket = env[binding];
10
+ if (!bucket || typeof bucket !== "object" || typeof bucket.put !== "function") {
11
+ throw new Error(`Missing R2 binding: ${binding}`);
12
+ }
13
+ return bucket;
14
+ }
15
+ export function requireQueue(env, binding) {
16
+ const queue = env[binding];
17
+ if (!queue || typeof queue !== "object" || typeof queue.send !== "function") {
18
+ throw new Error(`Missing Queue binding: ${binding}`);
19
+ }
20
+ return queue;
21
+ }
22
+ export function isCloudflareScheduledEvent(value) {
23
+ return Boolean(value && typeof value === "object" && "scheduledTime" in value && "cron" in value);
24
+ }
25
+ //# sourceMappingURL=cloudflare.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloudflare.js","sourceRoot":"","sources":["../src/cloudflare.ts"],"names":[],"mappings":"AASA,MAAM,UAAU,SAAS,CAAC,GAA4B,EAAE,OAAO,GAAG,IAAI;IACpE,MAAM,EAAE,GAAG,GAAG,CAAC,OAAO,CAAC,CAAC;IACxB,IAAI,CAAC,EAAE,IAAI,OAAO,EAAE,KAAK,QAAQ,IAAI,OAAQ,EAAiB,CAAC,OAAO,KAAK,UAAU,EAAE,CAAC;QACtF,MAAM,IAAI,KAAK,CAAC,uBAAuB,OAAO,EAAE,CAAC,CAAC;IACpD,CAAC;IACD,OAAO,EAAgB,CAAC;AAC1B,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,GAA4B,EAAE,OAAe;IACrE,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC,CAAC;IAC5B,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,OAAQ,MAAmB,CAAC,GAAG,KAAK,UAAU,EAAE,CAAC;QAC5F,MAAM,IAAI,KAAK,CAAC,uBAAuB,OAAO,EAAE,CAAC,CAAC;IACpD,CAAC;IACD,OAAO,MAAkB,CAAC;AAC5B,CAAC;AAED,MAAM,UAAU,YAAY,CAAc,GAA4B,EAAE,OAAe;IACrF,MAAM,KAAK,GAAG,GAAG,CAAC,OAAO,CAAC,CAAC;IAC3B,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,OAAQ,KAAkB,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;QAC1F,MAAM,IAAI,KAAK,CAAC,0BAA0B,OAAO,EAAE,CAAC,CAAC;IACvD,CAAC;IACD,OAAO,KAAiB,CAAC;AAC3B,CAAC;AAED,MAAM,UAAU,0BAA0B,CAAC,KAAc;IACvD,OAAO,OAAO,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,eAAe,IAAI,KAAK,IAAI,MAAM,IAAI,KAAK,CAAC,CAAC;AACpG,CAAC"}
@@ -0,0 +1,10 @@
1
+ export type EncryptedJsonEnvelope = {
2
+ v: 1;
3
+ alg: "A256GCM";
4
+ iv: string;
5
+ ciphertext: string;
6
+ };
7
+ export declare function createEncryptionKey(): string;
8
+ export declare function encryptJson(value: unknown, keyMaterial: string): Promise<EncryptedJsonEnvelope>;
9
+ export declare function decryptJson<T>(envelope: EncryptedJsonEnvelope, keyMaterial: string): Promise<T>;
10
+ //# sourceMappingURL=crypto.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"crypto.d.ts","sourceRoot":"","sources":["../src/crypto.ts"],"names":[],"mappings":"AAKA,MAAM,MAAM,qBAAqB,GAAG;IAClC,CAAC,EAAE,CAAC,CAAC;IACL,GAAG,EAAE,SAAS,CAAC;IACf,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,wBAAgB,mBAAmB,IAAI,MAAM,CAE5C;AAED,wBAAsB,WAAW,CAAC,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAWrG;AAED,wBAAsB,WAAW,CAAC,CAAC,EAAE,QAAQ,EAAE,qBAAqB,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CASrG"}
package/dist/crypto.js ADDED
@@ -0,0 +1,42 @@
1
+ import { fromBase64Url, randomBase64Url, toBase64Url } from "./ids.js";
2
+ const AES_GCM_IV_BYTES = 12;
3
+ const AES_GCM_KEY_BYTES = 32;
4
+ export function createEncryptionKey() {
5
+ return randomBase64Url(AES_GCM_KEY_BYTES);
6
+ }
7
+ export async function encryptJson(value, keyMaterial) {
8
+ const iv = crypto.getRandomValues(new Uint8Array(AES_GCM_IV_BYTES));
9
+ const key = await importAesKey(keyMaterial);
10
+ const plaintext = new TextEncoder().encode(JSON.stringify(value));
11
+ const ciphertext = await crypto.subtle.encrypt({ name: "AES-GCM", iv }, key, plaintext);
12
+ return {
13
+ v: 1,
14
+ alg: "A256GCM",
15
+ iv: toBase64Url(iv),
16
+ ciphertext: toBase64Url(new Uint8Array(ciphertext)),
17
+ };
18
+ }
19
+ export async function decryptJson(envelope, keyMaterial) {
20
+ if (envelope.v !== 1 || envelope.alg !== "A256GCM")
21
+ throw new Error("Unsupported encrypted JSON envelope.");
22
+ const key = await importAesKey(keyMaterial);
23
+ const plaintext = await crypto.subtle.decrypt({ name: "AES-GCM", iv: toArrayBuffer(fromBase64Url(envelope.iv)) }, key, toArrayBuffer(fromBase64Url(envelope.ciphertext)));
24
+ return JSON.parse(new TextDecoder().decode(plaintext));
25
+ }
26
+ async function importAesKey(keyMaterial) {
27
+ let raw;
28
+ try {
29
+ raw = fromBase64Url(keyMaterial);
30
+ }
31
+ catch {
32
+ throw new Error("Encryption key must be 32 base64url-encoded bytes.");
33
+ }
34
+ if (raw.byteLength !== AES_GCM_KEY_BYTES) {
35
+ throw new Error("Encryption key must be 32 base64url-encoded bytes.");
36
+ }
37
+ return crypto.subtle.importKey("raw", toArrayBuffer(raw), "AES-GCM", false, ["encrypt", "decrypt"]);
38
+ }
39
+ function toArrayBuffer(bytes) {
40
+ return bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
41
+ }
42
+ //# sourceMappingURL=crypto.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"crypto.js","sourceRoot":"","sources":["../src/crypto.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAEvE,MAAM,gBAAgB,GAAG,EAAE,CAAC;AAC5B,MAAM,iBAAiB,GAAG,EAAE,CAAC;AAS7B,MAAM,UAAU,mBAAmB;IACjC,OAAO,eAAe,CAAC,iBAAiB,CAAC,CAAC;AAC5C,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,KAAc,EAAE,WAAmB;IACnE,MAAM,EAAE,GAAG,MAAM,CAAC,eAAe,CAAC,IAAI,UAAU,CAAC,gBAAgB,CAAC,CAAC,CAAC;IACpE,MAAM,GAAG,GAAG,MAAM,YAAY,CAAC,WAAW,CAAC,CAAC;IAC5C,MAAM,SAAS,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC;IAClE,MAAM,UAAU,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,SAAS,CAAC,CAAC;IACxF,OAAO;QACL,CAAC,EAAE,CAAC;QACJ,GAAG,EAAE,SAAS;QACd,EAAE,EAAE,WAAW,CAAC,EAAE,CAAC;QACnB,UAAU,EAAE,WAAW,CAAC,IAAI,UAAU,CAAC,UAAU,CAAC,CAAC;KACpD,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAAI,QAA+B,EAAE,WAAmB;IACvF,IAAI,QAAQ,CAAC,CAAC,KAAK,CAAC,IAAI,QAAQ,CAAC,GAAG,KAAK,SAAS;QAAE,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;IAC5G,MAAM,GAAG,GAAG,MAAM,YAAY,CAAC,WAAW,CAAC,CAAC;IAC5C,MAAM,SAAS,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,OAAO,CAC3C,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,aAAa,CAAC,aAAa,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,EAAE,EAClE,GAAG,EACH,aAAa,CAAC,aAAa,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAClD,CAAC;IACF,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,CAAM,CAAC;AAC9D,CAAC;AAED,KAAK,UAAU,YAAY,CAAC,WAAmB;IAC7C,IAAI,GAAe,CAAC;IACpB,IAAI,CAAC;QACH,GAAG,GAAG,aAAa,CAAC,WAAW,CAAC,CAAC;IACnC,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAC;IACxE,CAAC;IACD,IAAI,GAAG,CAAC,UAAU,KAAK,iBAAiB,EAAE,CAAC;QACzC,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAC;IACxE,CAAC;IACD,OAAO,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,EAAE,aAAa,CAAC,GAAG,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC;AACtG,CAAC;AAED,SAAS,aAAa,CAAC,KAAiB;IACtC,OAAO,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC,UAAU,GAAG,KAAK,CAAC,UAAU,CAAgB,CAAC;AAClG,CAAC"}
package/dist/d1.d.ts ADDED
@@ -0,0 +1,34 @@
1
+ export type D1Primitive = string | number | boolean | null | Uint8Array;
2
+ export interface D1StatementResult {
3
+ success: boolean;
4
+ meta: Record<string, unknown>;
5
+ results?: Record<string, unknown>[];
6
+ }
7
+ export interface D1PreparedStatementLike {
8
+ bind(...values: D1Primitive[]): D1PreparedStatementLike;
9
+ run(): Promise<D1StatementResult>;
10
+ first<T extends object = Record<string, unknown>>(): Promise<T | null>;
11
+ all<T extends object = Record<string, unknown>>(): Promise<{
12
+ results: T[];
13
+ }>;
14
+ }
15
+ export interface D1DatabaseLike {
16
+ prepare(query: string): D1PreparedStatementLike;
17
+ batch(statements: D1PreparedStatementLike[]): Promise<D1StatementResult[]>;
18
+ exec(query: string): Promise<unknown>;
19
+ }
20
+ export type Migration = {
21
+ id: string;
22
+ sql: string;
23
+ };
24
+ export type MigrationResult = {
25
+ applied: string[];
26
+ skipped: string[];
27
+ };
28
+ export declare function ensureMigrationsTable(db: D1DatabaseLike, tableName?: string): Promise<void>;
29
+ export declare function applyD1Migrations(db: D1DatabaseLike, migrations: Migration[], options?: {
30
+ tableName?: string;
31
+ }): Promise<MigrationResult>;
32
+ export declare function parseJsonColumn<T>(value: string | null | undefined, fallback: T): T;
33
+ export declare function stringifyJsonColumn(value: unknown): string;
34
+ //# sourceMappingURL=d1.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"d1.d.ts","sourceRoot":"","sources":["../src/d1.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,UAAU,CAAC;AAExE,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;CACrC;AAED,MAAM,WAAW,uBAAuB;IACtC,IAAI,CAAC,GAAG,MAAM,EAAE,WAAW,EAAE,GAAG,uBAAuB,CAAC;IACxD,GAAG,IAAI,OAAO,CAAC,iBAAiB,CAAC,CAAC;IAClC,KAAK,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IACvE,GAAG,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC;QAAE,OAAO,EAAE,CAAC,EAAE,CAAA;KAAE,CAAC,CAAC;CAC9E;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,uBAAuB,CAAC;IAChD,KAAK,CAAC,UAAU,EAAE,uBAAuB,EAAE,GAAG,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAAC;IAC3E,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CACvC;AAED,MAAM,MAAM,SAAS,GAAG;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,MAAM,CAAC;CACb,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB,CAAC;AAEF,wBAAsB,qBAAqB,CAAC,EAAE,EAAE,cAAc,EAAE,SAAS,SAAsB,GAAG,OAAO,CAAC,IAAI,CAAC,CAQ9G;AAED,wBAAsB,iBAAiB,CACrC,EAAE,EAAE,cAAc,EAClB,UAAU,EAAE,SAAS,EAAE,EACvB,OAAO,GAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAO,GACnC,OAAO,CAAC,eAAe,CAAC,CAqB1B;AAED,wBAAgB,eAAe,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAAE,QAAQ,EAAE,CAAC,GAAG,CAAC,CAOnF;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAE1D"}
package/dist/d1.js ADDED
@@ -0,0 +1,44 @@
1
+ export async function ensureMigrationsTable(db, tableName = "schema_migrations") {
2
+ assertSafeIdentifier(tableName);
3
+ await db.exec(`CREATE TABLE IF NOT EXISTS ${tableName} (
4
+ id TEXT PRIMARY KEY,
5
+ applied_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP
6
+ )`);
7
+ }
8
+ export async function applyD1Migrations(db, migrations, options = {}) {
9
+ const tableName = options.tableName ?? "schema_migrations";
10
+ assertSafeIdentifier(tableName);
11
+ await ensureMigrationsTable(db, tableName);
12
+ const applied = [];
13
+ const skipped = [];
14
+ for (const migration of migrations) {
15
+ const existing = await db.prepare(`SELECT id FROM ${tableName} WHERE id = ? LIMIT 1`).bind(migration.id).first();
16
+ if (existing) {
17
+ skipped.push(migration.id);
18
+ continue;
19
+ }
20
+ await db.exec(migration.sql);
21
+ await db.prepare(`INSERT INTO ${tableName} (id) VALUES (?)`).bind(migration.id).run();
22
+ applied.push(migration.id);
23
+ }
24
+ return { applied, skipped };
25
+ }
26
+ export function parseJsonColumn(value, fallback) {
27
+ if (!value)
28
+ return fallback;
29
+ try {
30
+ return JSON.parse(value);
31
+ }
32
+ catch {
33
+ return fallback;
34
+ }
35
+ }
36
+ export function stringifyJsonColumn(value) {
37
+ return JSON.stringify(value ?? null);
38
+ }
39
+ function assertSafeIdentifier(value) {
40
+ if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(value)) {
41
+ throw new Error(`Unsafe SQL identifier: ${value}`);
42
+ }
43
+ }
44
+ //# sourceMappingURL=d1.js.map
package/dist/d1.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"d1.js","sourceRoot":"","sources":["../src/d1.ts"],"names":[],"mappings":"AA+BA,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAAC,EAAkB,EAAE,SAAS,GAAG,mBAAmB;IAC7F,oBAAoB,CAAC,SAAS,CAAC,CAAC;IAChC,MAAM,EAAE,CAAC,IAAI,CACX,8BAA8B,SAAS;;;MAGrC,CACH,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,EAAkB,EAClB,UAAuB,EACvB,UAAkC,EAAE;IAEpC,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,mBAAmB,CAAC;IAC3D,oBAAoB,CAAC,SAAS,CAAC,CAAC;IAChC,MAAM,qBAAqB,CAAC,EAAE,EAAE,SAAS,CAAC,CAAC;IAE3C,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,MAAM,OAAO,GAAa,EAAE,CAAC;IAE7B,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;QACnC,MAAM,QAAQ,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,kBAAkB,SAAS,uBAAuB,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC;QACjH,IAAI,QAAQ,EAAE,CAAC;YACb,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;YAC3B,SAAS;QACX,CAAC;QAED,MAAM,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;QAC7B,MAAM,EAAE,CAAC,OAAO,CAAC,eAAe,SAAS,kBAAkB,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC;QACtF,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;IAC7B,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;AAC9B,CAAC;AAED,MAAM,UAAU,eAAe,CAAI,KAAgC,EAAE,QAAW;IAC9E,IAAI,CAAC,KAAK;QAAE,OAAO,QAAQ,CAAC;IAC5B,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,CAAM,CAAC;IAChC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,QAAQ,CAAC;IAClB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,KAAc;IAChD,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC;AACvC,CAAC;AAED,SAAS,oBAAoB,CAAC,KAAa;IACzC,IAAI,CAAC,0BAA0B,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QAC5C,MAAM,IAAI,KAAK,CAAC,0BAA0B,KAAK,EAAE,CAAC,CAAC;IACrD,CAAC;AACH,CAAC"}
@@ -0,0 +1,33 @@
1
+ export type EmailAddress = {
2
+ email: string;
3
+ name?: string;
4
+ };
5
+ export type EmailAttachment = {
6
+ filename: string;
7
+ contentType: string;
8
+ data: Uint8Array | string;
9
+ };
10
+ export type SendEmailInput = {
11
+ from: EmailAddress;
12
+ to: EmailAddress[];
13
+ cc?: EmailAddress[];
14
+ bcc?: EmailAddress[];
15
+ replyTo?: EmailAddress[];
16
+ subject: string;
17
+ text?: string;
18
+ html?: string;
19
+ attachments?: EmailAttachment[];
20
+ tags?: Record<string, string>;
21
+ };
22
+ export type SendEmailResult = {
23
+ id: string;
24
+ provider?: string;
25
+ metadata?: Record<string, unknown>;
26
+ };
27
+ export interface EmailProvider {
28
+ send(input: SendEmailInput): Promise<SendEmailResult>;
29
+ }
30
+ export declare function formatEmailAddress(address: EmailAddress): string;
31
+ export declare function normalizeEmailAddress(email: string): string;
32
+ export declare function appendUnsubscribeFooter(text: string, unsubscribeUrl: string): string;
33
+ //# sourceMappingURL=email.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"email.d.ts","sourceRoot":"","sources":["../src/email.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,YAAY,GAAG;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,UAAU,GAAG,MAAM,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,IAAI,EAAE,YAAY,CAAC;IACnB,EAAE,EAAE,YAAY,EAAE,CAAC;IACnB,EAAE,CAAC,EAAE,YAAY,EAAE,CAAC;IACpB,GAAG,CAAC,EAAE,YAAY,EAAE,CAAC;IACrB,OAAO,CAAC,EAAE,YAAY,EAAE,CAAC;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,eAAe,EAAE,CAAC;IAChC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC/B,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC,CAAC;AAEF,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;CACvD;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,YAAY,GAAG,MAAM,CAIhE;AAED,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAI3D;AAED,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,MAAM,CAEpF"}
package/dist/email.js ADDED
@@ -0,0 +1,16 @@
1
+ export function formatEmailAddress(address) {
2
+ if (!address.name)
3
+ return address.email;
4
+ const escaped = address.name.replace(/"/g, '\\"');
5
+ return `"${escaped}" <${address.email}>`;
6
+ }
7
+ export function normalizeEmailAddress(email) {
8
+ const normalized = email.trim().toLowerCase();
9
+ if (!/^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(normalized))
10
+ throw new Error(`Invalid email address: ${email}`);
11
+ return normalized;
12
+ }
13
+ export function appendUnsubscribeFooter(text, unsubscribeUrl) {
14
+ return `${text.trim()}\n\nUnsubscribe: ${unsubscribeUrl}\n`;
15
+ }
16
+ //# sourceMappingURL=email.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"email.js","sourceRoot":"","sources":["../src/email.ts"],"names":[],"mappings":"AAkCA,MAAM,UAAU,kBAAkB,CAAC,OAAqB;IACtD,IAAI,CAAC,OAAO,CAAC,IAAI;QAAE,OAAO,OAAO,CAAC,KAAK,CAAC;IACxC,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IAClD,OAAO,IAAI,OAAO,MAAM,OAAO,CAAC,KAAK,GAAG,CAAC;AAC3C,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,KAAa;IACjD,MAAM,UAAU,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC9C,IAAI,CAAC,4BAA4B,CAAC,IAAI,CAAC,UAAU,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,0BAA0B,KAAK,EAAE,CAAC,CAAC;IACvG,OAAO,UAAU,CAAC;AACpB,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,IAAY,EAAE,cAAsB;IAC1E,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,oBAAoB,cAAc,IAAI,CAAC;AAC9D,CAAC"}
package/dist/env.d.ts ADDED
@@ -0,0 +1,11 @@
1
+ export type EnvSource = Record<string, unknown>;
2
+ export declare class EnvError extends Error {
3
+ constructor(message: string);
4
+ }
5
+ export declare function requiredString(env: EnvSource, key: string): string;
6
+ export declare function optionalString(env: EnvSource, key: string, fallback?: string): string | undefined;
7
+ export declare function requiredUrl(env: EnvSource, key: string): string;
8
+ export declare function optionalBoolean(env: EnvSource, key: string, fallback?: boolean): boolean;
9
+ export declare function requiredBinding<T>(env: EnvSource, key: string): T;
10
+ export declare function appUrl(env: EnvSource, fallback?: string): string;
11
+ //# sourceMappingURL=env.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../src/env.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEhD,qBAAa,QAAS,SAAQ,KAAK;gBACrB,OAAO,EAAE,MAAM;CAI5B;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAMlE;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAKjG;AAED,wBAAgB,WAAW,CAAC,GAAG,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAO/D;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,UAAQ,GAAG,OAAO,CAQtF;AAED,wBAAgB,eAAe,CAAC,CAAC,EAAE,GAAG,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,GAAG,CAAC,CAIjE;AAED,wBAAgB,MAAM,CAAC,GAAG,EAAE,SAAS,EAAE,QAAQ,SAA0B,GAAG,MAAM,CAGjF"}
package/dist/env.js ADDED
@@ -0,0 +1,55 @@
1
+ export class EnvError extends Error {
2
+ constructor(message) {
3
+ super(message);
4
+ this.name = "EnvError";
5
+ }
6
+ }
7
+ export function requiredString(env, key) {
8
+ const value = env[key];
9
+ if (typeof value !== "string" || value.trim() === "") {
10
+ throw new EnvError(`Missing required env var: ${key}`);
11
+ }
12
+ return value;
13
+ }
14
+ export function optionalString(env, key, fallback) {
15
+ const value = env[key];
16
+ if (value === undefined || value === null || value === "")
17
+ return fallback;
18
+ if (typeof value !== "string")
19
+ throw new EnvError(`Expected ${key} to be a string.`);
20
+ return value;
21
+ }
22
+ export function requiredUrl(env, key) {
23
+ const value = requiredString(env, key);
24
+ try {
25
+ return new URL(value).toString().replace(/\/$/, "");
26
+ }
27
+ catch {
28
+ throw new EnvError(`Expected ${key} to be a valid URL.`);
29
+ }
30
+ }
31
+ export function optionalBoolean(env, key, fallback = false) {
32
+ const value = env[key];
33
+ if (value === undefined || value === null || value === "")
34
+ return fallback;
35
+ if (typeof value === "boolean")
36
+ return value;
37
+ if (typeof value !== "string")
38
+ throw new EnvError(`Expected ${key} to be boolean-like.`);
39
+ if (/^(1|true|yes|on)$/i.test(value))
40
+ return true;
41
+ if (/^(0|false|no|off)$/i.test(value))
42
+ return false;
43
+ throw new EnvError(`Expected ${key} to be boolean-like.`);
44
+ }
45
+ export function requiredBinding(env, key) {
46
+ const value = env[key];
47
+ if (value === undefined || value === null)
48
+ throw new EnvError(`Missing required binding: ${key}`);
49
+ return value;
50
+ }
51
+ export function appUrl(env, fallback = "http://localhost:8787") {
52
+ const value = optionalString(env, "APP_URL") ?? optionalString(env, "BASE_URL") ?? optionalString(env, "PUBLIC_APP_URL") ?? fallback;
53
+ return value.replace(/\/$/, "");
54
+ }
55
+ //# sourceMappingURL=env.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env.js","sourceRoot":"","sources":["../src/env.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,QAAS,SAAQ,KAAK;IACjC,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,UAAU,CAAC;IACzB,CAAC;CACF;AAED,MAAM,UAAU,cAAc,CAAC,GAAc,EAAE,GAAW;IACxD,MAAM,KAAK,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC;IACvB,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;QACrD,MAAM,IAAI,QAAQ,CAAC,6BAA6B,GAAG,EAAE,CAAC,CAAC;IACzD,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,GAAc,EAAE,GAAW,EAAE,QAAiB;IAC3E,MAAM,KAAK,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC;IACvB,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,EAAE;QAAE,OAAO,QAAQ,CAAC;IAC3E,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,MAAM,IAAI,QAAQ,CAAC,YAAY,GAAG,kBAAkB,CAAC,CAAC;IACrF,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,GAAc,EAAE,GAAW;IACrD,MAAM,KAAK,GAAG,cAAc,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IACvC,IAAI,CAAC;QACH,OAAO,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IACtD,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,QAAQ,CAAC,YAAY,GAAG,qBAAqB,CAAC,CAAC;IAC3D,CAAC;AACH,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,GAAc,EAAE,GAAW,EAAE,QAAQ,GAAG,KAAK;IAC3E,MAAM,KAAK,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC;IACvB,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,EAAE;QAAE,OAAO,QAAQ,CAAC;IAC3E,IAAI,OAAO,KAAK,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC;IAC7C,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,MAAM,IAAI,QAAQ,CAAC,YAAY,GAAG,sBAAsB,CAAC,CAAC;IACzF,IAAI,oBAAoB,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAClD,IAAI,qBAAqB,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IACpD,MAAM,IAAI,QAAQ,CAAC,YAAY,GAAG,sBAAsB,CAAC,CAAC;AAC5D,CAAC;AAED,MAAM,UAAU,eAAe,CAAI,GAAc,EAAE,GAAW;IAC5D,MAAM,KAAK,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC;IACvB,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI;QAAE,MAAM,IAAI,QAAQ,CAAC,6BAA6B,GAAG,EAAE,CAAC,CAAC;IAClG,OAAO,KAAU,CAAC;AACpB,CAAC;AAED,MAAM,UAAU,MAAM,CAAC,GAAc,EAAE,QAAQ,GAAG,uBAAuB;IACvE,MAAM,KAAK,GAAG,cAAc,CAAC,GAAG,EAAE,SAAS,CAAC,IAAI,cAAc,CAAC,GAAG,EAAE,UAAU,CAAC,IAAI,cAAc,CAAC,GAAG,EAAE,gBAAgB,CAAC,IAAI,QAAQ,CAAC;IACrI,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;AAClC,CAAC"}