@greenpandastudios/aug-cli 0.19.0 → 0.20.1

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 (459) hide show
  1. package/README.md +9 -6
  2. package/THIRD_PARTY_NOTICES.md +4 -0
  3. package/bin/aug.mjs +12 -2
  4. package/docs/about.md +27 -0
  5. package/docs/api/crypto.md +103 -69
  6. package/docs/api/io.md +35 -33
  7. package/docs/api/json.md +3 -3
  8. package/docs/api/memory.md +23 -19
  9. package/docs/api/time.md +10 -9
  10. package/docs/api/web.md +33 -38
  11. package/docs/compatibility.md +3 -3
  12. package/docs/contributing-benchmarks.md +38 -0
  13. package/docs/dev-containers.md +95 -0
  14. package/docs/diagnostics.md +15 -5
  15. package/docs/docker.md +174 -12
  16. package/docs/editor.md +35 -0
  17. package/docs/example-projects.json +206 -24
  18. package/docs/examples/approved-design/counters.md +34 -126
  19. package/docs/examples/approved-design/dependencies/august/0.20.1/io/contracts.md +178 -0
  20. package/docs/examples/approved-design/domain/app.md +13 -77
  21. package/docs/examples/approved-design/domain/export.md +5 -19
  22. package/docs/examples/approved-design/domain/models.md +4 -23
  23. package/docs/examples/approved-design/domain/numbers.md +24 -114
  24. package/docs/examples/approved-design/index.md +16 -7
  25. package/docs/examples/approved-design/main.md +19 -96
  26. package/docs/examples/benchmark/index.md +6 -5
  27. package/docs/examples/benchmark/main.md +7 -35
  28. package/docs/examples/cli-args/index.md +6 -5
  29. package/docs/examples/cli-args/main.md +6 -31
  30. package/docs/examples/collections/index.md +6 -5
  31. package/docs/examples/collections/main.md +7 -35
  32. package/docs/examples/collections-benchmark/index.md +6 -5
  33. package/docs/examples/collections-benchmark/main.md +7 -35
  34. package/docs/examples/cpu-benchmark/index.md +6 -5
  35. package/docs/examples/cpu-benchmark/main.md +5 -24
  36. package/docs/examples/developer-workflow/calculator.md +39 -186
  37. package/docs/examples/developer-workflow/dependencies/august/0.20.1/io/contracts.md +178 -0
  38. package/docs/examples/developer-workflow/index.md +16 -7
  39. package/docs/examples/developer-workflow/logging/console.md +10 -56
  40. package/docs/examples/developer-workflow/logging/export.md +4 -14
  41. package/docs/examples/developer-workflow/logging/logger.md +7 -43
  42. package/docs/examples/developer-workflow/main.md +17 -69
  43. package/docs/examples/drop/index.md +6 -5
  44. package/docs/examples/drop/main.md +7 -27
  45. package/docs/examples/drop/resource.md +7 -30
  46. package/docs/examples/errors/errors.md +7 -27
  47. package/docs/examples/errors/index.md +6 -5
  48. package/docs/examples/errors/main.md +7 -28
  49. package/docs/examples/ffi/index.md +6 -5
  50. package/docs/examples/ffi/main.md +6 -20
  51. package/docs/examples/ffi/native.md +8 -34
  52. package/docs/examples/generic-di/dependencies/august/0.20.1/io/contracts.md +178 -0
  53. package/docs/examples/generic-di/index.md +6 -5
  54. package/docs/examples/generic-di/main.md +9 -39
  55. package/docs/examples/generic-di/types.md +23 -92
  56. package/docs/examples/generics/index.md +6 -5
  57. package/docs/examples/generics/main.md +10 -47
  58. package/docs/examples/generics/types.md +25 -100
  59. package/docs/examples/hello/app/export.md +4 -12
  60. package/docs/examples/hello/app/greeter.md +13 -91
  61. package/docs/examples/hello/dependencies/august/0.20.1/io/contracts.md +178 -0
  62. package/docs/examples/hello/index.md +17 -6
  63. package/docs/examples/hello/logging/console.md +10 -54
  64. package/docs/examples/hello/logging/export.md +4 -14
  65. package/docs/examples/hello/logging/logger.md +7 -45
  66. package/docs/examples/hello/main.md +9 -39
  67. package/docs/examples/http-benchmark/index.md +6 -5
  68. package/docs/examples/http-benchmark/main.md +6 -20
  69. package/docs/examples/http-benchmark/routes.md +9 -31
  70. package/docs/examples/index.md +46 -29
  71. package/docs/examples/interceptors/app.md +20 -139
  72. package/docs/examples/interceptors/dependencies/august/0.20.1/io/contracts.md +178 -0
  73. package/docs/examples/interceptors/index.md +6 -5
  74. package/docs/examples/interceptors/interceptors.md +24 -148
  75. package/docs/examples/interceptors/logging.md +13 -76
  76. package/docs/examples/interceptors/main.md +10 -65
  77. package/docs/examples/json-benchmark/data.md +4 -20
  78. package/docs/examples/json-benchmark/dependencies/packages/@git/url_2d3c37c690c0fa115be1/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301/contracts.md +67 -0
  79. package/docs/examples/json-benchmark/index.md +7 -5
  80. package/docs/examples/json-benchmark/main-yaml.md +20 -0
  81. package/docs/examples/json-benchmark/main.md +10 -49
  82. package/docs/examples/new-syntax/console.md +10 -52
  83. package/docs/examples/new-syntax/dependencies/august/0.20.1/io/contracts.md +178 -0
  84. package/docs/examples/new-syntax/greeter.md +13 -71
  85. package/docs/examples/new-syntax/index.md +6 -5
  86. package/docs/examples/new-syntax/logger.md +7 -43
  87. package/docs/examples/new-syntax/main.md +10 -53
  88. package/docs/examples/new-syntax/math.md +6 -24
  89. package/docs/examples/oidc-login/client/contracts.md +10 -61
  90. package/docs/examples/oidc-login/client/endpoints.md +32 -154
  91. package/docs/examples/oidc-login/client/export.md +5 -23
  92. package/docs/examples/oidc-login/client/login.md +234 -344
  93. package/docs/examples/oidc-login/client/logout.md +38 -143
  94. package/docs/examples/oidc-login/client/protocol.md +183 -304
  95. package/docs/examples/oidc-login/client/session.md +41 -149
  96. package/docs/examples/oidc-login/client/views.md +13 -58
  97. package/docs/examples/oidc-login/common/export.md +6 -26
  98. package/docs/examples/oidc-login/common/headers.md +42 -72
  99. package/docs/examples/oidc-login/common/keys.md +40 -164
  100. package/docs/examples/oidc-login/common/settings.md +24 -40
  101. package/docs/examples/oidc-login/common/views.md +7 -28
  102. package/docs/examples/oidc-login/dependencies/packages/@git/url_0eb7c89453c87681ed15/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301/store.md +205 -0
  103. package/docs/examples/oidc-login/dependencies/packages/@git/url_2d3c37c690c0fa115be1/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301/contracts.md +67 -0
  104. package/docs/examples/oidc-login/dependencies/packages/@git/url_897efafd565158fc4908/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301/contracts.md +267 -0
  105. package/docs/examples/oidc-login/dependencies/packages/@git/url_9ef654c66d34ab8f5527/0.0.0-git.b14a0f9aa41f1ce58bd51133bcdc424033e40d40/contracts.md +415 -0
  106. package/docs/examples/oidc-login/dependencies/packages/@git/url_9ef654c66d34ab8f5527/0.0.0-git.b14a0f9aa41f1ce58bd51133bcdc424033e40d40/jose.md +271 -0
  107. package/docs/examples/oidc-login/dependencies/packages/@git/url_c092cd151499c4e1d8a1/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301/contracts.md +89 -0
  108. package/docs/examples/oidc-login/index.md +8 -7
  109. package/docs/examples/oidc-login/main-yaml.md +7 -0
  110. package/docs/examples/oidc-login/main.md +26 -153
  111. package/docs/examples/oidc-login/provider/authorization.md +232 -275
  112. package/docs/examples/oidc-login/provider/contracts.md +24 -146
  113. package/docs/examples/oidc-login/provider/credentials.md +24 -57
  114. package/docs/examples/oidc-login/provider/discovery.md +48 -122
  115. package/docs/examples/oidc-login/provider/export.md +11 -37
  116. package/docs/examples/oidc-login/provider/token.md +159 -237
  117. package/docs/examples/oidc-login/provider/userinfo.md +47 -102
  118. package/docs/examples/oidc-login/provider/views.md +13 -53
  119. package/docs/examples/ownership/counter.md +17 -63
  120. package/docs/examples/ownership/index.md +6 -5
  121. package/docs/examples/ownership/main.md +7 -30
  122. package/docs/examples/ownership-transfer/dependencies/august/0.20.1/io/contracts.md +178 -0
  123. package/docs/examples/ownership-transfer/index.md +6 -5
  124. package/docs/examples/ownership-transfer/main.md +10 -52
  125. package/docs/examples/ownership-transfer/resource.md +15 -67
  126. package/docs/examples/packages-app/dependencies/packages/@example/aug-math/0.1.0/arithmetic.md +12 -50
  127. package/docs/examples/packages-app/index.md +7 -6
  128. package/docs/examples/packages-app/main.md +7 -25
  129. package/docs/examples/packages-math/aug-package-json.md +1 -1
  130. package/docs/examples/packages-math/index.md +7 -6
  131. package/docs/examples/packages-math/src/arithmetic.md +12 -50
  132. package/docs/examples/packages-math/src/export.md +4 -12
  133. package/docs/examples/startup-benchmark/index.md +6 -5
  134. package/docs/examples/startup-benchmark/main.md +5 -17
  135. package/docs/examples/visibility/counter.md +19 -67
  136. package/docs/examples/visibility/index.md +6 -5
  137. package/docs/examples/visibility/main.md +7 -31
  138. package/docs/examples/weather-api/forecasts.md +168 -0
  139. package/docs/examples/weather-api/index.md +42 -0
  140. package/docs/examples/weather-api/main-yaml.md +21 -0
  141. package/docs/examples/weather-api/main.md +65 -0
  142. package/docs/examples.json +10 -0
  143. package/docs/getting-started.md +105 -2
  144. package/docs/grammar.md +6 -4
  145. package/docs/guides/change-a-module.md +64 -0
  146. package/docs/guides/index.md +27 -0
  147. package/docs/index.md +51 -29
  148. package/docs/language-conformance.md +1 -1
  149. package/docs/language-constructs.md +22 -22
  150. package/docs/language-design-audit.md +1 -1
  151. package/docs/learn/data-and-errors.md +77 -0
  152. package/docs/learn/index.md +30 -0
  153. package/docs/learn/modules-and-dependencies.md +73 -0
  154. package/docs/learn/state-and-tests.md +71 -0
  155. package/docs/learn/values-and-functions.md +62 -0
  156. package/docs/lesson-failures.json +8 -0
  157. package/docs/maintaining-docs.md +16 -4
  158. package/docs/packages.md +72 -126
  159. package/docs/performance.md +13 -41
  160. package/docs/production-readiness.md +5 -4
  161. package/docs/public/downloads/approved-design.zip +0 -0
  162. package/docs/public/downloads/benchmark.zip +0 -0
  163. package/docs/public/downloads/cli-args.zip +0 -0
  164. package/docs/public/downloads/collections-benchmark.zip +0 -0
  165. package/docs/public/downloads/collections.zip +0 -0
  166. package/docs/public/downloads/cpu-benchmark.zip +0 -0
  167. package/docs/public/downloads/developer-workflow.zip +0 -0
  168. package/docs/public/downloads/drop.zip +0 -0
  169. package/docs/public/downloads/errors.zip +0 -0
  170. package/docs/public/downloads/ffi.zip +0 -0
  171. package/docs/public/downloads/generic-di.zip +0 -0
  172. package/docs/public/downloads/generics.zip +0 -0
  173. package/docs/public/downloads/hello.zip +0 -0
  174. package/docs/public/downloads/http-benchmark.zip +0 -0
  175. package/docs/public/downloads/interceptors.zip +0 -0
  176. package/docs/public/downloads/json-benchmark.zip +0 -0
  177. package/docs/public/downloads/new-syntax.zip +0 -0
  178. package/docs/public/downloads/oidc-login.zip +0 -0
  179. package/docs/public/downloads/ownership-transfer.zip +0 -0
  180. package/docs/public/downloads/ownership.zip +0 -0
  181. package/docs/public/downloads/packages-app.zip +0 -0
  182. package/docs/public/downloads/packages-math.zip +0 -0
  183. package/docs/public/downloads/startup-benchmark.zip +0 -0
  184. package/docs/public/downloads/visibility.zip +0 -0
  185. package/docs/public/downloads/weather-api.zip +0 -0
  186. package/docs/reference.md +23 -17
  187. package/docs/releasing.md +29 -15
  188. package/docs/research/code-to-natural-language.md +108 -0
  189. package/docs/research/ecosystem-workflow.md +41 -0
  190. package/docs/research/wiki-editorial-design.md +71 -0
  191. package/docs/roadmap.md +1 -1
  192. package/docs/specifications.md +27 -11
  193. package/docs/testing.md +19 -5
  194. package/docs/tooling.md +25 -12
  195. package/docs/weather-api.md +65 -0
  196. package/docs/web.md +50 -18
  197. package/docs/writing-docs.md +49 -0
  198. package/examples/{hello/.aug-spec/august/0.19.0 → approved-design/.aug-spec/august/0.20.1}/io/contracts.aug +4 -3
  199. package/examples/approved-design/.aug-spec/august/0.20.1/io/contracts.aug.md +82 -0
  200. package/examples/approved-design/.aug-spec/manifest.json +3 -3
  201. package/examples/approved-design/counters.aug +5 -4
  202. package/examples/approved-design/counters.aug.md +25 -132
  203. package/examples/approved-design/domain/app.aug +2 -1
  204. package/examples/approved-design/domain/app.aug.md +10 -80
  205. package/examples/approved-design/domain/export.aug +1 -0
  206. package/examples/approved-design/domain/export.aug.md +4 -20
  207. package/examples/approved-design/domain/models.aug +1 -0
  208. package/examples/approved-design/domain/models.aug.md +3 -25
  209. package/examples/approved-design/domain/numbers.aug +3 -2
  210. package/examples/approved-design/domain/numbers.aug.md +19 -116
  211. package/examples/approved-design/main.aug +1 -0
  212. package/examples/approved-design/main.aug.md +12 -95
  213. package/examples/benchmark/.aug-spec/manifest.json +1 -1
  214. package/examples/benchmark/main.aug +1 -0
  215. package/examples/benchmark/main.aug.md +6 -36
  216. package/examples/cli-args/.aug-spec/manifest.json +1 -1
  217. package/examples/cli-args/main.aug +1 -0
  218. package/examples/cli-args/main.aug.md +5 -32
  219. package/examples/collections/.aug-spec/manifest.json +1 -1
  220. package/examples/collections/main.aug +1 -0
  221. package/examples/collections/main.aug.md +6 -36
  222. package/examples/{generic-di/.aug-spec/august/0.19.0 → developer-workflow/.aug-spec/august/0.20.1}/io/contracts.aug +4 -3
  223. package/examples/developer-workflow/.aug-spec/august/0.20.1/io/contracts.aug.md +82 -0
  224. package/examples/developer-workflow/.aug-spec/manifest.json +3 -3
  225. package/examples/developer-workflow/calculator.aug +3 -2
  226. package/examples/developer-workflow/calculator.aug.md +28 -189
  227. package/examples/developer-workflow/logging/console.aug +2 -1
  228. package/examples/developer-workflow/logging/console.aug.md +7 -57
  229. package/examples/developer-workflow/logging/export.aug +1 -0
  230. package/examples/developer-workflow/logging/export.aug.md +3 -15
  231. package/examples/developer-workflow/logging/logger.aug +1 -0
  232. package/examples/developer-workflow/logging/logger.aug.md +6 -46
  233. package/examples/developer-workflow/main.aug +1 -0
  234. package/examples/developer-workflow/main.aug.md +10 -68
  235. package/examples/drop/.aug-spec/manifest.json +1 -1
  236. package/examples/drop/main.aug +1 -0
  237. package/examples/drop/main.aug.md +6 -28
  238. package/examples/drop/resource.aug +1 -0
  239. package/examples/drop/resource.aug.md +6 -34
  240. package/examples/errors/.aug-spec/manifest.json +1 -1
  241. package/examples/errors/errors.aug +2 -1
  242. package/examples/errors/errors.aug.md +4 -27
  243. package/examples/errors/main.aug +1 -0
  244. package/examples/errors/main.aug.md +6 -29
  245. package/examples/ffi/.aug-spec/manifest.json +1 -1
  246. package/examples/ffi/main.aug +1 -0
  247. package/examples/ffi/main.aug.md +5 -21
  248. package/examples/ffi/native.aug +2 -1
  249. package/examples/ffi/native.aug.md +5 -35
  250. package/examples/{approved-design/.aug-spec/august/0.19.0 → generic-di/.aug-spec/august/0.20.1}/io/contracts.aug +4 -3
  251. package/examples/generic-di/.aug-spec/august/0.20.1/io/contracts.aug.md +82 -0
  252. package/examples/generic-di/.aug-spec/manifest.json +3 -3
  253. package/examples/generic-di/main.aug +1 -0
  254. package/examples/generic-di/main.aug.md +8 -40
  255. package/examples/generic-di/types.aug +3 -2
  256. package/examples/generic-di/types.aug.md +18 -97
  257. package/examples/generics/.aug-spec/manifest.json +1 -1
  258. package/examples/generics/main.aug +1 -0
  259. package/examples/generics/main.aug.md +9 -48
  260. package/examples/generics/types.aug +4 -3
  261. package/examples/generics/types.aug.md +18 -104
  262. package/examples/{developer-workflow/.aug-spec/august/0.19.0 → hello/.aug-spec/august/0.20.1}/io/contracts.aug +4 -3
  263. package/examples/hello/.aug-spec/august/0.20.1/io/contracts.aug.md +82 -0
  264. package/examples/hello/.aug-spec/manifest.json +3 -3
  265. package/examples/hello/app/export.aug +1 -0
  266. package/examples/hello/app/export.aug.md +3 -13
  267. package/examples/hello/app/greeter.aug +2 -1
  268. package/examples/hello/app/greeter.aug.md +10 -94
  269. package/examples/hello/logging/console.aug +2 -1
  270. package/examples/hello/logging/console.aug.md +7 -55
  271. package/examples/hello/logging/export.aug +1 -0
  272. package/examples/hello/logging/export.aug.md +3 -15
  273. package/examples/hello/logging/logger.aug +1 -0
  274. package/examples/hello/logging/logger.aug.md +6 -48
  275. package/examples/hello/main.aug +1 -0
  276. package/examples/hello/main.aug.md +8 -40
  277. package/examples/interceptors/.aug-spec/august/0.20.1/io/contracts.aug +37 -0
  278. package/examples/interceptors/.aug-spec/august/0.20.1/io/contracts.aug.md +82 -0
  279. package/examples/interceptors/.aug-spec/manifest.json +3 -3
  280. package/examples/interceptors/app.aug +3 -2
  281. package/examples/interceptors/app.aug.md +15 -141
  282. package/examples/interceptors/interceptors.aug +3 -2
  283. package/examples/interceptors/interceptors.aug.md +19 -152
  284. package/examples/interceptors/logging.aug +2 -1
  285. package/examples/interceptors/logging.aug.md +10 -79
  286. package/examples/interceptors/main.aug +1 -0
  287. package/examples/interceptors/main.aug.md +9 -66
  288. package/examples/new-syntax/.aug-spec/august/0.20.1/io/contracts.aug +37 -0
  289. package/examples/new-syntax/.aug-spec/august/0.20.1/io/contracts.aug.md +82 -0
  290. package/examples/new-syntax/.aug-spec/manifest.json +3 -3
  291. package/examples/new-syntax/console.aug +2 -1
  292. package/examples/new-syntax/console.aug.md +7 -53
  293. package/examples/new-syntax/greeter.aug +2 -1
  294. package/examples/new-syntax/greeter.aug.md +10 -74
  295. package/examples/new-syntax/logger.aug +1 -0
  296. package/examples/new-syntax/logger.aug.md +6 -46
  297. package/examples/new-syntax/main.aug +1 -0
  298. package/examples/new-syntax/main.aug.md +9 -54
  299. package/examples/new-syntax/math.aug +2 -1
  300. package/examples/new-syntax/math.aug.md +3 -24
  301. package/examples/oidc-login/.aug-spec/manifest.json +13 -13
  302. package/examples/oidc-login/.aug-spec/packages/@git/url_0eb7c89453c87681ed15/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301/store.aug.md +71 -0
  303. package/examples/oidc-login/.aug-spec/packages/@git/url_2d3c37c690c0fa115be1/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301/contracts.aug.md +17 -0
  304. package/examples/oidc-login/.aug-spec/packages/@git/url_897efafd565158fc4908/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301/contracts.aug.md +125 -0
  305. package/examples/oidc-login/.aug-spec/{august/0.19.0/crypto → packages/@git/url_9ef654c66d34ab8f5527/0.0.0-git.b14a0f9aa41f1ce58bd51133bcdc424033e40d40}/contracts.aug +12 -11
  306. package/examples/oidc-login/.aug-spec/packages/@git/url_9ef654c66d34ab8f5527/0.0.0-git.b14a0f9aa41f1ce58bd51133bcdc424033e40d40/contracts.aug.md +244 -0
  307. package/examples/oidc-login/.aug-spec/{august/0.19.0/crypto → packages/@git/url_9ef654c66d34ab8f5527/0.0.0-git.b14a0f9aa41f1ce58bd51133bcdc424033e40d40}/jose.aug +6 -5
  308. package/examples/oidc-login/.aug-spec/packages/@git/url_9ef654c66d34ab8f5527/0.0.0-git.b14a0f9aa41f1ce58bd51133bcdc424033e40d40/jose.aug.md +71 -0
  309. package/examples/oidc-login/.aug-spec/packages/@git/url_c092cd151499c4e1d8a1/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301/contracts.aug.md +30 -0
  310. package/examples/oidc-login/aug.lock.json +100 -0
  311. package/examples/oidc-login/client/contracts.aug +1 -0
  312. package/examples/oidc-login/client/contracts.aug.md +9 -66
  313. package/examples/oidc-login/client/endpoints.aug +6 -5
  314. package/examples/oidc-login/client/endpoints.aug.md +13 -145
  315. package/examples/oidc-login/client/export.aug +1 -0
  316. package/examples/oidc-login/client/export.aug.md +4 -24
  317. package/examples/oidc-login/client/login.aug +7 -6
  318. package/examples/oidc-login/client/login.aug.md +25 -303
  319. package/examples/oidc-login/client/logout.aug +5 -4
  320. package/examples/oidc-login/client/logout.aug.md +13 -135
  321. package/examples/oidc-login/client/protocol.aug +7 -6
  322. package/examples/oidc-login/client/protocol.aug.md +36 -283
  323. package/examples/oidc-login/client/session.aug +5 -4
  324. package/examples/oidc-login/client/session.aug.md +12 -139
  325. package/examples/oidc-login/client/views.aug +3 -2
  326. package/examples/oidc-login/client/views.aug.md +8 -57
  327. package/examples/oidc-login/common/export.aug +1 -0
  328. package/examples/oidc-login/common/export.aug.md +5 -27
  329. package/examples/oidc-login/common/headers.aug +4 -3
  330. package/examples/oidc-login/common/headers.aug.md +9 -67
  331. package/examples/oidc-login/common/keys.aug +6 -5
  332. package/examples/oidc-login/common/keys.aug.md +29 -165
  333. package/examples/oidc-login/common/settings.aug +2 -1
  334. package/examples/oidc-login/common/settings.aug.md +5 -39
  335. package/examples/oidc-login/common/views.aug +2 -1
  336. package/examples/oidc-login/common/views.aug.md +4 -28
  337. package/examples/oidc-login/main.aug +6 -16
  338. package/examples/oidc-login/main.aug.md +17 -146
  339. package/examples/oidc-login/main.yaml +7 -0
  340. package/examples/oidc-login/provider/authorization.aug +7 -6
  341. package/examples/oidc-login/provider/authorization.aug.md +23 -238
  342. package/examples/oidc-login/provider/contracts.aug +1 -0
  343. package/examples/oidc-login/provider/contracts.aug.md +23 -158
  344. package/examples/oidc-login/provider/credentials.aug +3 -2
  345. package/examples/oidc-login/provider/credentials.aug.md +9 -53
  346. package/examples/oidc-login/provider/discovery.aug +4 -3
  347. package/examples/oidc-login/provider/discovery.aug.md +11 -118
  348. package/examples/oidc-login/provider/export.aug +1 -0
  349. package/examples/oidc-login/provider/export.aug.md +6 -34
  350. package/examples/oidc-login/provider/token.aug +6 -5
  351. package/examples/oidc-login/provider/token.aug.md +16 -204
  352. package/examples/oidc-login/provider/userinfo.aug +4 -3
  353. package/examples/oidc-login/provider/userinfo.aug.md +10 -92
  354. package/examples/oidc-login/provider/views.aug +3 -2
  355. package/examples/oidc-login/provider/views.aug.md +8 -52
  356. package/examples/ownership/.aug-spec/manifest.json +1 -1
  357. package/examples/ownership/counter.aug +3 -2
  358. package/examples/ownership/counter.aug.md +12 -66
  359. package/examples/ownership/main.aug +1 -0
  360. package/examples/ownership/main.aug.md +6 -31
  361. package/examples/ownership-transfer/.aug-spec/august/0.20.1/io/contracts.aug +37 -0
  362. package/examples/ownership-transfer/.aug-spec/august/0.20.1/io/contracts.aug.md +82 -0
  363. package/examples/ownership-transfer/.aug-spec/manifest.json +3 -3
  364. package/examples/ownership-transfer/main.aug +1 -0
  365. package/examples/ownership-transfer/main.aug.md +9 -53
  366. package/examples/ownership-transfer/resource.aug +2 -1
  367. package/examples/ownership-transfer/resource.aug.md +12 -71
  368. package/examples/packages/app/.aug-spec/manifest.json +1 -1
  369. package/examples/packages/app/.aug-spec/packages/@example/aug-math/0.1.0/arithmetic.aug +2 -1
  370. package/examples/packages/app/.aug-spec/packages/@example/aug-math/0.1.0/arithmetic.aug.md +9 -51
  371. package/examples/packages/app/main.aug +1 -0
  372. package/examples/packages/app/main.aug.md +6 -26
  373. package/examples/packages/math/.aug-spec/manifest.json +1 -1
  374. package/examples/packages/math/aug-package.json +1 -1
  375. package/examples/packages/math/src/arithmetic.aug +2 -1
  376. package/examples/packages/math/src/arithmetic.aug.md +9 -51
  377. package/examples/packages/math/src/export.aug +1 -0
  378. package/examples/packages/math/src/export.aug.md +3 -13
  379. package/examples/visibility/.aug-spec/manifest.json +1 -1
  380. package/examples/visibility/counter.aug +4 -3
  381. package/examples/visibility/counter.aug.md +12 -68
  382. package/examples/visibility/main.aug +1 -0
  383. package/examples/visibility/main.aug.md +6 -32
  384. package/examples/weather-api/.aug-spec/manifest.json +8 -0
  385. package/examples/weather-api/AGENTS.md +17 -0
  386. package/examples/weather-api/README.md +19 -0
  387. package/examples/weather-api/forecasts.aug +47 -0
  388. package/examples/weather-api/forecasts.aug.md +32 -0
  389. package/examples/weather-api/main.aug +4 -0
  390. package/examples/weather-api/main.aug.md +15 -0
  391. package/examples/weather-api/main.yaml +5 -0
  392. package/examples/weather-api/weather.http +5 -0
  393. package/package.json +3 -4
  394. package/scripts/bootstrap-native.mjs +181 -106
  395. package/scripts/native-setup.mjs +98 -0
  396. package/scripts/native-toolchain.mjs +28 -0
  397. package/src/builtins.js +1 -1
  398. package/src/checker.js +259 -72
  399. package/src/cli.js +114 -20
  400. package/src/codegen.js +1 -1
  401. package/src/config.js +1 -1
  402. package/src/contracts.js +10 -0
  403. package/src/editor.js +71 -16
  404. package/src/fixes.js +90 -2
  405. package/src/formatter.js +19 -8
  406. package/src/git-packages.js +110 -0
  407. package/src/help.js +24 -23
  408. package/src/http-contracts.js +14 -0
  409. package/src/http-policies.js +5 -5
  410. package/src/libraries.js +1 -1
  411. package/src/lsp.js +14 -5
  412. package/src/native.js +19 -13
  413. package/src/navigation.js +4 -2
  414. package/src/openapi.js +5 -4
  415. package/src/package-locking.js +45 -0
  416. package/src/package-manager.js +251 -67
  417. package/src/parser.js +13 -5
  418. package/src/policies.js +3 -3
  419. package/src/project-init.js +78 -4
  420. package/src/project.js +9 -7
  421. package/src/semantic.js +46 -2
  422. package/src/snippets.js +59 -0
  423. package/src/spec-hints.js +56 -0
  424. package/src/spec-tree.js +241 -0
  425. package/src/spec.js +626 -303
  426. package/docs/examples/approved-design/dependencies/august/0.19.0/io/contracts.md +0 -395
  427. package/docs/examples/developer-workflow/dependencies/august/0.19.0/io/contracts.md +0 -395
  428. package/docs/examples/generic-di/dependencies/august/0.19.0/io/contracts.md +0 -395
  429. package/docs/examples/hello/dependencies/august/0.19.0/io/contracts.md +0 -395
  430. package/docs/examples/interceptors/dependencies/august/0.19.0/io/contracts.md +0 -395
  431. package/docs/examples/json-benchmark/dependencies/august/0.19.0/json/contracts.md +0 -103
  432. package/docs/examples/new-syntax/dependencies/august/0.19.0/io/contracts.md +0 -395
  433. package/docs/examples/oidc-login/dependencies/august/0.19.0/crypto/contracts.md +0 -925
  434. package/docs/examples/oidc-login/dependencies/august/0.19.0/crypto/jose.md +0 -434
  435. package/docs/examples/oidc-login/dependencies/august/0.19.0/json/contracts.md +0 -103
  436. package/docs/examples/oidc-login/dependencies/august/0.19.0/memory/store.md +0 -374
  437. package/docs/examples/oidc-login/dependencies/august/0.19.0/time/contracts.md +0 -150
  438. package/docs/examples/oidc-login/dependencies/august/0.19.0/web/contracts.md +0 -532
  439. package/docs/examples/ownership-transfer/dependencies/august/0.19.0/io/contracts.md +0 -395
  440. package/examples/approved-design/.aug-spec/august/0.19.0/io/contracts.aug.md +0 -316
  441. package/examples/developer-workflow/.aug-spec/august/0.19.0/io/contracts.aug.md +0 -316
  442. package/examples/generic-di/.aug-spec/august/0.19.0/io/contracts.aug.md +0 -316
  443. package/examples/hello/.aug-spec/august/0.19.0/io/contracts.aug.md +0 -316
  444. package/examples/interceptors/.aug-spec/august/0.19.0/io/contracts.aug +0 -36
  445. package/examples/interceptors/.aug-spec/august/0.19.0/io/contracts.aug.md +0 -316
  446. package/examples/new-syntax/.aug-spec/august/0.19.0/io/contracts.aug +0 -36
  447. package/examples/new-syntax/.aug-spec/august/0.19.0/io/contracts.aug.md +0 -316
  448. package/examples/oidc-login/.aug-spec/august/0.19.0/crypto/contracts.aug.md +0 -791
  449. package/examples/oidc-login/.aug-spec/august/0.19.0/crypto/jose.aug.md +0 -266
  450. package/examples/oidc-login/.aug-spec/august/0.19.0/json/contracts.aug.md +0 -55
  451. package/examples/oidc-login/.aug-spec/august/0.19.0/memory/store.aug.md +0 -250
  452. package/examples/oidc-login/.aug-spec/august/0.19.0/time/contracts.aug.md +0 -96
  453. package/examples/oidc-login/.aug-spec/august/0.19.0/web/contracts.aug.md +0 -420
  454. package/examples/ownership-transfer/.aug-spec/august/0.19.0/io/contracts.aug +0 -36
  455. package/examples/ownership-transfer/.aug-spec/august/0.19.0/io/contracts.aug.md +0 -316
  456. /package/examples/oidc-login/.aug-spec/{august/0.19.0/memory → packages/@git/url_0eb7c89453c87681ed15/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301}/store.aug +0 -0
  457. /package/examples/oidc-login/.aug-spec/{august/0.19.0/json → packages/@git/url_2d3c37c690c0fa115be1/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301}/contracts.aug +0 -0
  458. /package/examples/oidc-login/.aug-spec/{august/0.19.0/web → packages/@git/url_897efafd565158fc4908/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301}/contracts.aug +0 -0
  459. /package/examples/oidc-login/.aug-spec/{august/0.19.0/time → packages/@git/url_c092cd151499c4e1d8a1/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301}/contracts.aug +0 -0
