@cowliss/cli 0.7.0 → 0.9.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.
@@ -1,21 +1,34 @@
1
- import { a as JourneyStepOutput, o as ManifestOutput, s as TemplateRenderOutput } from "./index-3PMqJKmc.js";
1
+ import { a as JourneyStepOutput, o as ManifestOutput, s as TemplateRenderOutput } from "./index-EqBCZnpq.js";
2
+ import { n as Template } from "./emails-5GindgMQ.js";
2
3
  //#region src/guest/driver.d.ts
3
4
  /**
4
5
  * The in-process driver: JSON in, JSON out (spec: Guest protocol). One
5
- * bundle is one module is one journey or one template, and this turns the
6
- * three inputs into the three outputs. `wasi.ts` wraps it for the sandbox;
6
+ * bundle is one module is one journey or one template, and this turns that
7
+ * bundle's inputs into its outputs. `wasi.ts` wraps it for the sandbox;
7
8
  * the simulator and the tests call `runGuest` directly.
8
9
  *
10
+ * There are two drivers, one per kind, because a bundle only pays for the
11
+ * one it is. This is the journey half: `manifest` and `journey`. The
12
+ * template half lives in `driver-emails.ts` and is the only one that
13
+ * imports `render.ts`, so react and react-dom (197KB minified) stay out of
14
+ * every journey bundle. `build/index.ts` picks the driver by source kind
15
+ * when it composes an entry; everything both kinds need is here and
16
+ * imported by that file.
17
+ *
9
18
  * Every output is validated with the shared schema before it leaves, so a
10
19
  * guest bug surfaces here rather than as a host-side parse failure.
11
20
  */
12
21
  /** A compiled bundle's module namespace, as `import * as module` sees it. */
13
22
  type GuestModule = Record<string, unknown>;
14
23
  type GuestOutput = JourneyStepOutput | TemplateRenderOutput | ManifestOutput;
24
+ declare function asTemplate(module: GuestModule): Template;
25
+ declare function readManifest(module: GuestModule): ManifestOutput;
15
26
  /**
16
- * Runs one guest invocation. `module` is the tenant module namespace the
17
- * bundle's entry imported; `input` is the raw JSON the host handed over.
27
+ * Runs one guest invocation against a journey bundle. `module` is the tenant
28
+ * module namespace the bundle's entry imported; `input` is the raw JSON the
29
+ * host handed over. A `template` input is a host bug, not a tenant one: this
30
+ * bundle was built from `journeys/` and carries no renderer.
18
31
  */
19
32
  declare function runGuest(module: GuestModule, input: unknown): Promise<GuestOutput>;
20
33
  //#endregion
21
- export { GuestModule, GuestOutput, runGuest };
34
+ export { GuestModule, GuestOutput, asTemplate, readManifest, runGuest };
@@ -1,3 +1,3 @@
1
- import { t as runGuest } from "./driver-C1bsCjZT.js";
1
+ import { n as readManifest, r as runGuest, t as asTemplate } from "./driver-poSdZIj8.js";
2
2
 
