@ripplo/testing 0.6.1 → 0.7.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 (44) hide show
  1. package/DSL.md +355 -0
  2. package/LICENSE.md +1 -0
  3. package/README.md +47 -273
  4. package/dist/engine-BT7hUouB.d.ts +1095 -0
  5. package/dist/express.d.ts +7 -9
  6. package/dist/express.js +422 -48
  7. package/dist/index.d.ts +122 -59
  8. package/dist/index.js +1630 -1126
  9. package/package.json +31 -113
  10. package/dist/actions.d.ts +0 -260
  11. package/dist/actions.js +0 -177
  12. package/dist/assert.d.ts +0 -188
  13. package/dist/assert.js +0 -111
  14. package/dist/builder-SsgqYqSC.d.ts +0 -156
  15. package/dist/chunk-2YLI7VD4.js +0 -65
  16. package/dist/chunk-4MGIQFAJ.js +0 -16
  17. package/dist/chunk-DCJBLS2U.js +0 -26
  18. package/dist/chunk-MGATMMCZ.js +0 -16
  19. package/dist/chunk-XO36IU66.js +0 -88
  20. package/dist/chunk-YFOTJIVF.js +0 -134
  21. package/dist/chunk-YQAEOH5W.js +0 -111
  22. package/dist/compiler.d.ts +0 -32
  23. package/dist/compiler.js +0 -8
  24. package/dist/control.d.ts +0 -45
  25. package/dist/control.js +0 -17
  26. package/dist/elysia.d.ts +0 -78
  27. package/dist/elysia.js +0 -114
  28. package/dist/engine-BOqzK_go.d.ts +0 -61
  29. package/dist/fastify.d.ts +0 -14
  30. package/dist/fastify.js +0 -79
  31. package/dist/hono.d.ts +0 -19
  32. package/dist/hono.js +0 -89
  33. package/dist/koa.d.ts +0 -14
  34. package/dist/koa.js +0 -135
  35. package/dist/locators.d.ts +0 -40
  36. package/dist/locators.js +0 -11
  37. package/dist/lockfile.d.ts +0 -722
  38. package/dist/lockfile.js +0 -707
  39. package/dist/nestjs.d.ts +0 -17
  40. package/dist/nestjs.js +0 -139
  41. package/dist/nextjs.d.ts +0 -14
  42. package/dist/nextjs.js +0 -137
  43. package/dist/step-De52hTLd.d.ts +0 -19
  44. package/dist/types-BzZrl65Z.d.ts +0 -115
