@flow-as-code/core 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (164) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +30 -0
  3. package/SPEC.md +92 -0
  4. package/dist/actions.d.ts +87 -0
  5. package/dist/actions.d.ts.map +1 -0
  6. package/dist/actions.js +204 -0
  7. package/dist/actions.js.map +1 -0
  8. package/dist/aws.d.ts +27 -0
  9. package/dist/aws.d.ts.map +1 -0
  10. package/dist/aws.js +32 -0
  11. package/dist/aws.js.map +1 -0
  12. package/dist/blocks.d.ts +287 -0
  13. package/dist/blocks.d.ts.map +1 -0
  14. package/dist/blocks.js +352 -0
  15. package/dist/blocks.js.map +1 -0
  16. package/dist/codegen.d.ts +21 -0
  17. package/dist/codegen.d.ts.map +1 -0
  18. package/dist/codegen.js +1027 -0
  19. package/dist/codegen.js.map +1 -0
  20. package/dist/export.d.ts +256 -0
  21. package/dist/export.d.ts.map +1 -0
  22. package/dist/export.js +799 -0
  23. package/dist/export.js.map +1 -0
  24. package/dist/flow.d.ts +41 -0
  25. package/dist/flow.d.ts.map +1 -0
  26. package/dist/flow.js +85 -0
  27. package/dist/flow.js.map +1 -0
  28. package/dist/flowdoc.d.ts +111 -0
  29. package/dist/flowdoc.d.ts.map +1 -0
  30. package/dist/flowdoc.js +139 -0
  31. package/dist/flowdoc.js.map +1 -0
  32. package/dist/index.d.ts +16 -0
  33. package/dist/index.d.ts.map +1 -0
  34. package/dist/index.js +26 -0
  35. package/dist/index.js.map +1 -0
  36. package/dist/layout.d.ts +11 -0
  37. package/dist/layout.d.ts.map +1 -0
  38. package/dist/layout.js +49 -0
  39. package/dist/layout.js.map +1 -0
  40. package/dist/lint/engine.d.ts +16 -0
  41. package/dist/lint/engine.d.ts.map +1 -0
  42. package/dist/lint/engine.js +37 -0
  43. package/dist/lint/engine.js.map +1 -0
  44. package/dist/lint/graph.d.ts +34 -0
  45. package/dist/lint/graph.d.ts.map +1 -0
  46. package/dist/lint/graph.js +79 -0
  47. package/dist/lint/graph.js.map +1 -0
  48. package/dist/lint/index.d.ts +7 -0
  49. package/dist/lint/index.d.ts.map +1 -0
  50. package/dist/lint/index.js +5 -0
  51. package/dist/lint/index.js.map +1 -0
  52. package/dist/lint/reporters.d.ts +6 -0
  53. package/dist/lint/reporters.d.ts.map +1 -0
  54. package/dist/lint/reporters.js +30 -0
  55. package/dist/lint/reporters.js.map +1 -0
  56. package/dist/lint/rules/action-allowed-in-flow-type.d.ts +11 -0
  57. package/dist/lint/rules/action-allowed-in-flow-type.d.ts.map +1 -0
  58. package/dist/lint/rules/action-allowed-in-flow-type.js +32 -0
  59. package/dist/lint/rules/action-allowed-in-flow-type.js.map +1 -0
  60. package/dist/lint/rules/action-count.d.ts +16 -0
  61. package/dist/lint/rules/action-count.d.ts.map +1 -0
  62. package/dist/lint/rules/action-count.js +32 -0
  63. package/dist/lint/rules/action-count.js.map +1 -0
  64. package/dist/lint/rules/error-branches.d.ts +10 -0
  65. package/dist/lint/rules/error-branches.d.ts.map +1 -0
  66. package/dist/lint/rules/error-branches.js +39 -0
  67. package/dist/lint/rules/error-branches.js.map +1 -0
  68. package/dist/lint/rules/index.d.ts +17 -0
  69. package/dist/lint/rules/index.d.ts.map +1 -0
  70. package/dist/lint/rules/index.js +36 -0
  71. package/dist/lint/rules/index.js.map +1 -0
  72. package/dist/lint/rules/module-depth-5.d.ts +14 -0
  73. package/dist/lint/rules/module-depth-5.d.ts.map +1 -0
  74. package/dist/lint/rules/module-depth-5.js +67 -0
  75. package/dist/lint/rules/module-depth-5.js.map +1 -0
  76. package/dist/lint/rules/no-literal-arn.d.ts +21 -0
  77. package/dist/lint/rules/no-literal-arn.d.ts.map +1 -0
  78. package/dist/lint/rules/no-literal-arn.js +58 -0
  79. package/dist/lint/rules/no-literal-arn.js.map +1 -0
  80. package/dist/lint/rules/no-unresolved-token.d.ts +8 -0
  81. package/dist/lint/rules/no-unresolved-token.d.ts.map +1 -0
  82. package/dist/lint/rules/no-unresolved-token.js +71 -0
  83. package/dist/lint/rules/no-unresolved-token.js.map +1 -0
  84. package/dist/lint/rules/prompt-length-3000.d.ts +16 -0
  85. package/dist/lint/rules/prompt-length-3000.d.ts.map +1 -0
  86. package/dist/lint/rules/prompt-length-3000.js +61 -0
  87. package/dist/lint/rules/prompt-length-3000.js.map +1 -0
  88. package/dist/lint/rules/reachable-blocks.d.ts +7 -0
  89. package/dist/lint/rules/reachable-blocks.d.ts.map +1 -0
  90. package/dist/lint/rules/reachable-blocks.js +45 -0
  91. package/dist/lint/rules/reachable-blocks.js.map +1 -0
  92. package/dist/lint/rules/recording-consent-before-record.d.ts +3 -0
  93. package/dist/lint/rules/recording-consent-before-record.d.ts.map +1 -0
  94. package/dist/lint/rules/recording-consent-before-record.js +87 -0
  95. package/dist/lint/rules/recording-consent-before-record.js.map +1 -0
  96. package/dist/lint/rules/terminal-blocks.d.ts +8 -0
  97. package/dist/lint/rules/terminal-blocks.d.ts.map +1 -0
  98. package/dist/lint/rules/terminal-blocks.js +40 -0
  99. package/dist/lint/rules/terminal-blocks.js.map +1 -0
  100. package/dist/lint/rules/unique-names.d.ts +7 -0
  101. package/dist/lint/rules/unique-names.d.ts.map +1 -0
  102. package/dist/lint/rules/unique-names.js +40 -0
  103. package/dist/lint/rules/unique-names.js.map +1 -0
  104. package/dist/lint/types.d.ts +30 -0
  105. package/dist/lint/types.d.ts.map +1 -0
  106. package/dist/lint/types.js +11 -0
  107. package/dist/lint/types.js.map +1 -0
  108. package/dist/materialize.d.ts +31 -0
  109. package/dist/materialize.d.ts.map +1 -0
  110. package/dist/materialize.js +192 -0
  111. package/dist/materialize.js.map +1 -0
  112. package/dist/package-names.d.ts +11 -0
  113. package/dist/package-names.d.ts.map +1 -0
  114. package/dist/package-names.js +25 -0
  115. package/dist/package-names.js.map +1 -0
  116. package/dist/refs.d.ts +35 -0
  117. package/dist/refs.d.ts.map +1 -0
  118. package/dist/refs.js +69 -0
  119. package/dist/refs.js.map +1 -0
  120. package/dist/serialize.d.ts +13 -0
  121. package/dist/serialize.d.ts.map +1 -0
  122. package/dist/serialize.js +86 -0
  123. package/dist/serialize.js.map +1 -0
  124. package/dist/simulate.d.ts +446 -0
  125. package/dist/simulate.d.ts.map +1 -0
  126. package/dist/simulate.js +1115 -0
  127. package/dist/simulate.js.map +1 -0
  128. package/dist/synth.d.ts +25 -0
  129. package/dist/synth.d.ts.map +1 -0
  130. package/dist/synth.js +93 -0
  131. package/dist/synth.js.map +1 -0
  132. package/package.json +73 -0
  133. package/src/actions.ts +221 -0
  134. package/src/aws.ts +55 -0
  135. package/src/blocks.ts +619 -0
  136. package/src/codegen.ts +1144 -0
  137. package/src/export.ts +1190 -0
  138. package/src/flow.ts +108 -0
  139. package/src/flowdoc.ts +261 -0
  140. package/src/index.ts +31 -0
  141. package/src/layout.ts +54 -0
  142. package/src/lint/engine.ts +56 -0
  143. package/src/lint/graph.ts +86 -0
  144. package/src/lint/index.ts +10 -0
  145. package/src/lint/reporters.ts +44 -0
  146. package/src/lint/rules/action-allowed-in-flow-type.ts +32 -0
  147. package/src/lint/rules/action-count.ts +35 -0
  148. package/src/lint/rules/error-branches.ts +45 -0
  149. package/src/lint/rules/index.ts +53 -0
  150. package/src/lint/rules/module-depth-5.ts +70 -0
  151. package/src/lint/rules/no-literal-arn.ts +64 -0
  152. package/src/lint/rules/no-unresolved-token.ts +80 -0
  153. package/src/lint/rules/prompt-length-3000.ts +66 -0
  154. package/src/lint/rules/reachable-blocks.ts +50 -0
  155. package/src/lint/rules/recording-consent-before-record.ts +90 -0
  156. package/src/lint/rules/terminal-blocks.ts +45 -0
  157. package/src/lint/rules/unique-names.ts +44 -0
  158. package/src/lint/types.ts +43 -0
  159. package/src/materialize.ts +230 -0
  160. package/src/package-names.ts +26 -0
  161. package/src/refs.ts +93 -0
  162. package/src/serialize.ts +97 -0
  163. package/src/simulate.ts +1610 -0
  164. package/src/synth.ts +110 -0
