@jay-framework/jay-stack-cli 0.19.6 → 0.19.7
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/agent-kit-template/INSTRUCTIONS.md +37 -0
- package/agent-kit-template/contracts/GUIDE.md +70 -0
- package/agent-kit-template/contracts/component-contracts.md +82 -0
- package/agent-kit-template/contracts/examples/cart-indicator.md +60 -0
- package/agent-kit-template/contracts/examples/category-list.md +77 -0
- package/agent-kit-template/contracts/examples/composing-contracts.md +100 -0
- package/agent-kit-template/contracts/examples/mini-cart.md +43 -0
- package/agent-kit-template/contracts/examples/product-card.md +70 -0
- package/agent-kit-template/contracts/examples/product-page.md +125 -0
- package/agent-kit-template/contracts/linked-contracts.md +75 -0
- package/agent-kit-template/contracts/page-contracts.md +73 -0
- package/agent-kit-template/contracts/syntax.md +190 -0
- package/agent-kit-template/designer/INSTRUCTIONS.md +10 -0
- package/agent-kit-template/designer/jay-html-components.md +11 -13
- package/agent-kit-template/designer/jay-html-template-syntax.md +1 -0
- package/agent-kit-template/designer/script-tags.md +83 -0
- package/agent-kit-template/developer/INSTRUCTIONS.md +15 -14
- package/agent-kit-template/developer/page-contracts.md +1 -1
- package/agent-kit-template/plugin/INSTRUCTIONS.md +20 -19
- package/agent-kit-template/plugin/contracts-guide.md +4 -2
- package/dist/index.js +27 -1
- package/package.json +11 -11
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# Linked and Composed Contracts
|
|
2
|
+
|
|
3
|
+
Contracts can reference other contract files using `link:` syntax. This lets you build reusable pieces and compose them into larger contracts.
|
|
4
|
+
|
|
5
|
+
## When to Extract a Sub-Contract
|
|
6
|
+
|
|
7
|
+
Extract a sub-contract into its own file when:
|
|
8
|
+
|
|
9
|
+
- The same data shape is used by multiple contracts (e.g., a product card used in search results and related products)
|
|
10
|
+
- The sub-contract is complex enough to warrant its own file for readability
|
|
11
|
+
- You want to share the structure between static and dynamic contracts
|
|
12
|
+
|
|
13
|
+
Keep a sub-contract inline when:
|
|
14
|
+
|
|
15
|
+
- It's only used in one place
|
|
16
|
+
- It's small (< 10 tags)
|
|
17
|
+
- Extracting it would make the parent harder to read
|
|
18
|
+
|
|
19
|
+
## Link Syntax
|
|
20
|
+
|
|
21
|
+
Reference another contract file with a relative path:
|
|
22
|
+
|
|
23
|
+
```yaml
|
|
24
|
+
- tag: mediaGallery
|
|
25
|
+
type: sub-contract
|
|
26
|
+
link: ./media-gallery # resolves to media-gallery.jay-contract in same directory
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
For cross-package references (e.g., dynamic contracts linking to static ones):
|
|
30
|
+
|
|
31
|
+
```yaml
|
|
32
|
+
- tag: gallery
|
|
33
|
+
type: sub-contract
|
|
34
|
+
link: '@my-org/my-plugin/media-gallery' # package path
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Composition Pattern
|
|
38
|
+
|
|
39
|
+
Build contracts from small pieces up to complex pages:
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
media.jay-contract (trivial: url + mediaType)
|
|
43
|
+
^
|
|
44
|
+
media-gallery.jay-contract (links to media, adds thumbnail navigation)
|
|
45
|
+
^
|
|
46
|
+
product-page.jay-contract (links to media-gallery, adds options, pricing, etc.)
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
```
|
|
50
|
+
product-options.jay-contract (reusable option/choice structure)
|
|
51
|
+
^
|
|
52
|
+
product-card.jay-contract (links to product-options for quick-add)
|
|
53
|
+
^
|
|
54
|
+
product-search.jay-contract (links to product-card for search results)
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Each level adds its own tags around the linked sub-contracts. The linked contracts stay focused on their single responsibility.
|
|
58
|
+
|
|
59
|
+
## Linked Repeated Sub-Contracts
|
|
60
|
+
|
|
61
|
+
A linked sub-contract can also be repeated:
|
|
62
|
+
|
|
63
|
+
```yaml
|
|
64
|
+
- tag: searchResults
|
|
65
|
+
type: sub-contract
|
|
66
|
+
repeated: true
|
|
67
|
+
trackBy: _id
|
|
68
|
+
link: ./product-card
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
The linked contract must have a tag matching the `trackBy` field.
|
|
72
|
+
|
|
73
|
+
## See Also
|
|
74
|
+
|
|
75
|
+
- [composing-contracts example](examples/composing-contracts.md) — Real-world composition hierarchy from wix-stores
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# Page Contracts
|
|
2
|
+
|
|
3
|
+
A page contract (`page.jay-contract`) defines page-level data for a route, alongside any headless plugin contracts the page imports.
|
|
4
|
+
|
|
5
|
+
## When to Use
|
|
6
|
+
|
|
7
|
+
- The page has its own data that isn't provided by a plugin
|
|
8
|
+
- The page component (`page.ts`) renders data into ViewState
|
|
9
|
+
- You want type-safe bindings between the page component and its jay-html template
|
|
10
|
+
|
|
11
|
+
If the page only uses plugin headless components and has no page-level data, a page contract is optional.
|
|
12
|
+
|
|
13
|
+
## File Placement
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
src/pages/
|
|
17
|
+
page.jay-html
|
|
18
|
+
page.jay-contract
|
|
19
|
+
page.ts
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
For dynamic routes:
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
src/pages/products/[slug]/
|
|
26
|
+
page.jay-html
|
|
27
|
+
page.jay-contract
|
|
28
|
+
page.ts
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Params for Dynamic Routes
|
|
32
|
+
|
|
33
|
+
Declare `params` matching the route's dynamic segments:
|
|
34
|
+
|
|
35
|
+
```yaml
|
|
36
|
+
name: product-page
|
|
37
|
+
params:
|
|
38
|
+
slug: string # required — from [slug]
|
|
39
|
+
prefix: string? # optional — from [[prefix]]
|
|
40
|
+
category: string? # optional
|
|
41
|
+
tags:
|
|
42
|
+
- tag: title
|
|
43
|
+
type: data
|
|
44
|
+
dataType: string
|
|
45
|
+
phase: slow
|
|
46
|
+
- tag: price
|
|
47
|
+
type: data
|
|
48
|
+
dataType: number
|
|
49
|
+
phase: fast+interactive
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Combining with Plugin Contracts
|
|
53
|
+
|
|
54
|
+
A page can have both a page contract and headless plugin contracts. The page contract covers page-owned data; plugins cover their own domains:
|
|
55
|
+
|
|
56
|
+
```html
|
|
57
|
+
<html>
|
|
58
|
+
<head>
|
|
59
|
+
<script type="application/jay-data" contract="./page.jay-contract"></script>
|
|
60
|
+
<script
|
|
61
|
+
type="application/jay-headless"
|
|
62
|
+
plugin="wix-stores"
|
|
63
|
+
contract="product-page"
|
|
64
|
+
key="product"
|
|
65
|
+
></script>
|
|
66
|
+
</head>
|
|
67
|
+
<body>
|
|
68
|
+
<h1>{heroTitle}</h1>
|
|
69
|
+
<div>{product.name}</div>
|
|
70
|
+
<div>{product.price}</div>
|
|
71
|
+
</body>
|
|
72
|
+
</html>
|
|
73
|
+
```
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
# Contract Syntax Reference
|
|
2
|
+
|
|
3
|
+
## Basic Structure
|
|
4
|
+
|
|
5
|
+
```yaml
|
|
6
|
+
name: ProductCard
|
|
7
|
+
description: What this contract does and when to use it.
|
|
8
|
+
props:
|
|
9
|
+
- name: productId
|
|
10
|
+
type: string
|
|
11
|
+
required: true
|
|
12
|
+
description: The product to display
|
|
13
|
+
params:
|
|
14
|
+
slug: string
|
|
15
|
+
tags:
|
|
16
|
+
- tag: name
|
|
17
|
+
type: data
|
|
18
|
+
dataType: string
|
|
19
|
+
phase: slow
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Tag Types
|
|
23
|
+
|
|
24
|
+
### `data` — Read-only values
|
|
25
|
+
|
|
26
|
+
```yaml
|
|
27
|
+
- tag: productName
|
|
28
|
+
type: data
|
|
29
|
+
dataType: string
|
|
30
|
+
required: true
|
|
31
|
+
phase: slow
|
|
32
|
+
description: Display name
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Data types: `string` (default), `html-string`, `number`, `boolean`, `date`.
|
|
36
|
+
|
|
37
|
+
### `variant` — Conditionals (enum or boolean)
|
|
38
|
+
|
|
39
|
+
```yaml
|
|
40
|
+
- tag: status
|
|
41
|
+
type: variant
|
|
42
|
+
dataType: enum (AVAILABLE | OUT_OF_STOCK | PREORDER)
|
|
43
|
+
phase: fast+interactive
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Use in jay-html: `if="status===AVAILABLE"` or `if="isActive"` for booleans.
|
|
47
|
+
|
|
48
|
+
### `interactive` — Element refs for user interaction
|
|
49
|
+
|
|
50
|
+
```yaml
|
|
51
|
+
- tag: addToCart
|
|
52
|
+
type: interactive
|
|
53
|
+
elementType: HTMLButtonElement
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Element types: `HTMLButtonElement`, `HTMLAnchorElement`, `HTMLInputElement`, `HTMLSelectElement`, `HTMLElement`, etc.
|
|
57
|
+
|
|
58
|
+
Interactive tags are always `fast+interactive` — do not specify a phase.
|
|
59
|
+
|
|
60
|
+
### Dual-type tags — Both data and interactive
|
|
61
|
+
|
|
62
|
+
```yaml
|
|
63
|
+
- tag: quantityInput
|
|
64
|
+
type: [data, interactive]
|
|
65
|
+
dataType: number
|
|
66
|
+
elementType: HTMLInputElement
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Use when an element both displays a value and accepts user input.
|
|
70
|
+
|
|
71
|
+
### `sub-contract` — Nested objects
|
|
72
|
+
|
|
73
|
+
Inline:
|
|
74
|
+
|
|
75
|
+
```yaml
|
|
76
|
+
- tag: pricing
|
|
77
|
+
type: sub-contract
|
|
78
|
+
tags:
|
|
79
|
+
- tag: amount
|
|
80
|
+
type: data
|
|
81
|
+
dataType: number
|
|
82
|
+
- tag: currency
|
|
83
|
+
type: data
|
|
84
|
+
dataType: string
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Linked (reference another contract file):
|
|
88
|
+
|
|
89
|
+
```yaml
|
|
90
|
+
- tag: author
|
|
91
|
+
type: sub-contract
|
|
92
|
+
link: ./author # relative path, resolves to author.jay-contract
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### `sub-contract` with `repeated: true` — Arrays
|
|
96
|
+
|
|
97
|
+
```yaml
|
|
98
|
+
- tag: items
|
|
99
|
+
type: sub-contract
|
|
100
|
+
repeated: true
|
|
101
|
+
trackBy: id
|
|
102
|
+
phase: fast
|
|
103
|
+
tags:
|
|
104
|
+
- tag: id
|
|
105
|
+
type: data
|
|
106
|
+
dataType: string
|
|
107
|
+
- tag: name
|
|
108
|
+
type: data
|
|
109
|
+
dataType: string
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
`trackBy` must reference a `data` tag with `string` or `number` type within the sub-contract.
|
|
113
|
+
|
|
114
|
+
## Rendering Phases
|
|
115
|
+
|
|
116
|
+
| Phase | When | Use for |
|
|
117
|
+
| ------------------ | ------------------ | -------------------------------------------- |
|
|
118
|
+
| `slow` | Build time (SSG) | Static content, SEO data, product names |
|
|
119
|
+
| `fast` | Request time (SSR) | Per-request data, live pricing, stock status |
|
|
120
|
+
| `fast+interactive` | Request + client | Data that also updates on the client |
|
|
121
|
+
| _(no phase)_ | All phases | Available everywhere |
|
|
122
|
+
|
|
123
|
+
**How to choose:**
|
|
124
|
+
|
|
125
|
+
- Known at build time? Use `slow`
|
|
126
|
+
- Changes per request (user, time, session)? Use `fast`
|
|
127
|
+
- Also updates on client after interaction? Use `fast+interactive`
|
|
128
|
+
- Interactive tags (refs) are always `fast+interactive`
|
|
129
|
+
|
|
130
|
+
**Phase rule for arrays:** Child phases must be >= parent phase.
|
|
131
|
+
|
|
132
|
+
## Props — Component configuration
|
|
133
|
+
|
|
134
|
+
Props are passed by the parent. Use for component inputs like IDs, configuration flags, display options.
|
|
135
|
+
|
|
136
|
+
```yaml
|
|
137
|
+
props:
|
|
138
|
+
- name: productId
|
|
139
|
+
type: string
|
|
140
|
+
required: true
|
|
141
|
+
description: The product to display
|
|
142
|
+
- name: showPricing
|
|
143
|
+
type: boolean
|
|
144
|
+
default: 'true'
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## Params — URL route segments
|
|
148
|
+
|
|
149
|
+
Params come from dynamic route segments. Use for page-level routing.
|
|
150
|
+
|
|
151
|
+
```yaml
|
|
152
|
+
params:
|
|
153
|
+
slug: string # required — from [slug]
|
|
154
|
+
lang: string? # optional — from [[lang]]
|
|
155
|
+
path: string[] # catch-all — from [...path]
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## Async Data
|
|
159
|
+
|
|
160
|
+
Wrap any tag in `Promise<T>` with `async: true`:
|
|
161
|
+
|
|
162
|
+
```yaml
|
|
163
|
+
- tag: reviews
|
|
164
|
+
type: data
|
|
165
|
+
async: true
|
|
166
|
+
dataType: string
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
## Tag Metadata
|
|
170
|
+
|
|
171
|
+
Free-form key-value map for plugin validators. The framework ignores `meta`; only validators read it.
|
|
172
|
+
|
|
173
|
+
```yaml
|
|
174
|
+
- tag: heroImage
|
|
175
|
+
type: data
|
|
176
|
+
dataType: string
|
|
177
|
+
meta:
|
|
178
|
+
vendor: wix-image
|
|
179
|
+
defaultTransform: w_800,h_400,q_80
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
## Validation Rules
|
|
183
|
+
|
|
184
|
+
- Tag names must be unique at each level
|
|
185
|
+
- `repeated: true` requires `trackBy`
|
|
186
|
+
- `trackBy` must reference a `data` tag with `string` or `number` type
|
|
187
|
+
- Interactive tags cannot have an explicit `phase`
|
|
188
|
+
- Sub-contracts must have either `tags` (inline) or `link` (external), not both
|
|
189
|
+
- Array children must have phase >= parent phase
|
|
190
|
+
- Prop names must be unique
|
|
@@ -46,9 +46,19 @@ There is no standalone "interactive" phase. Any tag with `type: interactive` (re
|
|
|
46
46
|
| [jay-html-styling.md](jay-html-styling.md) | Styling: inline, external, dynamic style bindings, class bindings |
|
|
47
47
|
| [routing.md](routing.md) | Directory-based routing: page structure, dynamic routes, route priority |
|
|
48
48
|
| [contracts-and-plugins.md](contracts-and-plugins.md) | Reading contracts, plugin.yaml, .jay-action files, and the materialized indexes |
|
|
49
|
+
| [Contract Authoring Guide](../contracts/GUIDE.md) | Writing contracts: syntax, page/component/linked contracts, examples |
|
|
50
|
+
| [script-tags.md](script-tags.md) | Script tag policy: use page.ts for behavior, jay-script="allow" for third-party scripts |
|
|
49
51
|
| [cli-commands.md](cli-commands.md) | CLI commands: setup, validate, params, action, dev server |
|
|
50
52
|
| `../references/<plugin>/` | Pre-generated discovery data: product catalogs, collection schemas (from `jay-stack agent-kit`) |
|
|
51
53
|
|
|
54
|
+
## When to Use Headfull Components
|
|
55
|
+
|
|
56
|
+
Use headfull full-stack components for **shared UI sections that should look the same across pages** — headers, navigation menus, footers, sidebars. These are placed in `src/components/` and imported into any page that needs them. This keeps the shared layout in one place: update the component once and every page reflects the change.
|
|
57
|
+
|
|
58
|
+
If a section is **unique to a single page**, write it directly in the page's `.jay-html` — no component needed.
|
|
59
|
+
|
|
60
|
+
See [jay-html-components.md](jay-html-components.md) for import syntax and component structure.
|
|
61
|
+
|
|
52
62
|
## Quick Start
|
|
53
63
|
|
|
54
64
|
### 1. Discover plugins and contracts
|
|
@@ -85,11 +85,13 @@ Use `<jay:contract-name>` tags with props:
|
|
|
85
85
|
|
|
86
86
|
Inside `<jay:...>`, bindings resolve to **that instance's** contract tags (not the parent).
|
|
87
87
|
|
|
88
|
-
## Headfull
|
|
88
|
+
## Headfull Components
|
|
89
89
|
|
|
90
|
-
|
|
90
|
+
In Jay Stack, headfull components are full-stack. They must have a `.jay-contract` file and are created using `makeJayStackComponent` in their `.ts` file. They support server rendering (slow/fast/interactive phases) and must include a `contract` attribute in the import.
|
|
91
91
|
|
|
92
|
-
|
|
92
|
+
Each headfull component lives in its own subdirectory under `src/components/` with three files: `.ts`, `.jay-html`, and `.jay-contract`. The production build only discovers server-side component modules from `src/components/` and `src/plugins/`. Placing them inside page directories will work in dev mode but fail in production.
|
|
93
|
+
|
|
94
|
+
> **Note:** In Jay (without Jay Stack), headfull components use `makeJayComponent` and do not require a contract. However, `makeJayComponent` components should not be used in Jay Stack because they do not support server rendering.
|
|
93
95
|
|
|
94
96
|
### Import Declaration
|
|
95
97
|
|
|
@@ -97,7 +99,7 @@ Headfull FS components must be placed in `src/components/` — each component in
|
|
|
97
99
|
<head>
|
|
98
100
|
<script
|
|
99
101
|
type="application/jay-headfull"
|
|
100
|
-
src="../components/shared-header"
|
|
102
|
+
src="../components/shared-header/shared-header"
|
|
101
103
|
names="SharedHeader"
|
|
102
104
|
contract="../components/shared-header/shared-header.jay-contract"
|
|
103
105
|
></script>
|
|
@@ -106,23 +108,19 @@ Headfull FS components must be placed in `src/components/` — each component in
|
|
|
106
108
|
|
|
107
109
|
**Attributes:**
|
|
108
110
|
|
|
109
|
-
- `src` — Path to the component
|
|
111
|
+
- `src` — Path to the component file (must include the filename, not just the directory)
|
|
110
112
|
- `names` — Component name to import
|
|
111
|
-
- `contract` — Path to the contract file (
|
|
113
|
+
- `contract` — Path to the component's `.jay-contract` file (required in Jay Stack)
|
|
112
114
|
|
|
113
115
|
### Usage
|
|
114
116
|
|
|
115
|
-
Same as client-only headfull, with props:
|
|
116
|
-
|
|
117
117
|
```html
|
|
118
118
|
<jay:SharedHeader logoUrl="/logo.png" />
|
|
119
119
|
```
|
|
120
120
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
### Headfull FS Component Structure
|
|
121
|
+
### Component Structure
|
|
124
122
|
|
|
125
|
-
A headfull
|
|
123
|
+
A headfull component has its own `.jay-html` file with the same structure as a page:
|
|
126
124
|
|
|
127
125
|
```html
|
|
128
126
|
<!-- components/header/header.jay-html -->
|
|
@@ -227,7 +225,7 @@ A homepage with key-based, instance-based, and headfull components:
|
|
|
227
225
|
></script>
|
|
228
226
|
<script
|
|
229
227
|
type="application/jay-headfull"
|
|
230
|
-
src="../components/shared-header"
|
|
228
|
+
src="../components/shared-header/shared-header"
|
|
231
229
|
names="SharedHeader"
|
|
232
230
|
contract="../components/shared-header/shared-header.jay-contract"
|
|
233
231
|
></script>
|
|
@@ -165,6 +165,7 @@ Iterate over repeated sub-contracts:
|
|
|
165
165
|
- `forEach` — the repeated tag name from the contract
|
|
166
166
|
- `trackBy` — stable unique key for each item (must match contract's trackBy)
|
|
167
167
|
- Inside the loop, bindings resolve to the **current item's** tags
|
|
168
|
+
- **Do not combine `if` and `forEach` on the same element.** Use a wrapper: `<div if="..."><div forEach="...">...</div></div>`
|
|
168
169
|
|
|
169
170
|
**Nested loops:**
|
|
170
171
|
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# Script Tags in Jay-HTML
|
|
2
|
+
|
|
3
|
+
## Default Rule
|
|
4
|
+
|
|
5
|
+
Use `page.ts` with `makeJayStackComponent` for all page behavior — animations, interactions, data fetching, DOM manipulation. Do not write inline `<script>` tags for page logic.
|
|
6
|
+
|
|
7
|
+
## When Scripts Are Needed
|
|
8
|
+
|
|
9
|
+
Some third-party tools provide script snippets that must be included as-is:
|
|
10
|
+
|
|
11
|
+
- **Analytics**: Google Analytics, Google Tag Manager, Meta Pixel
|
|
12
|
+
- **Tag managers**: GTM containers, consent management platforms
|
|
13
|
+
- **Chat widgets**: Intercom, Drift, Zendesk
|
|
14
|
+
- **A/B testing**: Optimizely, VWO
|
|
15
|
+
|
|
16
|
+
These scripts cannot be rewritten as `page.ts` components — they are third-party code meant to run as provided.
|
|
17
|
+
|
|
18
|
+
## How to Include Scripts
|
|
19
|
+
|
|
20
|
+
Add `jay-script="allow"` to mark a script for inclusion:
|
|
21
|
+
|
|
22
|
+
```html
|
|
23
|
+
<!-- External script -->
|
|
24
|
+
<script src="https://www.googletagmanager.com/gtag/js?id=G-XXXXX" async jay-script="allow"></script>
|
|
25
|
+
|
|
26
|
+
<!-- Inline bootstrap snippet (e.g., GTM configuration) -->
|
|
27
|
+
<script jay-script="allow">
|
|
28
|
+
window.dataLayer = window.dataLayer || [];
|
|
29
|
+
function gtag() {
|
|
30
|
+
dataLayer.push(arguments);
|
|
31
|
+
}
|
|
32
|
+
gtag('js', new Date());
|
|
33
|
+
gtag('config', 'G-XXXXX');
|
|
34
|
+
</script>
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Without `jay-script="allow"`:
|
|
38
|
+
|
|
39
|
+
- Inline scripts produce an **error**
|
|
40
|
+
- External scripts produce a **warning**
|
|
41
|
+
|
|
42
|
+
## What Is Not Supported
|
|
43
|
+
|
|
44
|
+
**Local script imports** are never allowed, even with `jay-script="allow"`:
|
|
45
|
+
|
|
46
|
+
```html
|
|
47
|
+
<!-- Error: always rejected -->
|
|
48
|
+
<script src="./my-script.js"></script>
|
|
49
|
+
<script src="../lib/utils.js" jay-script="allow"></script>
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Move local script logic into `page.ts`.
|
|
53
|
+
|
|
54
|
+
## Placement and Performance
|
|
55
|
+
|
|
56
|
+
Scripts can be placed in `<head>` or `<body>`. Choose based on loading priority:
|
|
57
|
+
|
|
58
|
+
| Placement | When to use |
|
|
59
|
+
| -------------------------------- | ------------------------------------------------------- |
|
|
60
|
+
| `<head>` with `async` | Script should load early without blocking (analytics) |
|
|
61
|
+
| `<head>` with `defer` | Script needs the DOM but should start downloading early |
|
|
62
|
+
| End of `<body>` | Non-critical scripts that should not delay page render |
|
|
63
|
+
| `<head>` without `async`/`defer` | Avoid — blocks page rendering |
|
|
64
|
+
|
|
65
|
+
```html
|
|
66
|
+
<head>
|
|
67
|
+
<!-- Good: async loading, doesn't block render -->
|
|
68
|
+
<script
|
|
69
|
+
src="https://www.googletagmanager.com/gtag/js?id=G-XXXXX"
|
|
70
|
+
async
|
|
71
|
+
jay-script="allow"
|
|
72
|
+
></script>
|
|
73
|
+
</head>
|
|
74
|
+
<body>
|
|
75
|
+
<main>...</main>
|
|
76
|
+
<!-- Good: loads after page content -->
|
|
77
|
+
<script src="https://cdn.example.com/chat-widget.js" defer jay-script="allow"></script>
|
|
78
|
+
</body>
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Per-Route Consideration
|
|
82
|
+
|
|
83
|
+
Not every page needs every script. Consider whether a third-party script is needed on all pages or only specific routes. Place scripts only on the pages that need them to avoid unnecessary loading.
|
|
@@ -18,17 +18,18 @@ The developer sets up the project, configures plugins, creates page-level compon
|
|
|
18
18
|
|
|
19
19
|
## Guides
|
|
20
20
|
|
|
21
|
-
| File
|
|
22
|
-
|
|
|
23
|
-
| [project-structure.md](project-structure.md)
|
|
24
|
-
| [routing.md](routing.md)
|
|
25
|
-
| [configuration.md](configuration.md)
|
|
26
|
-
| [page-contracts.md](page-contracts.md)
|
|
27
|
-
| [
|
|
28
|
-
| [
|
|
29
|
-
| [component-
|
|
30
|
-
| [component-
|
|
31
|
-
| [
|
|
32
|
-
| [
|
|
33
|
-
| [
|
|
34
|
-
|
|
|
21
|
+
| File | Topic |
|
|
22
|
+
| ------------------------------------------------- | -------------------------------------------------------------------- |
|
|
23
|
+
| [project-structure.md](project-structure.md) | Directory layout, configuration files |
|
|
24
|
+
| [routing.md](routing.md) | Directory-based routing, dynamic routes |
|
|
25
|
+
| [configuration.md](configuration.md) | .jay file, plugin config, init.ts |
|
|
26
|
+
| [page-contracts.md](page-contracts.md) | Page-level contracts (page.jay-contract) |
|
|
27
|
+
| [Contract Authoring Guide](../contracts/GUIDE.md) | Writing contracts: syntax, page/component/linked contracts, examples |
|
|
28
|
+
| [page-components.md](page-components.md) | page.ts: makeJayStackComponent for pages |
|
|
29
|
+
| [component-state.md](component-state.md) | createSignal, createMemo, createEffect, createDerivedArray |
|
|
30
|
+
| [component-refs.md](component-refs.md) | Refs, collection refs, element types |
|
|
31
|
+
| [component-data.md](component-data.md) | Immutable data, JSON Patch, patching |
|
|
32
|
+
| [render-results.md](render-results.md) | phaseOutput, RenderPipeline, errors, redirects |
|
|
33
|
+
| [seo-guide.md](seo-guide.md) | SEO head tags: title, meta, OG, canonical via phaseOutput |
|
|
34
|
+
| [cli-commands.md](cli-commands.md) | CLI commands: setup, validate, dev, agent-kit |
|
|
35
|
+
| `../references/<plugin>/` | Plugin reference data |
|
|
@@ -111,4 +111,4 @@ A page can have both a page contract and headless plugin contracts. The page con
|
|
|
111
111
|
|
|
112
112
|
## Contract Format Reference
|
|
113
113
|
|
|
114
|
-
See the
|
|
114
|
+
See the shared [Contract Authoring Guide](../contracts/GUIDE.md) for the full contract format, decision tree, and examples.
|
|
@@ -18,25 +18,26 @@ A plugin provides headless components (data + interactions, no UI) that project
|
|
|
18
18
|
|
|
19
19
|
## Guides
|
|
20
20
|
|
|
21
|
-
| File
|
|
22
|
-
|
|
|
23
|
-
| [
|
|
24
|
-
| [
|
|
25
|
-
| [
|
|
26
|
-
| [component-
|
|
27
|
-
| [component-
|
|
28
|
-
| [component-
|
|
29
|
-
| [component-
|
|
30
|
-
| [
|
|
31
|
-
| [
|
|
32
|
-
| [
|
|
33
|
-
| [
|
|
34
|
-
| [
|
|
35
|
-
| [
|
|
36
|
-
| [
|
|
37
|
-
| [
|
|
38
|
-
| [
|
|
39
|
-
|
|
|
21
|
+
| File | Topic |
|
|
22
|
+
| ------------------------------------------------- | ----------------------------------------------------------------------- |
|
|
23
|
+
| [Contract Authoring Guide](../contracts/GUIDE.md) | Writing contracts: syntax, page/component/linked contracts, examples |
|
|
24
|
+
| [contracts-guide.md](contracts-guide.md) | Plugin-specific contract concerns |
|
|
25
|
+
| [plugin-structure.md](plugin-structure.md) | plugin.yaml, package layout, exports |
|
|
26
|
+
| [component-structure.md](component-structure.md) | makeJayStackComponent, builder API, three-phase rendering |
|
|
27
|
+
| [component-state.md](component-state.md) | createSignal, createMemo, createEffect, createDerivedArray, createEvent |
|
|
28
|
+
| [component-refs.md](component-refs.md) | Refs, collection refs, element types |
|
|
29
|
+
| [component-data.md](component-data.md) | Immutable data, JSON Patch, createPatchableSignal |
|
|
30
|
+
| [component-context.md](component-context.md) | Context hooks: provide, reactive, global |
|
|
31
|
+
| [render-results.md](render-results.md) | phaseOutput, RenderPipeline, errors, redirects |
|
|
32
|
+
| [actions-guide.md](actions-guide.md) | makeJayAction, makeJayQuery, .jay-action files |
|
|
33
|
+
| [webhooks-guide.md](webhooks-guide.md) | makeWebhook, data change invalidation, renderer server |
|
|
34
|
+
| [services-guide.md](services-guide.md) | createJayService, makeJayInit |
|
|
35
|
+
| [plugin-routes.md](plugin-routes.md) | Plugin-provided pages: routes, jay-html templates, page components |
|
|
36
|
+
| [seo-guide.md](seo-guide.md) | SEO head tags: title, meta, OG, canonical via phaseOutput |
|
|
37
|
+
| [commands-guide.md](commands-guide.md) | makeCliCommand, .jay-command files, CONSOLE_CONTEXT, jay-stack run |
|
|
38
|
+
| [validation.md](validation.md) | jay-stack validate-plugin, writing custom jay-html validators |
|
|
39
|
+
| [dev-server-service.md](dev-server-service.md) | Dev server service API: routes, params, freeze management |
|
|
40
|
+
| `../references/<plugin>/` | Plugin reference data |
|
|
40
41
|
|
|
41
42
|
## Key Principles
|
|
42
43
|
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
# Contract
|
|
1
|
+
# Plugin Contract Guide
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
For the full contract syntax, decision tree, and examples, see the shared [Contract Authoring Guide](../contracts/GUIDE.md).
|
|
4
|
+
|
|
5
|
+
This file covers plugin-specific contract concerns. Contracts (`.jay-contract` files) are the source of truth for a component's data shape. Define the contract before implementing the component.
|
|
4
6
|
|
|
5
7
|
## Basic Structure
|
|
6
8
|
|
package/dist/index.js
CHANGED
|
@@ -4824,9 +4824,35 @@ async function ensureAgentKitDocs(projectRoot, _force, mode) {
|
|
|
4824
4824
|
getLogger().info(chalk.gray(` Created agent-kit/${role}/${filename}`));
|
|
4825
4825
|
}
|
|
4826
4826
|
}
|
|
4827
|
+
const topLevelFiles = (await fs$1.readdir(templateDir)).filter((f) => f.endsWith(".md"));
|
|
4828
|
+
for (const filename of topLevelFiles) {
|
|
4829
|
+
await fs$1.copyFile(path$1.join(templateDir, filename), path$1.join(agentKitDir, filename));
|
|
4830
|
+
getLogger().info(chalk.gray(` Created agent-kit/${filename}`));
|
|
4831
|
+
}
|
|
4832
|
+
const sharedDirs = ["contracts"];
|
|
4833
|
+
for (const dir of sharedDirs) {
|
|
4834
|
+
const srcDir = path$1.join(templateDir, dir);
|
|
4835
|
+
if (!fsSync.existsSync(srcDir))
|
|
4836
|
+
continue;
|
|
4837
|
+
await copyDirRecursive(srcDir, path$1.join(agentKitDir, dir));
|
|
4838
|
+
getLogger().info(chalk.gray(` Created agent-kit/${dir}/`));
|
|
4839
|
+
}
|
|
4840
|
+
}
|
|
4841
|
+
async function copyDirRecursive(src, dest) {
|
|
4842
|
+
await fs$1.mkdir(dest, { recursive: true });
|
|
4843
|
+
const entries = await fs$1.readdir(src, { withFileTypes: true });
|
|
4844
|
+
for (const entry of entries) {
|
|
4845
|
+
const srcPath = path$1.join(src, entry.name);
|
|
4846
|
+
const destPath = path$1.join(dest, entry.name);
|
|
4847
|
+
if (entry.isDirectory()) {
|
|
4848
|
+
await copyDirRecursive(srcPath, destPath);
|
|
4849
|
+
} else if (entry.name.endsWith(".md")) {
|
|
4850
|
+
await fs$1.copyFile(srcPath, destPath);
|
|
4851
|
+
}
|
|
4852
|
+
}
|
|
4827
4853
|
}
|
|
4828
4854
|
async function mergePluginAgentKitGuides(projectRoot, mode) {
|
|
4829
|
-
const plugins = await scanPlugins$1({ projectRoot });
|
|
4855
|
+
const plugins = await scanPlugins$1({ projectRoot, includeDevDeps: true });
|
|
4830
4856
|
const agentKitDir = path$1.join(projectRoot, "agent-kit");
|
|
4831
4857
|
const roles = mode && ALL_ROLES.includes(mode) ? [mode] : ALL_ROLES;
|
|
4832
4858
|
const copiedPerRole = /* @__PURE__ */ new Map();
|