3
- export { runGuest };
3
+ export { asTemplate, readManifest, runGuest };
@@ -0,0 +1,47 @@
1
+ import { z } from "zod";
2
+ import { ReactElement } from "react";
3
+ //#region ../../packages/shared/src/constants.d.ts
4
+ /**
5
+ * The two classes of send, declared on the template rather than passed per
6
+ * call so the class cannot drift between two sends of the same message.
7
+ *
8
+ * Marketing is everything a journey sends on the org's behalf: it carries
9
+ * the RFC 8058 unsubscribe headers and runs the full gate list.
10
+ * Transactional is the developer's own operational mail (a receipt, an
11
+ * export-is-ready notice): it carries neither header and skips consent and
12
+ * the per-user frequency cap, because an unsubscribe link on an invoice is
13
+ * wrong and a receipt must not silently vanish for anyone who once left a
14
+ * newsletter. Suppression, the quota, the sending pause, and the from-domain
15
+ * check still apply to both: those bound cost and protect the shared SES
16
+ * account, and none of them are about what the recipient asked for.
17
+ */
18
+ declare const SEND_CLASSES: readonly ["marketing", "transactional"];
19
+ type SendClass = (typeof SEND_CLASSES)[number];
20
+ //#endregion
21
+ //#region src/guest/emails.d.ts
22
+ /** A template's subject line, computed from the props it declares. */
23
+ type Subject<Schema extends z.ZodType> = (props: z.infer<Schema>) => string;
24
+ /**
25
+ * The shape `emails/<key>.tsx` exports. `cow build` reads `props` (turned
26
+ * into JSON Schema in the manifest and into `.cow/types.d.ts`), `subject`,
27
+ * and the optional metadata below it; the sandbox renders `default`.
28
+ */
29
+ type Template<Schema extends z.ZodType = z.ZodType> = {
30
+ default: (props: z.infer<Schema>) => ReactElement;
31
+ props: Schema;
32
+ subject: Subject<Schema> | string;
33
+ /** Defaults to "marketing". */
34
+ sendClass?: SendClass;
35
+ /** The author's labels; the dashboard's only grouping. Defaults to none. */
36
+ tags?: string[];
37
+ /** True asks the host to mint a signed `verifyUrl` prop at send time. */
38
+ verifyLink?: boolean;
39
+ /**
40
+ * True asks the host to mint a signed `unsubscribeUrl` prop at send time,
41
+ * for the author's own footer link. Leave it off and a marketing template
42
+ * still gets a platform footer with the link appended at send time.
43
+ */
44
+ unsubscribeLink?: boolean;
45
+ };
46
+ //#endregion
47
+ export { Template as n, SendClass as r, Subject as t };
@@ -1,47 +1,2 @@
1
- import { z } from "zod";
2
- import { ReactElement } from "react";
3
- //#region ../../packages/shared/src/constants.d.ts
4
- /**
5
- * The two classes of send, declared on the template rather than passed per
6
- * call so the class cannot drift between two sends of the same message.
7
- *
8
- * Marketing is everything a journey sends on the org's behalf: it carries
9
- * the RFC 8058 unsubscribe headers and runs the full gate list.
10
- * Transactional is the developer's own operational mail (a receipt, an
11
- * export-is-ready notice): it carries neither header and skips consent and
12
- * the per-user frequency cap, because an unsubscribe link on an invoice is
13
- * wrong and a receipt must not silently vanish for anyone who once left a
14
- * newsletter. Suppression, the quota, the sending pause, and the from-domain
15
- * check still apply to both: those bound cost and protect the shared SES
16
- * account, and none of them are about what the recipient asked for.
17
- */
18
- declare const SEND_CLASSES: readonly ["marketing", "transactional"];
19
- type SendClass = (typeof SEND_CLASSES)[number];
20
- //#endregion
21
- //#region src/guest/emails.d.ts
22
- /** A template's subject line, computed from the props it declares. */
23
- type Subject<Schema extends z.ZodType> = (props: z.infer<Schema>) => string;
24
- /**
25
- * The shape `emails/<key>.tsx` exports. `cow build` reads `props` (turned
26
- * into JSON Schema in the manifest and into `.cow/types.d.ts`), `subject`,
27
- * and the optional metadata below it; the sandbox renders `default`.
28
- */
29
- type Template<Schema extends z.ZodType = z.ZodType> = {
30
- default: (props: z.infer<Schema>) => ReactElement;
31
- props: Schema;
32
- subject: Subject<Schema> | string;
33
- /** Defaults to "marketing". */
34
- sendClass?: SendClass;
35
- /** The author's labels; the dashboard's only grouping. Defaults to none. */
36
- tags?: string[];
37
- /** True asks the host to mint a signed `verifyUrl` prop at send time. */
38
- verifyLink?: boolean;
39
- /**
40
- * True asks the host to mint a signed `unsubscribeUrl` prop at send time,
41
- * for the author's own footer link. Leave it off and a marketing template
42
- * still gets a platform footer with the link appended at send time.
43
- */
44
- unsubscribeLink?: boolean;
45
- };
46
- //#endregion
1
+ import { n as Template, r as SendClass, t as Subject } from "./emails-5GindgMQ.js";
47
2
  export { type SendClass, Subject, Template };
