@webstir-io/module-contract 0.2.0 → 0.3.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.
package/README.md CHANGED
@@ -346,12 +346,12 @@ bun install
346
346
  bun run clean # remove dist/schema artifacts
347
347
  bun run build # compiles TypeScript, regenerates schema/*.schema.json
348
348
  bun run test # type-checks the Accounts example module
349
- # From the repository root, prepare the synchronized production release set
350
- bun run release:prepare -- webstir patch
349
+ # From the repository root, describe the change for the next release
350
+ bun run changeset
351
351
  ```
352
352
 
353
353
  - The `schema/` folder contains `*-definition.schema.json` files derived from the exported Zod schemas. Commit them with contract changes.
354
- - The release-set workflow publishes the contract, backend, frontend, and CLI together after exact-commit CI succeeds.
354
+ - Merging the "Version packages" pull request publishes the contract, backend, frontend, and CLI together.
355
355
 
356
356
  ## License
357
357
 
@@ -0,0 +1,19 @@
1
+ /**
2
+ * The wire protocol between the client-nav feature and the backend runtime. Constants only, so a
3
+ * browser bundle can import them without the rest of the contract.
4
+ */
5
+ export declare const CLIENT_NAV_HEADERS: {
6
+ /** Sent on every request client-nav makes itself. */
7
+ readonly request: 'x-webstir-client-nav';
8
+ /**
9
+ * Sent when client-nav can follow a redirect itself: the backend then answers a redirect with
10
+ * 204 and `location` instead of 3xx, so the destination keeps its #fragment.
11
+ */
12
+ readonly acceptLocation: 'x-webstir-accept-location';
13
+ /** Where to go next, in place of a redirect's Location. */
14
+ readonly location: 'x-webstir-location';
15
+ /** Identifies one form submission, so the same post sent again gets the first answer. */
16
+ readonly submission: 'x-webstir-submission';
17
+ };
18
+ /** The form field carrying the submission id when client-nav falls back to a normal post. */
19
+ export declare const CLIENT_NAV_SUBMISSION_FIELD = "_webstir_submission";
@@ -0,0 +1,19 @@
1
+ /**
2
+ * The wire protocol between the client-nav feature and the backend runtime. Constants only, so a
3
+ * browser bundle can import them without the rest of the contract.
4
+ */
5
+ export const CLIENT_NAV_HEADERS = {
6
+ /** Sent on every request client-nav makes itself. */
7
+ request: 'x-webstir-client-nav',
8
+ /**
9
+ * Sent when client-nav can follow a redirect itself: the backend then answers a redirect with
10
+ * 204 and `location` instead of 3xx, so the destination keeps its #fragment.
11
+ */
12
+ acceptLocation: 'x-webstir-accept-location',
13
+ /** Where to go next, in place of a redirect's Location. */
14
+ location: 'x-webstir-location',
15
+ /** Identifies one form submission, so the same post sent again gets the first answer. */
16
+ submission: 'x-webstir-submission',
17
+ };
18
+ /** The form field carrying the submission id when client-nav falls back to a normal post. */
19
+ export const CLIENT_NAV_SUBMISSION_FIELD = '_webstir_submission';
package/dist/index.d.ts CHANGED
@@ -4554,3 +4554,4 @@ export { RENDER_PROGRAM_FILE, RENDER_PROGRAM_VERSION, renderFlashMessageSchema,
4554
4554
  export type { RenderFlashMessage, RenderNode, RenderPath, RenderProgram, RenderSourceLocation, } from './render-program.js';
4555
4555
  export { executeRenderProgram, programUsesCsrf, readRenderProgram, RENDER_CSRF_FIELD, RenderProgramError, prepareViewData, schemaDeclaresField, } from './render-execute.js';
4556
4556
  export type { ExecuteRenderProgramOptions, PreparedViewData } from './render-execute.js';
4557
+ export { CLIENT_NAV_HEADERS, CLIENT_NAV_SUBMISSION_FIELD } from './client-nav.js';
package/dist/index.js CHANGED
@@ -234,3 +234,4 @@ export function createModule(definition) {
234
234
  export { fromTsRestRoute, fromTsRestRouter } from './adapters/ts-rest.js';
235
235
  export { RENDER_PROGRAM_FILE, RENDER_PROGRAM_VERSION, renderFlashMessageSchema, renderFlashSchema, renderNodeSchema, renderPathSchema, renderProgramSchema, renderSourceLocationSchema, } from './render-program.js';
236
236
  export { executeRenderProgram, programUsesCsrf, readRenderProgram, RENDER_CSRF_FIELD, RenderProgramError, prepareViewData, schemaDeclaresField, } from './render-execute.js';
237
+ export { CLIENT_NAV_HEADERS, CLIENT_NAV_SUBMISSION_FIELD } from './client-nav.js';
@@ -2,6 +2,27 @@ import { RENDER_PROGRAM_VERSION, } from './render-program.js';
2
2
  export const RENDER_CSRF_FIELD = '_csrf';
3
3
  const SAFE_URL_SCHEMES = new Set(['http', 'https', 'mailto', 'tel']);
4
4
  const BLOCKED_URL = 'about:invalid';
5
+ // ARIA attributes whose values include the tokens "true" and "false" (WAI-ARIA 1.2). The rest take
6
+ // text or ids, where false still leaves the attribute out.
7
+ const ARIA_TRUE_FALSE = new Set([
8
+ 'aria-atomic',
9
+ 'aria-busy',
10
+ 'aria-checked',
11
+ 'aria-current',
12
+ 'aria-disabled',
13
+ 'aria-expanded',
14
+ 'aria-grabbed',
15
+ 'aria-haspopup',
16
+ 'aria-hidden',
17
+ 'aria-invalid',
18
+ 'aria-modal',
19
+ 'aria-multiline',
20
+ 'aria-multiselectable',
21
+ 'aria-pressed',
22
+ 'aria-readonly',
23
+ 'aria-required',
24
+ 'aria-selected',
25
+ ]);
5
26
  export class RenderProgramError extends Error {
6
27
  loc;
7
28
  constructor(loc, message) {
@@ -52,7 +73,11 @@ function run(nodes, data, scopes, options, out) {
52
73
  }
53
74
  case 'attr': {
54
75
  const value = read(node.path, data, scopes);
55
- if (value === true) {
76
+ // ARIA states are the words "true" and "false", not an attribute's presence.
77
+ if (typeof value === 'boolean' && ARIA_TRUE_FALSE.has(node.name.toLowerCase())) {
78
+ out.push(` ${node.name}="${value}"`);
79
+ }
80
+ else if (value === true) {
56
81
  out.push(` ${node.name}`);
57
82
  }
58
83
  else if (value !== false && value !== null && value !== undefined) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webstir-io/module-contract",
3
- "version": "0.2.0",
3
+ "version": "0.3.1",
4
4
  "description": "Public contract definitions for Webstir frontend and backend module providers.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -11,6 +11,11 @@
11
11
  "import": "./dist/index.js",
12
12
  "default": "./dist/index.js"
13
13
  },
14
+ "./client-nav": {
15
+ "types": "./dist/client-nav.d.ts",
16
+ "import": "./dist/client-nav.js",
17
+ "default": "./dist/client-nav.js"
18
+ },
14
19
  "./ts-rest": {
15
20
  "types": "./dist/adapters/ts-rest.d.ts",
16
21
  "import": "./dist/adapters/ts-rest.js",