package/LICENSE ADDED
@@ -0,0 +1,202 @@
1
+
2
+ Apache License
3
+ Version 2.0, January 2004
4
+ http://www.apache.org/licenses/
5
+
6
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7
+
8
+ 1. Definitions.
9
+
10
+ "License" shall mean the terms and conditions for use, reproduction,
11
+ and distribution as defined by Sections 1 through 9 of this document.
12
+
13
+ "Licensor" shall mean the copyright owner or entity authorized by
14
+ the copyright owner that is granting the License.
15
+
16
+ "Legal Entity" shall mean the union of the acting entity and all
17
+ other entities that control, are controlled by, or are under common
18
+ control with that entity. For the purposes of this definition,
19
+ "control" means (i) the power, direct or indirect, to cause the
20
+ direction or management of such entity, whether by contract or
21
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
22
+ outstanding shares, or (iii) beneficial ownership of such entity.
23
+
24
+ "You" (or "Your") shall mean an individual or Legal Entity
25
+ exercising permissions granted by this License.
26
+
27
+ "Source" form shall mean the preferred form for making modifications,
28
+ including but not limited to software source code, documentation
29
+ source, and configuration files.
30
+
31
+ "Object" form shall mean any form resulting from mechanical
32
+ transformation or translation of a Source form, including but
33
+ not limited to compiled object code, generated documentation,
34
+ and conversions to other media types.
35
+
36
+ "Work" shall mean the work of authorship, whether in Source or
37
+ Object form, made available under the License, as indicated by a
38
+ copyright notice that is included in or attached to the work
39
+ (an example is provided in the Appendix below).
40
+
41
+ "Derivative Works" shall mean any work, whether in Source or Object
42
+ form, that is based on (or derived from) the Work and for which the
43
+ editorial revisions, annotations, elaborations, or other modifications
44
+ represent, as a whole, an original work of authorship. For the purposes
45
+ of this License, Derivative Works shall not include works that remain
46
+ separable from, or merely link (or bind by name) to the interfaces of,
47
+ the Work and Derivative Works thereof.
48
+
49
+ "Contribution" shall mean any work of authorship, including
50
+ the original version of the Work and any modifications or additions
51
+ to that Work or Derivative Works thereof, that is intentionally
52
+ submitted to Licensor for inclusion in the Work by the copyright owner
53
+ or by an individual or Legal Entity authorized to submit on behalf of
54
+ the copyright owner. For the purposes of this definition, "submitted"
55
+ means any form of electronic, verbal, or written communication sent
56
+ to the Licensor or its representatives, including but not limited to
57
+ communication on electronic mailing lists, source code control systems,
58
+ and issue tracking systems that are managed by, or on behalf of, the
59
+ Licensor for the purpose of discussing and improving the Work, but
60
+ excluding communication that is conspicuously marked or otherwise
61
+ designated in writing by the copyright owner as "Not a Contribution."
62
+
63
+ "Contributor" shall mean Licensor and any individual or Legal Entity
64
+ on behalf of whom a Contribution has been received by Licensor and
65
+ subsequently incorporated within the Work.
66
+
67
+ 2. Grant of Copyright License. Subject to the terms and conditions of
68
+ this License, each Contributor hereby grants to You a perpetual,
69
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70
+ copyright license to reproduce, prepare Derivative Works of,
71
+ publicly display, publicly perform, sublicense, and distribute the
72
+ Work and such Derivative Works in Source or Object form.
73
+
74
+ 3. Grant of Patent License. Subject to the terms and conditions of
75
+ this License, each Contributor hereby grants to You a perpetual,
76
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77
+ (except as stated in this section) patent license to make, have made,
78
+ use, offer to sell, sell, import, and otherwise transfer the Work,
79
+ where such license applies only to those patent claims licensable
80
+ by such Contributor that are necessarily infringed by their
81
+ Contribution(s) alone or by combination of their Contribution(s)
82
+ with the Work to which such Contribution(s) was submitted. If You
83
+ institute patent litigation against any entity (including a
84
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
85
+ or a Contribution incorporated within the Work constitutes direct
86
+ or contributory patent infringement, then any patent licenses
87
+ granted to You under this License for that Work shall terminate
88
+ as of the date such litigation is filed.
89
+
90
+ 4. Redistribution. You may reproduce and distribute copies of the
91
+ Work or Derivative Works thereof in any medium, with or without
92
+ modifications, and in Source or Object form, provided that You
93
+ meet the following conditions:
94
+
95
+ (a) You must give any other recipients of the Work or
96
+ Derivative Works a copy of this License; and
97
+
98
+ (b) You must cause any modified files to carry prominent notices
99
+ stating that You changed the files; and
100
+
101
+ (c) You must retain, in the Source form of any Derivative Works
102
+ that You distribute, all copyright, patent, trademark, and
103
+ attribution notices from the Source form of the Work,
104
+ excluding those notices that do not pertain to any part of
105
+ the Derivative Works; and
106
+
107
+ (d) If the Work includes a "NOTICE" text file as part of its
108
+ distribution, then any Derivative Works that You distribute must
109
+ include a readable copy of the attribution notices contained
110
+ within such NOTICE file, excluding those notices that do not
111
+ pertain to any part of the Derivative Works, in at least one
112
+ of the following places: within a NOTICE text file distributed
113
+ as part of the Derivative Works; within the Source form or
114
+ documentation, if provided along with the Derivative Works; or,
115
+ within a display generated by the Derivative Works, if and
116
+ wherever such third-party notices normally appear. The contents
117
+ of the NOTICE file are for informational purposes only and
118
+ do not modify the License. You may add Your own attribution
119
+ notices within Derivative Works that You distribute, alongside
120
+ or as an addendum to the NOTICE text from the Work, provided
121
+ that such additional attribution notices cannot be construed
122
+ as modifying the License.
123
+
124
+ You may add Your own copyright statement to Your modifications and
125
+ may provide additional or different license terms and conditions
126
+ for use, reproduction, or distribution of Your modifications, or
127
+ for any such Derivative Works as a whole, provided Your use,
128
+ reproduction, and distribution of the Work otherwise complies with
129
+ the conditions stated in this License.
130
+
131
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
132
+ any Contribution intentionally submitted for inclusion in the Work
133
+ by You to the Licensor shall be under the terms and conditions of
134
+ this License, without any additional terms or conditions.
135
+ Notwithstanding the above, nothing herein shall supersede or modify
136
+ the terms of any separate license agreement you may have executed
137
+ with Licensor regarding such Contributions.
138
+
139
+ 6. Trademarks. This License does not grant permission to use the trade
140
+ names, trademarks, service marks, or product names of the Licensor,
141
+ except as required for reasonable and customary use in describing the
142
+ origin of the Work and reproducing the content of the NOTICE file.
143
+
144
+ 7. Disclaimer of Warranty. Unless required by applicable law or
145
+ agreed to in writing, Licensor provides the Work (and each
146
+ Contributor provides its Contributions) on an "AS IS" BASIS,
147
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148
+ implied, including, without limitation, any warranties or conditions
149
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150
+ PARTICULAR PURPOSE. You are solely responsible for determining the
151
+ appropriateness of using or redistributing the Work and assume any
152
+ risks associated with Your exercise of permissions under this License.
153
+
154
+ 8. Limitation of Liability. In no event and under no legal theory,
155
+ whether in tort (including negligence), contract, or otherwise,
156
+ unless required by applicable law (such as deliberate and grossly
157
+ negligent acts) or agreed to in writing, shall any Contributor be
158
+ liable to You for damages, including any direct, indirect, special,
159
+ incidental, or consequential damages of any character arising as a
160
+ result of this License or out of the use or inability to use the
161
+ Work (including but not limited to damages for loss of goodwill,
162
+ work stoppage, computer failure or malfunction, or any and all
163
+ other commercial damages or losses), even if such Contributor
164
+ has been advised of the possibility of such damages.
165
+
166
+ 9. Accepting Warranty or Additional Liability. While redistributing
167
+ the Work or Derivative Works thereof, You may choose to offer,
168
+ and charge a fee for, acceptance of support, warranty, indemnity,
169
+ or other liability obligations and/or rights consistent with this
170
+ License. However, in accepting such obligations, You may act only
171
+ on Your own behalf and on Your sole responsibility, not on behalf
172
+ of any other Contributor, and only if You agree to indemnify,
173
+ defend, and hold each Contributor harmless for any liability
174
+ incurred by, or claims asserted against, such Contributor by reason
175
+ of your accepting any such warranty or additional liability.
176
+
177
+ END OF TERMS AND CONDITIONS
178
+
179
+ APPENDIX: How to apply the Apache License to your work.
180
+
181
+ To apply the Apache License to your work, attach the following
182
+ boilerplate notice, with the fields enclosed by brackets "[]"
183
+ replaced with your own identifying information. (Don't include
184
+ the brackets!) The text should be enclosed in the appropriate
185
+ comment syntax for the file format. We also recommend that a
186
+ file or class name and description of purpose be included on the
187
+ same "printed page" as the copyright notice for easier
188
+ identification within third-party archives.
189
+
190
+ Copyright 2026 The flow-as-code Authors
191
+
192
+ Licensed under the Apache License, Version 2.0 (the "License");
193
+ you may not use this file except in compliance with the License.
194
+ You may obtain a copy of the License at
195
+
196
+ http://www.apache.org/licenses/LICENSE-2.0
197
+
198
+ Unless required by applicable law or agreed to in writing, software
199
+ distributed under the License is distributed on an "AS IS" BASIS,
200
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201
+ See the License for the specific language governing permissions and
202
+ limitations under the License.
package/README.md ADDED
@@ -0,0 +1,30 @@
1
+ # @flow-as-code/core
2
+
3
+ ```
4
+ npm i @flow-as-code/core
5
+ ```
6
+
7
+ Apache-2.0, Node 22.12 or newer. The five packages version together and are
8
+ released as a set, so keep them at matching versions.
9
+
10
+ The engine. Typed builder and synthesizer, FlowDoc interchange (docs/01-flowdoc-spec.md), lint engine, codegen (FlowDoc to idiomatic TypeScript), export from live instances, and the simulate scenario format, runner, and reporters. No CDK dependency; references are abstract `${cdref:type:name}` tokens materialized by `@flow-as-code/cdk` (CloudFormation tokens), `@flow-as-code/tf` (templatefile variables), or a resource map (`flow-cli render`).
11
+
12
+ ## Export
13
+
14
+ `exportInstance(client, options)` turns a live Amazon Connect instance into FlowDocs, and TypeScript alongside them when asked. `exportFlow(content, reverseMap, options)` does one flow from its Flow language JSON. An ARN with no entry in the instance inventory is a hard error listing every unknown ARN at once.
15
+
16
+ The client is an interface, so the whole path is testable offline against the recorded fixtures in `conformance/export/`. `createConnectInventoryClient` adapts an `@aws-sdk/client-connect` client to it and owns pagination and the 2 rps throttle budget. It loads the SDK with a dynamic import, so importing `@flow-as-code/core` never requires the optional peer dependency.
17
+
18
+ ## Simulate
19
+
20
+ There is no Amazon Connect API called Simulate. The operations are the TestCase family, and a scenario has to be created on the instance as a published test case before it can run. See SPEC.md, which records the corrections, and `src/simulate.ts`, which cites the doc URL for every shape.
21
+
22
+ A scenario is authored as an ordered list of steps (`conformance/schema/scenario-0.1.schema.json`); `compileScenario` lowers it to the Connect Testing language graph that `CreateTestCase` takes. `runScenarios` owns the create, execute, poll, collect, delete lifecycle within the documented limits: 5 concurrent, 100 in flight including the running 5, and a 5-minute hard cap per scenario. `junitReport` and `jsonReport` are byte-deterministic for the same run.
23
+
24
+ Live paths are gated on `FLOW_TEST_INSTANCE_ARN` and, for simulate, `FLOW_TEST_SIMULATE=1`. `npm test` never touches an AWS account. The export half is read-only (`List*` and `Describe*` only); everything that writes takes its own opt-in, including `@flow-as-code/cdk`'s deploy test (`FLOW_TEST_DEPLOY=1`), which `npm run test:integration` also runs.
25
+
26
+ ### What CI runs and what an operator runs
27
+
28
+ The `sandbox integration` job in `.github/workflows/ci.yml` sets `FLOW_TEST_INSTANCE_ARN` and `FLOW_TEST_DEPLOY` only, so it covers exactly two things: the whole-instance live export in `src/integration.test.ts`, and `@flow-as-code/cdk`'s A07 live deploy. It runs only on a push to `main` or a `workflow_dispatch`, and only when the `CONNECT_SANDBOX_ENABLED` repository variable is set.
29
+
30
+ The other two `describe` blocks in `src/integration.test.ts`, the simulate suite and the lossless export of the deployed demo flow, are gated on `FLOW_TEST_SIMULATE` and `FLOW_TEST_RESOURCE_MAP` and skip in that job by design. Both need a superset stack deployed first (the demo flow's hours, queues, Lambda, and the Lambda's integration association) and a resource map written from that stack's outputs, neither of which a stateless CI job can produce. They stay an operator run; `tasks/A06-export-and-simulate.md` records the procedure, the exact command, and the results of each session.
package/SPEC.md ADDED
@@ -0,0 +1,92 @@
1
+ # @flow-as-code/core specification
2
+
3
+ ## Builder model
4
+
5
+ - `Flow`, `FlowModule` classes; blocks as typed classes named after the Connect action they emit, not the console block. Modeled as of 2026-09-01 (`src/blocks.ts`, fourteen classes): `MessageParticipant`, `GetParticipantInput` (DTMF menu form only, see below), `DisconnectParticipant`, `CheckHoursOfOperation`, `Compare`, `TransferToFlow`, `EndFlowExecution`, `UpdateContactTargetQueue`, `TransferContactToQueue`, `UpdateContactAttributes`, `UpdateContactRecordingBehavior`, `InvokeFlowModule`, `EndFlowModuleExecution`, `InvokeLambdaFunction`. Every other action type, and every unmodeled form of a modeled one, round-trips as `GenericBlock`. See conformance/flow-language/actions.md for the mapping and the citations.
6
+ - Blocks map one-to-one onto Actions. "Transfer to queue" is two blocks, because Connect models it as two actions.
7
+ - Branch wiring is explicit and type-checked: error branches are required properties on each block's config object, so omitting one is a compile-time error. See docs/adr/0002-error-branch-enforcement.md.
8
+ - Synth emits declaration order, not a graph-derived canonical order. See docs/adr/0003-action-ordering.md.
9
+ - References: `Refs.queue("front-desk")` etc. Serialized as `${cdref:queue:front-desk}` in synthesized JSON.
10
+ - Not built: per-location expansion (a `FlowTemplate<Params>` rendering one Flow per location with typed params). Nothing in tasks/ schedules it.
11
+
12
+ Added 2026-09-01: `GetParticipantInput` models the DTMF menu form of the action only: an optional Text, SSML or PromptId body, `timeoutSeconds` (a JS integer 1 to 180, serialized as the console's string), `StoreInput: "False"`, and one `Equals` condition per single-key branch, each key branching at most once (the constructor refuses a repeated key, and a document that carries one stays `GenericBlock`; conformance/roundtrip/repeated-key). The three menu-form errors (`InputTimeLimitExceeded`, `NoMatchingCondition`, `NoMatchingError`) are required config properties and `NextAction` mirrors the `NoMatchingCondition` target, as the console writes it. Stored-input, Lex, validation and encryption forms are not modeled and stay `GenericBlock`. Parameters and constraints are transcribed in conformance/flow-language/actions.md.
13
+
14
+ ## Synthesis output
15
+
16
+ - One FlowDoc per flow or module (`synth(flow)` returns it; `flow-cli synth` writes `<name>.flowdoc.json` per exported flow, next to the builder file unless `--out` says otherwise). The token inventory is the FlowDoc `refs` index and the content hash is `meta.sourceHash`. Not built: a separate manifest.json with a dependency graph; nothing in tasks/ schedules it.
17
+
18
+ ## Materialization
19
+
20
+ - `materializeWithMap(json, resourceMap)`: strict; missing keys listed all at once.
21
+ - `materializeWithBinder(json, binder)`: binder returns opaque strings (CDK tokens); used by `@flow-as-code/cdk`. Output may contain CloudFormation intrinsic tokens and must not be linted for arn-shape.
22
+ - Both return deployable content only: `layout`, `refs`, and `meta` are dropped, and `layout` is projected into `content.Metadata` (`EntryPointPosition` plus `ActionMetadata.<id>.Position`, per the Flow language example) first. `serializeContent(content)` emits the byte-stable deployable JSON. Fixtures live in conformance/materialize/.
23
+
24
+ ## Lint rules (ids stable, fixtures in /conformance)
25
+
26
+ Eleven rules, in the order `allRules` lists them (`src/lint/rules/index.ts`): no-literal-arn, no-unresolved-token, reachable-blocks, error-branches, terminal-blocks, module-depth-5, prompt-length-3000, recording-consent-before-record, unique-names, action-allowed-in-flow-type, action-count.
27
+
28
+ `action-allowed-in-flow-type` (added 2026-08-31): almost every Connect action documents the flow types it is legal in, and violating one fails at create time with a message that does not name the offending block. Restrictions are recorded per action in conformance/flow-language/actions.md. `action-count` reports a flow whose Action count exceeds the 250 Connect allows, the same limit the schema enforces.
29
+
30
+ Added 2026-09-01: `prompt-length-3000` also counts a `GetParticipantInput` body, which is billed the same way as a message. `recording-consent-before-record` treats a `GetParticipantInput` that plays a body as an announcement; a menu with no body is silent and does not satisfy the rule. Content is what counts on both announcing actions: an empty or blank `Text` or `SSML` plays nothing, on a menu or a `MessageParticipant`, and the studio writes `Text: ""` until the author types. `action-allowed-in-flow-type` restricts `GetParticipantInput` to contact, transfer, customer queue and module flows.
31
+
32
+ `no-literal-arn` and `no-unresolved-token` are hard rules: the studio may never save through them (docs/02-studio-design.md). Every other rule reports.
33
+
34
+ The engine is browser-safe and dependency-free, exported separately as `@flow-as-code/core/lint` so the studio's worker does not carry dagre. Enforced by a static import-graph test, not by running under a DOM shim, which would prove nothing since `node:fs` still resolves there.
35
+
36
+ ## Export
37
+
38
+ Corrected 2026-08-31 against the current API reference. The earlier text named
39
+ the wrong discovery operations; the record of what changed is at the end of this
40
+ section.
41
+
42
+ - Inventory: `ListContactFlows` + `DescribeContactFlow`, `ListContactFlowModules` + `DescribeContactFlowModule`, `ListQueues` (`QueueTypes=[STANDARD]`, or agent queues truncate the page), `ListHoursOfOperations`, `ListPrompts`, `ListLambdaFunctions`, `ListBots` (once per `lexVersion`, which is required). `DescribeContactFlow` is the operation that returns the Flow language; the list operations return summaries only.
43
+ - `buildReverseMap(inventory)` maps ARN to `RefEntry`. Two ARN keywords do not match their IAM resource-type names, and a map keyed on the type name silently fails to resolve either: a contact-flow-module is `flow-module` and an hours-of-operation is `operating-hours`. A flow ARN may also carry a `:$SAVED` or `:{version}` qualifier, which is stripped before lookup. Names are slugged from console names, per ref type, with a deterministic numeric suffix on a collision and a warning.
44
+ - `exportFlow(content, reverseMap, options)` rewrites every ARN that occupies a whole field value into its token, lifts `content.Metadata` positions into `layout` (both `Position` and `position` spellings), keeps any other Metadata in content, derives `refs`, and sets `meta.generator`. An ARN with no reverse-map entry is a hard error naming the flow and listing every unknown ARN at once, alongside any ARN found interpolated into a longer string, which cannot become a token at all (FlowDoc invariant 4).
45
+ - Live content omits `Parameters` from an action that takes none, rather than writing an empty map, and FlowDoc requires the key on every action. `exportFlow` fills in the empty map the absence means. This is not a content change: materializing the result re-emits `"Parameters": {}`, which is the form the console writes for most parameterless actions in the same flow. `Transitions` is normalized the same way, defensively, because canonicalization reads through it unconditionally. Recorded in `conformance/export/omitted-parameters/`.
46
+ - `exportInstance(client, options)` walks the inventory and emits one FlowDoc per flow and module, plus TS codegen when asked. `DescribeContactFlow` throws `ContactFlowNotPublishedException` for a flow that has never been published, so the exporter retries through the documented `$SAVED` alias. A `ContactFlowType` FlowDoc cannot represent (`CAMPAIGN`) is skipped with a warning; a module's `Settings` and `ExternalInvocationConfiguration` are warned about rather than dropped silently.
47
+ - The client is an interface (`ConnectInventoryClient`), so every path is testable offline against recorded fixtures in `conformance/export/`. The SDK adapter owns pagination and the 2 rps throttle budget and loads `@aws-sdk/client-connect` with a dynamic import, so importing `@flow-as-code/core` never requires the optional peer dependency.
48
+ - Verified 2026-09-01 against a live instance carrying the 20 stock sample flows. Two behaviours the hand-written fixtures did not have: the omitted `Parameters` above, which broke 7 of the 20; and the stock `Sample Lambda integration` flow, which calls `arn:aws:lambda:us-east-1:<aws-account>:function:state-lookup`, a Lambda in an AWS-owned account that is not associated with the instance, so `ListLambdaFunctions` cannot return it and no reverse-map entry can exist. That flow is an unknown-ARN hard error by design: naming it `${cdref:lambda:state-lookup}` would produce a document that no resource map can materialize. A whole-instance export of a fresh instance therefore needs `onError: "collect"`, or it aborts on that one flow.
49
+ - AWS-managed resources (verified 2026-09-01): the stock `Sample after contact work flow` references the view `arn:aws:connect:<region>:aws:view/after-contact-work:1`, with the literal `aws` where the account id goes. `ListViews` documents `AWS_MANAGED` views beside `CUSTOMER_MANAGED` ones. https://docs.aws.amazon.com/connect/latest/APIReference/API_ListViews.html The ARN patterns accept `aws` as an account segment, so that reference is reported as an unknown ARN like any other and the flow fails to export by design; before the fix the digits-only pattern passed it through as prose and the exported document carried a literal ARN. A `view` ref type backed by `ListViews` is the fix that would export the flow, and it is not modeled yet. Recorded in `conformance/export/unknown-arns/`.
50
+ - Lossless against a deployed flow (verified 2026-09-01, via the CLI): with the demo flow deployed through the `@flow-as-code/cdk` `FlowSet` stack, `flow-cli export --instance <arn> --out <dir>` wrote `appointment-line.flowdoc.json` equal to `conformance/demo/appointment-line.flowdoc.json` in `content`, `layout` (all eleven positions, as CloudFormation wrote them and `DescribeContactFlow` returned them), and `refs`, in the same key order; the only difference is `meta`, which the demo document does not carry and the export fills with `generator`, `source` (`contentSha256`, `id`, `instanceId`, `name`), and `sourceHash`. `flow-cli codegen` on that export was byte-equal to the `.flow.ts` the export itself wrote, `flow-cli synth` on that TypeScript reproduced the exported document and the demo document (same `content`, `layout`, `refs`, and the same `meta.sourceHash`), and a second `codegen` of the synthesized document was byte-equal to the first. The `live export of the demo` case in `src/integration.test.ts` asserts the same equality and passed in all ten suite runs that day and in the five of the 2026-09-02 re-check; the CLI's whole-instance export ran once that day and once in the re-check, exited 1 both times, and named the two stock flows above and no other.
51
+ - What changed: the old text said the reverse map comes from "ListQueues, ListContactFlows, Lambda/Lex associations". "Lambda/Lex associations" means `ListIntegrationAssociations`, whose `IntegrationType` enum has no `LAMBDA_FUNCTION` and no `LEX_BOT` member, so it cannot discover either. https://docs.aws.amazon.com/connect/latest/APIReference/API_ListIntegrationAssociations.html Hours, prompts, and modules were missing from the list as well, and without modules the exporter cannot round-trip FlowDoc `kind: "module"` at all. Sources: https://docs.aws.amazon.com/connect/latest/APIReference/API_ListLambdaFunctions.html https://docs.aws.amazon.com/connect/latest/APIReference/API_ListBots.html https://docs.aws.amazon.com/connect/latest/APIReference/API_DescribeContactFlow.html
52
+
53
+ ## Simulate
54
+
55
+ Rewritten 2026-08-31. The previous version of this section described an API that
56
+ does not exist.
57
+
58
+ - There is no Amazon Connect operation named Simulate, StartFlowSimulation, or anything containing "Simulate". The family that does the work is eleven TestCase operations in `connect-2017-08-08`: `CreateTestCase`, `DescribeTestCase`, `UpdateTestCase`, `DeleteTestCase`, `ListTestCases`, `SearchTestCases`, `StartTestCaseExecution`, `StopTestCaseExecution`, `GetTestCaseExecutionSummary`, `ListTestCaseExecutions`, `ListTestCaseExecutionRecords`. https://docs.aws.amazon.com/connect/latest/APIReference/API_Operations.html The CLI verb stays `simulate`; the code and comments name the real operations.
59
+ - A test case is a server-side resource, not a body posted to a run endpoint. `StartTestCaseExecution` "Starts executing a published test case" and takes only a `TestCaseId`, so the runner's lifecycle is create with `Status=PUBLISHED`, execute, poll, collect, delete, with cleanup on failure. https://docs.aws.amazon.com/connect/latest/APIReference/API_StartTestCaseExecution.html
60
+ - Inputs and expectations are not API fields. They live inside the opaque `Content` string as the Connect Testing language, a graph of Observations each pairing one expected Event with the Actions taken in response, wired by `Transitions.NextObservations`. https://docs.aws.amazon.com/connect/latest/devguide/testing-language.html
61
+ - Scenario schema (ours, `conformance/schema/scenario-0.1.schema.json`): entry point, contact attributes, ordered steps, and the SPEC's five expectations. `compileScenario` lowers the ordered form to the Observation graph. Corrections to the old shape: the channel is an entry-point property (`TestCaseEntryPointType` is `CHAT | VOICE_CALL`), not an input kind; the three input kinds are `DtmfInput`, `Utterance`, and `Disconnect`; contact attributes are the `InitializationData` JSON string, whose working shape is `{"Attributes": {...}, "SegmentAttributes": {}}` (see the verified findings below); "Lambda invoked" and "transfer target" are `FlowActionStarted` events rather than assertions, while "queue reached" and "attribute set" are `Assert` actions.
62
+ - Limits, all from the admin guide and none of them a Service Quota, so none can be raised by request: 5 concurrent tests; 100 executions in the queue **including** the 5 running, which is an admission ceiling of 100 in flight and yields `ServiceQuotaExceededException` (HTTP 402) when exceeded; 5 minutes maximum duration, which is a hard timeout reported as FAILED rather than a neutral stop. https://docs.aws.amazon.com/connect/latest/adminguide/testing-simulation-execute-test-cases.html
63
+ - Safety, and it is a default rather than an option: "If you do not end the test before the simulated contact is transferred to a queue, the simulated contact might reach the agent queue and connect with a live agent as a contact." Every compiled scenario therefore ends with a `TestControl` `EndTest` action, and a scenario that expects a transfer with `endTest: false` and no `OverrideSystemBehavior` queue substitution fails validation.
64
+ - Reporters: JUnit XML and JSON, both byte-deterministic for the same run, with goldens in `conformance/simulate/report/`.
65
+ - Verified 2026-09-01 against a sandbox instance, by creating test cases with `Status=PUBLISHED` (which validates `Content` server-side; the JS SDK surfaces the findings as `problemDetails[].message` on `InvalidTestCaseException`, where the API reference says `Problems`) and executing the three-scenario suite in `conformance/simulate/` end to end: twice in an afternoon session, ten times back to back in a re-check the same evening (runs 1 to 5 with `after-hours-message` over voice, runs 6 to 10 over chat), and five more times on 2026-09-02 with the integration test asserting PASSED. Every scenario reached Connect's evaluator in every run (none ERRORED, so the compiled `Content` is what the service accepts). With `after-hours-message` authored over chat, as it now is, all three scenarios PASSED in every one of those ten chat-form suite runs (the two chat scenarios in 8.5 to 9.8 s, the voice transfer in 13.2 to 16.1 s) and in both runs through `flow-cli simulate`. The same scenario over voice PASSED in only 2 of the 5 voice-form suite runs and 6 of 10 executions overall; the record of why is in tasks/A06-export-and-simulate.md and summarised under `MessageReceived` below. The Testing language pages are wrong or silent in the places below; the compiler, the validator, and the scenario schema encode what the service accepted.
66
+ - `Utterance` carries its text as `Properties.Value`, optionally with `LanguageCode`, not the `Text` or `SSML` the page shows. `DtmfInput` is rejected under a `CHAT` entry point. Input sent while the flow is not listening for it is accepted and ignored. https://docs.aws.amazon.com/connect/latest/devguide/testing-language-actions-send-instruction.html
67
+ - `Assert` has no working `Exists` operator; the eight operators on the page that CreateTestCase accepts (`Equals`, `TextStartsWith`, `TextEndsWith`, `TextContains`, `NumberGreaterThan`, `NumberGreaterOrEqualTo`, `NumberLessThan`, `NumberLessOrEqualTo`) were each accepted with an `Operand`, `TextContains` and `TextStartsWith` with an empty one. `Equals` without an `Operand` was rejected ("Invalid operand parameter for AssertAction"); the other seven were not sent without one, so the compiler always emits an `Operand` and the validator requires a value for every operator. `$.Attributes.<key>`, `$.Queue.Name`, and `$.Channel` all resolve; the execution record reports the actual value in `ActualParameters.Namespace`. https://docs.aws.amazon.com/connect/latest/devguide/testing-language-actions-assertion.html
68
+ - `VoiceCallEntryPointParameters` takes `FlowId` (a bare id or the flow ARN) with `SourcePhoneNumber` (E.164, verified with the fictional `+15550100`), and rejects `FlowId` together with `DestinationPhoneNumber` ("Must specify either FlowId or phone numbers"). No phone number needs to be claimed on the instance. https://docs.aws.amazon.com/connect/latest/APIReference/API_VoiceCallEntryPointParameters.html
69
+ - `OverrideSystemBehavior` with `Strategy.Type=SubstituteResource` works for `TransferContactToQueue` (`QueueId`) and `CheckHoursOfOperation` (`HoursOfOperationId`) and requires the action's own `ActionParameters` (an empty map is rejected). Both substitutions are honored, shown from outside the execution record with `DescribeContact` on the `ContactId` the `EXECUTION_START` record carries (https://docs.aws.amazon.com/connect/latest/APIReference/API_DescribeContact.html). Hours: every after-hours contact, in passing and failing executions alike, ended by the flow's own disconnect (`DisconnectReason` `CONTACT_FLOW_DISCONNECT`) after about 12 s with no queue, which is the closed branch; the open branch enqueues the contact. Queue: with the appointments queue substituted by the overflow queue and the test left running past the transfer, `DescribeContact` reported `QueueInfo` on the overflow queue 0.2 s after the transfer event and `GetCurrentMetricData` `CONTACTS_IN_QUEUE` counted 1 on overflow and nothing on appointments (https://docs.aws.amazon.com/connect/latest/APIReference/API_GetCurrentMetricData.html). In the suite the `EndTest` on the transfer observation disconnects the contact before it is enqueued (no `QueueInfo`, `DisconnectReason` `OTHER`, about 9 s), so nothing ever waits in a queue. `InvokeLambdaFunction` (`LambdaFunctionARN`) is documented on the same page and has not been sent live. `MockResponse` on `CheckHoursOfOperation` was rejected for every `ExecutionResult` value tried, so hours are forced by substitution only. https://docs.aws.amazon.com/connect/latest/devguide/testing-language-actions-override-system-behavior.html
70
+ - `FlowActionStarted` reports the flow's authored parameters, not the substitute: with the appointments queue substituted, the `TransferContactToQueue` event still carries the original `QueueId`, and `$.Queue.Name` at that moment is the working queue the flow set (`Appointments`). A scenario that substitutes a queue therefore expects the authored queue and the authored working-queue name; the substitution is the safety net, not an observable. The event supports only `InvokeLambdaFunction`, `CheckHoursOfOperation`, `TransferContactToQueue`, and `ConnectParticipantWithLexBot`; `CreateTestCase` rejects `DisconnectParticipant` and `UpdateContactTargetQueue` with "Invalid action type for FlowActionStarted event", so a disconnect cannot be observed as a flow action. https://docs.aws.amazon.com/connect/latest/devguide/testing-language-events-flow-action-started.html
71
+ - `MessageReceived` on voice is emitted when playback of the prompt ends, not when it starts: in passing executions its timestamp was about 6 s after the hours check for the demo's one-sentence closed message and about 0.9 s after the contact's own `DisconnectTimestamp`. When the flow disconnects straight after the prompt, that event races the disconnect and is lost in roughly a third of executions (4 of 10 voice executions failed the observation with `OBSERVE_EVENT` about 45 s after the contact had ended; concurrency made no difference, alone it went 2 of 4). On chat the message is a text turn delivered about 0.6 s after the hours check, before the disconnect, and the same scenario passed 11 of 11 executions. A scenario whose expected prompt is the last thing the flow does before hanging up is therefore authored over chat, or on voice expects an earlier prompt. https://docs.aws.amazon.com/connect/latest/devguide/testing-language-events-message-received.html
72
+ - `TestCompleted` is not an end-of-flow assertion. Under the hours substitution it fired about 40 s after the closed branch's disconnect (execution PASSED in 55 s); without the substitution the contact sat in the appointments queue and the event fired at the 5-minute limit with the execution reported PASSED and `CompletionReason.Type` `TIMEOUT`, so a scenario ending on it cannot tell the two branches apart and always runs to the limit on the open branch. https://docs.aws.amazon.com/connect/latest/devguide/testing-language-events-test-completed.html
73
+ - `StopTestCaseExecution` ends the execution at once (`COMPLETION` `STOPPED`, `CompletionReason.Type` `TIMEOUT`, "Test case execution stopped by user request") but not the simulated contact: with the contact enqueued on the substitute queue and no `EndTest`, `DescribeContact` and `CONTACTS_IN_QUEUE` still reported it in the queue after the stop, and it was gone only after a `StopContact` 40 s later. `EndTest` inside the test is what keeps a simulated contact out of a queue; stopping the execution from outside is not a substitute. https://docs.aws.amazon.com/connect/latest/APIReference/API_StopTestCaseExecution.html
74
+ - An execution can be accepted by `StartTestCaseExecution` and then reported FAILED with `CompletionReason.FailureReasons` `["INITIALIZATION_FAILURE"]`, message "Failed to start execution of test case due to limit reached.", and zero observations. It happened in 3 of 6 back-to-back suite runs that carried two voice scenarios (never in the 13 later runs with one voice scenario, never for a scenario run alone), with at most three executions in flight, so it is not the documented 5-concurrent or 100-queued limit and the page names no other. The runner treats it as a start that did not take and starts the same test case again under a fresh `ClientToken`, within `startRetries`, reporting only the last attempt's observation counts; the integration test refuses a FAILED result with zero observations as a verdict. Neither the retry nor that refusal has fired live: the failure has not recurred since the retry landed.
75
+ - `InitializationData` is documented only as "Defines the initial custom attributes for your test" with no shape. https://docs.aws.amazon.com/connect/latest/APIReference/API_CreateTestCase.html Executing variants showed that `{"Attributes": {...}, "SegmentAttributes": {}}` is the only shape an `$.Attributes.<key>` Assert read back; a flat map and the `ContactData`, `ContactAttributes`, `CustomAttributes` and JSONPath-keyed wrappers are accepted but the Assert read the attribute back empty; the lowercase `attributes` wrapper is accepted but its one execution failed on an observation before the Assert ran, so nothing is known about its value; and `{"Attributes": {...}}` without `SegmentAttributes` is accepted but not shown to work: of three executions, one stayed `INITIATED` for the whole 240 s wait and two started the contact but failed on an observation before the Assert ran. The compiler always emits both keys because the two-key shape is the one shown to work.
76
+ - `MatchingCriteria` `Inclusion` and `Similarity` both matched the demo's prompts. An execution ends within seconds of `EndTest`: a PASSED scenario took 8.5 to 17.7 seconds across the seventeen recorded suite runs (the two chat scenarios 8.5 to 10.5 s, the voice transfer 13.2 to 16.1 s, and the voice form of `after-hours-message` 17.5 to 17.6 s in the two runs it passed). An unmet observation is reported after about 45 to 60 seconds on voice; on chat, Connect failed one right after the flow disconnected the contact (4.8 s), 10.6 s into the one run that expected a prompt the flow never sends (2026-09-02). All well inside the 5-minute limit.
77
+ - No `AccessDenied` was seen; the run needs the `connect:CreateTestCase`, `connect:StartTestCaseExecution`, `connect:GetTestCaseExecutionSummary`, `connect:ListTestCaseExecutionRecords`, `connect:StopTestCaseExecution` and `connect:DeleteTestCase` actions the adapter calls, plus `connect:DescribeContactFlow` and the `List*` operations of the export half.
78
+
79
+ ## FlowDoc (added 2026-08-30)
80
+
81
+ - Synthesis emits FlowDoc per docs/01-flowdoc-spec.md (content + layout + refs + meta), not bare Flow JSON. Deterministic ordering and dagre auto-layout for missing positions.
82
+ - GenericBlock: any unmodeled Action round-trips verbatim through builder, studio, and codegen.
83
+
84
+ ## Codegen (FlowDoc -> TypeScript)
85
+
86
+ - `codegen(doc, options?)` emits one exported zero-arg factory named camelCase of `doc.name`, returning `Flow` (`FlowModule` for kind "module"). The body is `new Flow({ name, connectType }).add(...)` with one inline block construction per Action, in doc Action order. Synth preserves declaration order (docs/adr/0003-action-ordering.md), so emitting doc order makes synth(codegen(doc)) reproduce the doc with no reordering or normalization pass.
87
+ - An Action of a modeled Type emits its block class only when the class reproduces the Action exactly, verified by constructing the block and comparing its synthesized Action against the source. Any other shape (extra parameters, missing required error branch, nonstandard conditions) falls back to `GenericBlock`, so the round-trip is lossless by construction. For `GetParticipantInput` that means the menu form exactly: string timeout, `StoreInput: "False"`, single-key `Equals` conditions, the three errors in the class's order, and `NextAction` mirroring the no-match target; a stored-input or Lex-shaped action emits `GenericBlock` (2026-09-01).
88
+ - Reference-bearing fields become `Refs.*` calls; a JSONPath value becomes `jsonPath(...)`. Tokens inside GenericBlock parameters stay verbatim strings and are never rewritten.
89
+ - `layout` equal to the deterministic auto-layout is omitted from the emitted config; hand-placed positions are emitted verbatim. Either way synth reproduces `doc.layout`.
90
+ - `options.moduleSpecifier` sets the import path (default `@flow-as-code/core`); only the names actually used are imported. `options.previous` re-attaches `// ... @keep` comment lines from a prior generation: ones immediately preceding a block construction whose id still exists, and ones immediately preceding the export function. Other comments regenerate away.
91
+ - Byte-stable: same FlowDoc in, identical TS out, and the output is a fixed point of the repo Prettier config and passes the repo ESLint untouched (both asserted in tests). codegen(synth(code)) is byte-stable with no normalization cycle because nothing reorders.
92
+ - Round-trip invariants (CI): synth(codegen(doc)) deep-equals doc modulo `meta`; fixtures in /conformance/roundtrip, runnable alone via `npm run test:roundtrip`.
@@ -0,0 +1,87 @@
1
+ import type { RefType } from "./flowdoc.js";
2
+ export declare const ActionType: {
3
+ readonly MessageParticipant: "MessageParticipant";
4
+ readonly GetParticipantInput: "GetParticipantInput";
5
+ readonly DisconnectParticipant: "DisconnectParticipant";
6
+ readonly CheckHoursOfOperation: "CheckHoursOfOperation";
7
+ readonly Compare: "Compare";
8
+ readonly TransferToFlow: "TransferToFlow";
9
+ readonly EndFlowExecution: "EndFlowExecution";
10
+ readonly TransferContactToQueue: "TransferContactToQueue";
11
+ readonly UpdateContactTargetQueue: "UpdateContactTargetQueue";
12
+ readonly UpdateContactAttributes: "UpdateContactAttributes";
13
+ readonly UpdateContactRecordingBehavior: "UpdateContactRecordingBehavior";
14
+ readonly InvokeFlowModule: "InvokeFlowModule";
15
+ readonly EndFlowModuleExecution: "EndFlowModuleExecution";
16
+ readonly InvokeLambdaFunction: "InvokeLambdaFunction";
17
+ };
18
+ export type ModeledActionType = (typeof ActionType)[keyof typeof ActionType];
19
+ /**
20
+ * Reference-bearing parameter fields, by action type. These are the only
21
+ * places a `${cdref:...}` token may appear.
22
+ */
23
+ export declare const REFERENCE_FIELDS: Readonly<Record<string, Readonly<Record<string, RefType>>>>;
24
+ /**
25
+ * Actions that terminate the flow. These carry an empty Transitions object and
26
+ * have no errors at all.
27
+ */
28
+ export declare const TERMINAL_ACTIONS: readonly string[];
29
+ /**
30
+ * The catch-all error every non-terminal modeled action supports. `Compare` is
31
+ * the exception: it fails with NoMatchingCondition instead.
32
+ */
33
+ export declare const NO_MATCHING_ERROR = "NoMatchingError";
34
+ export declare const NO_MATCHING_CONDITION = "NoMatchingCondition";
35
+ /** The error GetParticipantInput takes when no digit arrives in time. */
36
+ export declare const INPUT_TIME_LIMIT_EXCEEDED = "InputTimeLimitExceeded";
37
+ /**
38
+ * Additional error types beyond the catch-all, by action type, in the order
39
+ * the builder emits them.
40
+ */
41
+ export declare const EXTRA_ERRORS: Readonly<Record<string, readonly string[]>>;
42
+ /**
43
+ * Which flow types each action is legal in, transcribed from the Restrictions
44
+ * section of each action's doc page (the modeled set and its pages are listed
45
+ * in conformance/flow-language/actions.md). Consumed by the
46
+ * `action-allowed-in-flow-type` lint rule.
47
+ *
48
+ * An action absent from this table is unrestricted; FLOW_TYPE_UNRESTRICTED
49
+ * names those explicitly, and actions.test.ts holds the two lists to the whole
50
+ * modeled set so a new block cannot land with its Restrictions section unread.
51
+ */
52
+ export declare const FLOW_TYPE_RESTRICTIONS: Readonly<Record<string, readonly string[]>>;
53
+ /**
54
+ * Modeled actions whose doc page states no flow-type restriction. Listed rather
55
+ * than merely omitted from the table above so that "unrestricted" is a recorded
56
+ * reading of the page, not a gap.
57
+ *
58
+ * Compare: "This action is available in every type of flow."
59
+ * https://docs.aws.amazon.com/connect/latest/devguide/flow-control-actions-compare.html
60
+ * UpdateContactAttributes: "None. This can be used in any type of flow and any
61
+ * channel."
62
+ * https://docs.aws.amazon.com/connect/latest/devguide/contact-actions-updatecontactattributes.html
63
+ * InvokeLambdaFunction: "None. This action is supported by all channels and in
64
+ * all types of flows."
65
+ * https://docs.aws.amazon.com/connect/latest/devguide/interactions-invokelambdafunction.html
66
+ */
67
+ export declare const FLOW_TYPE_UNRESTRICTED: readonly string[];
68
+ /** InvokeLambdaFunction.InvocationTimeLimitSeconds bounds, per the doc page. */
69
+ export declare const LAMBDA_TIMEOUT_MIN = 1;
70
+ export declare const LAMBDA_TIMEOUT_MAX = 8;
71
+ /**
72
+ * GetParticipantInput.InputTimeLimitSeconds bounds. The action page requires
73
+ * "a valid integer larger than zero"; the ceiling is the console's Set timeout
74
+ * control, which accepts 1 to 180 seconds.
75
+ * https://docs.aws.amazon.com/connect/latest/devguide/participant-actions-getparticipantinput.html
76
+ * https://docs.aws.amazon.com/connect/latest/adminguide/get-customer-input.html
77
+ */
78
+ export declare const INPUT_TIMEOUT_MIN = 1;
79
+ export declare const INPUT_TIMEOUT_MAX = 180;
80
+ /**
81
+ * The keys a DTMF menu branch may match: "must be static and be a single
82
+ * character - 0-9 numeric, *, or #".
83
+ * https://docs.aws.amazon.com/connect/latest/devguide/participant-actions-getparticipantinput.html
84
+ */
85
+ export declare const DTMF_DIGITS: readonly ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "*", "#"];
86
+ export type DtmfDigit = (typeof DTMF_DIGITS)[number];
87
+ //# sourceMappingURL=actions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../src/actions.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAE5C,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;CAeb,CAAC;AAEX,MAAM,MAAM,iBAAiB,GAAG,CAAC,OAAO,UAAU,CAAC,CAAC,MAAM,OAAO,UAAU,CAAC,CAAC;AAE7E;;;GAGG;AACH,eAAO,MAAM,gBAAgB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CAQxF,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,gBAAgB,EAAE,SAAS,MAAM,EAI7C,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,iBAAiB,oBAAoB,CAAC;AACnD,eAAO,MAAM,qBAAqB,wBAAwB,CAAC;AAE3D,yEAAyE;AACzE,eAAO,MAAM,yBAAyB,2BAA2B,CAAC;AAElE;;;GAGG;AACH,eAAO,MAAM,YAAY,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,CAMpE,CAAC;AA8BF;;;;;;;;;GASG;AACH,eAAO,MAAM,sBAAsB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,CA+D9E,CAAC;AAEF;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,sBAAsB,EAAE,SAAS,MAAM,EAInD,CAAC;AAEF,gFAAgF;AAChF,eAAO,MAAM,kBAAkB,IAAI,CAAC;AACpC,eAAO,MAAM,kBAAkB,IAAI,CAAC;AAEpC;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,IAAI,CAAC;AACnC,eAAO,MAAM,iBAAiB,MAAM,CAAC;AAErC;;;;GAIG;AACH,eAAO,MAAM,WAAW,uEAAwE,CAAC;AACjG,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC"}