@@ -252,14 +252,12 @@ declare const manifestOutputSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
252
252
  tags: z.ZodPipe<z.ZodDefault<z.ZodArray<z.ZodString>>, z.ZodTransform<string[], string[]>>;
253
253
  trigger: z.ZodUnion<readonly [z.ZodObject<{
254
254
  event: z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>;
255
- appId: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
256
255
  }, z.core.$strict>, z.ZodObject<{
257
256
  segment: z.ZodObject<{
258
257
  match: z.ZodDefault<z.ZodEnum<{
259
258
  all: "all";
260
259
  any: "any";
261
260
  }>>;
262
- appId: z.ZodOptional<z.ZodNullable<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>>;
263
261
  predicates: z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
264
262
  kind: z.ZodLiteral<"trait">;
265
263
  name: z.ZodString;
@@ -323,9 +321,12 @@ type ManifestOutput = z.infer<typeof manifestOutputSchema>;
323
321
  declare const durationSchema: z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>;
324
322
  type Duration = z.infer<typeof durationSchema>;
325
323
  /**
326
- * What starts a journey: an event (optionally narrowed to an app id or a
327
- * list of them), or entry into the segment the trigger itself describes.
328
- * The registry DTO in `../journeys` reuses it.
324
+ * What starts a journey: an event, or entry into the segment the trigger
325
+ * itself describes. The registry DTO in `../journeys` reuses it.
326
+ *
327
+ * No trigger names an app (ADR 0022): a repository is one app, the journey
328
+ * row carries its `app_id`, and the runtime compares that with the event's.
329
+ * An `appId` here would be a second way to say it, and the way to leak.
329
330
  *
330
331
  * A segment trigger carries the predicate list, not a name: the push
331
332
  * materializes one segment row per journey that inlines a definition, owned
@@ -334,22 +335,20 @@ type Duration = z.infer<typeof durationSchema>;
334
335
  * definition is data — validated here, carried on the version, never
335
336
  * compiled and never executed.
336
337
  *
337
- * Both members are strict, so a journey holding the retired `source` key, or
338
- * the retired `{ segment: "name" }` form, fails to build instead of silently
339
- * triggering on every app or on nothing. There is deliberately no pipe
340
- * filter: a trigger narrows by the app the write is attributed to, the same
341
- * token a segment definition names.
338
+ * Both members are strict, so a journey holding the retired `source` or
339
+ * `appId` key, or the retired `{ segment: "name" }` form, fails to build
340
+ * instead of silently triggering on every app or on nothing. There is
341
+ * deliberately no pipe filter and no app filter: the journey's own app is
342
+ * the only narrowing there is.
342
343
  */
343
344
  declare const triggerSchema: z.ZodUnion<readonly [z.ZodObject<{
344
345
  event: z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>;
345
- appId: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
346
346
  }, z.core.$strict>, z.ZodObject<{
347
347
  segment: z.ZodObject<{
348
348
  match: z.ZodDefault<z.ZodEnum<{
349
349
  all: "all";
350
350
  any: "any";
351
351
  }>>;
352
- appId: z.ZodOptional<z.ZodNullable<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>>;
353
352
  predicates: z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
354
353
  kind: z.ZodLiteral<"trait">;
355
354
  name: z.ZodString;
@@ -4,6 +4,34 @@ import { z } from "zod";
4
4
  /** The public docs site, for the mail and the pages that point people at it. */
5
5
  const DOCS_URL = "https://docs.cowliss.com";
6
6
  /**
7
+ * Stripe-style ID prefixes per resource type, so ids in logs, URLs, and
8
+ * payloads are self-describing.
9
+ */
10
+ const ID_PREFIXES = {
11
+ user: "usr_",
12
+ event: "evt_",
13
+ identifier: "idn_",
14
+ segment: "seg_",
15
+ /** The attribution unit: a readable `app_<slug>`, not a TypeID. */
16
+ app: "app_",
17
+ /** One inbound pipe into an app; a TypeID like everything else. */
18
+ source: "src_",
19
+ webhook: "whk_",
20
+ push: "psh_",
21
+ version: "ver_",
22
+ execution: "exe_",
23
+ delivery: "dlv_",
24
+ violation: "vio_",
25
+ quarantineEntry: "qtn_",
26
+ idempotencyKey: "idk_",
27
+ abuseEvent: "abu_",
28
+ suppression: "sup_",
29
+ senderDomain: "dom_",
30
+ journeyRun: "run_",
31
+ topup: "top_",
32
+ emailAddress: "eml_"
33
+ };
34
+ /**
7
35
  * Clerk ID prefix marking an organization-scoped subject. Ingestion API keys
8
36
  * must resolve to an org subject; user-scoped keys are rejected.
9
37
  */
@@ -71,21 +99,18 @@ const COW_CONFIG_SCHEMA_URL = `${DOCS_URL}${COW_CONFIG_SCHEMA_PATH}`;
71
99
  * history, combined with `all` or `any`. Deliberately flat — nested predicate groups are YAGNI for the
72
100
  * prototype, and a flat list keeps the pure evaluator a fold.
73
101
  *
74
- * `appId` scopes the EVENT side of a definition only. Traits are
75
- * per-profile and profiles merge across apps, so there is nothing
76
- * app-shaped to filter on the trait side.
77
- *
78
- * A definition and the membership it produces are both the
79
- * organization's.
102
+ * A definition names no app (ADR 0022): the segment row's own `app_id` is
103
+ * the one app it evaluates, so the events and the profiles it reads are
104
+ * that app's and there is nothing to filter by here.
80
105
  *
81
106
  * Apart from `./segments` because a journey's trigger carries a definition
82
107
  * and the trigger schema is bundled into the wasm guest, where an edge to
83
108
  * `@cowliss/db` (which `./segments` has, for the row schema) is a hard
84
109
  * bundler failure. Nothing here imports anything but zod.
85
110
  *
86
- * The object is strict: a definition holding the retired `sourceId` key
87
- * (which meant the app) fails loudly instead of parsing as an unfiltered
88
- * definition that evaluates over every app. There is deliberately no pipe
111
+ * The object is strict: a definition holding the retired `sourceId` or
112
+ * `appId` key (both of which meant the app) fails loudly instead of parsing
113
+ * as an unfiltered definition that evaluates over every app. There is deliberately no pipe
89
114
  * filter here — filtering by source is a later feature, and accepting one
90
115
  * now would make a stale `sourceId` parse as a filter on a pipe that does
91
116
  * not exist and silently match nothing.
@@ -138,15 +163,8 @@ const segmentPredicateSchema = z.discriminatedUnion("kind", [z.object({
138
163
  /** Rolling window, relative to evaluation time; absent means all history. */
139
164
  withinDays: z.number().int().min(1).optional()
140
165
  })]).refine((predicate) => predicate.kind !== "trait" || VALUELESS_TRAIT_OPS.includes(predicate.op) || predicate.value !== void 0, { message: "value is required unless op is exists or notExists" });
141
- const appIdSchema = z.string().trim().min(1);
142
166
  const segmentDefinitionSchema = z.strictObject({
143
167
  match: z.enum(["all", "any"]).default("all"),
144
- /**
145
- * Optional app filter over the event side; null/absent spans apps.
146
- * A list matches any of the named apps, which is how one definition
147
- * names the development and the production id of the same app.
148
- */
149
- appId: z.union([appIdSchema, z.array(appIdSchema).min(1)]).nullish(),
150
168
  predicates: z.array(segmentPredicateSchema).min(1, "at least one predicate is required")
151
169
  });
152
170
 
@@ -259,9 +277,12 @@ const purposesSchema = z.array(declaredPurposeSchema).max(20, "a project declare
259
277
  const onePatternSchema = z.string().min(1).max(200, "a pattern must be at most 200 characters");
260
278
  const patternSchema = z.union([onePatternSchema, z.array(onePatternSchema).min(1).max(20, "a matcher takes at most 20 patterns")]);
261
279
  /**
262
- * What starts a journey: an event (optionally narrowed to an app id or a
263
- * list of them), or entry into the segment the trigger itself describes.
264
- * The registry DTO in `../journeys` reuses it.
280
+ * What starts a journey: an event, or entry into the segment the trigger
281
+ * itself describes. The registry DTO in `../journeys` reuses it.
282
+ *
283
+ * No trigger names an app (ADR 0022): a repository is one app, the journey
284
+ * row carries its `app_id`, and the runtime compares that with the event's.
285
+ * An `appId` here would be a second way to say it, and the way to leak.
265
286
  *
266
287
  * A segment trigger carries the predicate list, not a name: the push
267
288
  * materializes one segment row per journey that inlines a definition, owned
@@ -270,16 +291,13 @@ const patternSchema = z.union([onePatternSchema, z.array(onePatternSchema).min(1
270
291
  * definition is data — validated here, carried on the version, never
271
292
  * compiled and never executed.
272
293
  *
273
- * Both members are strict, so a journey holding the retired `source` key, or
274
- * the retired `{ segment: "name" }` form, fails to build instead of silently
275
- * triggering on every app or on nothing. There is deliberately no pipe
276
- * filter: a trigger narrows by the app the write is attributed to, the same
277
- * token a segment definition names.
294
+ * Both members are strict, so a journey holding the retired `source` or
295
+ * `appId` key, or the retired `{ segment: "name" }` form, fails to build
296
+ * instead of silently triggering on every app or on nothing. There is
297
+ * deliberately no pipe filter and no app filter: the journey's own app is
298
+ * the only narrowing there is.
278
299
  */
279
- const triggerSchema = z.union([z.strictObject({
280
- event: patternSchema,
281
- appId: patternSchema.optional()
282
- }), z.strictObject({ segment: segmentDefinitionSchema })]);
300
+ const triggerSchema = z.union([z.strictObject({ event: patternSchema }), z.strictObject({ segment: segmentDefinitionSchema })]);
283
301
  /**
284
302
  * The address half of a from-header: a local part, an `@`, and a dotted
285
303
  * domain. Deliberately narrower than RFC 5322 (no quoted local parts, no
@@ -501,30 +519,56 @@ const versionManifestSchema = z.union([manifestJourneySchema, manifestTemplateSc
501
519
  //#endregion
502
520
  //#region ../../packages/shared/src/journeys-v2/config.ts
503
521
  /**
504
- * A project's name: what `cow init` asked for, and what the `projects` row
505
- * stores. Lives here rather than beside the release DTOs because `cow.json`
506
- * is the file a developer types it into; `createProjectBodySchema` reuses it.
522
+ * An app id as `cow.json` carries it: the readable `app_<slug>`
523
+ * `appIdFromName` derives, which is the one id a developer types by hand.
524
+ *
525
+ * It lives here rather than beside the app DTOs in ../apps because that
526
+ * module imports the Drizzle schema, which neither the wasmtime guest nor
527
+ * the Temporal workflow isolate can carry, and because `cow.json` is the
528
+ * file a developer types it into. Everything that names an app on the wire
529
+ * reuses it.
530
+ */
531
+ const appIdSchema = z.string().trim().max(200).regex(new RegExp(`^${ID_PREFIXES.app}[a-z0-9]+(-[a-z0-9]+)*$`), "an app id looks like \"app_website\"");
532
+ /**
533
+ * A source id: the one inbound pipe an ingestion or send call names. It
534
+ * lives beside `appIdSchema` for the same two reasons — the sources module
535
+ * imports the Drizzle schema, and both are ids that travel on the wire — and
536
+ * it has the same shape, so a bare `src_` is refused here rather than at the
537
+ * database.
538
+ *
539
+ * The prefixes above and here are interpolated raw; `journeys-v2.test.ts`
540
+ * asserts they are plain `<word>_` literals, so none of them can quietly
541
+ * change what these patterns match.
507
542
  */
508
- const projectNameSchema = z.string().trim().min(1).max(200);
543
+ const sourceIdSchema = z.string().trim().max(200).regex(new RegExp(`^${ID_PREFIXES.source}[a-z0-9_]+$`), "a source id looks like \"src_01j8x…\"");
509
544
  /**
510
- * `cow.json` (spec: Project layout): the org, and which of its projects this
511
- * directory is. Auth never lives in the project. Strict, so a typo'd key
512
- * is a build error rather than a silently ignored setting.
545
+ * A Clerk organization id, as `cow.json` spells it. Exported beside
546
+ * `appIdSchema` because the push body carries the org the file names so the
547
+ * server can refuse a push aimed at another one (ADR 0022).
548
+ */
549
+ const orgIdSchema = z.string().trim().max(200).startsWith(CLERK_ORG_SUBJECT_PREFIX, "orgId must be a Clerk org id");
550
+ /**
551
+ * `cow.json` (spec: Project layout): the org, and which of its apps this
552
+ * repository pushes to. Auth never lives in the file. Strict, so a typo'd
553
+ * key is a build error rather than a silently ignored setting — which is
554
+ * also what turns the retired `project` key into a refusal (`cow build`
555
+ * says what to rename it to).
513
556
  */
514
557
  const cowConfigSchema = z.strictObject({
515
558
  $schema: z.url().optional(),
516
- orgId: z.string().startsWith(CLERK_ORG_SUBJECT_PREFIX, "orgId must be a Clerk org id"),
559
+ orgId: orgIdSchema,
517
560
  /**
518
- * Which project of the org this directory pushes to. One org can hold
519
- * several, one per repo, each with its own release sequence and its own
520
- * slice of the deployed journeys, so every project says which it is.
561
+ * Which app of the org this repository pushes to (ADR 0022). The app is
562
+ * the push unit: it owns the journey and template keys, and `cow
563
+ * status`, `cow enable --all` and `cow pull` all resolve against it. One
564
+ * repository is one app, so no journey file names one.
521
565
  */
522
- project: projectNameSchema,
566
+ appId: appIdSchema,
523
567
  /**
524
- * The consent purposes this project declares. They are org-wide, so two
525
- * projects declaring one key must agree on its label and default or the
526
- * deploy is refused; a deploy adds and updates them and never deletes
527
- * one, because profiles hold answers against them.
568
+ * The consent purposes this repository declares. They are org-wide, so
569
+ * two apps declaring one key must agree on its label and default or the
570
+ * push is refused; a push adds and updates them and never deletes one,
571
+ * because profiles hold answers against them.
528
572
  */
529
573
  purposes: purposesSchema.optional(),
530
574
  /** Overrides the API the CLI talks to; the hosted product needs none. */
@@ -537,7 +581,7 @@ const cowConfigSchema = z.strictObject({
537
581
  webUrl: z.url().optional()
538
582
  }).meta({
539
583
  title: "cow.json",
540
- description: "A cow project: the organization and the project it pushes to."
584
+ description: "A cow project: the organization and the app it pushes to."
541
585
  });
542
586
 
543
587
  //#endregion
@@ -866,6 +910,10 @@ const journeyConfigSchema = manifestJourneySchema.pick({
866
910
  *
867
911
  * There is no environment gate here: an organization has one data space, and
868
912
  * a journey runs wherever it is on and nowhere else (ADR 0011, ADR 0013).
913
+ *
914
+ * There is no app gate either. A journey belongs to the one app `cow.json`
915
+ * names, so it only ever sees that app's events, profiles and segments
916
+ * (ADR 0022); a trigger naming an app is refused rather than honoured.
869
917
  */
870
918
  function defineJourney(input) {
871
919
  const config = journeyConfigSchema.parse({
@@ -1,4 +1,4 @@
1
- import { i as GuestEvent, n as Trigger, r as TriggerInput, t as Duration } from "./index-3PMqJKmc.js";
1
+ import { i as GuestEvent, n as Trigger, r as TriggerInput, t as Duration } from "./index-EqBCZnpq.js";
2
2
  //#region src/guest/journeys.d.ts
3
3
  /** The event a journey runs for, or the one a `waitForEvent` resolved with. */
4
4
  type Event = GuestEvent;
@@ -32,10 +32,10 @@ declare class CapabilityError extends Error {
32
32
  constructor(code: string, message: string);
33
33
  }
34
34
  /**
35
- * The project's templates, keyed by template key. `cow build` writes the
35
+ * The repository's templates, keyed by template key. `cow build` writes the
36
36
  * real interface into `.cow/types.d.ts` and TypeScript merges it into this
37
37
  * one, which is what types `api.send.email`. Empty here on purpose: a
38
- * project that has not built yet still compiles, with string keys.
38
+ * repository that has not built yet still compiles, with string keys.
39
39
  */
40
40
  interface CowTemplates {}
41
41
  type TemplateKey = keyof CowTemplates extends never ? string : keyof CowTemplates;
@@ -122,8 +122,8 @@ type JourneyConfig = {
122
122
  trigger: Trigger;
123
123
  /**
124
124
  * Why this journey contacts someone: `marketing`, `transactional`, or a
125
- * purpose this project declares in `cow.json`. The key's shape is checked
126
- * here; that the org declares it is checked when the release is deployed.
125
+ * purpose this repository declares in `cow.json`. The key's shape is
126
+ * checked here; that the org declares it is checked when the push lands.
127
127
  */
128
128
  purpose: string;
129
129
  /**
@@ -167,12 +167,17 @@ type Journey = JourneyConfig & {
167
167
  *
168
168
  * There is no environment gate here: an organization has one data space, and
169
169
  * a journey runs wherever it is on and nowhere else (ADR 0011, ADR 0013).
170
+ *
171
+ * There is no app gate either. A journey belongs to the one app `cow.json`
172
+ * names, so it only ever sees that app's events, profiles and segments
173
+ * (ADR 0022); a trigger naming an app is refused rather than honoured.
170
174
  */
171
175
  declare function defineJourney(input: Omit<JourneyConfig, "tags" | "trigger"> & {
172
176
  /**
173
- * What starts it: `{ event }`, or `{ segment }` carrying the predicate
174
- * list of the segment this journey enrolls from. Written form, so a
175
- * predicate can leave `match` and `atLeast` out.
177
+ * What starts it: `{ event }`, one event-name pattern or a list of
178
+ * them, or `{ segment }` carrying the predicate list of the segment
179
+ * this journey enrolls from. Written form, so a predicate can leave
180
+ * `match` and `atLeast` out. No app: the repository's app is the scope.
176
181
  */
177
182
  trigger: TriggerInput;
178
183
  tags?: string[];
@@ -1,3 +1,3 @@
1
- import { n as defineJourney, t as CapabilityError } from "./journeys-Dpsp225V.js";
1
+ import { n as defineJourney, t as CapabilityError } from "./journeys-F8Yk8s1P.js";
2
2
 
3
3
  export { CapabilityError, defineJourney };
@@ -1,6 +1,8 @@
1
- import { GuestModule } from "./driver.js";
1
+ import { GuestModule, GuestOutput } from "./driver.js";
2
2
  //#region src/guest/wasi.d.ts
3
+ /** The kind-specific driver the entry hands over. */
4
+ type RunGuest = (module: GuestModule, input: unknown) => Promise<GuestOutput>;
3
5
  /** Drives one invocation of the module this bundle was built for. */
4
- declare function main(module: GuestModule): void;
6
+ declare function main(module: GuestModule, runGuest: RunGuest): void;
5
7
  //#endregion
6
8
  export { main };
@@ -1,5 +1,3 @@
1
- import { t as runGuest } from "./driver-C1bsCjZT.js";
2
-
3
1
  //#region src/guest/wasi.ts
4
2
  const STDIN = 0;
5
3
  const STDOUT = 1;
@@ -27,7 +25,7 @@ function write(fd, text) {
27
25
  Javy.IO.writeSync(fd, new TextEncoder().encode(text));
28
26
  }
29
27
  /** Drives one invocation of the module this bundle was built for. */
30
- function main(module) {
28
+ function main(module, runGuest) {
31
29
  const fail = (error) => {
32
30
  write(STDERR, error instanceof Error ? error.message : String(error));
33
31
  throw error;