@@ -49,16 +49,17 @@ pageClass: aug-example-page
49
49
  ::: code-group
50
50
 
51
51
  ```aug [Indentation]
52
+ // aug-spec: "authorization.aug.md" explains this file. Read it before changes; refresh with aug spec.
52
53
  import AuthorizationRequest and AuthorizationCode and LoginForm and LoginError from contracts
53
54
  import ProviderLogin and ProviderFailure from views
54
55
  import verifyCredentials from credentials
55
56
  import settings and securityHeaders and withCookie from common
56
- import Crypto from august.crypto
57
- import Clock from august.time
58
- import ExpiringStore and StoreFull from august.memory
59
- import urlEncode from august.web
57
+ import Crypto from crypto
58
+ import Clock from time
59
+ import ExpiringStore and StoreFull from memory
60
+ import urlEncode from web
60
61
  /** Validate the registered client before offering a login form. A malformed redirect is never followed. */
61
- endpoint GET "/provider/authorize" as authorize(string response_type from query, string client_id from query, string redirect_uri from query, string requestedScope from query "scope", string state from query, string nonce from query, string code_challenge from query, string code_challenge_method from query, resolve Crypto crypto, resolve Clock clock, resolve ExpiringStore<AuthorizationRequest> requests) returns HttpResponse<Html> uses crypto.random and crypto.decodeBase64url and clock.now and requests.put unless LoginError with status 400 and CryptoError with status 503 and TimeError with status 503 and StoreFull with status 503 and HttpError:
62
+ endpoint GET "/provider/authorize" as authorize(string response_type from query, string client_id from query, string redirect_uri from query, string requestedScope from query "scope", string state from query, string nonce from query, string code_challenge from query, string code_challenge_method from query, resolve Crypto crypto, resolve Clock clock, resolve ExpiringStore<AuthorizationRequest> requests) unless LoginError with status 400 and CryptoError with status 503 and TimeError with status 503 and StoreFull with status 503 and HttpError:
62
63
  config = settings()
63
64
  if client_id != config.clientId or redirect_uri != config.callback or response_type != "code" or code_challenge_method != "S256":
64
65
  throw LoginError()
@@ -75,50 +76,135 @@ endpoint GET "/provider/authorize" as authorize(string response_type from query,
75
76
  browser = crypto.random(size=32).base64url()
76
77
  csrf = crypto.random(size=32).base64url()
77
78
  now = clock.now()
78
- request = AuthorizationRequest(clientId=client_id, redirectUri=redirect_uri, state=state, nonce=nonce, challenge=code_challenge, browser=browser, csrf=csrf, expires=now + 300)
79
+ request = AuthorizationRequest(
80
+ clientId=client_id,
81
+ redirectUri=redirect_uri,
82
+ state=state,
83
+ nonce=nonce,
84
+ challenge=code_challenge,
85
+ browser=browser,
86
+ csrf=csrf,
87
+ expires=now + 300
88
+ )
79
89
  requests.put(key=requestId, value=request, expires=request.expires, now=now)
80
- headers = withCookie(headers=securityHeaders(), name="aug_authorize", value=browser, path="/provider", maxAge=300, secure=config.secureCookies)
81
- return HttpResponse(body=ProviderLogin(requestId, csrf, message="Authorize the registered August login app.", submit=handle providerLogin(input from form)), headers=headers)
90
+ headers = withCookie(
91
+ headers=securityHeaders(),
92
+ name="aug_authorize",
93
+ value=browser,
94
+ path="/provider",
95
+ maxAge=300,
96
+ secure=config.secureCookies
97
+ )
98
+ return HttpResponse(
99
+ body=ProviderLogin(
100
+ requestId,
101
+ csrf,
102
+ message="Authorize the registered August login app.",
103
+ submit=handle providerLogin(input from form)
104
+ ),
105
+ headers=headers
106
+ )
82
107
  /** The browser binding and CSRF token are checked before credentials. Each form request is consumed once. */
83
- endpoint POST "/provider/login" as providerLogin(LoginForm form from form, optional string browser from cookie "aug_authorize", optional string origin from header "origin", resolve Crypto crypto, resolve Clock clock, resolve ExpiringStore<AuthorizationRequest> requests, resolve ExpiringStore<AuthorizationCode> codes) returns HttpResponse<Html> uses crypto.equal and crypto.random and crypto.passwordHash and crypto.decodeBase64url and clock.now and requests.take and codes.put unless CryptoError with status 503 and TimeError with status 503 and StoreFull with status 503 and HttpError:
108
+ endpoint POST "/provider/login" as providerLogin(LoginForm form from form, optional string browser from cookie "aug_authorize", optional string origin from header "origin", resolve Crypto crypto, resolve Clock clock, resolve ExpiringStore<AuthorizationRequest> requests, resolve ExpiringStore<AuthorizationCode> codes) unless CryptoError with status 503 and TimeError with status 503 and StoreFull with status 503 and HttpError:
84
109
  config = settings()
85
110
  try:
86
111
  if origin != config.baseUrl:
87
- return HttpResponse(body=ProviderFailure(message="The sign-in form must come from this app."), status=403, headers=securityHeaders())
112
+ return HttpResponse(
113
+ body=ProviderFailure(message="The sign-in form must come from this app."),
114
+ status=403,
115
+ headers=securityHeaders()
116
+ )
88
117
  match requests.take(key=form.request_id, now=clock.now()):
89
118
  when null:
90
- return HttpResponse(body=ProviderFailure(message="The sign-in request expired or was already used."), status=400, headers=securityHeaders())
119
+ return HttpResponse(
120
+ body=ProviderFailure(
121
+ message="The sign-in request expired or was already used."
122
+ ),
123
+ status=400,
124
+ headers=securityHeaders()
125
+ )
91
126
  when some request:
92
127
  match browser:
93
128
  when null:
94
- return HttpResponse(body=ProviderFailure(message="The browser binding is missing."), status=403, headers=securityHeaders())
129
+ return HttpResponse(
130
+ body=ProviderFailure(
131
+ message="The browser binding is missing."
132
+ ),
133
+ status=403,
134
+ headers=securityHeaders()
135
+ )
95
136
  when some secret:
96
- if not crypto.equal(left=secret.bytes(), right=request.browser.bytes()) or not crypto.equal(left=form.csrf.bytes(), right=request.csrf.bytes()):
97
- return HttpResponse(body=ProviderFailure(message="The sign-in form could not be verified."), status=403, headers=securityHeaders())
98
- if not verifyCredentials(username=form.username, password=form.password):
99
- return HttpResponse(body=ProviderFailure(message="The username or password was not accepted."), status=401, headers=securityHeaders())
137
+ if not crypto.equal(
138
+ left=secret.bytes(),
139
+ right=request.browser.bytes()
140
+ ) or not crypto.equal(
141
+ left=form.csrf.bytes(),
142
+ right=request.csrf.bytes()
143
+ ):
144
+ return HttpResponse(
145
+ body=ProviderFailure(
146
+ message="The sign-in form could not be verified."
147
+ ),
148
+ status=403,
149
+ headers=securityHeaders()
150
+ )
151
+ if not verifyCredentials(
152
+ username=form.username,
153
+ password=form.password
154
+ ):
155
+ return HttpResponse(
156
+ body=ProviderFailure(
157
+ message="The username or password was not accepted."
158
+ ),
159
+ status=401,
160
+ headers=securityHeaders()
161
+ )
100
162
  now = clock.now()
101
163
  code = crypto.random(size=32).base64url()
102
- grant = AuthorizationCode(clientId=request.clientId, redirectUri=request.redirectUri, challenge=request.challenge, nonce=request.nonce, subject="demo-ada", name="Ada", expires=now + 60)
164
+ grant = AuthorizationCode(
165
+ clientId=request.clientId,
166
+ redirectUri=request.redirectUri,
167
+ challenge=request.challenge,
168
+ nonce=request.nonce,
169
+ subject="demo-ada",
170
+ name="Ada",
171
+ expires=now + 60
172
+ )
103
173
  codes.put(key=code, value=grant, expires=grant.expires, now=now)
104
174
  location = request.redirectUri + "?code=" + urlEncode(input=code) + "&state=" + urlEncode(input=request.state)
105
- headers = withCookie(headers=securityHeaders().with(name="location", value=location), name="aug_authorize", value="", path="/provider", maxAge=0, secure=config.secureCookies)
106
- return HttpResponse(body=<p>Returning to the application.</p>, status=303, headers=headers)
175
+ headers = withCookie(
176
+ headers=securityHeaders().with(name="location", value=location),
177
+ name="aug_authorize",
178
+ value="",
179
+ path="/provider",
180
+ maxAge=0,
181
+ secure=config.secureCookies
182
+ )
183
+ return HttpResponse(
184
+ body=<p>Returning to the application.</p>,
185
+ status=303,
186
+ headers=headers
187
+ )
107
188
  catch HttpError error:
108
- return HttpResponse(body=ProviderFailure(message="The submitted form is invalid."), status=400, headers=securityHeaders())
189
+ return HttpResponse(
190
+ body=ProviderFailure(message="The submitted form is invalid."),
191
+ status=400,
192
+ headers=securityHeaders()
193
+ )
109
194
  ```
