@shware/workflow 0.0.0-stage → 0.0.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.
- package/LICENSE +21 -0
- package/README.md +154 -2
- package/dist/_virtual/_rolldown/runtime.cjs +23 -0
- package/dist/apns-relay.cjs +105 -0
- package/dist/apns-relay.cjs.map +1 -0
- package/dist/apns-relay.d.cts +28 -0
- package/dist/apns-relay.d.cts.map +1 -0
- package/dist/apns-relay.d.mts +28 -0
- package/dist/apns-relay.d.mts.map +1 -0
- package/dist/apns-relay.mjs +104 -0
- package/dist/apns-relay.mjs.map +1 -0
- package/dist/apns.cjs +121 -0
- package/dist/apns.cjs.map +1 -0
- package/dist/apns.d.cts +63 -0
- package/dist/apns.d.cts.map +1 -0
- package/dist/apns.d.mts +63 -0
- package/dist/apns.d.mts.map +1 -0
- package/dist/apns.mjs +116 -0
- package/dist/apns.mjs.map +1 -0
- package/dist/client.cjs +125 -0
- package/dist/client.cjs.map +1 -0
- package/dist/client.d.cts +108 -0
- package/dist/client.d.cts.map +1 -0
- package/dist/client.d.mts +108 -0
- package/dist/client.d.mts.map +1 -0
- package/dist/client.mjs +122 -0
- package/dist/client.mjs.map +1 -0
- package/dist/cloudflare/bindings.cjs +28 -0
- package/dist/cloudflare/bindings.cjs.map +1 -0
- package/dist/cloudflare/bindings.d.cts +144 -0
- package/dist/cloudflare/bindings.d.cts.map +1 -0
- package/dist/cloudflare/bindings.d.mts +144 -0
- package/dist/cloudflare/bindings.d.mts.map +1 -0
- package/dist/cloudflare/bindings.mjs +25 -0
- package/dist/cloudflare/bindings.mjs.map +1 -0
- package/dist/cloudflare/channels.cjs +164 -0
- package/dist/cloudflare/channels.cjs.map +1 -0
- package/dist/cloudflare/channels.d.cts +29 -0
- package/dist/cloudflare/channels.d.cts.map +1 -0
- package/dist/cloudflare/channels.d.mts +29 -0
- package/dist/cloudflare/channels.d.mts.map +1 -0
- package/dist/cloudflare/channels.mjs +161 -0
- package/dist/cloudflare/channels.mjs.map +1 -0
- package/dist/cloudflare/d1-env.cjs +17 -0
- package/dist/cloudflare/d1-env.cjs.map +1 -0
- package/dist/cloudflare/d1-env.d.cts +12 -0
- package/dist/cloudflare/d1-env.d.cts.map +1 -0
- package/dist/cloudflare/d1-env.d.mts +12 -0
- package/dist/cloudflare/d1-env.d.mts.map +1 -0
- package/dist/cloudflare/d1-env.mjs +16 -0
- package/dist/cloudflare/d1-env.mjs.map +1 -0
- package/dist/cloudflare/index.cjs +54 -0
- package/dist/cloudflare/index.d.cts +19 -0
- package/dist/cloudflare/index.d.mts +19 -0
- package/dist/cloudflare/index.mjs +16 -0
- package/dist/cloudflare/router.cjs +516 -0
- package/dist/cloudflare/router.cjs.map +1 -0
- package/dist/cloudflare/router.d.cts +157 -0
- package/dist/cloudflare/router.d.cts.map +1 -0
- package/dist/cloudflare/router.d.mts +157 -0
- package/dist/cloudflare/router.d.mts.map +1 -0
- package/dist/cloudflare/router.mjs +503 -0
- package/dist/cloudflare/router.mjs.map +1 -0
- package/dist/cloudflare/runner.cjs +225 -0
- package/dist/cloudflare/runner.cjs.map +1 -0
- package/dist/cloudflare/runner.d.cts +73 -0
- package/dist/cloudflare/runner.d.cts.map +1 -0
- package/dist/cloudflare/runner.d.mts +73 -0
- package/dist/cloudflare/runner.d.mts.map +1 -0
- package/dist/cloudflare/runner.mjs +224 -0
- package/dist/cloudflare/runner.mjs.map +1 -0
- package/dist/cloudflare/schema.sql +127 -0
- package/dist/cloudflare/senders.cjs +114 -0
- package/dist/cloudflare/senders.cjs.map +1 -0
- package/dist/cloudflare/senders.d.cts +68 -0
- package/dist/cloudflare/senders.d.cts.map +1 -0
- package/dist/cloudflare/senders.d.mts +68 -0
- package/dist/cloudflare/senders.d.mts.map +1 -0
- package/dist/cloudflare/senders.mjs +108 -0
- package/dist/cloudflare/senders.mjs.map +1 -0
- package/dist/cloudflare/worker.cjs +228 -0
- package/dist/cloudflare/worker.cjs.map +1 -0
- package/dist/cloudflare/worker.d.cts +92 -0
- package/dist/cloudflare/worker.d.cts.map +1 -0
- package/dist/cloudflare/worker.d.mts +92 -0
- package/dist/cloudflare/worker.d.mts.map +1 -0
- package/dist/cloudflare/worker.mjs +224 -0
- package/dist/cloudflare/worker.mjs.map +1 -0
- package/dist/cloudflare/workers.d.cjs +0 -0
- package/dist/cloudflare/workers.d.cts +44 -0
- package/dist/cloudflare/workers.d.cts.map +1 -0
- package/dist/cloudflare/workers.d.mts +44 -0
- package/dist/cloudflare/workers.d.mts.map +1 -0
- package/dist/config.cjs +151 -0
- package/dist/config.cjs.map +1 -0
- package/dist/config.d.cts +149 -0
- package/dist/config.d.cts.map +1 -0
- package/dist/config.d.mts +149 -0
- package/dist/config.d.mts.map +1 -0
- package/dist/config.mjs +143 -0
- package/dist/config.mjs.map +1 -0
- package/dist/contract.cjs +212 -0
- package/dist/contract.cjs.map +1 -0
- package/dist/contract.d.cts +90 -0
- package/dist/contract.d.cts.map +1 -0
- package/dist/contract.d.mts +90 -0
- package/dist/contract.d.mts.map +1 -0
- package/dist/contract.mjs +206 -0
- package/dist/contract.mjs.map +1 -0
- package/dist/dsl/action.cjs +29 -0
- package/dist/dsl/action.cjs.map +1 -0
- package/dist/dsl/action.d.cts +64 -0
- package/dist/dsl/action.d.cts.map +1 -0
- package/dist/dsl/action.d.mts +64 -0
- package/dist/dsl/action.d.mts.map +1 -0
- package/dist/dsl/action.mjs +28 -0
- package/dist/dsl/action.mjs.map +1 -0
- package/dist/dsl/base.cjs +34 -0
- package/dist/dsl/base.cjs.map +1 -0
- package/dist/dsl/base.d.cts +45 -0
- package/dist/dsl/base.d.cts.map +1 -0
- package/dist/dsl/base.d.mts +45 -0
- package/dist/dsl/base.d.mts.map +1 -0
- package/dist/dsl/base.mjs +30 -0
- package/dist/dsl/base.mjs.map +1 -0
- package/dist/dsl/bundle.cjs +207 -0
- package/dist/dsl/bundle.cjs.map +1 -0
- package/dist/dsl/bundle.d.cts +19 -0
- package/dist/dsl/bundle.d.cts.map +1 -0
- package/dist/dsl/bundle.d.mts +19 -0
- package/dist/dsl/bundle.d.mts.map +1 -0
- package/dist/dsl/bundle.mjs +206 -0
- package/dist/dsl/bundle.mjs.map +1 -0
- package/dist/dsl/condition.cjs +177 -0
- package/dist/dsl/condition.cjs.map +1 -0
- package/dist/dsl/condition.d.cts +140 -0
- package/dist/dsl/condition.d.cts.map +1 -0
- package/dist/dsl/condition.d.mts +140 -0
- package/dist/dsl/condition.d.mts.map +1 -0
- package/dist/dsl/condition.mjs +156 -0
- package/dist/dsl/condition.mjs.map +1 -0
- package/dist/dsl/flow.cjs +228 -0
- package/dist/dsl/flow.cjs.map +1 -0
- package/dist/dsl/flow.d.cts +223 -0
- package/dist/dsl/flow.d.cts.map +1 -0
- package/dist/dsl/flow.d.mts +223 -0
- package/dist/dsl/flow.d.mts.map +1 -0
- package/dist/dsl/flow.mjs +226 -0
- package/dist/dsl/flow.mjs.map +1 -0
- package/dist/dsl/index.cjs +38 -0
- package/dist/dsl/index.d.cts +10 -0
- package/dist/dsl/index.d.mts +10 -0
- package/dist/dsl/index.mjs +9 -0
- package/dist/dsl/refs.cjs +59 -0
- package/dist/dsl/refs.cjs.map +1 -0
- package/dist/dsl/refs.d.cts +88 -0
- package/dist/dsl/refs.d.cts.map +1 -0
- package/dist/dsl/refs.d.mts +88 -0
- package/dist/dsl/refs.d.mts.map +1 -0
- package/dist/dsl/refs.mjs +55 -0
- package/dist/dsl/refs.mjs.map +1 -0
- package/dist/dsl/template.cjs +65 -0
- package/dist/dsl/template.cjs.map +1 -0
- package/dist/dsl/template.d.cts +75 -0
- package/dist/dsl/template.d.cts.map +1 -0
- package/dist/dsl/template.d.mts +75 -0
- package/dist/dsl/template.d.mts.map +1 -0
- package/dist/dsl/template.mjs +63 -0
- package/dist/dsl/template.mjs.map +1 -0
- package/dist/dsl/trigger.cjs +40 -0
- package/dist/dsl/trigger.cjs.map +1 -0
- package/dist/dsl/trigger.d.cts +65 -0
- package/dist/dsl/trigger.d.cts.map +1 -0
- package/dist/dsl/trigger.d.mts +65 -0
- package/dist/dsl/trigger.d.mts.map +1 -0
- package/dist/dsl/trigger.mjs +39 -0
- package/dist/dsl/trigger.mjs.map +1 -0
- package/dist/dsl/workflow.cjs +121 -0
- package/dist/dsl/workflow.cjs.map +1 -0
- package/dist/dsl/workflow.d.cts +59 -0
- package/dist/dsl/workflow.d.cts.map +1 -0
- package/dist/dsl/workflow.d.mts +59 -0
- package/dist/dsl/workflow.d.mts.map +1 -0
- package/dist/dsl/workflow.mjs +120 -0
- package/dist/dsl/workflow.mjs.map +1 -0
- package/dist/engine/actions.cjs +27 -0
- package/dist/engine/actions.cjs.map +1 -0
- package/dist/engine/actions.d.cts +40 -0
- package/dist/engine/actions.d.cts.map +1 -0
- package/dist/engine/actions.d.mts +40 -0
- package/dist/engine/actions.d.mts.map +1 -0
- package/dist/engine/actions.mjs +26 -0
- package/dist/engine/actions.mjs.map +1 -0
- package/dist/engine/bucket.cjs +72 -0
- package/dist/engine/bucket.cjs.map +1 -0
- package/dist/engine/bucket.d.cts +32 -0
- package/dist/engine/bucket.d.cts.map +1 -0
- package/dist/engine/bucket.d.mts +32 -0
- package/dist/engine/bucket.d.mts.map +1 -0
- package/dist/engine/bucket.mjs +69 -0
- package/dist/engine/bucket.mjs.map +1 -0
- package/dist/engine/condition.cjs +166 -0
- package/dist/engine/condition.cjs.map +1 -0
- package/dist/engine/condition.d.cts +52 -0
- package/dist/engine/condition.d.cts.map +1 -0
- package/dist/engine/condition.d.mts +52 -0
- package/dist/engine/condition.d.mts.map +1 -0
- package/dist/engine/condition.mjs +161 -0
- package/dist/engine/condition.mjs.map +1 -0
- package/dist/engine/index.cjs +20 -0
- package/dist/engine/index.d.cts +8 -0
- package/dist/engine/index.d.mts +8 -0
- package/dist/engine/index.mjs +7 -0
- package/dist/engine/interpreter.cjs +428 -0
- package/dist/engine/interpreter.cjs.map +1 -0
- package/dist/engine/interpreter.d.cts +6 -0
- package/dist/engine/interpreter.d.cts.map +1 -0
- package/dist/engine/interpreter.d.mts +6 -0
- package/dist/engine/interpreter.d.mts.map +1 -0
- package/dist/engine/interpreter.mjs +427 -0
- package/dist/engine/interpreter.mjs.map +1 -0
- package/dist/engine/ports.cjs +0 -0
- package/dist/engine/ports.d.cts +252 -0
- package/dist/engine/ports.d.cts.map +1 -0
- package/dist/engine/ports.d.mts +252 -0
- package/dist/engine/ports.d.mts.map +1 -0
- package/dist/engine/ports.mjs +1 -0
- package/dist/engine/recipient.cjs +23 -0
- package/dist/engine/recipient.cjs.map +1 -0
- package/dist/engine/recipient.d.cts +13 -0
- package/dist/engine/recipient.d.cts.map +1 -0
- package/dist/engine/recipient.d.mts +13 -0
- package/dist/engine/recipient.d.mts.map +1 -0
- package/dist/engine/recipient.mjs +22 -0
- package/dist/engine/recipient.mjs.map +1 -0
- package/dist/engine/time-scale.cjs +54 -0
- package/dist/engine/time-scale.cjs.map +1 -0
- package/dist/engine/time-scale.d.cts +31 -0
- package/dist/engine/time-scale.d.cts.map +1 -0
- package/dist/engine/time-scale.d.mts +31 -0
- package/dist/engine/time-scale.d.mts.map +1 -0
- package/dist/engine/time-scale.mjs +52 -0
- package/dist/engine/time-scale.mjs.map +1 -0
- package/dist/engine/time-window.cjs +149 -0
- package/dist/engine/time-window.cjs.map +1 -0
- package/dist/engine/time-window.d.cts +22 -0
- package/dist/engine/time-window.d.cts.map +1 -0
- package/dist/engine/time-window.d.mts +22 -0
- package/dist/engine/time-window.d.mts.map +1 -0
- package/dist/engine/time-window.mjs +147 -0
- package/dist/engine/time-window.mjs.map +1 -0
- package/dist/fcm.cjs +125 -0
- package/dist/fcm.cjs.map +1 -0
- package/dist/fcm.d.cts +48 -0
- package/dist/fcm.d.cts.map +1 -0
- package/dist/fcm.d.mts +48 -0
- package/dist/fcm.d.mts.map +1 -0
- package/dist/fcm.mjs +121 -0
- package/dist/fcm.mjs.map +1 -0
- package/dist/hash.cjs +245 -0
- package/dist/hash.cjs.map +1 -0
- package/dist/hash.d.cts +30 -0
- package/dist/hash.d.cts.map +1 -0
- package/dist/hash.d.mts +30 -0
- package/dist/hash.d.mts.map +1 -0
- package/dist/hash.mjs +239 -0
- package/dist/hash.mjs.map +1 -0
- package/dist/index.cjs +100 -0
- package/dist/index.d.cts +18 -0
- package/dist/index.d.mts +18 -0
- package/dist/index.mjs +17 -0
- package/dist/ir.cjs +366 -0
- package/dist/ir.cjs.map +1 -0
- package/dist/ir.d.cts +486 -0
- package/dist/ir.d.cts.map +1 -0
- package/dist/ir.d.mts +486 -0
- package/dist/ir.d.mts.map +1 -0
- package/dist/ir.mjs +344 -0
- package/dist/ir.mjs.map +1 -0
- package/dist/jwt.cjs +22 -0
- package/dist/jwt.cjs.map +1 -0
- package/dist/jwt.d.cts +9 -0
- package/dist/jwt.d.cts.map +1 -0
- package/dist/jwt.d.mts +9 -0
- package/dist/jwt.d.mts.map +1 -0
- package/dist/jwt.mjs +20 -0
- package/dist/jwt.mjs.map +1 -0
- package/dist/plan.cjs +223 -0
- package/dist/plan.cjs.map +1 -0
- package/dist/plan.d.cts +68 -0
- package/dist/plan.d.cts.map +1 -0
- package/dist/plan.d.mts +68 -0
- package/dist/plan.d.mts.map +1 -0
- package/dist/plan.mjs +221 -0
- package/dist/plan.mjs.map +1 -0
- package/dist/postgres-js.cjs +42 -0
- package/dist/postgres-js.cjs.map +1 -0
- package/dist/postgres-js.d.cts +28 -0
- package/dist/postgres-js.d.cts.map +1 -0
- package/dist/postgres-js.d.mts +28 -0
- package/dist/postgres-js.d.mts.map +1 -0
- package/dist/postgres-js.mjs +38 -0
- package/dist/postgres-js.mjs.map +1 -0
- package/dist/provenance.cjs +67 -0
- package/dist/provenance.cjs.map +1 -0
- package/dist/provenance.d.cts +41 -0
- package/dist/provenance.d.cts.map +1 -0
- package/dist/provenance.d.mts +41 -0
- package/dist/provenance.d.mts.map +1 -0
- package/dist/provenance.mjs +65 -0
- package/dist/provenance.mjs.map +1 -0
- package/dist/push.cjs +14 -0
- package/dist/push.cjs.map +1 -0
- package/dist/push.d.cts +16 -0
- package/dist/push.d.cts.map +1 -0
- package/dist/push.d.mts +16 -0
- package/dist/push.d.mts.map +1 -0
- package/dist/push.mjs +13 -0
- package/dist/push.mjs.map +1 -0
- package/dist/react-email.cjs +48 -0
- package/dist/react-email.cjs.map +1 -0
- package/dist/react-email.d.cts +7 -0
- package/dist/react-email.d.cts.map +1 -0
- package/dist/react-email.d.mts +7 -0
- package/dist/react-email.d.mts.map +1 -0
- package/dist/react-email.mjs +47 -0
- package/dist/react-email.mjs.map +1 -0
- package/dist/reporting/classify.cjs +42 -0
- package/dist/reporting/classify.cjs.map +1 -0
- package/dist/reporting/classify.d.cts +60 -0
- package/dist/reporting/classify.d.cts.map +1 -0
- package/dist/reporting/classify.d.mts +60 -0
- package/dist/reporting/classify.d.mts.map +1 -0
- package/dist/reporting/classify.mjs +38 -0
- package/dist/reporting/classify.mjs.map +1 -0
- package/dist/reporting/observer.cjs +63 -0
- package/dist/reporting/observer.cjs.map +1 -0
- package/dist/reporting/observer.d.cts +18 -0
- package/dist/reporting/observer.d.cts.map +1 -0
- package/dist/reporting/observer.d.mts +18 -0
- package/dist/reporting/observer.d.mts.map +1 -0
- package/dist/reporting/observer.mjs +62 -0
- package/dist/reporting/observer.mjs.map +1 -0
- package/dist/reporting/tracking.cjs +153 -0
- package/dist/reporting/tracking.cjs.map +1 -0
- package/dist/reporting/tracking.d.cts +43 -0
- package/dist/reporting/tracking.d.cts.map +1 -0
- package/dist/reporting/tracking.d.mts +43 -0
- package/dist/reporting/tracking.d.mts.map +1 -0
- package/dist/reporting/tracking.mjs +151 -0
- package/dist/reporting/tracking.mjs.map +1 -0
- package/dist/runtime.cjs +19 -0
- package/dist/runtime.cjs.map +1 -0
- package/dist/runtime.d.cts +30 -0
- package/dist/runtime.d.cts.map +1 -0
- package/dist/runtime.d.mts +30 -0
- package/dist/runtime.d.mts.map +1 -0
- package/dist/runtime.mjs +18 -0
- package/dist/runtime.mjs.map +1 -0
- package/dist/store/d1.cjs +185 -0
- package/dist/store/d1.cjs.map +1 -0
- package/dist/store/d1.d.cts +55 -0
- package/dist/store/d1.d.cts.map +1 -0
- package/dist/store/d1.d.mts +55 -0
- package/dist/store/d1.d.mts.map +1 -0
- package/dist/store/d1.mjs +184 -0
- package/dist/store/d1.mjs.map +1 -0
- package/dist/store/facts.cjs +60 -0
- package/dist/store/facts.cjs.map +1 -0
- package/dist/store/facts.d.cts +38 -0
- package/dist/store/facts.d.cts.map +1 -0
- package/dist/store/facts.d.mts +38 -0
- package/dist/store/facts.d.mts.map +1 -0
- package/dist/store/facts.mjs +58 -0
- package/dist/store/facts.mjs.map +1 -0
- package/dist/store/index.cjs +31 -0
- package/dist/store/index.cjs.map +1 -0
- package/dist/store/index.d.cts +291 -0
- package/dist/store/index.d.cts.map +1 -0
- package/dist/store/index.d.mts +291 -0
- package/dist/store/index.d.mts.map +1 -0
- package/dist/store/index.mjs +22 -0
- package/dist/store/index.mjs.map +1 -0
- package/dist/store/postgres-reporting.cjs +213 -0
- package/dist/store/postgres-reporting.cjs.map +1 -0
- package/dist/store/postgres-reporting.d.cts +63 -0
- package/dist/store/postgres-reporting.d.cts.map +1 -0
- package/dist/store/postgres-reporting.d.mts +63 -0
- package/dist/store/postgres-reporting.d.mts.map +1 -0
- package/dist/store/postgres-reporting.mjs +212 -0
- package/dist/store/postgres-reporting.mjs.map +1 -0
- package/dist/store/postgres.cjs +309 -0
- package/dist/store/postgres.cjs.map +1 -0
- package/dist/store/postgres.d.cts +77 -0
- package/dist/store/postgres.d.cts.map +1 -0
- package/dist/store/postgres.d.mts +77 -0
- package/dist/store/postgres.d.mts.map +1 -0
- package/dist/store/postgres.mjs +306 -0
- package/dist/store/postgres.mjs.map +1 -0
- package/dist/store/sql.cjs +24 -0
- package/dist/store/sql.cjs.map +1 -0
- package/dist/store/sql.d.cts +25 -0
- package/dist/store/sql.d.cts.map +1 -0
- package/dist/store/sql.d.mts +25 -0
- package/dist/store/sql.d.mts.map +1 -0
- package/dist/store/sql.mjs +23 -0
- package/dist/store/sql.mjs.map +1 -0
- package/dist/store/tables.cjs +404 -0
- package/dist/store/tables.cjs.map +1 -0
- package/dist/store/tables.d.cts +81 -0
- package/dist/store/tables.d.cts.map +1 -0
- package/dist/store/tables.d.mts +81 -0
- package/dist/store/tables.d.mts.map +1 -0
- package/dist/store/tables.mjs +399 -0
- package/dist/store/tables.mjs.map +1 -0
- package/dist/templates.cjs +247 -0
- package/dist/templates.cjs.map +1 -0
- package/dist/templates.d.cts +187 -0
- package/dist/templates.d.cts.map +1 -0
- package/dist/templates.d.mts +187 -0
- package/dist/templates.d.mts.map +1 -0
- package/dist/templates.mjs +230 -0
- package/dist/templates.mjs.map +1 -0
- package/dist/webhooks.cjs +96 -0
- package/dist/webhooks.cjs.map +1 -0
- package/dist/webhooks.d.cts +25 -0
- package/dist/webhooks.d.cts.map +1 -0
- package/dist/webhooks.d.mts +25 -0
- package/dist/webhooks.d.mts.map +1 -0
- package/dist/webhooks.mjs +94 -0
- package/dist/webhooks.mjs.map +1 -0
- package/dist/webpush.cjs +180 -0
- package/dist/webpush.cjs.map +1 -0
- package/dist/webpush.d.cts +53 -0
- package/dist/webpush.d.cts.map +1 -0
- package/dist/webpush.d.mts +53 -0
- package/dist/webpush.d.mts.map +1 -0
- package/dist/webpush.mjs +175 -0
- package/dist/webpush.mjs.map +1 -0
- package/package.json +189 -3
- package/src/cloudflare/schema.sql +127 -0
- package/src/cloudflare/workers.d.ts +44 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contract.mjs","names":[],"sources":["../src/contract.ts"],"sourcesContent":["import * as z from 'zod/mini';\nimport type * as core from 'zod/v4/core';\nimport { type EventRefs, type UserRefs, event, user } from './dsl';\n\n/**\n * `defineContract({ events, profile })` — the producer/engine contract as Zod\n * schemas, written once in a package both sides import. From it:\n *\n * - `contract.events` / `contract.user` are the DSL's typed reference tables\n * (what `event<E>()` / `user<U>()` used to be, now derived from the schemas);\n * - `JourneyClient({ contract })` types `track` / `identify` by event name and\n * checks payloads before sending;\n * - `journeyWorker({ contract })` re-validates every inbound `/events` and\n * `/identify` — never trusting the caller used the SDK — and refuses a bad\n * one with a 4xx before anything is stored, woken or started.\n *\n * Supported schemas (v1), synchronous and JSON-shaped: event payloads are\n * object schemas (`z.looseObject` keeps a producer's extra analytics fields,\n * `z.strictObject` refuses them) and may nest objects and arrays; the profile\n * is a flat object of string / number / boolean / enum / literal fields. Input\n * and output must mean the same thing, so defaults, transforms, coercion,\n * custom refinements and async checks are refused when the contract is\n * defined. The Zod instances stay in the host; nothing here changes the IR.\n */\n\ntype ObjectSchema = core.$ZodObject;\n\n/** The declared fields of an object schema — without a loose object's `[key: string]: unknown`, so the DSL only offers fields that were written down. */\nexport type DeclaredOutput<S> =\n S extends core.$ZodObject<infer Shape>\n ? core.$InferObjectOutput<Shape, Record<never, never>>\n : never;\n\nexport interface ContractDefinition<\n E extends Record<string, ObjectSchema>,\n P extends ObjectSchema,\n> {\n events: E;\n profile: P;\n}\n\n/** One rejected field, with the dotted path the producer can fix. */\nexport interface ContractIssue {\n path: string;\n message: string;\n}\n\nexport type ContractResult<T> = { ok: true; data: T } | { ok: false; issues: ContractIssue[] };\n\nexport interface Contract<\n E extends Record<string, ObjectSchema> = Record<string, ObjectSchema>,\n P extends ObjectSchema = ObjectSchema,\n> {\n readonly kind: 'journey-contract';\n /** The DSL's event reference table: `e.purchase` — payload refs from the declared fields only. */\n readonly events: EventRefs<{ [K in keyof E]: DeclaredOutput<E[K]> }>;\n /** The DSL's user-property reference table: `u.name`, plus the system `u.userId`. */\n readonly user: UserRefs<DeclaredOutput<P> & { userId: string }>;\n /** The raw schemas, for hosts that need them (validation, docs). */\n readonly schemas: { readonly events: E; readonly profile: P };\n /** Every event name the contract declares — what a producer forwards. */\n readonly eventNames: readonly (keyof E & string)[];\n isEvent(name: string): name is keyof E & string;\n /** Validate one event's payload; the parsed value is what may be stored. */\n parseEvent<K extends keyof E & string>(\n name: K,\n payload: unknown\n ): ContractResult<core.output<E[K]>>;\n /**\n * Validate an `/identify` merge patch: omitted fields stay as they are,\n * `null` removes a field, every provided value is checked against its field\n * schema, and an undeclared field is refused — a patch, never a full parse\n * that would fill defaults over fields the caller did not send.\n */\n parseProfilePatch(patch: unknown): ContractResult<ProfilePatch<P>>;\n}\n\n/** An `/identify` patch over the profile: any subset of fields, `null` to remove one. */\nexport type ProfilePatch<P> = { [K in keyof DeclaredOutput<P>]?: DeclaredOutput<P>[K] | null };\n\n/** Payload type of one event, for producers: `EventPayload<typeof contract, 'purchase'>`. */\nexport type EventPayload<C, K extends string> =\n C extends Contract<infer E> ? (K extends keyof E ? core.input<E[K]> : never) : never;\n\nexport function defineContract<E extends Record<string, ObjectSchema>, P extends ObjectSchema>(\n definition: ContractDefinition<E, P>\n): Contract<E, P> {\n for (const [name, schema] of Object.entries(definition.events)) {\n if (name.startsWith('$')) {\n throw new TypeError(`contract event '${name}': names starting with $ are reserved`);\n }\n assertJsonSchema(schema, `event '${name}'`, true);\n }\n assertJsonSchema(definition.profile, 'profile', true);\n const profileShape = (definition.profile._zod.def as core.$ZodObjectDef).shape;\n for (const [field, schema] of Object.entries(profileShape)) {\n assertFlatScalar(schema, `profile.${field}`);\n }\n const strictProfile = definition.profile._zod.def.catchall?._zod.def.type === 'never';\n\n const names = Object.keys(definition.events) as (keyof E & string)[];\n return {\n kind: 'journey-contract',\n events: event() as never,\n user: user() as never,\n schemas: { events: definition.events, profile: definition.profile },\n eventNames: names,\n isEvent: (name): name is keyof E & string => Object.hasOwn(definition.events, name),\n parseEvent(name, payload) {\n if (!Object.hasOwn(definition.events, name)) {\n return { ok: false, issues: [{ path: '', message: `unknown event '${name}'` }] };\n }\n return toResult(z.safeParse(definition.events[name], payload));\n },\n parseProfilePatch(patch) {\n if (typeof patch !== 'object' || patch === null || Array.isArray(patch)) {\n return { ok: false, issues: [{ path: '', message: 'props must be an object' }] };\n }\n const issues: ContractIssue[] = [];\n const data: Record<string, unknown> = {};\n for (const [field, value] of Object.entries(patch)) {\n if (!Object.hasOwn(profileShape, field)) {\n // userId is the request's identity, not a profile field\n if (strictProfile || field === 'userId') {\n issues.push({ path: field, message: 'not a declared profile field' });\n } else {\n data[field] = value;\n }\n continue;\n }\n if (value === null) {\n data[field] = null;\n continue;\n }\n const result = z.safeParse(profileShape[field], value);\n if (result.success) data[field] = result.data;\n else issues.push(...prefixed(field, result.error));\n }\n return issues.length > 0 ? { ok: false, issues } : { ok: true, data: data as never };\n },\n };\n}\n\n/**\n * An event the contract refuses — raised for events a journey emits itself\n * (`.sendEvent()`), which never pass the HTTP ingest: they go through the same\n * check, and a refusal is deterministic, so it is not retried.\n */\nexport class ContractValidationError extends Error {\n override readonly name = 'ContractValidationError';\n constructor(\n readonly event: string,\n readonly issues: ContractIssue[]\n ) {\n super(\n `event '${event}' refused by the contract: ${issues\n .map((i) => `${i.path || '(root)'} ${i.message}`)\n .join('; ')}`\n );\n }\n}\n\n/** The one check every event passes, from HTTP or from a journey: declared, and its payload parses. */\nexport function checkEvent(\n contract: Contract,\n name: string,\n payload: unknown\n): ContractResult<Record<string, unknown>> {\n if (!contract.isEvent(name)) {\n return {\n ok: false,\n issues: [{ path: '', message: `'${String(name)}' is not in the contract` }],\n };\n }\n return contract.parseEvent(name, payload);\n}\n\nexport function isContract(value: unknown): value is Contract {\n return (\n typeof value === 'object' &&\n value !== null &&\n (value as { kind?: unknown }).kind === 'journey-contract'\n );\n}\n\nfunction toResult<T>(result: core.util.SafeParseResult<T>): ContractResult<T> {\n return result.success\n ? { ok: true, data: result.data }\n : { ok: false, issues: prefixed('', result.error) };\n}\n\nfunction prefixed(prefix: string, error: core.$ZodError): ContractIssue[] {\n return error.issues.map((issue) => ({\n path: [prefix, ...issue.path.map(String)].filter((p) => p !== '').join('.'),\n message: issue.message,\n }));\n}\n\n/* ---------------------------- supported schemas ---------------------------- */\n\n/**\n * The schema types a contract may use — JSON shapes that parse synchronously\n * and mean the same before and after parsing. Anything not listed (default,\n * transform, pipe, lazy, promise, custom, date, bigint, …) is refused, and\n * every container is walked so nothing unsupported hides inside one.\n */\nconst ALLOWED = new Set([\n 'object',\n 'array',\n 'tuple',\n 'union',\n 'intersection',\n 'record',\n 'optional',\n 'nullable',\n 'readonly',\n 'nonoptional',\n 'string',\n 'number',\n 'boolean',\n 'null',\n 'enum',\n 'literal',\n 'unknown',\n 'any',\n 'never',\n]);\n\n/** Checks that change the value (`overwrite`: `.trim()`, `.toLowerCase()`, …) or run arbitrary code (`custom`: `.refine()`, async or not). */\nconst REFUSED_CHECKS = new Set(['custom', 'overwrite']);\n\nfunction assertJsonSchema(schema: unknown, where: string, top = false): void {\n const def = (schema as core.$ZodType | undefined)?._zod?.def;\n if (def === undefined) throw new TypeError(`contract ${where}: not a Zod schema`);\n if (top && def.type !== 'object') {\n throw new TypeError(\n `contract ${where}: must be an object schema (z.looseObject / z.strictObject)`\n );\n }\n if (!ALLOWED.has(def.type)) {\n throw new TypeError(\n `contract ${where}: ${def.type} schemas are not supported (input and output must mean the same JSON, parsed synchronously)`\n );\n }\n if ((def as { coerce?: boolean }).coerce === true) {\n throw new TypeError(`contract ${where}: coercion (z.coerce) is not supported`);\n }\n for (const check of def.checks ?? []) {\n if (REFUSED_CHECKS.has(check._zod.def.check)) {\n throw new TypeError(\n `contract ${where}: ${check._zod.def.check === 'overwrite' ? 'value-changing checks (.overwrite, .trim, …)' : 'custom refinements'} are not supported`\n );\n }\n }\n const children: [string, unknown][] = [];\n switch (def.type) {\n case 'object': {\n const object = def as core.$ZodObjectDef;\n for (const [k, v] of Object.entries(object.shape)) children.push([`${where}.${k}`, v]);\n if (object.catchall !== undefined) children.push([`${where}.*`, object.catchall]);\n break;\n }\n case 'optional':\n case 'nullable':\n case 'readonly':\n case 'nonoptional':\n children.push([where, (def as unknown as { innerType: unknown }).innerType]);\n break;\n case 'array':\n children.push([`${where}[]`, (def as core.$ZodArrayDef).element]);\n break;\n case 'tuple': {\n const tuple = def as core.$ZodTupleDef;\n tuple.items.forEach((item, index) => children.push([`${where}[${index}]`, item]));\n if (tuple.rest !== null) children.push([`${where}[…]`, tuple.rest]);\n break;\n }\n case 'union':\n for (const option of (def as core.$ZodUnionDef).options) children.push([where, option]);\n break;\n case 'intersection': {\n const intersection = def as core.$ZodIntersectionDef;\n children.push([where, intersection.left], [where, intersection.right]);\n break;\n }\n case 'record': {\n const record = def as core.$ZodRecordDef;\n children.push([`${where}{key}`, record.keyType], [`${where}{}`, record.valueType]);\n break;\n }\n default:\n break;\n }\n for (const [path, child] of children) assertJsonSchema(child, path);\n}\n\nconst SCALARS = new Set(['string', 'number', 'boolean', 'enum', 'literal']);\n\nfunction assertFlatScalar(schema: unknown, where: string): void {\n let def = (schema as core.$ZodType)._zod.def;\n if (def.type === 'optional') def = (def as core.$ZodOptionalDef).innerType._zod.def;\n if (!SCALARS.has(def.type)) {\n throw new TypeError(\n `contract ${where}: profile fields must be flat scalars (string, number, boolean, enum, literal), got ${def.type}`\n );\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
const require_hash = require("../hash.cjs");
|
|
3
|
+
//#region src/dsl/action.ts
|
|
4
|
+
/**
|
|
5
|
+
* Define a custom action. The generic `A` types the args `.run()` accepts —
|
|
6
|
+
* the only type injection point, mirroring `template.email<P>()`:
|
|
7
|
+
*
|
|
8
|
+
* const syncCrm = action<{ plan: string }>('sync_crm', async ({ plan }, { userId }) => {
|
|
9
|
+
* await fetch('https://crm.example.com/sync', { method: 'POST', body: JSON.stringify({ userId, plan }) });
|
|
10
|
+
* });
|
|
11
|
+
*
|
|
12
|
+
* workflow(...).run(syncCrm, { plan: u.subscription_plan })
|
|
13
|
+
*
|
|
14
|
+
* codeHash comes from `handler.toString()`, so it changes when the code
|
|
15
|
+
* changes and stays put when it does not. Different build pipelines can print
|
|
16
|
+
* the same function differently (minification), which is why the default
|
|
17
|
+
* runtime policy on mismatch is warn, not fail.
|
|
18
|
+
*/
|
|
19
|
+
function action(name, handler) {
|
|
20
|
+
return {
|
|
21
|
+
name,
|
|
22
|
+
codeHash: require_hash.sha256Hex(handler.toString()).slice(0, 32),
|
|
23
|
+
handler
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
//#endregion
|
|
27
|
+
exports.action = action;
|
|
28
|
+
|
|
29
|
+
//# sourceMappingURL=action.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"action.cjs","names":["sha256Hex"],"sources":["../../src/dsl/action.ts"],"sourcesContent":["import { sha256Hex } from '../hash';\n\n/**\n * Custom actions — the escape hatch for side effects the built-in nodes do not\n * cover (CRM sync, coupon issuing, outbound webhooks with custom auth, …).\n *\n * Dual-plane model: the *code* solidifies into the Worker bundle at deploy\n * time (it ships with the app, like any other module), while the *identity*\n * solidifies into IR as `{ type: 'action', action: name, args, codeHash }`.\n * The runtime resolves the name against a registry (see engine/actions.ts) and\n * compares codeHash to detect version skew between a pinned IR and the\n * currently deployed implementation.\n *\n * Deliberately NOT supported: custom *conditions*. Branching stays declarative\n * so the canvas can always explain why a user took a path — an action that\n * needs to influence routing writes a property or emits an event, and the\n * decision is expressed as a normal predicate on that data.\n */\n\n/** Runtime context handed to the handler; deliberately small — facts and messaging have their own nodes. */\nexport interface ActionContext {\n userId: string;\n /**\n * `${instanceId}:${nodeId}` — stable across replays and retries of this one\n * action node. A handler with an external side effect (charging, issuing,\n * POSTing) must pass it along so the far side collapses the duplicate: the\n * step body can re-run after the handler already resolved.\n */\n idempotencyKey: string;\n}\n\n/**\n * The handler: plain code, executed inside a durable step (`step.do`), so a\n * throw is retried by the runtime and a success is checkpointed — it should be\n * idempotent under retry, which is what `ctx.idempotencyKey` is for. Args\n * arrive with user_property references already resolved to values.\n */\nexport type ActionHandler<A extends object> = (args: A, ctx: ActionContext) => Promise<void> | void;\n\n/**\n * A registered custom action: the named asset `.run()` refers to. Carries the\n * implementation for the runtime registry and the codeHash for the IR pin.\n */\nexport interface ActionRef<A extends object = Record<never, never>> {\n readonly name: string;\n /** Hash of the handler's source text at definition time — the code-identity pin recorded in IR. */\n readonly codeHash: string;\n /** Method syntax on purpose: bivariant args let refs with different arg shapes share one list (compileBundle, registries). */\n handler(args: A, ctx: ActionContext): Promise<void> | void;\n}\n\n/**\n * Define a custom action. The generic `A` types the args `.run()` accepts —\n * the only type injection point, mirroring `template.email<P>()`:\n *\n * const syncCrm = action<{ plan: string }>('sync_crm', async ({ plan }, { userId }) => {\n * await fetch('https://crm.example.com/sync', { method: 'POST', body: JSON.stringify({ userId, plan }) });\n * });\n *\n * workflow(...).run(syncCrm, { plan: u.subscription_plan })\n *\n * codeHash comes from `handler.toString()`, so it changes when the code\n * changes and stays put when it does not. Different build pipelines can print\n * the same function differently (minification), which is why the default\n * runtime policy on mismatch is warn, not fail.\n */\nexport function action<A extends object = Record<never, never>>(\n name: string,\n handler: ActionHandler<A>\n): ActionRef<A> {\n return { name, codeHash: sha256Hex(handler.toString()).slice(0, 32), handler };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAkEA,SAAgB,OACd,MACA,SACc;CACd,OAAO;EAAE;EAAM,UAAUA,aAAAA,UAAU,QAAQ,SAAS,CAAC,CAAC,CAAC,MAAM,GAAG,EAAE;EAAG;CAAQ;AAC/E"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
//#region src/dsl/action.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Custom actions — the escape hatch for side effects the built-in nodes do not
|
|
4
|
+
* cover (CRM sync, coupon issuing, outbound webhooks with custom auth, …).
|
|
5
|
+
*
|
|
6
|
+
* Dual-plane model: the *code* solidifies into the Worker bundle at deploy
|
|
7
|
+
* time (it ships with the app, like any other module), while the *identity*
|
|
8
|
+
* solidifies into IR as `{ type: 'action', action: name, args, codeHash }`.
|
|
9
|
+
* The runtime resolves the name against a registry (see engine/actions.ts) and
|
|
10
|
+
* compares codeHash to detect version skew between a pinned IR and the
|
|
11
|
+
* currently deployed implementation.
|
|
12
|
+
*
|
|
13
|
+
* Deliberately NOT supported: custom *conditions*. Branching stays declarative
|
|
14
|
+
* so the canvas can always explain why a user took a path — an action that
|
|
15
|
+
* needs to influence routing writes a property or emits an event, and the
|
|
16
|
+
* decision is expressed as a normal predicate on that data.
|
|
17
|
+
*/
|
|
18
|
+
/** Runtime context handed to the handler; deliberately small — facts and messaging have their own nodes. */
|
|
19
|
+
export interface ActionContext {
|
|
20
|
+
userId: string;
|
|
21
|
+
/**
|
|
22
|
+
* `${instanceId}:${nodeId}` — stable across replays and retries of this one
|
|
23
|
+
* action node. A handler with an external side effect (charging, issuing,
|
|
24
|
+
* POSTing) must pass it along so the far side collapses the duplicate: the
|
|
25
|
+
* step body can re-run after the handler already resolved.
|
|
26
|
+
*/
|
|
27
|
+
idempotencyKey: string;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* The handler: plain code, executed inside a durable step (`step.do`), so a
|
|
31
|
+
* throw is retried by the runtime and a success is checkpointed — it should be
|
|
32
|
+
* idempotent under retry, which is what `ctx.idempotencyKey` is for. Args
|
|
33
|
+
* arrive with user_property references already resolved to values.
|
|
34
|
+
*/
|
|
35
|
+
export type ActionHandler<A extends object> = (args: A, ctx: ActionContext) => Promise<void> | void;
|
|
36
|
+
/**
|
|
37
|
+
* A registered custom action: the named asset `.run()` refers to. Carries the
|
|
38
|
+
* implementation for the runtime registry and the codeHash for the IR pin.
|
|
39
|
+
*/
|
|
40
|
+
export interface ActionRef<A extends object = Record<never, never>> {
|
|
41
|
+
readonly name: string;
|
|
42
|
+
/** Hash of the handler's source text at definition time — the code-identity pin recorded in IR. */
|
|
43
|
+
readonly codeHash: string;
|
|
44
|
+
/** Method syntax on purpose: bivariant args let refs with different arg shapes share one list (compileBundle, registries). */
|
|
45
|
+
handler(args: A, ctx: ActionContext): Promise<void> | void;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Define a custom action. The generic `A` types the args `.run()` accepts —
|
|
49
|
+
* the only type injection point, mirroring `template.email<P>()`:
|
|
50
|
+
*
|
|
51
|
+
* const syncCrm = action<{ plan: string }>('sync_crm', async ({ plan }, { userId }) => {
|
|
52
|
+
* await fetch('https://crm.example.com/sync', { method: 'POST', body: JSON.stringify({ userId, plan }) });
|
|
53
|
+
* });
|
|
54
|
+
*
|
|
55
|
+
* workflow(...).run(syncCrm, { plan: u.subscription_plan })
|
|
56
|
+
*
|
|
57
|
+
* codeHash comes from `handler.toString()`, so it changes when the code
|
|
58
|
+
* changes and stays put when it does not. Different build pipelines can print
|
|
59
|
+
* the same function differently (minification), which is why the default
|
|
60
|
+
* runtime policy on mismatch is warn, not fail.
|
|
61
|
+
*/
|
|
62
|
+
export declare function action<A extends object = Record<never, never>>(name: string, handler: ActionHandler<A>): ActionRef<A>;
|
|
63
|
+
//#endregion
|
|
64
|
+
//# sourceMappingURL=action.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"action.d.cts","names":[],"sources":["../../src/dsl/action.ts"],"mappings":";;;;;;;;;;;;;;;;;;iBAoBiB;EACf;;;;;;;EAOA;;;;;;;;YASU,cAAc,qBAAqB,MAAM,GAAG,KAAK,kBAAkB;;;;;iBAM9D,UAAU,mBAAmB;WACnC;;WAEA;;EAET,QAAQ,MAAM,GAAG,KAAK,gBAAgB;;;;;;;;;;;;;;;;;wBAkBxB,OAAO,mBAAmB,sBACxC,cACA,SAAS,cAAc,KACtB,UAAU"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
//#region src/dsl/action.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Custom actions — the escape hatch for side effects the built-in nodes do not
|
|
4
|
+
* cover (CRM sync, coupon issuing, outbound webhooks with custom auth, …).
|
|
5
|
+
*
|
|
6
|
+
* Dual-plane model: the *code* solidifies into the Worker bundle at deploy
|
|
7
|
+
* time (it ships with the app, like any other module), while the *identity*
|
|
8
|
+
* solidifies into IR as `{ type: 'action', action: name, args, codeHash }`.
|
|
9
|
+
* The runtime resolves the name against a registry (see engine/actions.ts) and
|
|
10
|
+
* compares codeHash to detect version skew between a pinned IR and the
|
|
11
|
+
* currently deployed implementation.
|
|
12
|
+
*
|
|
13
|
+
* Deliberately NOT supported: custom *conditions*. Branching stays declarative
|
|
14
|
+
* so the canvas can always explain why a user took a path — an action that
|
|
15
|
+
* needs to influence routing writes a property or emits an event, and the
|
|
16
|
+
* decision is expressed as a normal predicate on that data.
|
|
17
|
+
*/
|
|
18
|
+
/** Runtime context handed to the handler; deliberately small — facts and messaging have their own nodes. */
|
|
19
|
+
export interface ActionContext {
|
|
20
|
+
userId: string;
|
|
21
|
+
/**
|
|
22
|
+
* `${instanceId}:${nodeId}` — stable across replays and retries of this one
|
|
23
|
+
* action node. A handler with an external side effect (charging, issuing,
|
|
24
|
+
* POSTing) must pass it along so the far side collapses the duplicate: the
|
|
25
|
+
* step body can re-run after the handler already resolved.
|
|
26
|
+
*/
|
|
27
|
+
idempotencyKey: string;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* The handler: plain code, executed inside a durable step (`step.do`), so a
|
|
31
|
+
* throw is retried by the runtime and a success is checkpointed — it should be
|
|
32
|
+
* idempotent under retry, which is what `ctx.idempotencyKey` is for. Args
|
|
33
|
+
* arrive with user_property references already resolved to values.
|
|
34
|
+
*/
|
|
35
|
+
export type ActionHandler<A extends object> = (args: A, ctx: ActionContext) => Promise<void> | void;
|
|
36
|
+
/**
|
|
37
|
+
* A registered custom action: the named asset `.run()` refers to. Carries the
|
|
38
|
+
* implementation for the runtime registry and the codeHash for the IR pin.
|
|
39
|
+
*/
|
|
40
|
+
export interface ActionRef<A extends object = Record<never, never>> {
|
|
41
|
+
readonly name: string;
|
|
42
|
+
/** Hash of the handler's source text at definition time — the code-identity pin recorded in IR. */
|
|
43
|
+
readonly codeHash: string;
|
|
44
|
+
/** Method syntax on purpose: bivariant args let refs with different arg shapes share one list (compileBundle, registries). */
|
|
45
|
+
handler(args: A, ctx: ActionContext): Promise<void> | void;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Define a custom action. The generic `A` types the args `.run()` accepts —
|
|
49
|
+
* the only type injection point, mirroring `template.email<P>()`:
|
|
50
|
+
*
|
|
51
|
+
* const syncCrm = action<{ plan: string }>('sync_crm', async ({ plan }, { userId }) => {
|
|
52
|
+
* await fetch('https://crm.example.com/sync', { method: 'POST', body: JSON.stringify({ userId, plan }) });
|
|
53
|
+
* });
|
|
54
|
+
*
|
|
55
|
+
* workflow(...).run(syncCrm, { plan: u.subscription_plan })
|
|
56
|
+
*
|
|
57
|
+
* codeHash comes from `handler.toString()`, so it changes when the code
|
|
58
|
+
* changes and stays put when it does not. Different build pipelines can print
|
|
59
|
+
* the same function differently (minification), which is why the default
|
|
60
|
+
* runtime policy on mismatch is warn, not fail.
|
|
61
|
+
*/
|
|
62
|
+
export declare function action<A extends object = Record<never, never>>(name: string, handler: ActionHandler<A>): ActionRef<A>;
|
|
63
|
+
//#endregion
|
|
64
|
+
//# sourceMappingURL=action.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"action.d.mts","names":[],"sources":["../../src/dsl/action.ts"],"mappings":";;;;;;;;;;;;;;;;;;iBAoBiB;EACf;;;;;;;EAOA;;;;;;;;YASU,cAAc,qBAAqB,MAAM,GAAG,KAAK,kBAAkB;;;;;iBAM9D,UAAU,mBAAmB;WACnC;;WAEA;;EAET,QAAQ,MAAM,GAAG,KAAK,gBAAgB;;;;;;;;;;;;;;;;;wBAkBxB,OAAO,mBAAmB,sBACxC,cACA,SAAS,cAAc,KACtB,UAAU"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { sha256Hex } from "../hash.mjs";
|
|
2
|
+
//#region src/dsl/action.ts
|
|
3
|
+
/**
|
|
4
|
+
* Define a custom action. The generic `A` types the args `.run()` accepts —
|
|
5
|
+
* the only type injection point, mirroring `template.email<P>()`:
|
|
6
|
+
*
|
|
7
|
+
* const syncCrm = action<{ plan: string }>('sync_crm', async ({ plan }, { userId }) => {
|
|
8
|
+
* await fetch('https://crm.example.com/sync', { method: 'POST', body: JSON.stringify({ userId, plan }) });
|
|
9
|
+
* });
|
|
10
|
+
*
|
|
11
|
+
* workflow(...).run(syncCrm, { plan: u.subscription_plan })
|
|
12
|
+
*
|
|
13
|
+
* codeHash comes from `handler.toString()`, so it changes when the code
|
|
14
|
+
* changes and stays put when it does not. Different build pipelines can print
|
|
15
|
+
* the same function differently (minification), which is why the default
|
|
16
|
+
* runtime policy on mismatch is warn, not fail.
|
|
17
|
+
*/
|
|
18
|
+
function action(name, handler) {
|
|
19
|
+
return {
|
|
20
|
+
name,
|
|
21
|
+
codeHash: sha256Hex(handler.toString()).slice(0, 32),
|
|
22
|
+
handler
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
//#endregion
|
|
26
|
+
export { action };
|
|
27
|
+
|
|
28
|
+
//# sourceMappingURL=action.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"action.mjs","names":[],"sources":["../../src/dsl/action.ts"],"sourcesContent":["import { sha256Hex } from '../hash';\n\n/**\n * Custom actions — the escape hatch for side effects the built-in nodes do not\n * cover (CRM sync, coupon issuing, outbound webhooks with custom auth, …).\n *\n * Dual-plane model: the *code* solidifies into the Worker bundle at deploy\n * time (it ships with the app, like any other module), while the *identity*\n * solidifies into IR as `{ type: 'action', action: name, args, codeHash }`.\n * The runtime resolves the name against a registry (see engine/actions.ts) and\n * compares codeHash to detect version skew between a pinned IR and the\n * currently deployed implementation.\n *\n * Deliberately NOT supported: custom *conditions*. Branching stays declarative\n * so the canvas can always explain why a user took a path — an action that\n * needs to influence routing writes a property or emits an event, and the\n * decision is expressed as a normal predicate on that data.\n */\n\n/** Runtime context handed to the handler; deliberately small — facts and messaging have their own nodes. */\nexport interface ActionContext {\n userId: string;\n /**\n * `${instanceId}:${nodeId}` — stable across replays and retries of this one\n * action node. A handler with an external side effect (charging, issuing,\n * POSTing) must pass it along so the far side collapses the duplicate: the\n * step body can re-run after the handler already resolved.\n */\n idempotencyKey: string;\n}\n\n/**\n * The handler: plain code, executed inside a durable step (`step.do`), so a\n * throw is retried by the runtime and a success is checkpointed — it should be\n * idempotent under retry, which is what `ctx.idempotencyKey` is for. Args\n * arrive with user_property references already resolved to values.\n */\nexport type ActionHandler<A extends object> = (args: A, ctx: ActionContext) => Promise<void> | void;\n\n/**\n * A registered custom action: the named asset `.run()` refers to. Carries the\n * implementation for the runtime registry and the codeHash for the IR pin.\n */\nexport interface ActionRef<A extends object = Record<never, never>> {\n readonly name: string;\n /** Hash of the handler's source text at definition time — the code-identity pin recorded in IR. */\n readonly codeHash: string;\n /** Method syntax on purpose: bivariant args let refs with different arg shapes share one list (compileBundle, registries). */\n handler(args: A, ctx: ActionContext): Promise<void> | void;\n}\n\n/**\n * Define a custom action. The generic `A` types the args `.run()` accepts —\n * the only type injection point, mirroring `template.email<P>()`:\n *\n * const syncCrm = action<{ plan: string }>('sync_crm', async ({ plan }, { userId }) => {\n * await fetch('https://crm.example.com/sync', { method: 'POST', body: JSON.stringify({ userId, plan }) });\n * });\n *\n * workflow(...).run(syncCrm, { plan: u.subscription_plan })\n *\n * codeHash comes from `handler.toString()`, so it changes when the code\n * changes and stays put when it does not. Different build pipelines can print\n * the same function differently (minification), which is why the default\n * runtime policy on mismatch is warn, not fail.\n */\nexport function action<A extends object = Record<never, never>>(\n name: string,\n handler: ActionHandler<A>\n): ActionRef<A> {\n return { name, codeHash: sha256Hex(handler.toString()).slice(0, 32), handler };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAkEA,SAAgB,OACd,MACA,SACc;CACd,OAAO;EAAE;EAAM,UAAU,UAAU,QAAQ,SAAS,CAAC,CAAC,CAAC,MAAM,GAAG,EAAE;EAAG;CAAQ;AAC/E"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
const require_runtime = require("../_virtual/_rolldown/runtime.cjs");
|
|
3
|
+
let ms = require("ms");
|
|
4
|
+
ms = require_runtime.__toESM(ms, 1);
|
|
5
|
+
//#region src/dsl/base.ts
|
|
6
|
+
const TIME_OF_DAY = /^([01]\d|2[0-3]):([0-5]\d)$/;
|
|
7
|
+
/**
|
|
8
|
+
* Parse an 'HH:mm' literal to minutes since midnight, throwing on anything the
|
|
9
|
+
* type let through ('9:00', '25:00', 'ab:cd').
|
|
10
|
+
* @internal shared by flow builders, not part of the public API
|
|
11
|
+
*/
|
|
12
|
+
function timeOfDayMinutes(value) {
|
|
13
|
+
const match = TIME_OF_DAY.exec(value);
|
|
14
|
+
if (!match) throw new Error(`Invalid time of day: '${value}' (expected 'HH:mm', e.g. '09:00')`);
|
|
15
|
+
return Number(match[1]) * 60 + Number(match[2]);
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Duration parsing delegates to `ms` (typed StringValue); Duration is it's
|
|
19
|
+
* stricter, full-word subset.
|
|
20
|
+
* @internal shared by condition/flow/workflow, not part of the public API
|
|
21
|
+
*/
|
|
22
|
+
function durationIR(value) {
|
|
23
|
+
const millis = (0, ms.default)(value);
|
|
24
|
+
if (typeof millis !== "number" || Number.isNaN(millis) || millis < 0) throw new Error(`Invalid duration: '${value}'`);
|
|
25
|
+
return {
|
|
26
|
+
value,
|
|
27
|
+
ms: millis
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
//#endregion
|
|
31
|
+
exports.durationIR = durationIR;
|
|
32
|
+
exports.timeOfDayMinutes = timeOfDayMinutes;
|
|
33
|
+
|
|
34
|
+
//# sourceMappingURL=base.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base.cjs","names":[],"sources":["../../src/dsl/base.ts"],"sourcesContent":["import ms from 'ms';\nimport type { DurationIR } from '../ir';\n\n/**\n * Base vocabulary shared by the whole DSL: the schema constraints an app's\n * types must satisfy, and the literal types (durations, weekdays, clock times)\n * the builder methods accept.\n *\n * Type technique: `Duration` is a template-literal union — '1 huor' is a\n * compile error, no runtime validation needed for the common case.\n */\n\n/**\n * Event name → payload shape, supplied by the app (its analytics schema).\n * Constrained to `object` rather than `Record`: interfaces have no implicit\n * index signature, so a Record constraint would reject an interface-defined\n * schema. Event names come from `keyof E`, payloads from `E[N]`.\n */\nexport type EventMap = object;\n\n/**\n * Base shape of user properties; the app extends it with concrete fields.\n * `email` is optional: a profile can exist before (or without) an address,\n * and an email step refuses to send when the recipient is missing.\n */\nexport interface UserPropertyBase {\n userId: string;\n email?: string;\n}\n\n/** Duration literal: '1 hour' / '23 hours' / '30 days' — typos fail to compile. */\nexport type Duration = `${number} ${\n | 'second'\n | 'seconds'\n | 'minute'\n | 'minutes'\n | 'hour'\n | 'hours'\n | 'day'\n | 'days'\n | 'week'\n | 'weeks'}`;\n\nexport type Weekday = 'mon' | 'tue' | 'wed' | 'thu' | 'fri' | 'sat' | 'sun';\n\n/** 'HH:mm' (24h, leading zeros). The type cannot express digit ranges, so builders validate at runtime via timeOfDayMinutes. */\nexport type TimeOfDay = `${string}:${string}`;\n\nconst TIME_OF_DAY = /^([01]\\d|2[0-3]):([0-5]\\d)$/;\n\n/**\n * Parse an 'HH:mm' literal to minutes since midnight, throwing on anything the\n * type let through ('9:00', '25:00', 'ab:cd').\n * @internal shared by flow builders, not part of the public API\n */\nexport function timeOfDayMinutes(value: TimeOfDay): number {\n const match = TIME_OF_DAY.exec(value);\n if (!match) throw new Error(`Invalid time of day: '${value}' (expected 'HH:mm', e.g. '09:00')`);\n return Number(match[1]) * 60 + Number(match[2]);\n}\n\n/**\n * Duration parsing delegates to `ms` (typed StringValue); Duration is it's\n * stricter, full-word subset.\n * @internal shared by condition/flow/workflow, not part of the public API\n */\nexport function durationIR(value: Duration): DurationIR {\n const millis = ms(value);\n if (typeof millis !== 'number' || Number.isNaN(millis) || millis < 0) {\n throw new Error(`Invalid duration: '${value}'`);\n }\n return { value, ms: millis };\n}\n"],"mappings":";;;;;AAgDA,MAAM,cAAc;;;;;;AAOpB,SAAgB,iBAAiB,OAA0B;CACzD,MAAM,QAAQ,YAAY,KAAK,KAAK;CACpC,IAAI,CAAC,OAAO,MAAM,IAAI,MAAM,yBAAyB,MAAM,mCAAmC;CAC9F,OAAO,OAAO,MAAM,EAAE,IAAI,KAAK,OAAO,MAAM,EAAE;AAChD;;;;;;AAOA,SAAgB,WAAW,OAA6B;CACtD,MAAM,UAAA,GAAS,GAAA,QAAA,CAAG,KAAK;CACvB,IAAI,OAAO,WAAW,YAAY,OAAO,MAAM,MAAM,KAAK,SAAS,GACjE,MAAM,IAAI,MAAM,sBAAsB,MAAM,EAAE;CAEhD,OAAO;EAAE;EAAO,IAAI;CAAO;AAC7B"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { DurationIR } from "../ir.cjs";
|
|
2
|
+
//#region src/dsl/base.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* Base vocabulary shared by the whole DSL: the schema constraints an app's
|
|
5
|
+
* types must satisfy, and the literal types (durations, weekdays, clock times)
|
|
6
|
+
* the builder methods accept.
|
|
7
|
+
*
|
|
8
|
+
* Type technique: `Duration` is a template-literal union — '1 huor' is a
|
|
9
|
+
* compile error, no runtime validation needed for the common case.
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Event name → payload shape, supplied by the app (its analytics schema).
|
|
13
|
+
* Constrained to `object` rather than `Record`: interfaces have no implicit
|
|
14
|
+
* index signature, so a Record constraint would reject an interface-defined
|
|
15
|
+
* schema. Event names come from `keyof E`, payloads from `E[N]`.
|
|
16
|
+
*/
|
|
17
|
+
export type EventMap = object;
|
|
18
|
+
/**
|
|
19
|
+
* Base shape of user properties; the app extends it with concrete fields.
|
|
20
|
+
* `email` is optional: a profile can exist before (or without) an address,
|
|
21
|
+
* and an email step refuses to send when the recipient is missing.
|
|
22
|
+
*/
|
|
23
|
+
export interface UserPropertyBase {
|
|
24
|
+
userId: string;
|
|
25
|
+
email?: string;
|
|
26
|
+
}
|
|
27
|
+
/** Duration literal: '1 hour' / '23 hours' / '30 days' — typos fail to compile. */
|
|
28
|
+
export type Duration = `${number} ${'second' | 'seconds' | 'minute' | 'minutes' | 'hour' | 'hours' | 'day' | 'days' | 'week' | 'weeks'}`;
|
|
29
|
+
export type Weekday = 'mon' | 'tue' | 'wed' | 'thu' | 'fri' | 'sat' | 'sun';
|
|
30
|
+
/** 'HH:mm' (24h, leading zeros). The type cannot express digit ranges, so builders validate at runtime via timeOfDayMinutes. */
|
|
31
|
+
export type TimeOfDay = `${string}:${string}`;
|
|
32
|
+
/**
|
|
33
|
+
* Parse an 'HH:mm' literal to minutes since midnight, throwing on anything the
|
|
34
|
+
* type let through ('9:00', '25:00', 'ab:cd').
|
|
35
|
+
* @internal shared by flow builders, not part of the public API
|
|
36
|
+
*/
|
|
37
|
+
export declare function timeOfDayMinutes(value: TimeOfDay): number;
|
|
38
|
+
/**
|
|
39
|
+
* Duration parsing delegates to `ms` (typed StringValue); Duration is it's
|
|
40
|
+
* stricter, full-word subset.
|
|
41
|
+
* @internal shared by condition/flow/workflow, not part of the public API
|
|
42
|
+
*/
|
|
43
|
+
export declare function durationIR(value: Duration): DurationIR;
|
|
44
|
+
//#endregion
|
|
45
|
+
//# sourceMappingURL=base.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base.d.cts","names":[],"sources":["../../src/dsl/base.ts"],"mappings":";;;;;;;;;;;;;;;;YAkBY;;;;;;iBAOK;EACf;EACA;;;YAIU;YAYA;;YAGA;;;;;;wBASI,iBAAiB,OAAO;;;;;;wBAWxB,WAAW,OAAO,WAAW"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { DurationIR } from "../ir.mjs";
|
|
2
|
+
//#region src/dsl/base.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* Base vocabulary shared by the whole DSL: the schema constraints an app's
|
|
5
|
+
* types must satisfy, and the literal types (durations, weekdays, clock times)
|
|
6
|
+
* the builder methods accept.
|
|
7
|
+
*
|
|
8
|
+
* Type technique: `Duration` is a template-literal union — '1 huor' is a
|
|
9
|
+
* compile error, no runtime validation needed for the common case.
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Event name → payload shape, supplied by the app (its analytics schema).
|
|
13
|
+
* Constrained to `object` rather than `Record`: interfaces have no implicit
|
|
14
|
+
* index signature, so a Record constraint would reject an interface-defined
|
|
15
|
+
* schema. Event names come from `keyof E`, payloads from `E[N]`.
|
|
16
|
+
*/
|
|
17
|
+
export type EventMap = object;
|
|
18
|
+
/**
|
|
19
|
+
* Base shape of user properties; the app extends it with concrete fields.
|
|
20
|
+
* `email` is optional: a profile can exist before (or without) an address,
|
|
21
|
+
* and an email step refuses to send when the recipient is missing.
|
|
22
|
+
*/
|
|
23
|
+
export interface UserPropertyBase {
|
|
24
|
+
userId: string;
|
|
25
|
+
email?: string;
|
|
26
|
+
}
|
|
27
|
+
/** Duration literal: '1 hour' / '23 hours' / '30 days' — typos fail to compile. */
|
|
28
|
+
export type Duration = `${number} ${'second' | 'seconds' | 'minute' | 'minutes' | 'hour' | 'hours' | 'day' | 'days' | 'week' | 'weeks'}`;
|
|
29
|
+
export type Weekday = 'mon' | 'tue' | 'wed' | 'thu' | 'fri' | 'sat' | 'sun';
|
|
30
|
+
/** 'HH:mm' (24h, leading zeros). The type cannot express digit ranges, so builders validate at runtime via timeOfDayMinutes. */
|
|
31
|
+
export type TimeOfDay = `${string}:${string}`;
|
|
32
|
+
/**
|
|
33
|
+
* Parse an 'HH:mm' literal to minutes since midnight, throwing on anything the
|
|
34
|
+
* type let through ('9:00', '25:00', 'ab:cd').
|
|
35
|
+
* @internal shared by flow builders, not part of the public API
|
|
36
|
+
*/
|
|
37
|
+
export declare function timeOfDayMinutes(value: TimeOfDay): number;
|
|
38
|
+
/**
|
|
39
|
+
* Duration parsing delegates to `ms` (typed StringValue); Duration is it's
|
|
40
|
+
* stricter, full-word subset.
|
|
41
|
+
* @internal shared by condition/flow/workflow, not part of the public API
|
|
42
|
+
*/
|
|
43
|
+
export declare function durationIR(value: Duration): DurationIR;
|
|
44
|
+
//#endregion
|
|
45
|
+
//# sourceMappingURL=base.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base.d.mts","names":[],"sources":["../../src/dsl/base.ts"],"mappings":";;;;;;;;;;;;;;;;YAkBY;;;;;;iBAOK;EACf;EACA;;;YAIU;YAYA;;YAGA;;;;;;wBASI,iBAAiB,OAAO;;;;;;wBAWxB,WAAW,OAAO,WAAW"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import ms from "ms";
|
|
2
|
+
//#region src/dsl/base.ts
|
|
3
|
+
const TIME_OF_DAY = /^([01]\d|2[0-3]):([0-5]\d)$/;
|
|
4
|
+
/**
|
|
5
|
+
* Parse an 'HH:mm' literal to minutes since midnight, throwing on anything the
|
|
6
|
+
* type let through ('9:00', '25:00', 'ab:cd').
|
|
7
|
+
* @internal shared by flow builders, not part of the public API
|
|
8
|
+
*/
|
|
9
|
+
function timeOfDayMinutes(value) {
|
|
10
|
+
const match = TIME_OF_DAY.exec(value);
|
|
11
|
+
if (!match) throw new Error(`Invalid time of day: '${value}' (expected 'HH:mm', e.g. '09:00')`);
|
|
12
|
+
return Number(match[1]) * 60 + Number(match[2]);
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Duration parsing delegates to `ms` (typed StringValue); Duration is it's
|
|
16
|
+
* stricter, full-word subset.
|
|
17
|
+
* @internal shared by condition/flow/workflow, not part of the public API
|
|
18
|
+
*/
|
|
19
|
+
function durationIR(value) {
|
|
20
|
+
const millis = ms(value);
|
|
21
|
+
if (typeof millis !== "number" || Number.isNaN(millis) || millis < 0) throw new Error(`Invalid duration: '${value}'`);
|
|
22
|
+
return {
|
|
23
|
+
value,
|
|
24
|
+
ms: millis
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
//#endregion
|
|
28
|
+
export { durationIR, timeOfDayMinutes };
|
|
29
|
+
|
|
30
|
+
//# sourceMappingURL=base.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base.mjs","names":[],"sources":["../../src/dsl/base.ts"],"sourcesContent":["import ms from 'ms';\nimport type { DurationIR } from '../ir';\n\n/**\n * Base vocabulary shared by the whole DSL: the schema constraints an app's\n * types must satisfy, and the literal types (durations, weekdays, clock times)\n * the builder methods accept.\n *\n * Type technique: `Duration` is a template-literal union — '1 huor' is a\n * compile error, no runtime validation needed for the common case.\n */\n\n/**\n * Event name → payload shape, supplied by the app (its analytics schema).\n * Constrained to `object` rather than `Record`: interfaces have no implicit\n * index signature, so a Record constraint would reject an interface-defined\n * schema. Event names come from `keyof E`, payloads from `E[N]`.\n */\nexport type EventMap = object;\n\n/**\n * Base shape of user properties; the app extends it with concrete fields.\n * `email` is optional: a profile can exist before (or without) an address,\n * and an email step refuses to send when the recipient is missing.\n */\nexport interface UserPropertyBase {\n userId: string;\n email?: string;\n}\n\n/** Duration literal: '1 hour' / '23 hours' / '30 days' — typos fail to compile. */\nexport type Duration = `${number} ${\n | 'second'\n | 'seconds'\n | 'minute'\n | 'minutes'\n | 'hour'\n | 'hours'\n | 'day'\n | 'days'\n | 'week'\n | 'weeks'}`;\n\nexport type Weekday = 'mon' | 'tue' | 'wed' | 'thu' | 'fri' | 'sat' | 'sun';\n\n/** 'HH:mm' (24h, leading zeros). The type cannot express digit ranges, so builders validate at runtime via timeOfDayMinutes. */\nexport type TimeOfDay = `${string}:${string}`;\n\nconst TIME_OF_DAY = /^([01]\\d|2[0-3]):([0-5]\\d)$/;\n\n/**\n * Parse an 'HH:mm' literal to minutes since midnight, throwing on anything the\n * type let through ('9:00', '25:00', 'ab:cd').\n * @internal shared by flow builders, not part of the public API\n */\nexport function timeOfDayMinutes(value: TimeOfDay): number {\n const match = TIME_OF_DAY.exec(value);\n if (!match) throw new Error(`Invalid time of day: '${value}' (expected 'HH:mm', e.g. '09:00')`);\n return Number(match[1]) * 60 + Number(match[2]);\n}\n\n/**\n * Duration parsing delegates to `ms` (typed StringValue); Duration is it's\n * stricter, full-word subset.\n * @internal shared by condition/flow/workflow, not part of the public API\n */\nexport function durationIR(value: Duration): DurationIR {\n const millis = ms(value);\n if (typeof millis !== 'number' || Number.isNaN(millis) || millis < 0) {\n throw new Error(`Invalid duration: '${value}'`);\n }\n return { value, ms: millis };\n}\n"],"mappings":";;AAgDA,MAAM,cAAc;;;;;;AAOpB,SAAgB,iBAAiB,OAA0B;CACzD,MAAM,QAAQ,YAAY,KAAK,KAAK;CACpC,IAAI,CAAC,OAAO,MAAM,IAAI,MAAM,yBAAyB,MAAM,mCAAmC;CAC9F,OAAO,OAAO,MAAM,EAAE,IAAI,KAAK,OAAO,MAAM,EAAE;AAChD;;;;;;AAOA,SAAgB,WAAW,OAA6B;CACtD,MAAM,SAAS,GAAG,KAAK;CACvB,IAAI,OAAO,WAAW,YAAY,OAAO,MAAM,MAAM,KAAK,SAAS,GACjE,MAAM,IAAI,MAAM,sBAAsB,MAAM,EAAE;CAEhD,OAAO;EAAE;EAAO,IAAI;CAAO;AAC7B"}
|