package/dist/assert.d.ts DELETED
@@ -1,188 +0,0 @@
1
- import { O as ObserverHandle, a as ObserverInput, P as Primitive, b as ObserverBudgetTier } from './types-BzZrl65Z.js';
2
- import { Variable, StaticStringRef, VariableRef } from './control.js';
3
- import { U as UnlabeledStep } from './step-De52hTLd.js';
4
- import { CheckLocator, AnyLocator } from './locators.js';
5
- import '@ripplo/spec';
6
-
7
- type StringOrVariable = string | Variable<string>;
8
- declare const assert: {
9
- not: {
10
- checked(locator: CheckLocator): UnlabeledStep<{
11
- locator: {
12
- by: "testId";
13
- value: string;
14
- } | {
15
- by: "role";
16
- role: string;
17
- name?: string | undefined;
18
- };
19
- type: "assertNotChecked";
20
- }>;
21
- enabled(locator: AnyLocator): UnlabeledStep<{
22
- locator: {
23
- by: "testId";
24
- value: string;
25
- } | {
26
- by: "role";
27
- role: string;
28
- name?: string | undefined;
29
- };
30
- type: "assertDisabled";
31
- }>;
32
- focused(locator: AnyLocator): UnlabeledStep<{
33
- locator: {
34
- by: "testId";
35
- value: string;
36
- } | {
37
- by: "role";
38
- role: string;
39
- name?: string | undefined;
40
- };
41
- type: "assertNotFocused";
42
- }>;
43
- visible(locator: AnyLocator): UnlabeledStep<{
44
- locator: {
45
- by: "testId";
46
- value: string;
47
- } | {
48
- by: "role";
49
- role: string;
50
- name?: string | undefined;
51
- };
52
- type: "assertNotVisible";
53
- }>;
54
- };
55
- attribute(locator: AnyLocator, attribute: string, expected: StringOrVariable): UnlabeledStep<{
56
- attribute: string;
57
- expected: StaticStringRef | VariableRef;
58
- locator: {
59
- by: "testId";
60
- value: string;
61
- } | {
62
- by: "role";
63
- role: string;
64
- name?: string | undefined;
65
- };
66
- operator: "equals";
67
- type: "assertAttribute";
68
- }>;
69
- /**
70
- * Verify a backend side effect by polling an observer. The server-side
71
- * observer impl returns `ctx.retry(reason)` for transient states (keep
72
- * polling) and `ctx.fail(reason)` only for invariant violations (stop
73
- * early). The observer's `.budget()` governs poll interval and timeout.
74
- */
75
- backend<THandle extends ObserverHandle>(observer: THandle, params: ObserverInput<THandle> & Record<string, Primitive>): UnlabeledStep<{
76
- budget: ObserverBudgetTier;
77
- observer: string;
78
- params: Record<string, {
79
- readonly type: "static";
80
- readonly value: Primitive;
81
- }>;
82
- type: "assertObserver";
83
- }>;
84
- checked(locator: CheckLocator): UnlabeledStep<{
85
- locator: {
86
- by: "testId";
87
- value: string;
88
- } | {
89
- by: "role";
90
- role: string;
91
- name?: string | undefined;
92
- };
93
- type: "assertChecked";
94
- }>;
95
- count(locator: AnyLocator, expected: number): UnlabeledStep<{
96
- expected: {
97
- type: "static";
98
- value: number;
99
- };
100
- locator: {
101
- by: "testId";
102
- value: string;
103
- } | {
104
- by: "role";
105
- role: string;
106
- name?: string | undefined;
107
- };
108
- operator: "equals";
109
- type: "assertCount";
110
- }>;
111
- disabled(locator: AnyLocator): UnlabeledStep<{
112
- locator: {
113
- by: "testId";
114
- value: string;
115
- } | {
116
- by: "role";
117
- role: string;
118
- name?: string | undefined;
119
- };
120
- type: "assertDisabled";
121
- }>;
122
- enabled(locator: AnyLocator): UnlabeledStep<{
123
- locator: {
124
- by: "testId";
125
- value: string;
126
- } | {
127
- by: "role";
128
- role: string;
129
- name?: string | undefined;
130
- };
131
- type: "assertEnabled";
132
- }>;
133
- focused(locator: AnyLocator): UnlabeledStep<{
134
- locator: {
135
- by: "testId";
136
- value: string;
137
- } | {
138
- by: "role";
139
- role: string;
140
- name?: string | undefined;
141
- };
142
- type: "assertFocused";
143
- }>;
144
- text(locator: AnyLocator, expected: StringOrVariable): UnlabeledStep<{
145
- expected: StaticStringRef | VariableRef;
146
- locator: {
147
- by: "testId";
148
- value: string;
149
- } | {
150
- by: "role";
151
- role: string;
152
- name?: string | undefined;
153
- };
154
- operator: "equals";
155
- type: "assertText";
156
- }>;
157
- url(expected: StringOrVariable): UnlabeledStep<{
158
- expected: StaticStringRef | VariableRef;
159
- operator: "contains";
160
- type: "assertUrl";
161
- }>;
162
- value(locator: AnyLocator, expected: StringOrVariable): UnlabeledStep<{
163
- expected: StaticStringRef | VariableRef;
164
- locator: {
165
- by: "testId";
166
- value: string;
167
- } | {
168
- by: "role";
169
- role: string;
170
- name?: string | undefined;
171
- };
172
- operator: "equals";
173
- type: "assertValue";
174
- }>;
175
- visible(locator: AnyLocator): UnlabeledStep<{
176
- locator: {
177
- by: "testId";
178
- value: string;
179
- } | {
180
- by: "role";
181
- role: string;
182
- name?: string | undefined;
183
- };
184
- type: "assertVisible";
185
- }>;
186
- };
187
-
188
- export { assert };
package/dist/assert.js DELETED
@@ -1,111 +0,0 @@
1
- import {
2
- readObserverBudget,
3
- readObserverName
4
- } from "./chunk-YQAEOH5W.js";
5
- import {
6
- toSpecLocator,
7
- toStringValueRef
8
- } from "./chunk-2YLI7VD4.js";
9
- import "./chunk-DCJBLS2U.js";
10
- import {
11
- createStep
12
- } from "./chunk-MGATMMCZ.js";
13
- import "./chunk-4MGIQFAJ.js";
14
-
15
- // src/steps/assert.ts
16
- var assert = {
17
- not: {
18
- checked(locator) {
19
- return createStep({ locator: toSpecLocator(locator), type: "assertNotChecked" });
20
- },
21
- enabled(locator) {
22
- return createStep({ locator: toSpecLocator(locator), type: "assertDisabled" });
23
- },
24
- focused(locator) {
25
- return createStep({ locator: toSpecLocator(locator), type: "assertNotFocused" });
26
- },
27
- visible(locator) {
28
- return createStep({ locator: toSpecLocator(locator), type: "assertNotVisible" });
29
- }
30
- },
31
- attribute(locator, attribute, expected) {
32
- return createStep({
33
- attribute,
34
- expected: toStringValueRef(expected),
35
- locator: toSpecLocator(locator),
36
- operator: "equals",
37
- type: "assertAttribute"
38
- });
39
- },
40
- // eslint-disable-next-line no-comments/disallowComments
41
- /**
42
- * Verify a backend side effect by polling an observer. The server-side
43
- * observer impl returns `ctx.retry(reason)` for transient states (keep
44
- * polling) and `ctx.fail(reason)` only for invariant violations (stop
45
- * early). The observer's `.budget()` governs poll interval and timeout.
46
- */
47
- backend(observer, params) {
48
- return createStep({
49
- budget: readObserverBudget(observer),
50
- observer: readObserverName(observer),
51
- params: paramsToValueRefs(params),
52
- type: "assertObserver"
53
- });
54
- },
55
- checked(locator) {
56
- return createStep({ locator: toSpecLocator(locator), type: "assertChecked" });
57
- },
58
- count(locator, expected) {
59
- return createStep({
60
- expected: { type: "static", value: expected },
61
- locator: toSpecLocator(locator),
62
- operator: "equals",
63
- type: "assertCount"
64
- });
65
- },
66
- disabled(locator) {
67
- return createStep({ locator: toSpecLocator(locator), type: "assertDisabled" });
68
- },
69
- enabled(locator) {
70
- return createStep({ locator: toSpecLocator(locator), type: "assertEnabled" });
71
- },
72
- focused(locator) {
73
- return createStep({ locator: toSpecLocator(locator), type: "assertFocused" });
74
- },
75
- text(locator, expected) {
76
- return createStep({
77
- expected: toStringValueRef(expected),
78
- locator: toSpecLocator(locator),
79
- operator: "equals",
80
- type: "assertText"
81
- });
82
- },
83
- url(expected) {
84
- return createStep({
85
- expected: toStringValueRef(expected),
86
- operator: "contains",
87
- type: "assertUrl"
88
- });
89
- },
90
- value(locator, expected) {
91
- return createStep({
92
- expected: toStringValueRef(expected),
93
- locator: toSpecLocator(locator),
94
- operator: "equals",
95
- type: "assertValue"
96
- });
97
- },
98
- visible(locator) {
99
- return createStep({ locator: toSpecLocator(locator), type: "assertVisible" });
100
- }
101
- };
102
- function paramsToValueRefs(params) {
103
- const out = {};
104
- Object.entries(params).forEach(([key, value]) => {
105
- out[key] = { type: "static", value };
106
- });
107
- return out;
108
- }
109
- export {
110
- assert
111
- };
@@ -1,156 +0,0 @@
1
- import { P as Primitive, O as ObserverHandle, h as Precondition, m as PreconditionData, j as TestDefinition, f as ObserverDefinition, l as PreconditionDefinition, U as UnimplementedItems, e as ObserverContext, g as ObserverOutcome, S as SetupContext, k as TestValue, T as TeardownContext } from './types-BzZrl65Z.js';
2
- import { ObserverBudget } from '@ripplo/spec';
3
- import { S as Step } from './step-De52hTLd.js';
4
-
5
- interface ObserverNeedsDescription {
6
- readonly description: (text: string) => ObserverNeedsBudget;
7
- }
8
- interface ObserverNeedsBudget {
9
- /**
10
- * Polling envelope: interval + total timeout the runner uses when calling
11
- * `assert.backend()`. Pick by where the side effect lands — fast for
12
- * same-request DB reads, slow for job-queue settle, async for
13
- * webhook/email delivery. Too tight = flaky; too loose = slow suite.
14
- */
15
- readonly budget: (tier: ObserverBudget) => ObserverNeedsInput;
16
- }
17
- interface ObserverNeedsInput {
18
- readonly input: <TInput extends Record<string, Primitive>>() => ObserverReady<TInput>;
19
- }
20
- interface ObserverReady<TInput extends Record<string, Primitive>> {
21
- readonly contract: () => ObserverHandle<TInput>;
22
- }
23
-
24
- interface CoverageRegistry {
25
- }
26
- type RegistryKeys = keyof CoverageRegistry;
27
- type CoverageStatementId = [RegistryKeys] extends [never] ? string : Extract<RegistryKeys, string>;
28
-
29
- type PreconditionRecord = Record<string, Precondition>;
30
- type ResolveDeps<TDeps extends PreconditionRecord> = {
31
- readonly [K in keyof TDeps]: PreconditionData<TDeps[K]>;
32
- };
33
- interface PreconditionNeedsSetup {
34
- readonly contract: <TData extends Record<string, Primitive>>() => Precondition<TData>;
35
- readonly description: (text: string) => PreconditionNeedsSetup;
36
- readonly requires: <TDeps extends PreconditionRecord>(deps: TDeps) => PreconditionNeedsSetupWithDeps<TDeps>;
37
- }
38
- interface PreconditionNeedsSetupWithDeps<TDeps extends PreconditionRecord> {
39
- readonly contract: <TData extends Record<string, Primitive>>() => Precondition<TData, ResolveDeps<TDeps>>;
40
- }
41
- interface TestNeedsName {
42
- readonly name: (displayName: string) => TestNeedsRequires;
43
- }
44
- interface TestNeedsRequires {
45
- readonly description: (text: string) => TestNeedsRequires;
46
- /**
47
- * Declare the preconditions this test needs. The object keys become the
48
- * destructured parameter in `.startsAt` / `.steps`, and each precondition's
49
- * return data flows through as a typed proxy — interpolate proxy fields
50
- * directly (e.g. `` `/workspaces/${workspace.id}` ``); never hand-write
51
- * `{{namespace.key}}` template strings (lint blocks this).
52
- */
53
- readonly requires: <TReqs extends PreconditionRecord>(reqs: TReqs) => TestNeedsOutcome<ResolveDeps<TReqs>>;
54
- }
55
- interface TestNeedsOutcome<TVars extends Record<string, Record<string, Primitive>>> {
56
- readonly expectedOutcome: (text: string) => TestNeedsStartsAt<TVars>;
57
- }
58
-
59
- interface TestNeedsStartsAt<TVars extends Record<string, Record<string, Primitive>>> {
60
- /**
61
- * Skip implementation — compiles as a planning stub and is reported in
62
- * `getUnimplemented()`. The test appears in the lockfile but is not run.
63
- */
64
- readonly notImplemented: () => TestDefinition;
65
- /**
66
- * Starting URL for the test, derived from precondition data. The function
67
- * receives the `.requires()` object destructured as typed proxies; it runs
68
- * at compile time, not at test-author time.
69
- */
70
- readonly startsAt: (fn: (vars: TVars) => string) => TestNeedsSteps<TVars>;
71
- }
72
- interface TestNeedsSteps<TVars extends Record<string, Record<string, Primitive>>> {
73
- /**
74
- * Declare the ordered step list. Receives destructured precondition data as
75
- * typed proxies (same as `.startsAt`). Every step must be labeled with
76
- * `.as("…")` — lint enforces it.
77
- */
78
- readonly steps: (fn: (vars: TVars) => ReadonlyArray<Step>) => TestNeedsCoverage;
79
- }
80
- interface TestNeedsCoverage {
81
- /**
82
- * Finalize the test and declare which mutation/AST branches it covers.
83
- * Coverage IDs feed LLM-driven test scoping on diffs so only relevant tests
84
- * run for a change. `.coverage()` (or `.notImplemented()`) is the only way
85
- * to terminate the chain into a runnable `TestDefinition`.
86
- */
87
- readonly coverage: (...ids: ReadonlyArray<CoverageStatementId>) => TestDefinition;
88
- }
89
-
90
- type PreconditionSetupResult<TData extends Record<string, Primitive>> = {
91
- readonly [K in keyof TData]: TestValue<TData[K]>;
92
- };
93
- interface PreconditionSetupItem<TDeps extends Record<string, Record<string, Primitive>>> {
94
- readonly ctx: SetupContext;
95
- readonly deps: TDeps;
96
- }
97
- interface PreconditionTeardownItem<TData extends Record<string, Primitive>> {
98
- readonly ctx: TeardownContext<TData>;
99
- }
100
- interface PreconditionImpl<TData extends Record<string, Primitive>, TDeps extends Record<string, Record<string, Primitive>>> {
101
- readonly setup: (items: ReadonlyArray<PreconditionSetupItem<TDeps>>) => Promise<ReadonlyArray<PreconditionSetupResult<TData>>>;
102
- readonly teardown: (items: ReadonlyArray<PreconditionTeardownItem<TData>>) => Promise<void>;
103
- }
104
- type ObserverImplFn<TInput extends Record<string, Primitive>> = (ctx: ObserverContext, params: TInput) => Promise<ObserverOutcome>;
105
- interface TestOptions {
106
- readonly uiOnly?: boolean;
107
- }
108
- type PreconditionRegistry = Record<string, Precondition>;
109
- type ObserverRegistry = Record<string, ObserverHandle<Record<string, Primitive>>>;
110
- interface RipploRegistries<P extends PreconditionRegistry, O extends ObserverRegistry> {
111
- readonly observers: O;
112
- readonly preconditions: P;
113
- readonly tests: ReadonlyArray<TestDefinition>;
114
- }
115
- interface RipploInstance<P extends PreconditionRegistry = PreconditionRegistry, O extends ObserverRegistry = ObserverRegistry> {
116
- readonly observers: O;
117
- readonly preconditions: P;
118
- readonly tests: ReadonlyArray<TestDefinition>;
119
- readonly getObservers: () => ReadonlyArray<ObserverDefinition>;
120
- readonly getPreconditions: () => ReadonlyArray<PreconditionDefinition>;
121
- readonly getTests: () => ReadonlyArray<TestDefinition>;
122
- readonly getUnimplemented: () => UnimplementedItems;
123
- }
124
- type RipploBuilder = RipploInstance;
125
- /**
126
- * Declare a precondition — a named, reusable piece of test data setup. Returns
127
- * a pure handle (no side effects at definition time); the setup/teardown impl
128
- * is wired once in `createEngine`. Depend on other preconditions via
129
- * `.requires()` so the DAG can resolve independents in parallel, giving every
130
- * test a clean, isolated slate.
131
- */
132
- declare function precondition(name: string): PreconditionNeedsSetup;
133
- /**
134
- * Declare a backend assertion — checked from tests via `assert.backend()`.
135
- * The impl runs on your server (where DB/queue access lives) and is polled
136
- * until pass/fail; `.budget()` picks the polling envelope. Use this instead
137
- * of sleeps when verifying async side effects (jobs, webhooks, emails, DB rows).
138
- */
139
- declare function observer(name: string): ObserverNeedsDescription;
140
- /**
141
- * Start a test definition. `id` is a stable kebab-case key persisted in the
142
- * lockfile and used for run history — changing it renames the test and loses
143
- * history. Set `options.uiOnly` only for genuinely read-only flows (no
144
- * mutations); do not use it to silence observer lint on flows that mutate
145
- * state — wire the observer instead.
146
- */
147
- declare function test(id: string, options?: TestOptions): TestNeedsName;
148
- /**
149
- * The single registration point for the DSL graph. Collects the three
150
- * registries into an instance consumed both by `ripplo compile` (to write
151
- * `.ripplo/ripplo.lock`) and by `createEngine` on the server, where
152
- * TypeScript exhaustiveness-checks that every handle has exactly one impl.
153
- */
154
- declare function createRipplo<P extends PreconditionRegistry, O extends ObserverRegistry>(registries: RipploRegistries<P, O>): RipploInstance<P, O>;
155
-
156
- export { type CoverageRegistry as C, type ObserverImplFn as O, type PreconditionImpl as P, type ResolveDeps as R, type ObserverRegistry as a, type PreconditionRecord as b, type PreconditionRegistry as c, type PreconditionSetupItem as d, type PreconditionTeardownItem as e, type RipploBuilder as f, type RipploInstance as g, type RipploRegistries as h, createRipplo as i, observer as o, precondition as p, test as t };
@@ -1,65 +0,0 @@
1
- import {
2
- readLocator
3
- } from "./chunk-DCJBLS2U.js";
4
- import {
5
- createStep
6
- } from "./chunk-MGATMMCZ.js";
7
-
8
- // src/steps/to-spec-locator.ts
9
- function toSpecLocator(loc) {
10
- const spec = readLocator(loc);
11
- switch (spec.by) {
12
- case "role": {
13
- return { by: "role", name: spec.name, role: spec.role };
14
- }
15
- case "testId": {
16
- return { by: "testId", value: spec.value };
17
- }
18
- }
19
- }
20
-
21
- // src/steps/control.ts
22
- function variable(name) {
23
- return { name };
24
- }
25
- function readVariable(v) {
26
- return v.name;
27
- }
28
- function isVariable(v) {
29
- if (typeof v !== "object" || v == null) {
30
- return false;
31
- }
32
- if (!("name" in v)) {
33
- return false;
34
- }
35
- return typeof v.name === "string";
36
- }
37
- function toStringValueRef(value) {
38
- if (typeof value === "string") {
39
- return { type: "static", value };
40
- }
41
- if (!isVariable(value)) {
42
- const raw = value;
43
- const got = raw == null ? String(raw) : typeof raw;
44
- throw new TypeError(
45
- `Expected a string or variable() \u2014 got ${got}. Wrap dynamic values with variable("name") and pair them with extract().`
46
- );
47
- }
48
- return { name: readVariable(value), type: "variable" };
49
- }
50
- function extract(locator, target) {
51
- return createStep({
52
- locator: toSpecLocator(locator),
53
- type: "extractText",
54
- variable: readVariable(target)
55
- });
56
- }
57
-
58
- export {
59
- toSpecLocator,
60
- variable,
61
- readVariable,
62
- isVariable,
63
- toStringValueRef,
64
- extract
65
- };
@@ -1,16 +0,0 @@
1
- var __defProp = Object.defineProperty;
2
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
- var __decorateClass = (decorators, target, key, kind) => {
4
- var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
5
- for (var i = decorators.length - 1, decorator; i >= 0; i--)
6
- if (decorator = decorators[i])
7
- result = (kind ? decorator(target, key, result) : decorator(result)) || result;
8
- if (kind && result) __defProp(target, key, result);
9
- return result;
10
- };
11
- var __decorateParam = (index, decorator) => (target, key) => decorator(target, key, index);
12
-
13
- export {
14
- __decorateClass,
15
- __decorateParam
16
- };
@@ -1,26 +0,0 @@
1
- // src/locators.ts
2
- function readLocator(loc) {
3
- return loc.spec;
4
- }
5
- function makeLocator(spec) {
6
- return { spec };
7
- }
8
- function role(ariaRole, name) {
9
- return makeLocator({
10
- by: "role",
11
- name: name ?? void 0,
12
- role: ariaRole
13
- });
14
- }
15
- function testId(id) {
16
- return makeLocator({
17
- by: "testId",
18
- value: id
19
- });
20
- }
21
-
22
- export {
23
- readLocator,
24
- role,
25
- testId
26
- };
@@ -1,16 +0,0 @@
1
- // src/steps/step.ts
2
- function readStep(step) {
3
- return step.data;
4
- }
5
- function createStep(node) {
6
- return {
7
- as(label) {
8
- return { data: { label, node } };
9
- }
10
- };
11
- }
12
-
13
- export {
14
- readStep,
15
- createStep
16
- };
@@ -1,88 +0,0 @@
1
- // src/adapters/shared.ts
2
- import { Webhook, WebhookVerificationError } from "standardwebhooks";
3
- import { z } from "zod";
4
- function readAdapterWebhookSecret() {
5
- const value = process.env.RIPPLO_WEBHOOK_SECRET;
6
- if (value == null || value.length === 0) {
7
- throw new Error(
8
- "ripplo: RIPPLO_WEBHOOK_SECRET is not set. The adapter needs it to verify precondition calls. Run `ripplo init` to generate one, or unset `enabled` to disable the adapter."
9
- );
10
- }
11
- return value;
12
- }
13
- var primitiveSchema = z.union([z.string(), z.number(), z.boolean()]);
14
- var dataSchema = z.record(z.string(), z.record(z.string(), primitiveSchema));
15
- var batchRequestSchema = z.object({
16
- batch: z.array(
17
- z.object({
18
- preconditions: z.array(z.string().min(1)),
19
- runId: z.string().min(1)
20
- })
21
- ).min(1)
22
- });
23
- var teardownRequestSchema = z.object({
24
- batch: z.array(
25
- z.object({
26
- data: dataSchema,
27
- preconditions: z.array(z.string().min(1)),
28
- runId: z.string().min(1)
29
- })
30
- ).min(1)
31
- });
32
- var observerRequestSchema = z.object({
33
- observer: z.string().min(1).max(200),
34
- params: z.record(z.string().max(200), primitiveSchema)
35
- });
36
- function verifyWebhookSignature(payload, headers, secret) {
37
- try {
38
- const wh = new Webhook(secret);
39
- wh.verify(payload, {
40
- "webhook-id": headers["webhook-id"] ?? "",
41
- "webhook-signature": headers["webhook-signature"] ?? "",
42
- "webhook-timestamp": headers["webhook-timestamp"] ?? ""
43
- });
44
- return true;
45
- } catch (error) {
46
- if (error instanceof WebhookVerificationError) {
47
- return false;
48
- }
49
- throw error;
50
- }
51
- }
52
- function serializeCookie(cookie) {
53
- return {
54
- domain: cookie.options?.domain,
55
- expires: cookie.options?.expires,
56
- httpOnly: cookie.options?.httpOnly,
57
- name: cookie.name,
58
- path: cookie.options?.path,
59
- sameSite: cookie.options?.sameSite,
60
- secure: cookie.options?.secure,
61
- value: cookie.value
62
- };
63
- }
64
- function toBatchRunResults(results) {
65
- return results.map(
66
- (r) => r.success ? {
67
- cookies: r.cookies.map((c) => serializeCookie(c)),
68
- data: r.data,
69
- executed: [...r.executed],
70
- ok: true,
71
- runId: r.runId
72
- } : { error: r.error ?? "unknown error", ok: false, runId: r.runId }
73
- );
74
- }
75
- function toTeardownResults(results) {
76
- return results.map((r) => ({ error: r.error, ok: r.success, runId: r.runId }));
77
- }
78
-
79
- export {
80
- readAdapterWebhookSecret,
81
- batchRequestSchema,
82
- teardownRequestSchema,
83
- observerRequestSchema,
84
- verifyWebhookSignature,
85
- serializeCookie,
86
- toBatchRunResults,
87
- toTeardownResults
88
- };