110
195
 
111
196
  ```aug [Braces]
197
+ // aug-spec: "authorization.aug.md" explains this file. Read it before changes; refresh with aug spec.
112
198
  import AuthorizationRequest and AuthorizationCode and LoginForm and LoginError from contracts
113
199
  import ProviderLogin and ProviderFailure from views
114
200
  import verifyCredentials from credentials
115
201
  import settings and securityHeaders and withCookie from common
116
- import Crypto from august.crypto
117
- import Clock from august.time
118
- import ExpiringStore and StoreFull from august.memory
119
- import urlEncode from august.web
202
+ import Crypto from crypto
203
+ import Clock from time
204
+ import ExpiringStore and StoreFull from memory
205
+ import urlEncode from web
120
206
  /** Validate the registered client before offering a login form. A malformed redirect is never followed. */
121
- endpoint GET "/provider/authorize" as authorize(string response_type from query, string client_id from query, string redirect_uri from query, string requestedScope from query "scope", string state from query, string nonce from query, string code_challenge from query, string code_challenge_method from query, resolve Crypto crypto, resolve Clock clock, resolve ExpiringStore<AuthorizationRequest> requests) returns HttpResponse<Html> uses crypto.random and crypto.decodeBase64url and clock.now and requests.put unless LoginError with status 400 and CryptoError with status 503 and TimeError with status 503 and StoreFull with status 503 and HttpError {
207
+ endpoint GET "/provider/authorize" as authorize(string response_type from query, string client_id from query, string redirect_uri from query, string requestedScope from query "scope", string state from query, string nonce from query, string code_challenge from query, string code_challenge_method from query, resolve Crypto crypto, resolve Clock clock, resolve ExpiringStore<AuthorizationRequest> requests) unless LoginError with status 400 and CryptoError with status 503 and TimeError with status 503 and StoreFull with status 503 and HttpError {
122
208
  config = settings()
123
209
  if client_id != config.clientId or redirect_uri != config.callback or response_type != "code" or code_challenge_method != "S256" {
124
210
  throw LoginError()
@@ -141,48 +227,132 @@ endpoint GET "/provider/authorize" as authorize(string response_type from query,
141
227
  browser = crypto.random(size=32).base64url()
142
228
  csrf = crypto.random(size=32).base64url()
143
229
  now = clock.now()
144
- request = AuthorizationRequest(clientId=client_id, redirectUri=redirect_uri, state=state, nonce=nonce, challenge=code_challenge, browser=browser, csrf=csrf, expires=now + 300)
230
+ request = AuthorizationRequest(
231
+ clientId=client_id,
232
+ redirectUri=redirect_uri,
233
+ state=state,
234
+ nonce=nonce,
235
+ challenge=code_challenge,
236
+ browser=browser,
237
+ csrf=csrf,
238
+ expires=now + 300
239
+ )
145
240
  requests.put(key=requestId, value=request, expires=request.expires, now=now)
146
- headers = withCookie(headers=securityHeaders(), name="aug_authorize", value=browser, path="/provider", maxAge=300, secure=config.secureCookies)
147
- return HttpResponse(body=ProviderLogin(requestId, csrf, message="Authorize the registered August login app.", submit=handle providerLogin(input from form)), headers=headers)
241
+ headers = withCookie(
242
+ headers=securityHeaders(),
243
+ name="aug_authorize",
244
+ value=browser,
245
+ path="/provider",
246
+ maxAge=300,
247
+ secure=config.secureCookies
248
+ )
249
+ return HttpResponse(
250
+ body=ProviderLogin(
251
+ requestId,
252
+ csrf,
253
+ message="Authorize the registered August login app.",
254
+ submit=handle providerLogin(input from form)
255
+ ),
256
+ headers=headers
257
+ )
148
258
  }
149
259
  /** The browser binding and CSRF token are checked before credentials. Each form request is consumed once. */
150
- endpoint POST "/provider/login" as providerLogin(LoginForm form from form, optional string browser from cookie "aug_authorize", optional string origin from header "origin", resolve Crypto crypto, resolve Clock clock, resolve ExpiringStore<AuthorizationRequest> requests, resolve ExpiringStore<AuthorizationCode> codes) returns HttpResponse<Html> uses crypto.equal and crypto.random and crypto.passwordHash and crypto.decodeBase64url and clock.now and requests.take and codes.put unless CryptoError with status 503 and TimeError with status 503 and StoreFull with status 503 and HttpError {
260
+ endpoint POST "/provider/login" as providerLogin(LoginForm form from form, optional string browser from cookie "aug_authorize", optional string origin from header "origin", resolve Crypto crypto, resolve Clock clock, resolve ExpiringStore<AuthorizationRequest> requests, resolve ExpiringStore<AuthorizationCode> codes) unless CryptoError with status 503 and TimeError with status 503 and StoreFull with status 503 and HttpError {
151
261
  config = settings()
152
262
  try {
153
263
  if origin != config.baseUrl {
154
- return HttpResponse(body=ProviderFailure(message="The sign-in form must come from this app."), status=403, headers=securityHeaders())
264
+ return HttpResponse(
265
+ body=ProviderFailure(message="The sign-in form must come from this app."),
266
+ status=403,
267
+ headers=securityHeaders()
268
+ )
155
269
  }
156
270
  match requests.take(key=form.request_id, now=clock.now()) {
157
271
  when null {
158
- return HttpResponse(body=ProviderFailure(message="The sign-in request expired or was already used."), status=400, headers=securityHeaders())
272
+ return HttpResponse(
273
+ body=ProviderFailure(
274
+ message="The sign-in request expired or was already used."
275
+ ),
276
+ status=400,
277
+ headers=securityHeaders()
278
+ )
159
279
  }
160
280
  when some request {
161
281
  match browser {
162
282
  when null {
163
- return HttpResponse(body=ProviderFailure(message="The browser binding is missing."), status=403, headers=securityHeaders())
283
+ return HttpResponse(
284
+ body=ProviderFailure(
285
+ message="The browser binding is missing."
286
+ ),
287
+ status=403,
288
+ headers=securityHeaders()
289
+ )
164
290
  }
165
291
  when some secret {
166
- if not crypto.equal(left=secret.bytes(), right=request.browser.bytes()) or not crypto.equal(left=form.csrf.bytes(), right=request.csrf.bytes()) {
167
- return HttpResponse(body=ProviderFailure(message="The sign-in form could not be verified."), status=403, headers=securityHeaders())
292
+ if not crypto.equal(
293
+ left=secret.bytes(),
294
+ right=request.browser.bytes()
295
+ ) or not crypto.equal(
296
+ left=form.csrf.bytes(),
297
+ right=request.csrf.bytes()
298
+ ) {
299
+ return HttpResponse(
300
+ body=ProviderFailure(
301
+ message="The sign-in form could not be verified."
302
+ ),
303
+ status=403,
304
+ headers=securityHeaders()
305
+ )
168
306
  }
169
307
  }
170
308
  }
171
- if not verifyCredentials(username=form.username, password=form.password) {
172
- return HttpResponse(body=ProviderFailure(message="The username or password was not accepted."), status=401, headers=securityHeaders())
309
+ if not verifyCredentials(
310
+ username=form.username,
311
+ password=form.password
312
+ ) {
313
+ return HttpResponse(
314
+ body=ProviderFailure(
315
+ message="The username or password was not accepted."
316
+ ),
317
+ status=401,
318
+ headers=securityHeaders()
319
+ )
173
320
  }
174
321
  now = clock.now()
175
322
  code = crypto.random(size=32).base64url()
176
- grant = AuthorizationCode(clientId=request.clientId, redirectUri=request.redirectUri, challenge=request.challenge, nonce=request.nonce, subject="demo-ada", name="Ada", expires=now + 60)
323
+ grant = AuthorizationCode(
324
+ clientId=request.clientId,
325
+ redirectUri=request.redirectUri,
326
+ challenge=request.challenge,
327
+ nonce=request.nonce,
328
+ subject="demo-ada",
329
+ name="Ada",
330
+ expires=now + 60
331
+ )
177
332
  codes.put(key=code, value=grant, expires=grant.expires, now=now)
178
333
  location = request.redirectUri + "?code=" + urlEncode(input=code) + "&state=" + urlEncode(input=request.state)
179
- headers = withCookie(headers=securityHeaders().with(name="location", value=location), name="aug_authorize", value="", path="/provider", maxAge=0, secure=config.secureCookies)
180
- return HttpResponse(body=<p>Returning to the application.</p>, status=303, headers=headers)
334
+ headers = withCookie(
335
+ headers=securityHeaders().with(name="location", value=location),
336
+ name="aug_authorize",
337
+ value="",
338
+ path="/provider",
339
+ maxAge=0,
340
+ secure=config.secureCookies
341
+ )
342
+ return HttpResponse(
343
+ body=<p>Returning to the application.</p>,
344
+ status=303,
345
+ headers=headers
346
+ )
181
347
  }
182
348
  }
183
349
  }
184
350
  catch HttpError error {
185
- return HttpResponse(body=ProviderFailure(message="The submitted form is invalid."), status=400, headers=securityHeaders())
351
+ return HttpResponse(
352
+ body=ProviderFailure(message="The submitted form is invalid."),
353
+ status=400,
354
+ headers=securityHeaders()
355
+ )
186
356
  }
187
357
  }
188
358
  ```
