gateproof 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 (63) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +118 -0
  3. package/dist/act.d.ts +31 -0
  4. package/dist/act.d.ts.map +1 -0
  5. package/dist/act.js +25 -0
  6. package/dist/act.js.map +1 -0
  7. package/dist/action-executors.d.ts +12 -0
  8. package/dist/action-executors.d.ts.map +1 -0
  9. package/dist/action-executors.js +124 -0
  10. package/dist/action-executors.js.map +1 -0
  11. package/dist/assert.d.ts +39 -0
  12. package/dist/assert.d.ts.map +1 -0
  13. package/dist/assert.js +88 -0
  14. package/dist/assert.js.map +1 -0
  15. package/dist/cloudflare/analytics.d.ts +9 -0
  16. package/dist/cloudflare/analytics.d.ts.map +1 -0
  17. package/dist/cloudflare/analytics.js +98 -0
  18. package/dist/cloudflare/analytics.js.map +1 -0
  19. package/dist/cloudflare/cli-stream.d.ts +7 -0
  20. package/dist/cloudflare/cli-stream.d.ts.map +1 -0
  21. package/dist/cloudflare/cli-stream.js +81 -0
  22. package/dist/cloudflare/cli-stream.js.map +1 -0
  23. package/dist/cloudflare/index.d.ts +7 -0
  24. package/dist/cloudflare/index.d.ts.map +1 -0
  25. package/dist/cloudflare/index.js +44 -0
  26. package/dist/cloudflare/index.js.map +1 -0
  27. package/dist/cloudflare/polling-backend.d.ts +18 -0
  28. package/dist/cloudflare/polling-backend.d.ts.map +1 -0
  29. package/dist/cloudflare/polling-backend.js +53 -0
  30. package/dist/cloudflare/polling-backend.js.map +1 -0
  31. package/dist/cloudflare/workers-logs.d.ts +9 -0
  32. package/dist/cloudflare/workers-logs.d.ts.map +1 -0
  33. package/dist/cloudflare/workers-logs.js +51 -0
  34. package/dist/cloudflare/workers-logs.js.map +1 -0
  35. package/dist/index.d.ts +48 -0
  36. package/dist/index.d.ts.map +1 -0
  37. package/dist/index.js +168 -0
  38. package/dist/index.js.map +1 -0
  39. package/dist/observe.d.ts +26 -0
  40. package/dist/observe.d.ts.map +1 -0
  41. package/dist/observe.js +83 -0
  42. package/dist/observe.js.map +1 -0
  43. package/dist/provider.d.ts +6 -0
  44. package/dist/provider.d.ts.map +1 -0
  45. package/dist/provider.js +2 -0
  46. package/dist/provider.js.map +1 -0
  47. package/dist/test-helpers.d.ts +12 -0
  48. package/dist/test-helpers.d.ts.map +1 -0
  49. package/dist/test-helpers.js +33 -0
  50. package/dist/test-helpers.js.map +1 -0
  51. package/dist/types.d.ts +41 -0
  52. package/dist/types.d.ts.map +1 -0
  53. package/dist/types.js +2 -0
  54. package/dist/types.js.map +1 -0
  55. package/dist/utils.d.ts +22 -0
  56. package/dist/utils.d.ts.map +1 -0
  57. package/dist/utils.js +48 -0
  58. package/dist/utils.js.map +1 -0
  59. package/dist/validation.d.ts +6 -0
  60. package/dist/validation.d.ts.map +1 -0
  61. package/dist/validation.js +34 -0
  62. package/dist/validation.js.map +1 -0
  63. package/package.json +74 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 gateproof contributors
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,118 @@
1
+ # gateproof
2
+
3
+ E2E testing harness. Observe logs, run actions, assert results.
4
+
5
+ **Minimal surface area. Maximum power.**
6
+
7
+ ## Quick Start
8
+
9
+ ```typescript
10
+ import { Gate, Act, Assert } from "gateproof";
11
+ import { CloudflareProvider } from "gateproof/cloudflare";
12
+
13
+ const provider = CloudflareProvider({
14
+ accountId: process.env.CLOUDFLARE_ACCOUNT_ID!,
15
+ apiToken: process.env.CLOUDFLARE_API_TOKEN!
16
+ });
17
+
18
+ const result = await Gate.run({
19
+ observe: provider.observe({ backend: "analytics", dataset: "worker_logs" }),
20
+ act: [Act.browser({ url: "https://my-worker.workers.dev" })],
21
+ assert: [Assert.noErrors(), Assert.hasAction("request_received")]
22
+ });
23
+
24
+ if (result.status !== "success") process.exit(1);
25
+ ```
26
+
27
+ That's it. Three concepts: **Gate**, **Act**, **Assert**.
28
+
29
+ ## Core API
30
+
31
+ ### Gate.run(spec)
32
+ Run a gate. Returns a result with status, logs, and evidence.
33
+
34
+ ### Actions
35
+ ```typescript
36
+ Act.exec("command") // Run shell command
37
+ Act.browser({ url, headless? }) // Browser automation (needs playwright)
38
+ Act.wait(ms) // Sleep
39
+ Act.deploy({ worker }) // Deploy marker
40
+ ```
41
+
42
+ ### Assertions
43
+ ```typescript
44
+ Assert.noErrors() // No error logs
45
+ Assert.hasAction("name") // Action was logged
46
+ Assert.hasStage("worker") // Stage was seen
47
+ Assert.custom("name", fn) // Custom: (logs) => boolean
48
+ ```
49
+
50
+ ### Result
51
+ ```typescript
52
+ {
53
+ status: "success" | "failed" | "timeout",
54
+ durationMs: number,
55
+ logs: Log[],
56
+ evidence: {
57
+ requestIds: string[],
58
+ stagesSeen: string[],
59
+ actionsSeen: string[],
60
+ errorTags: string[]
61
+ },
62
+ error?: Error
63
+ }
64
+ ```
65
+
66
+ ## Plug Your Backend
67
+
68
+ gateproof works with any observability backend. Just implement the `Backend` interface:
69
+
70
+ ```typescript
71
+ interface Backend {
72
+ start(): Effect.Effect<LogStream, ObservabilityError>;
73
+ stop(): Effect.Effect<void, ObservabilityError>;
74
+ }
75
+ ```
76
+
77
+ See `patterns/` for examples including:
78
+ - Cloudflare Analytics Engine
79
+ - Cloudflare Workers Logs API
80
+ - CLI Stream (local dev)
81
+ - Custom backends
82
+
83
+ ## Cloudflare Backends
84
+
85
+ ```typescript
86
+ const provider = CloudflareProvider({ accountId, apiToken });
87
+
88
+ // Analytics Engine (recommended)
89
+ provider.observe({ backend: "analytics", dataset: "worker_logs" })
90
+
91
+ // Workers Logs API
92
+ provider.observe({ backend: "workers-logs", workerName: "my-worker" })
93
+
94
+ // CLI Stream (local dev)
95
+ provider.observe({ backend: "cli-stream", workerName: "my-worker" })
96
+ ```
97
+
98
+ ## Examples
99
+
100
+ See `patterns/` for complete examples:
101
+ - `patterns/basic/` - Basic usage patterns
102
+ - `patterns/cloudflare/` - Cloudflare-specific patterns
103
+ - `patterns/ci-cd/` - CI/CD integration
104
+ - `patterns/advanced/` - Advanced patterns
105
+
106
+ ## CI/CD
107
+
108
+ gateproof works great in CI/CD. See `patterns/ci-cd/github-actions.ts` for examples.
109
+
110
+ ## Requirements
111
+
112
+ - Node.js 18+ or Bun
113
+ - `playwright` (optional, for Act.browser)
114
+ - Cloudflare credentials (for CloudflareProvider, or bring your own backend)
115
+
116
+ ## License
117
+
118
+ MIT
package/dist/act.d.ts ADDED
@@ -0,0 +1,31 @@
1
+ export type Action = {
2
+ _tag: "Deploy";
3
+ worker: string;
4
+ } | {
5
+ _tag: "Browser";
6
+ url: string;
7
+ headless?: boolean;
8
+ waitMs?: number;
9
+ } | {
10
+ _tag: "Wait";
11
+ ms: number;
12
+ } | {
13
+ _tag: "Exec";
14
+ command: string;
15
+ cwd?: string;
16
+ };
17
+ export declare namespace Act {
18
+ function deploy(config: {
19
+ worker: string;
20
+ }): Action;
21
+ function browser(config: {
22
+ url: string;
23
+ headless?: boolean;
24
+ waitMs?: number;
25
+ }): Action;
26
+ function wait(ms: number): Action;
27
+ function exec(command: string, opts?: {
28
+ cwd?: string;
29
+ }): Action;
30
+ }
31
+ //# sourceMappingURL=act.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"act.d.ts","sourceRoot":"","sources":["../src/act.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,MAAM,GACd;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAClC;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GACrE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAC5B;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAEpD,yBAAiB,GAAG,CAAC;IACnB,SAAgB,MAAM,CAAC,MAAM,EAAE;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,MAAM,CAEzD;IAED,SAAgB,OAAO,CAAC,MAAM,EAAE;QAC9B,GAAG,EAAE,MAAM,CAAC;QACZ,QAAQ,CAAC,EAAE,OAAO,CAAC;QACnB,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,GAAG,MAAM,CAOT;IAED,SAAgB,IAAI,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAEvC;IAED,SAAgB,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE;QAAE,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,MAAM,CAErE;CACF"}
package/dist/act.js ADDED
@@ -0,0 +1,25 @@
1
+ export var Act;
2
+ (function (Act) {
3
+ function deploy(config) {
4
+ return { _tag: "Deploy", worker: config.worker };
5
+ }
6
+ Act.deploy = deploy;
7
+ function browser(config) {
8
+ return {
9
+ _tag: "Browser",
10
+ url: config.url,
11
+ headless: config.headless ?? true,
12
+ waitMs: config.waitMs ?? 5000
13
+ };
14
+ }
15
+ Act.browser = browser;
16
+ function wait(ms) {
17
+ return { _tag: "Wait", ms };
18
+ }
19
+ Act.wait = wait;
20
+ function exec(command, opts) {
21
+ return { _tag: "Exec", command, cwd: opts?.cwd };
22
+ }
23
+ Act.exec = exec;
24
+ })(Act || (Act = {}));
25
+ //# sourceMappingURL=act.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"act.js","sourceRoot":"","sources":["../src/act.ts"],"names":[],"mappings":"AAQA,MAAM,KAAW,GAAG,CAyBnB;AAzBD,WAAiB,GAAG;IAClB,SAAgB,MAAM,CAAC,MAA0B;QAC/C,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC;IACnD,CAAC;IAFe,UAAM,SAErB,CAAA;IAED,SAAgB,OAAO,CAAC,MAIvB;QACC,OAAO;YACL,IAAI,EAAE,SAAS;YACf,GAAG,EAAE,MAAM,CAAC,GAAG;YACf,QAAQ,EAAE,MAAM,CAAC,QAAQ,IAAI,IAAI;YACjC,MAAM,EAAE,MAAM,CAAC,MAAM,IAAI,IAAI;SAC9B,CAAC;IACJ,CAAC;IAXe,WAAO,UAWtB,CAAA;IAED,SAAgB,IAAI,CAAC,EAAU;QAC7B,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;IAC9B,CAAC;IAFe,QAAI,OAEnB,CAAA;IAED,SAAgB,IAAI,CAAC,OAAe,EAAE,IAAuB;QAC3D,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC;IACnD,CAAC;IAFe,QAAI,OAEnB,CAAA;AACH,CAAC,EAzBgB,GAAG,KAAH,GAAG,QAyBnB"}
@@ -0,0 +1,12 @@
1
+ import { Effect } from "effect";
2
+ import type { Action } from "./act";
3
+ import { GateError } from "./index";
4
+ export interface ActionExecutor {
5
+ execute(action: Action): Effect.Effect<void, GateError>;
6
+ }
7
+ export declare const WaitExecutor: ActionExecutor;
8
+ export declare const DeployExecutor: ActionExecutor;
9
+ export declare const ExecExecutor: ActionExecutor;
10
+ export declare const BrowserExecutor: ActionExecutor;
11
+ export declare function getActionExecutor(action: Action): ActionExecutor;
12
+ //# sourceMappingURL=action-executors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"action-executors.d.ts","sourceRoot":"","sources":["../src/action-executors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAY,MAAM,QAAQ,CAAC;AAC1C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AACpC,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAGpC,MAAM,WAAW,cAAc;IAC7B,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;CACzD;AAED,eAAO,MAAM,YAAY,EAAE,cAU1B,CAAC;AAEF,eAAO,MAAM,cAAc,EAAE,cA+B5B,CAAC;AAEF,eAAO,MAAM,YAAY,EAAE,cA+B1B,CAAC;AAEF,eAAO,MAAM,eAAe,EAAE,cA0C7B,CAAC;AAEF,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,cAAc,CAahE"}
@@ -0,0 +1,124 @@
1
+ import { Effect, Schedule } from "effect";
2
+ import { GateError } from "./index";
3
+ import { validateCommand, validateUrl, validateWorkerName } from "./validation";
4
+ export const WaitExecutor = {
5
+ execute(action) {
6
+ if (action._tag !== "Wait") {
7
+ return Effect.fail(new GateError({ cause: new Error("Invalid action") }));
8
+ }
9
+ if (action.ms < 0 || action.ms > 3600000) {
10
+ return Effect.fail(new GateError({ cause: new Error("Wait time must be between 0 and 3600000ms") }));
11
+ }
12
+ return Effect.sleep(`${action.ms} millis`);
13
+ }
14
+ };
15
+ export const DeployExecutor = {
16
+ execute(action) {
17
+ if (action._tag !== "Deploy") {
18
+ return Effect.fail(new GateError({ cause: new Error("Invalid action") }));
19
+ }
20
+ return Effect.gen(function* () {
21
+ yield* validateWorkerName(action.worker);
22
+ yield* Effect.tryPromise({
23
+ try: async () => {
24
+ const { spawn } = await import("node:child_process");
25
+ return new Promise((resolve, reject) => {
26
+ const proc = spawn("wrangler", ["deploy"], {
27
+ shell: false,
28
+ stdio: "inherit",
29
+ env: { ...process.env }
30
+ });
31
+ proc.on("close", (code) => {
32
+ if (code === 0)
33
+ resolve();
34
+ else
35
+ reject(new Error(`Deployment failed with code ${code}`));
36
+ });
37
+ proc.on("error", reject);
38
+ });
39
+ },
40
+ catch: (e) => new GateError({ cause: e })
41
+ }).pipe(Effect.timeout("5 minutes"), Effect.retry(Schedule.exponential("1 second").pipe(Schedule.compose(Schedule.recurs(2)))), Effect.catchTag("TimeoutException", (e) => Effect.fail(new GateError({ cause: e }))));
42
+ });
43
+ }
44
+ };
45
+ export const ExecExecutor = {
46
+ execute(action) {
47
+ if (action._tag !== "Exec") {
48
+ return Effect.fail(new GateError({ cause: new Error("Invalid action") }));
49
+ }
50
+ return Effect.gen(function* () {
51
+ yield* validateCommand(action.command);
52
+ yield* Effect.tryPromise({
53
+ try: async () => {
54
+ const { spawn } = await import("node:child_process");
55
+ return new Promise((resolve, reject) => {
56
+ const proc = spawn(action.command, { shell: true, cwd: action.cwd });
57
+ let stderr = "";
58
+ proc.stderr?.on("data", (data) => {
59
+ stderr += data.toString();
60
+ });
61
+ proc.on("close", (code) => {
62
+ if (code === 0)
63
+ resolve();
64
+ else
65
+ reject(new Error(`Command failed with code ${code}${stderr ? `: ${stderr}` : ""}`));
66
+ });
67
+ proc.on("error", reject);
68
+ });
69
+ },
70
+ catch: (e) => new GateError({ cause: e })
71
+ }).pipe(Effect.timeout("30 seconds"), Effect.retry(Schedule.exponential("100 millis").pipe(Schedule.compose(Schedule.recurs(3)))), Effect.catchTag("TimeoutException", (e) => Effect.fail(new GateError({ cause: e }))));
72
+ });
73
+ }
74
+ };
75
+ export const BrowserExecutor = {
76
+ execute(action) {
77
+ if (action._tag !== "Browser") {
78
+ return Effect.fail(new GateError({ cause: new Error("Invalid action") }));
79
+ }
80
+ return Effect.gen(function* () {
81
+ yield* validateUrl(action.url);
82
+ yield* Effect.acquireUseRelease(Effect.tryPromise({
83
+ try: async () => {
84
+ try {
85
+ const pw = await import("playwright");
86
+ return await pw.chromium.launch({ headless: action.headless });
87
+ }
88
+ catch (e) {
89
+ throw new Error(`Playwright not available: ${e instanceof Error ? e.message : String(e)}`);
90
+ }
91
+ },
92
+ catch: (e) => new GateError({ cause: e })
93
+ }), (browser) => Effect.gen(function* () {
94
+ const page = yield* Effect.tryPromise({
95
+ try: () => browser.newPage(),
96
+ catch: (e) => new GateError({ cause: e })
97
+ });
98
+ yield* Effect.tryPromise({
99
+ try: () => page.goto(action.url),
100
+ catch: (e) => new GateError({ cause: e })
101
+ });
102
+ yield* Effect.sleep(`${action.waitMs ?? 5000} millis`);
103
+ }), (browser) => Effect.tryPromise({
104
+ try: () => browser.close(),
105
+ catch: () => undefined
106
+ }).pipe(Effect.catchAll(() => Effect.void))).pipe(Effect.timeout(`${(action.waitMs ?? 5000) + 10000} millis`), Effect.catchTag("TimeoutException", (e) => Effect.fail(new GateError({ cause: e }))));
107
+ });
108
+ }
109
+ };
110
+ export function getActionExecutor(action) {
111
+ switch (action._tag) {
112
+ case "Wait":
113
+ return WaitExecutor;
114
+ case "Deploy":
115
+ return DeployExecutor;
116
+ case "Exec":
117
+ return ExecExecutor;
118
+ case "Browser":
119
+ return BrowserExecutor;
120
+ default:
121
+ throw new Error(`Unknown action type: ${action._tag}`);
122
+ }
123
+ }
124
+ //# sourceMappingURL=action-executors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"action-executors.js","sourceRoot":"","sources":["../src/action-executors.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ import { Effect, Schema } from "effect";
2
+ import type { Log } from "./types";
3
+ declare const AssertionFailed_base: Schema.TaggedErrorClass<AssertionFailed, "AssertionFailed", {
4
+ readonly _tag: Schema.tag<"AssertionFailed">;
5
+ } & {
6
+ assertion: typeof Schema.String;
7
+ details: typeof Schema.Unknown;
8
+ }>;
9
+ export declare class AssertionFailed extends AssertionFailed_base {
10
+ }
11
+ declare const AssertionAggregateFailed_base: Schema.TaggedErrorClass<AssertionAggregateFailed, "AssertionAggregateFailed", {
12
+ readonly _tag: Schema.tag<"AssertionAggregateFailed">;
13
+ } & {
14
+ failures: Schema.Array$<Schema.instanceOf<AssertionFailed>>;
15
+ }>;
16
+ export declare class AssertionAggregateFailed extends AssertionAggregateFailed_base {
17
+ }
18
+ export type Assertion = {
19
+ _tag: "NoErrors";
20
+ } | {
21
+ _tag: "HasAction";
22
+ action: string;
23
+ } | {
24
+ _tag: "HasStage";
25
+ stage: string;
26
+ } | {
27
+ _tag: "Custom";
28
+ fn: (logs: Log[]) => boolean;
29
+ name: string;
30
+ };
31
+ export declare namespace Assert {
32
+ function noErrors(): Assertion;
33
+ function hasAction(action: string): Assertion;
34
+ function hasStage(stage: string): Assertion;
35
+ function custom(name: string, fn: (logs: Log[]) => boolean): Assertion;
36
+ function run(assertions: Assertion[], logs: Log[]): Effect.Effect<void, AssertionFailed | AssertionAggregateFailed>;
37
+ }
38
+ export {};
39
+ //# sourceMappingURL=assert.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assert.d.ts","sourceRoot":"","sources":["../src/assert.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AACxC,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,SAAS,CAAC;;;;;;;AAEnC,qBAAa,eAAgB,SAAQ,oBAMpC;CAAG;;;;;;AAEJ,qBAAa,wBAAyB,SAAQ,6BAK7C;CAAG;AAEJ,MAAM,MAAM,SAAS,GACjB;IAAE,IAAI,EAAE,UAAU,CAAA;CAAE,GACpB;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACrC;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACnC;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,EAAE,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,KAAK,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAEnE,yBAAiB,MAAM,CAAC;IACtB,SAAgB,QAAQ,IAAI,SAAS,CAEpC;IAED,SAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAEnD;IAED,SAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,CAEjD;IAED,SAAgB,MAAM,CACpB,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,KAAK,OAAO,GAC3B,SAAS,CAEX;IAED,SAAgB,GAAG,CACjB,UAAU,EAAE,SAAS,EAAE,EACvB,IAAI,EAAE,GAAG,EAAE,GACV,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,eAAe,GAAG,wBAAwB,CAAC,CA8DjE;CACF"}
package/dist/assert.js ADDED
@@ -0,0 +1,88 @@
1
+ import { Effect, Schema } from "effect";
2
+ export class AssertionFailed extends Schema.TaggedError()("AssertionFailed", {
3
+ assertion: Schema.String,
4
+ details: Schema.Unknown
5
+ }) {
6
+ }
7
+ export class AssertionAggregateFailed extends Schema.TaggedError()("AssertionAggregateFailed", {
8
+ failures: Schema.Array(Schema.instanceOf(AssertionFailed))
9
+ }) {
10
+ }
11
+ export var Assert;
12
+ (function (Assert) {
13
+ function noErrors() {
14
+ return { _tag: "NoErrors" };
15
+ }
16
+ Assert.noErrors = noErrors;
17
+ function hasAction(action) {
18
+ return { _tag: "HasAction", action };
19
+ }
20
+ Assert.hasAction = hasAction;
21
+ function hasStage(stage) {
22
+ return { _tag: "HasStage", stage };
23
+ }
24
+ Assert.hasStage = hasStage;
25
+ function custom(name, fn) {
26
+ return { _tag: "Custom", fn, name };
27
+ }
28
+ Assert.custom = custom;
29
+ function run(assertions, logs) {
30
+ return Effect.gen(function* () {
31
+ const failures = [];
32
+ for (const assertion of assertions) {
33
+ if (assertion._tag === "NoErrors") {
34
+ const errorLog = logs.find((l) => l.status === "error" || l.error);
35
+ if (errorLog) {
36
+ failures.push(new AssertionFailed({
37
+ assertion: "NoErrors",
38
+ details: { found: errorLog }
39
+ }));
40
+ }
41
+ }
42
+ else if (assertion._tag === "HasAction") {
43
+ const found = logs.some((l) => l.action === assertion.action);
44
+ if (!found) {
45
+ failures.push(new AssertionFailed({
46
+ assertion: "HasAction",
47
+ details: {
48
+ missing: assertion.action,
49
+ seen: logs.map((l) => l.action).filter(Boolean)
50
+ }
51
+ }));
52
+ }
53
+ }
54
+ else if (assertion._tag === "HasStage") {
55
+ const found = logs.some((l) => l.stage === assertion.stage);
56
+ if (!found) {
57
+ failures.push(new AssertionFailed({
58
+ assertion: "HasStage",
59
+ details: {
60
+ missing: assertion.stage,
61
+ seen: logs.map((l) => l.stage).filter(Boolean)
62
+ }
63
+ }));
64
+ }
65
+ }
66
+ else if (assertion._tag === "Custom") {
67
+ const passed = assertion.fn(logs);
68
+ if (!passed) {
69
+ failures.push(new AssertionFailed({
70
+ assertion: assertion.name,
71
+ details: { custom: true }
72
+ }));
73
+ }
74
+ }
75
+ }
76
+ if (failures.length > 0) {
77
+ if (failures.length === 1) {
78
+ yield* Effect.fail(failures[0]);
79
+ }
80
+ else {
81
+ yield* Effect.fail(new AssertionAggregateFailed({ failures }));
82
+ }
83
+ }
84
+ });
85
+ }
86
+ Assert.run = run;
87
+ })(Assert || (Assert = {}));
88
+ //# sourceMappingURL=assert.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assert.js","sourceRoot":"","sources":["../src/assert.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import { type Backend } from "../observe";
2
+ export interface AnalyticsConfig {
3
+ accountId: string;
4
+ apiToken: string;
5
+ dataset: string;
6
+ pollInterval?: number;
7
+ }
8
+ export declare function createAnalyticsBackend(config: AnalyticsConfig): Backend;
9
+ //# sourceMappingURL=analytics.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analytics.d.ts","sourceRoot":"","sources":["../../src/cloudflare/analytics.ts"],"names":[],"mappings":"AAEA,OAAO,EAAgD,KAAK,OAAO,EAAE,MAAM,YAAY,CAAC;AAGxF,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAgBD,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,eAAe,GACtB,OAAO,CA+GT"}
@@ -0,0 +1,98 @@
1
+ import { Effect, Schedule, Ref } from "effect";
2
+ import { createObservabilityError } from "../observe";
3
+ import { createPollingBackend } from "./polling-backend";
4
+ export function createAnalyticsBackend(config) {
5
+ const cacheRef = Ref.unsafeMake(new Map());
6
+ const CACHE_TTL = 5000;
7
+ const lastRequestRef = Ref.unsafeMake(0);
8
+ const MIN_REQUEST_INTERVAL = 100;
9
+ const fetchRows = (lastTimestamp) => {
10
+ const cacheKey = `${config.dataset}:${lastTimestamp}`;
11
+ return Effect.gen(function* () {
12
+ const cache = yield* Ref.get(cacheRef);
13
+ const cached = cache.get(cacheKey);
14
+ const now = Date.now();
15
+ if (cached && (now - cached.timestamp) < CACHE_TTL) {
16
+ return cached.data;
17
+ }
18
+ const query = `SELECT blob1 AS requestId, blob2 AS stage, blob3 AS action, blob4 AS status, blob5 AS durableObjectId, blob6 AS containerId, blob7 AS errorTag, blob8 AS errorMessage, blob9 AS data, double1 AS durationMs, double2 AS timestamp FROM ${config.dataset} WHERE double2 > ${lastTimestamp} ORDER BY double2 ASC LIMIT 100`;
19
+ const response = yield* Effect.tryPromise({
20
+ try: async () => {
21
+ return await fetch(`https://api.cloudflare.com/client/v4/accounts/${config.accountId}/analytics_engine/sql`, {
22
+ method: "POST",
23
+ headers: {
24
+ Authorization: `Bearer ${config.apiToken}`,
25
+ "Content-Type": "text/plain"
26
+ },
27
+ body: query
28
+ });
29
+ },
30
+ catch: (e) => createObservabilityError(e)
31
+ }).pipe(Effect.timeout("30 seconds"), Effect.retry(Schedule.exponential("100 millis").pipe(Schedule.compose(Schedule.recurs(3)))), Effect.catchTag("TimeoutException", (e) => Effect.fail(createObservabilityError(e))));
32
+ if (!response.ok) {
33
+ yield* Effect.fail(createObservabilityError(new Error(`API request failed: ${response.status}`)));
34
+ }
35
+ const data = yield* Effect.tryPromise({
36
+ try: async () => (await response.json()),
37
+ catch: (e) => createObservabilityError(e)
38
+ });
39
+ const rows = data.result && Array.isArray(data.result) ? data.result : [];
40
+ yield* Ref.update(cacheRef, (cache) => {
41
+ const newCache = new Map(cache);
42
+ newCache.set(cacheKey, { data: rows, timestamp: now });
43
+ if (newCache.size > 100) {
44
+ const entries = Array.from(newCache.entries());
45
+ entries.sort((a, b) => b[1].timestamp - a[1].timestamp);
46
+ return new Map(entries.slice(0, 100));
47
+ }
48
+ return newCache;
49
+ });
50
+ return rows;
51
+ });
52
+ };
53
+ const parseRow = (row) => {
54
+ if (!row.timestamp || !row.requestId)
55
+ return null;
56
+ return {
57
+ requestId: row.requestId,
58
+ timestamp: new Date(row.timestamp).toISOString(),
59
+ stage: (row.stage || "worker"),
60
+ action: row.action || "unknown",
61
+ status: (row.status || "info"),
62
+ ...(row.durableObjectId && { durableObjectId: row.durableObjectId }),
63
+ ...(row.containerId && { containerId: row.containerId }),
64
+ ...(row.errorTag && {
65
+ error: {
66
+ tag: row.errorTag,
67
+ message: row.errorMessage || ""
68
+ }
69
+ }),
70
+ ...(row.data && (() => {
71
+ try {
72
+ return { data: JSON.parse(row.data) };
73
+ }
74
+ catch {
75
+ return {};
76
+ }
77
+ })()),
78
+ ...(row.durationMs !== undefined && { durationMs: row.durationMs })
79
+ };
80
+ };
81
+ const backend = {
82
+ fetchData: fetchRows,
83
+ processData(rows, lastTimestamp) {
84
+ const logs = [];
85
+ let newTimestamp = lastTimestamp;
86
+ for (const row of rows) {
87
+ const log = parseRow(row);
88
+ if (log) {
89
+ logs.push(log);
90
+ newTimestamp = Math.max(newTimestamp, row.timestamp || newTimestamp);
91
+ }
92
+ }
93
+ return { logs, newTimestamp };
94
+ }
95
+ };
96
+ return createPollingBackend({ pollInterval: config.pollInterval ?? 1000 }, backend);
97
+ }
98
+ //# sourceMappingURL=analytics.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analytics.js","sourceRoot":"","sources":["../../src/cloudflare/analytics.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import { type Backend } from "../observe";
2
+ export interface CliStreamConfig {
3
+ accountId?: string;
4
+ workerName?: string;
5
+ }
6
+ export declare function createCliStreamBackend(config: CliStreamConfig): Backend;
7
+ //# sourceMappingURL=cli-stream.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli-stream.d.ts","sourceRoot":"","sources":["../../src/cloudflare/cli-stream.ts"],"names":[],"mappings":"AAGA,OAAO,EAA0E,KAAK,OAAO,EAAE,MAAM,YAAY,CAAC;AAElH,MAAM,WAAW,eAAe;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AA0BD,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,eAAe,GACtB,OAAO,CAiFT"}