@@ -195,262 +365,49 @@ endpoint POST "/provider/login" as providerLogin(LoginForm form from form, optio
195
365
 
196
366
  ## Compiled specification {#specification}
197
367
 
198
- August 0.19.0. This document is compiled from checked code with deterministic wording guided by Simplified Technical English.
368
+ Plain handler results default to HTTP 200 unless another status is declared. HttpResponse values choose their own status. Unhandled request failures return HTTP 500 and cancel the request tasks.
199
369
 
200
- ### In this file
370
+ ### `authorize` · [source](authorization.md#code) {#symbol-authorize}
201
371
 
202
- - [`authorize`](authorization.md#symbol-authorize) handles `GET` `/provider/authorize` returning `HttpResponse<Html>`.
203
- - [`providerLogin`](authorization.md#symbol-providerLogin) handles `POST` `/provider/login` returning `HttpResponse<Html>`.
372
+ `authorize` handles `GET /provider/authorize`. Validate the registered client before offering a login form. A malformed redirect is never followed.
204
373
 
205
- ### `authorize` {#symbol-authorize}
374
+ It reads `response_type`, `client_id`, `redirect_uri`, `scope`, `state`, `nonce`, `code_challenge`, and `code_challenge_method` from the HTTP query. `scope` is called `requestedScope` here. It gets `crypto` ([`Crypto`](../dependencies/packages/%40git/url_9ef654c66d34ab8f5527/0.0.0-git.b14a0f9aa41f1ce58bd51133bcdc424033e40d40/contracts.md#symbol-Crypto)), `clock` ([`Clock`](../dependencies/packages/%40git/url_c092cd151499c4e1d8a1/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301/contracts.md#symbol-Clock)), and `requests` ([`ExpiringStore<AuthorizationRequest>`](../dependencies/packages/%40git/url_0eb7c89453c87681ed15/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301/store.md#symbol-ExpiringStore)) from dependency injection. The handler responds with HTTP 400 for [`LoginError`](contracts.md#symbol-LoginError), HTTP 503 for `CryptoError`, HTTP 503 for `TimeError`, and HTTP 503 for [`StoreFull`](../dependencies/packages/%40git/url_0eb7c89453c87681ed15/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301/store.md#symbol-StoreFull).
206
375
 
207
- [source](authorization.md#code)
208
-
209
- **Inputs**
210
-
211
- - `response_type` (`string`) — read from the HTTP query.
212
- - `client_id` (`string`) — read from the HTTP query.
213
- - `redirect_uri` (`string`) — read from the HTTP query.
214
- - `requestedScope` (`string`) — read from the HTTP query named `scope`.
215
- - `state` (`string`) — read from the HTTP query.
216
- - `nonce` (`string`) — read from the HTTP query.
217
- - `code_challenge` (`string`) — read from the HTTP query.
218
- - `code_challenge_method` (`string`) — read from the HTTP query.
219
- - `crypto` ([`Crypto`](../dependencies/august/0.19.0/crypto/contracts.md#symbol-Crypto)) — injected; callers omit it.
220
- - `clock` ([`Clock`](../dependencies/august/0.19.0/time/contracts.md#symbol-Clock)) — injected; callers omit it.
221
- - `requests` ([`ExpiringStore<AuthorizationRequest>`](../dependencies/august/0.19.0/memory/store.md#symbol-ExpiringStore)) — injected; callers omit it.
376
+ It can also raise `HttpError`. It gets `config` from [`settings`](../common/settings.md#symbol-settings). It checks that `client_id` equals `config.clientId` and `redirect_uri` equals `config.callback` and `response_type` equals `"code"` and `code_challenge_method` equals `"S256"`, `requestedScope` is either `"openid"` or `"openid profile"`, and `state` is a URL-safe ASCII token with `43` to `128` characters and `nonce` is a URL-safe ASCII token with `43` to `128` characters and the byte length of `code_challenge` equals `43`. It raises a [`LoginError`](contracts.md#symbol-LoginError) at the first failed check.
222
377
 
223
- Returns: `HttpResponse<Html>`.
378
+ It checks that the byte length of [`crypto.decodeBase64url`](../dependencies/packages/%40git/url_9ef654c66d34ab8f5527/0.0.0-git.b14a0f9aa41f1ce58bd51133bcdc424033e40d40/contracts.md#symbol-Crypto.decodeBase64url) with `input` from `code_challenge` equals `32`. It raises a [`LoginError`](contracts.md#symbol-LoginError) at the first failed check. If this work raises `CryptoError`, it raises a [`LoginError`](contracts.md#symbol-LoginError). It sets `requestId`, `browser`, and `csrf` separately, each to the URL-safe base64 encoding of [`crypto.random`](../dependencies/packages/%40git/url_9ef654c66d34ab8f5527/0.0.0-git.b14a0f9aa41f1ce58bd51133bcdc424033e40d40/contracts.md#symbol-Crypto.random) with `size` `32`.
224
379
 
225
- Capabilities: [`crypto.random`](../dependencies/august/0.19.0/crypto/contracts.md#symbol-Crypto.random), [`crypto.decodeBase64url`](../dependencies/august/0.19.0/crypto/contracts.md#symbol-Crypto.decodeBase64url), [`clock.now`](../dependencies/august/0.19.0/time/contracts.md#symbol-Clock.now), [`requests.put`](../dependencies/august/0.19.0/memory/store.md#symbol-ExpiringStore.put).
380
+ It sets `now` to [`clock.now`](../dependencies/packages/%40git/url_c092cd151499c4e1d8a1/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301/contracts.md#symbol-Clock.now). It sets `request` to an [`AuthorizationRequest`](contracts.md#symbol-AuthorizationRequest) with `clientId` from `client_id`, `redirectUri` from `redirect_uri`, `state`, `nonce`, `challenge` from `code_challenge`, `browser`, `csrf`, and `expires` from `now` plus `300`. It calls [`requests.put`](../dependencies/packages/%40git/url_0eb7c89453c87681ed15/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301/store.md#symbol-ExpiringStore.put) with `key` from `requestId`, `value` from `request`, `request.expires`, and `now`. It sets `headers` to [`withCookie`](../common/headers.md#symbol-withCookie) with `headers` from [`securityHeaders`](../common/headers.md#symbol-securityHeaders), `name` `"aug_authorize"`, `value` from `browser`, `path` `"/provider"`, `maxAge` `300`, and `secure` from `config.secureCookies`.
226
381
 
227
- Can fail with `LoginError`, `CryptoError`, `TimeError`, `StoreFull`, `HttpError`. Callers must catch or propagate these errors.
382
+ It returns HTTP 200 with [`ProviderLogin`](views.md#symbol-ProviderLogin) with `requestId`, `csrf`, `message` `"Authorize the registered August login app."`, and `submit` from a form action that sends `POST /provider/login` to [`providerLogin`](authorization.md#symbol-providerLogin) on submission and `headers` headers.
228
383
 
229
- HTTP route: `GET` `/provider/authorize`. Use status 200 when the handler returns a body; a returned HttpResponse can set its own status. An unhandled request failure returns status 500 and cancels its request tasks.
384
+ ### `providerLogin` · [source](authorization.md#code) {#symbol-providerLogin}
230
385
 
231
- Declared HTTP failures: [`LoginError`](contracts.md#symbol-LoginError) returns status 400; `CryptoError` returns status 503; `TimeError` returns status 503; [`StoreFull`](../dependencies/august/0.19.0/memory/store.md#symbol-StoreFull) returns status 503.
386
+ `providerLogin` handles `POST /provider/login`. The browser binding and CSRF token are checked before credentials. Each form request is consumed once.
232
387
 
233
- **What it does**
388
+ It takes `form` as [`LoginForm`](contracts.md#symbol-LoginForm) from the HTTP form, `browser` as `optional string` from the HTTP cookie `aug_authorize`, and `origin` as `optional string` from the HTTP header `origin`. It gets `crypto` ([`Crypto`](../dependencies/packages/%40git/url_9ef654c66d34ab8f5527/0.0.0-git.b14a0f9aa41f1ce58bd51133bcdc424033e40d40/contracts.md#symbol-Crypto)), `clock` ([`Clock`](../dependencies/packages/%40git/url_c092cd151499c4e1d8a1/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301/contracts.md#symbol-Clock)), `requests` ([`ExpiringStore<AuthorizationRequest>`](../dependencies/packages/%40git/url_0eb7c89453c87681ed15/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301/store.md#symbol-ExpiringStore)), and `codes` ([`ExpiringStore<AuthorizationCode>`](../dependencies/packages/%40git/url_0eb7c89453c87681ed15/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301/store.md#symbol-ExpiringStore)) from dependency injection. Omitted optional inputs are null. The handler responds with HTTP 503 for `CryptoError`, HTTP 503 for `TimeError`, and HTTP 503 for [`StoreFull`](../dependencies/packages/%40git/url_0eb7c89453c87681ed15/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301/store.md#symbol-StoreFull).
234
389
 
235
- - Set `config` to call [`settings`](../common/settings.md#symbol-settings).
236
- - If (((`client_id` does not equal `clientId` of `config`) or (`redirect_uri` does not equal `callback` of `config`)) or (`response_type` does not equal `"code"`)) or (`code_challenge_method` does not equal `"S256"`):
237
- - Fail with call [`LoginError`](contracts.md#symbol-LoginError). Transfer control to a matching catch or propagate the failure.
238
- - If (`requestedScope` does not equal `"openid"`) and (`requestedScope` does not equal `"openid profile"`):
239
- - Fail with call [`LoginError`](contracts.md#symbol-LoginError). Transfer control to a matching catch or propagate the failure.
240
- - If (not (call `isToken` on `state` with `min` = `43`; `max` = `128`) or not (call `isToken` on `nonce` with `min` = `43`; `max` = `128`)) or (call `length` on `code_challenge` does not equal `43`):
241
- - Fail with call [`LoginError`](contracts.md#symbol-LoginError). Transfer control to a matching catch or propagate the failure.
242
- - Try these operations:
243
- - If call `length` on call [`Crypto.decodeBase64url`](../dependencies/august/0.19.0/crypto/contracts.md#symbol-Crypto.decodeBase64url) on `crypto` with `input` = `code_challenge` does not equal `32`:
244
- - Fail with call [`LoginError`](contracts.md#symbol-LoginError). Transfer control to a matching catch or propagate the failure.
245
- - If they fail with `CryptoError`, name the failure `error` and recover:
246
- - Fail with call [`LoginError`](contracts.md#symbol-LoginError). Transfer control to a matching catch or propagate the failure.
247
- - Set `requestId` to call `base64url` on call [`Crypto.random`](../dependencies/august/0.19.0/crypto/contracts.md#symbol-Crypto.random) on `crypto` with `size` = `32`.
248
- - Set `browser` to call `base64url` on call [`Crypto.random`](../dependencies/august/0.19.0/crypto/contracts.md#symbol-Crypto.random) on `crypto` with `size` = `32`.
249
- - Set `csrf` to call `base64url` on call [`Crypto.random`](../dependencies/august/0.19.0/crypto/contracts.md#symbol-Crypto.random) on `crypto` with `size` = `32`.
250
- - Set `now` to call [`Clock.now`](../dependencies/august/0.19.0/time/contracts.md#symbol-Clock.now) on `clock`.
251
- - Set `request` to call [`AuthorizationRequest`](contracts.md#symbol-AuthorizationRequest) with `clientId` = `client_id`; `redirectUri` = `redirect_uri`; `state` = `state`; `nonce` = `nonce`; `challenge` = `code_challenge`; `browser` = `browser`; `csrf` = `csrf`; `expires` = (`now` plus `300`).
252
- - Call [`ExpiringStore.put`](../dependencies/august/0.19.0/memory/store.md#symbol-ExpiringStore.put) on `requests` with `key` = `requestId`; `value` = `request`; `expires` = `expires` of `request`; `now` = `now`.
253
- - Set `headers` to call [`withCookie`](../common/headers.md#symbol-withCookie) with `headers` = call [`securityHeaders`](../common/headers.md#symbol-securityHeaders); `name` = `"aug_authorize"`; `value` = `browser`; `path` = `"/provider"`; `maxAge` = `300`; `secure` = `secureCookies` of `config`.
254
- - Return call `HttpResponse` with `body` = call [`ProviderLogin`](views.md#symbol-ProviderLogin) with `requestId` = `requestId`; `csrf` = `csrf`; `message` = `"Authorize the registered August login app."`; `submit` = a deferred HTTP form action for [`providerLogin`](authorization.md#symbol-providerLogin); inputs: `1` from the checked form input supplied when the HTTP form is submitted; capture supplied values when rendering, and read form inputs when submitted; send the form to that endpoint with its declared HTTP method; `headers` = `headers`.
390
+ It can also raise `HttpError`.
255
391
 
256
- **Author documentation**
392
+ It gets `config` from [`settings`](../common/settings.md#symbol-settings). If `origin` does not equal `config.baseUrl`, it returns HTTP 403 with [`ProviderFailure`](views.md#symbol-ProviderFailure) showing `"The sign-in form must come from this app."` and [`securityHeaders`](../common/headers.md#symbol-securityHeaders) headers. It obtains [`requests.take`](../dependencies/packages/%40git/url_0eb7c89453c87681ed15/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301/store.md#symbol-ExpiringStore.take) with `key` from `form.request_id` and `now` from [`clock.now`](../dependencies/packages/%40git/url_c092cd151499c4e1d8a1/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301/contracts.md#symbol-Clock.now). If no value is found, it returns HTTP 400 with [`ProviderFailure`](views.md#symbol-ProviderFailure) showing `"The sign-in request expired or was already used."` and [`securityHeaders`](../common/headers.md#symbol-securityHeaders) headers.
257
393
 
258
- Validate the registered client before offering a login form. A malformed redirect is never followed.
394
+ The non-null result becomes `request`. If `browser` is null, it returns HTTP 403 with [`ProviderFailure`](views.md#symbol-ProviderFailure) showing `"The browser binding is missing."` and [`securityHeaders`](../common/headers.md#symbol-securityHeaders) headers. The non-null `browser` becomes `secret`. If [`crypto.equal`](../dependencies/packages/%40git/url_9ef654c66d34ab8f5527/0.0.0-git.b14a0f9aa41f1ce58bd51133bcdc424033e40d40/contracts.md#symbol-Crypto.equal) with `left` from the UTF-8 bytes of `secret` and `right` from the UTF-8 bytes of `request.browser` returns false or [`crypto.equal`](../dependencies/packages/%40git/url_9ef654c66d34ab8f5527/0.0.0-git.b14a0f9aa41f1ce58bd51133bcdc424033e40d40/contracts.md#symbol-Crypto.equal) with `left` from the UTF-8 bytes of `form.csrf` and `right` from the UTF-8 bytes of `request.csrf` returns false, it returns HTTP 403 with [`ProviderFailure`](views.md#symbol-ProviderFailure) showing `"The sign-in form could not be verified."` and [`securityHeaders`](../common/headers.md#symbol-securityHeaders) headers.
259
395
 
260
- ### `providerLogin` {#symbol-providerLogin}
396
+ If [`verifyCredentials`](credentials.md#symbol-verifyCredentials) with `form.username` and `form.password` using injected `crypto` returns false, it returns HTTP 401 with [`ProviderFailure`](views.md#symbol-ProviderFailure) showing `"The username or password was not accepted."` and [`securityHeaders`](../common/headers.md#symbol-securityHeaders) headers. It sets `now` to [`clock.now`](../dependencies/packages/%40git/url_c092cd151499c4e1d8a1/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301/contracts.md#symbol-Clock.now). It sets `code` to the URL-safe base64 encoding of [`crypto.random`](../dependencies/packages/%40git/url_9ef654c66d34ab8f5527/0.0.0-git.b14a0f9aa41f1ce58bd51133bcdc424033e40d40/contracts.md#symbol-Crypto.random) with `size` `32`. It sets `grant` to an [`AuthorizationCode`](contracts.md#symbol-AuthorizationCode) with `request.clientId`, `request.redirectUri`, `request.challenge`, `request.nonce`, `subject` `"demo-ada"`, `name` `"Ada"`, and `expires` from `now` plus `60`.
261
397
 
262
- [source](authorization.md#code)
398
+ It calls [`codes.put`](../dependencies/packages/%40git/url_0eb7c89453c87681ed15/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301/store.md#symbol-ExpiringStore.put) with `key` from `code`, `value` from `grant`, `grant.expires`, and `now`. It builds `location` as the text `{request.redirectUri}?code={urlEncode with input from code}&state={urlEncode with input from request.state}`. It sets `headers` to [`withCookie`](../common/headers.md#symbol-withCookie) with `headers` from [`securityHeaders`](../common/headers.md#symbol-securityHeaders) with the header `"location"` set to `location`, `name` `"aug_authorize"`, `value` `""`, `path` `"/provider"`, `maxAge` `0`, and `secure` from `config.secureCookies`. It returns HTTP 303 with a paragraph containing `Returning to the application.` with escaped text and `headers` headers.
263
399
 
264
- **Inputs**
400
+ If this work raises `HttpError`, it returns HTTP 400 with [`ProviderFailure`](views.md#symbol-ProviderFailure) showing `"The submitted form is invalid."` and [`securityHeaders`](../common/headers.md#symbol-securityHeaders) headers.
265
401
 
266
- - `form` ([`LoginForm`](contracts.md#symbol-LoginForm)) — read from the HTTP form.
267
- - `browser` (`optional string`) — read from the HTTP cookie named `aug_authorize`; absent value becomes null.
268
- - `origin` (`optional string`) — read from the HTTP header named `origin`; absent value becomes null.
269
- - `crypto` ([`Crypto`](../dependencies/august/0.19.0/crypto/contracts.md#symbol-Crypto)) — injected; callers omit it.
270
- - `clock` ([`Clock`](../dependencies/august/0.19.0/time/contracts.md#symbol-Clock)) — injected; callers omit it.
271
- - `requests` ([`ExpiringStore<AuthorizationRequest>`](../dependencies/august/0.19.0/memory/store.md#symbol-ExpiringStore)) — injected; callers omit it.
272
- - `codes` ([`ExpiringStore<AuthorizationCode>`](../dependencies/august/0.19.0/memory/store.md#symbol-ExpiringStore)) — injected; callers omit it.
402
+ ### Dependencies
273
403
 
274
- Returns: `HttpResponse<Html>`.
404
+ It uses [`ExpiringStore`](../dependencies/packages/%40git/url_0eb7c89453c87681ed15/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301/store.md#symbol-ExpiringStore) ([`put`](../dependencies/packages/%40git/url_0eb7c89453c87681ed15/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301/store.md#symbol-ExpiringStore.put) and [`take`](../dependencies/packages/%40git/url_0eb7c89453c87681ed15/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301/store.md#symbol-ExpiringStore.take)) and [`StoreFull`](../dependencies/packages/%40git/url_0eb7c89453c87681ed15/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301/store.md#symbol-StoreFull) from `memory`. It uses [`urlEncode`](../dependencies/packages/%40git/url_897efafd565158fc4908/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301/contracts.md#symbol-urlEncode) from `web`. It uses [`Crypto`](../dependencies/packages/%40git/url_9ef654c66d34ab8f5527/0.0.0-git.b14a0f9aa41f1ce58bd51133bcdc424033e40d40/contracts.md#symbol-Crypto) ([`decodeBase64url`](../dependencies/packages/%40git/url_9ef654c66d34ab8f5527/0.0.0-git.b14a0f9aa41f1ce58bd51133bcdc424033e40d40/contracts.md#symbol-Crypto.decodeBase64url), [`equal`](../dependencies/packages/%40git/url_9ef654c66d34ab8f5527/0.0.0-git.b14a0f9aa41f1ce58bd51133bcdc424033e40d40/contracts.md#symbol-Crypto.equal), [`passwordHash`](../dependencies/packages/%40git/url_9ef654c66d34ab8f5527/0.0.0-git.b14a0f9aa41f1ce58bd51133bcdc424033e40d40/contracts.md#symbol-Crypto.passwordHash), and [`random`](../dependencies/packages/%40git/url_9ef654c66d34ab8f5527/0.0.0-git.b14a0f9aa41f1ce58bd51133bcdc424033e40d40/contracts.md#symbol-Crypto.random)) from `crypto`. It uses [`Clock`](../dependencies/packages/%40git/url_c092cd151499c4e1d8a1/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301/contracts.md#symbol-Clock) ([`now`](../dependencies/packages/%40git/url_c092cd151499c4e1d8a1/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301/contracts.md#symbol-Clock.now)) from `time`.
275
405
 
276
- Capabilities: [`crypto.equal`](../dependencies/august/0.19.0/crypto/contracts.md#symbol-Crypto.equal), [`crypto.random`](../dependencies/august/0.19.0/crypto/contracts.md#symbol-Crypto.random), [`crypto.passwordHash`](../dependencies/august/0.19.0/crypto/contracts.md#symbol-Crypto.passwordHash), [`crypto.decodeBase64url`](../dependencies/august/0.19.0/crypto/contracts.md#symbol-Crypto.decodeBase64url), [`clock.now`](../dependencies/august/0.19.0/time/contracts.md#symbol-Clock.now), [`requests.take`](../dependencies/august/0.19.0/memory/store.md#symbol-ExpiringStore.take), [`codes.put`](../dependencies/august/0.19.0/memory/store.md#symbol-ExpiringStore.put).
406
+ It uses [`securityHeaders`](../common/headers.md#symbol-securityHeaders), [`withCookie`](../common/headers.md#symbol-withCookie), and [`settings`](../common/settings.md#symbol-settings) from `common`. It uses [`Settings`](../common/settings.md#symbol-Settings) (`baseUrl`, `callback`, `clientId`, and `secureCookies`). It uses [`AuthorizationCode`](contracts.md#symbol-AuthorizationCode) (`expires`), [`AuthorizationRequest`](contracts.md#symbol-AuthorizationRequest) (`browser`, `challenge`, `clientId`, `csrf`, `expires`, `nonce`, `redirectUri`, and `state`), [`LoginError`](contracts.md#symbol-LoginError), and [`LoginForm`](contracts.md#symbol-LoginForm) (`csrf`, `password`, `request_id`, and `username`) from `contracts`. It uses [`verifyCredentials`](credentials.md#symbol-verifyCredentials) from `credentials`.
277
407
 
278
- Can fail with `CryptoError`, `TimeError`, `StoreFull`, `HttpError`. Callers must catch or propagate these errors.
408
+ It uses [`ProviderFailure`](views.md#symbol-ProviderFailure) and [`ProviderLogin`](views.md#symbol-ProviderLogin) from `views`.
279
409
 
280
- HTTP route: `POST` `/provider/login`. Use status 200 when the handler returns a body; a returned HttpResponse can set its own status. An unhandled request failure returns status 500 and cancels its request tasks.
281
-
282
- Declared HTTP failures: `CryptoError` returns status 503; `TimeError` returns status 503; [`StoreFull`](../dependencies/august/0.19.0/memory/store.md#symbol-StoreFull) returns status 503.
283
-
284
- **What it does**
285
-
286
- - Set `config` to call [`settings`](../common/settings.md#symbol-settings).
287
- - Try these operations:
288
- - If `origin` does not equal `baseUrl` of `config`:
289
- - Return call `HttpResponse` with `body` = call [`ProviderFailure`](views.md#symbol-ProviderFailure) with `message` = `"The sign-in form must come from this app."`; `status` = `403`; `headers` = call [`securityHeaders`](../common/headers.md#symbol-securityHeaders).
290
- - Select the matching case for call [`ExpiringStore.take`](../dependencies/august/0.19.0/memory/store.md#symbol-ExpiringStore.take) on `requests` with `key` = `request_id` of `form`; `now` = call [`Clock.now`](../dependencies/august/0.19.0/time/contracts.md#symbol-Clock.now) on `clock`:
291
- - A null value, including omitted optional input:
292
- - Return call `HttpResponse` with `body` = call [`ProviderFailure`](views.md#symbol-ProviderFailure) with `message` = `"The sign-in request expired or was already used."`; `status` = `400`; `headers` = call [`securityHeaders`](../common/headers.md#symbol-securityHeaders).
293
- - A present, non-null value, named `request`:
294
- - Select the matching case for `browser`:
295
- - A null value, including omitted optional input:
296
- - Return call `HttpResponse` with `body` = call [`ProviderFailure`](views.md#symbol-ProviderFailure) with `message` = `"The browser binding is missing."`; `status` = `403`; `headers` = call [`securityHeaders`](../common/headers.md#symbol-securityHeaders).
297
- - A present, non-null value, named `secret`:
298
- - If not (call [`Crypto.equal`](../dependencies/august/0.19.0/crypto/contracts.md#symbol-Crypto.equal) on `crypto` with `left` = call `bytes` on `secret`; `right` = call `bytes` on `browser` of `request`) or not (call [`Crypto.equal`](../dependencies/august/0.19.0/crypto/contracts.md#symbol-Crypto.equal) on `crypto` with `left` = call `bytes` on `csrf` of `form`; `right` = call `bytes` on `csrf` of `request`):
299
- - Return call `HttpResponse` with `body` = call [`ProviderFailure`](views.md#symbol-ProviderFailure) with `message` = `"The sign-in form could not be verified."`; `status` = `403`; `headers` = call [`securityHeaders`](../common/headers.md#symbol-securityHeaders).
300
- - If not (call [`verifyCredentials`](credentials.md#symbol-verifyCredentials) with `username` = `username` of `form`; `password` = `password` of `form`; inject `crypto` from `crypto`):
301
- - Return call `HttpResponse` with `body` = call [`ProviderFailure`](views.md#symbol-ProviderFailure) with `message` = `"The username or password was not accepted."`; `status` = `401`; `headers` = call [`securityHeaders`](../common/headers.md#symbol-securityHeaders).
302
- - Set `now` to call [`Clock.now`](../dependencies/august/0.19.0/time/contracts.md#symbol-Clock.now) on `clock`.
303
- - Set `code` to call `base64url` on call [`Crypto.random`](../dependencies/august/0.19.0/crypto/contracts.md#symbol-Crypto.random) on `crypto` with `size` = `32`.
304
- - Set `grant` to call [`AuthorizationCode`](contracts.md#symbol-AuthorizationCode) with `clientId` = `clientId` of `request`; `redirectUri` = `redirectUri` of `request`; `challenge` = `challenge` of `request`; `nonce` = `nonce` of `request`; `subject` = `"demo-ada"`; `name` = `"Ada"`; `expires` = (`now` plus `60`).
305
- - Call [`ExpiringStore.put`](../dependencies/august/0.19.0/memory/store.md#symbol-ExpiringStore.put) on `codes` with `key` = `code`; `value` = `grant`; `expires` = `expires` of `grant`; `now` = `now`.
306
- - Build `location` by joining these text parts without separators, in order:
307
- 1. `redirectUri` of `request`
308
- 2. `"?code="`
309
- 3. call [`urlEncode`](../dependencies/august/0.19.0/web/contracts.md#symbol-urlEncode) with `input` = `code`
310
- 4. `"&state="`
311
- 5. call [`urlEncode`](../dependencies/august/0.19.0/web/contracts.md#symbol-urlEncode) with `input` = `state` of `request`
312
- - Set `headers` to call [`withCookie`](../common/headers.md#symbol-withCookie) with `headers` = call `with` on call [`securityHeaders`](../common/headers.md#symbol-securityHeaders) with `name` = `"location"`; `value` = `location`; `name` = `"aug_authorize"`; `value` = `""`; `path` = `"/provider"`; `maxAge` = `0`; `secure` = `secureCookies` of `config`.
313
- - Return call `HttpResponse` with `body` = the HTML element `p` containing `Returning to the application.` (rendered on the server with embedded text escaped); `status` = `303`; `headers` = `headers`.
314
- - If they fail with `HttpError`, name the failure `error` and recover:
315
- - Return call `HttpResponse` with `body` = call [`ProviderFailure`](views.md#symbol-ProviderFailure) with `message` = `"The submitted form is invalid."`; `status` = `400`; `headers` = call [`securityHeaders`](../common/headers.md#symbol-securityHeaders).
316
-
317
- **Author documentation**
318
-
319
- The browser binding and CSRF token are checked before credentials. Each form request is consumed once.
320
-
321
- ### Dependencies used by this file
322
-
323
- Only referenced types and operations appear here. Each name links to its complete specification.
324
-
325
- #### [`Crypto`](../dependencies/august/0.19.0/crypto/contracts.md#symbol-Crypto)
326
-
327
- Capability interface from `august.crypto`.
328
-
329
- - [`Crypto.decodeBase64url`](../dependencies/august/0.19.0/crypto/contracts.md#symbol-Crypto.decodeBase64url) (`input`: `string`) → `Bytes`; can fail with `CryptoError`.
330
- - [`Crypto.equal`](../dependencies/august/0.19.0/crypto/contracts.md#symbol-Crypto.equal) (`left`: `Bytes`, `right`: `Bytes`) → `bool`.
331
- - [`Crypto.passwordHash`](../dependencies/august/0.19.0/crypto/contracts.md#symbol-Crypto.passwordHash) (`password`: `Bytes`, `salt`: `Bytes`, `iterations`: `int`) → `Bytes`; can fail with `CryptoError`.
332
- - [`Crypto.random`](../dependencies/august/0.19.0/crypto/contracts.md#symbol-Crypto.random) (`size`: `int`) → `Bytes`; can fail with `CryptoError`.
333
-
334
- #### [`ExpiringStore`](../dependencies/august/0.19.0/memory/store.md#symbol-ExpiringStore)
335
-
336
- Capability interface from `august.memory`.
337
-
338
- - [`ExpiringStore.put`](../dependencies/august/0.19.0/memory/store.md#symbol-ExpiringStore.put) (`key`: `string`, `value`: `T`, `expires`: `int`, `now`: `int`) → `void`; can fail with `StoreFull`.
339
- - [`ExpiringStore.take`](../dependencies/august/0.19.0/memory/store.md#symbol-ExpiringStore.take) (`key`: `string`, `now`: `int`) → `optional T`.
340
-
341
- #### [`StoreFull`](../dependencies/august/0.19.0/memory/store.md#symbol-StoreFull)
342
-
343
- Class from `august.memory`.
344
-
345
- Used as a type or provider.
346
-
347
- #### [`Clock`](../dependencies/august/0.19.0/time/contracts.md#symbol-Clock)
348
-
349
- Capability interface from `august.time`.
350
-
351
- - [`Clock.now`](../dependencies/august/0.19.0/time/contracts.md#symbol-Clock.now) (no caller inputs) → `int`; can fail with `TimeError`.
352
-
353
- #### [`urlEncode`](../dependencies/august/0.19.0/web/contracts.md#symbol-urlEncode)
354
-
355
- Function from `august.web`.
356
-
357
- - [`urlEncode`](../dependencies/august/0.19.0/web/contracts.md#symbol-urlEncode) (`input`: `string`) → `string`; can fail with `HttpError`.
358
-
359
- #### [`securityHeaders`](../common/headers.md#symbol-securityHeaders)
360
-
361
- Function from `common`.
362
-
363
- - [`securityHeaders`](../common/headers.md#symbol-securityHeaders) (no caller inputs) → `Headers`; can fail with `HttpError`.
364
-
365
- #### [`withCookie`](../common/headers.md#symbol-withCookie)
366
-
367
- Function from `common`.
368
-
369
- - [`withCookie`](../common/headers.md#symbol-withCookie) (`headers`: `Headers`, `name`: `string`, `value`: `string`, `path`: `string`, `maxAge`: `int`, `secure`: `bool`) → `Headers`; can fail with `HttpError`.
370
-
371
- #### [`Settings`](../common/settings.md#symbol-Settings)
372
-
373
- Record.
374
-
375
- - Read `baseUrl` (`string`).
376
- - Read `callback` (`string`).
377
- - Read `clientId` (`string`).
378
- - Read `secureCookies` (`bool`).
379
-
380
- #### [`settings`](../common/settings.md#symbol-settings)
381
-
382
- Function from `common`.
383
-
384
- - [`settings`](../common/settings.md#symbol-settings) (no caller inputs) → [`Settings`](../common/settings.md#symbol-Settings).
385
-
386
- #### [`AuthorizationCode`](contracts.md#symbol-AuthorizationCode)
387
-
388
- Record from `contracts`.
389
-
390
- - Construct with `clientId`: `string`, `redirectUri`: `string`, `challenge`: `string`, `nonce`: `string`, `subject`: `string`, `name`: `string`, `expires`: `int` → [`AuthorizationCode`](contracts.md#symbol-AuthorizationCode).
391
- - Read `expires` (`int`).
392
-
393
- #### [`AuthorizationRequest`](contracts.md#symbol-AuthorizationRequest)
394
-
395
- Record from `contracts`.
396
-
397
- - Construct with `clientId`: `string`, `redirectUri`: `string`, `state`: `string`, `nonce`: `string`, `challenge`: `string`, `browser`: `string`, `csrf`: `string`, `expires`: `int` → [`AuthorizationRequest`](contracts.md#symbol-AuthorizationRequest).
398
- - Read `browser` (`string`).
399
- - Read `challenge` (`string`).
400
- - Read `clientId` (`string`).
401
- - Read `csrf` (`string`).
402
- - Read `expires` (`int`).
403
- - Read `nonce` (`string`).
404
- - Read `redirectUri` (`string`).
405
- - Read `state` (`string`).
406
-
407
- #### [`LoginError`](contracts.md#symbol-LoginError)
408
-
409
- Class from `contracts`.
410
-
411
- - Construct with no caller inputs → [`LoginError`](contracts.md#symbol-LoginError).
412
-
413
- #### [`LoginForm`](contracts.md#symbol-LoginForm)
414
-
415
- Record from `contracts`.
416
-
417
- - Read `csrf` (`string`).
418
- - Read `password` (`string`).
419
- - Read `request_id` (`string`).
420
- - Read `username` (`string`).
421
-
422
- #### [`verifyCredentials`](credentials.md#symbol-verifyCredentials)
423
-
424
- Function from `credentials`.
425
-
426
- - [`verifyCredentials`](credentials.md#symbol-verifyCredentials) (`username`: `string`, `password`: `string`) → `bool`; inject `crypto`: [`Crypto`](../dependencies/august/0.19.0/crypto/contracts.md#symbol-Crypto); uses [`crypto.passwordHash`](../dependencies/august/0.19.0/crypto/contracts.md#symbol-Crypto.passwordHash), [`crypto.decodeBase64url`](../dependencies/august/0.19.0/crypto/contracts.md#symbol-Crypto.decodeBase64url), [`crypto.equal`](../dependencies/august/0.19.0/crypto/contracts.md#symbol-Crypto.equal); can fail with `CryptoError`.
427
-
428
- #### [`ProviderFailure`](views.md#symbol-ProviderFailure)
429
-
430
- Function from `views`.
431
-
432
- - [`ProviderFailure`](views.md#symbol-ProviderFailure) (`message`: `string`) → `Html`.
433
-
434
- #### [`ProviderLogin`](views.md#symbol-ProviderLogin)
435
-
436
- Function from `views`.
437
-
438
- - [`ProviderLogin`](views.md#symbol-ProviderLogin) (`requestId`: `string`, `csrf`: `string`, `message`: `string`, `submit`: `HttpAction`) → `Html`.
439
-
440
- ### Built-in operations used by this file
441
-
442
- - `Bytes.base64url` (no inputs) → `string`: Encode immutable bytes as unpadded RFC 4648 URL-safe base64.
443
- - `Bytes.length` (no inputs) → `int`: Read the number of elements.
444
- - `Headers.with` (`name`: `string`, `value`: `string`) → `Headers`: Return new headers with one additional validated field. Header names ignore case; duplicate values remain separate. Can fail with `HttpError`.
445
- - `string.bytes` (no inputs) → `Bytes`: Encode this string as immutable UTF-8 bytes.
446
- - `string.isToken` (`min`: `int`, `max`: `int`) → `bool`: Require an ASCII RFC 3986 unreserved token with a bounded length.
447
- - `string.length` (no inputs) → `int`: Read the number of UTF-8 bytes. Unicode text is preserved losslessly.
448
-
449
- [Full built-in reference](https://greenpandastudios.github.io/augscript/language-constructs).
450
-
451
- ### Shared language rules
452
-
453
- See the [language reference](https://greenpandastudios.github.io/augscript/reference) for numeric, equality, ownership, and task rules.
410
+ Built-in operations follow the [language reference](https://greenpandastudios.github.io/augscript/language-constructs).
454
411
 
455
412
  ::::
456
413