@jarenjs/studio 0.75.0 → 0.83.2
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 +27 -2
- package/dist/types/assemble.d.ts +5 -8
- package/dist/types/author.d.ts +27 -0
- package/dist/types/component/index.d.ts +46 -29
- package/dist/types/component/view.d.ts +45 -28
- package/dist/types/errors.d.ts +1 -0
- package/dist/types/export.d.ts +5 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/resolve.d.ts +27 -0
- package/dist/types/skeletons.d.ts +6 -0
- package/dist/types/validate.d.ts +1 -1
- package/docs/PROJECT-FORMAT.md +99 -24
- package/package.json +18 -9
- package/schemas/jaren-project.draft-07.schema.json +80 -12
- package/schemas/jaren-project.schema.json +77 -13
- package/src/assemble.js +34 -14
- package/src/author.js +55 -0
- package/src/component/view.js +14 -8
- package/src/component/viewmodel.js +13 -8
- package/src/errors.js +1 -0
- package/src/export.js +66 -0
- package/src/index.js +2 -0
- package/src/project.js +1 -1
- package/src/resolve.js +111 -0
- package/src/skeletons.js +33 -0
- package/src/validate.js +26 -7
- package/styles/studio.css +14 -0
package/README.md
CHANGED
|
@@ -26,14 +26,19 @@ This package ships in two layers, the suite's convention:
|
|
|
26
26
|
(hot-update via `app.setState`) and the drag splitter — which are
|
|
27
27
|
browser-verified. Mounted live at the website's `#/project`, where `app`
|
|
28
28
|
files boot, `jslt`/`query` files run against a data file, `contract`
|
|
29
|
-
files render their `describe()`/OpenAPI projections,
|
|
30
|
-
|
|
29
|
+
files render their `describe()`/OpenAPI projections, `fsm`/`dag` files
|
|
30
|
+
mount the Flow editor, and collection models run in private SQLite workers
|
|
31
|
+
with query plans and live results. All ten file kinds can be created,
|
|
32
|
+
renamed, deleted and opened from templates.
|
|
31
33
|
|
|
32
34
|
## The project document
|
|
33
35
|
|
|
34
36
|
A thin envelope over typed files — the full contract is
|
|
35
37
|
[PROJECT-FORMAT.md](docs/PROJECT-FORMAT.md).
|
|
36
38
|
|
|
39
|
+
`KINDS` lists all ten file kinds; `ADDABLE_KINDS` and `fileSkeleton` supply
|
|
40
|
+
the creation menu and starter text from one shared table.
|
|
41
|
+
|
|
37
42
|
```js
|
|
38
43
|
import { parseProject, validateFile, assembleArtifacts, classifyChange, describe }
|
|
39
44
|
from '@jarenjs/studio';
|
|
@@ -52,6 +57,24 @@ validateFile(project.files[1]); // { valid, kind, total, errors: [{ code, messag
|
|
|
52
57
|
assembleArtifacts(project); // the runnable set
|
|
53
58
|
```
|
|
54
59
|
|
|
60
|
+
Files can import named members from other files: an app's `view`, `actions`
|
|
61
|
+
and `state` can each live in their own editor. The assembler checks references,
|
|
62
|
+
tracks dependencies and writes diagram edits back into their source files.
|
|
63
|
+
Explicit `input`, `model` and `collection` metadata route queries and model
|
|
64
|
+
seeds; the [format](docs/PROJECT-FORMAT.md) specifies ownership and lifetimes.
|
|
65
|
+
|
|
66
|
+
`@jarenjs/studio/author` exposes `createStudioFileAuthor({ client })`: generate
|
|
67
|
+
one file under its authoring profile, validate with the full engine, and repair
|
|
68
|
+
bounded failures before returning a candidate. The website assistant uses this
|
|
69
|
+
path and protects edits made while generation is running. No provider quality
|
|
70
|
+
claim is inferred from the mocked generation tests.
|
|
71
|
+
|
|
72
|
+
`@jarenjs/studio/export` exposes `exportProject(project, assets)` and
|
|
73
|
+
`createProjectZip(files)`. The website's **Offline ZIP** includes a standalone
|
|
74
|
+
runner and the installed runtime dependencies, including SQLite and fonts.
|
|
75
|
+
It runs from a local HTTP server without an install or external network.
|
|
76
|
+
Runtime rows remain transient; explicit seed files travel with the project.
|
|
77
|
+
|
|
55
78
|
## Why per-file validation
|
|
56
79
|
|
|
57
80
|
The published `jaren-query` / `jaren-jslt` grammars are *closed*, so a data
|
|
@@ -77,6 +100,8 @@ Every subpath a consumer can import, derived from the manifest by
|
|
|
77
100
|
| `@jarenjs/studio/schemas/jaren-project.schema.json` | schema | — |
|
|
78
101
|
| `@jarenjs/studio/styles/studio.css` | asset | — |
|
|
79
102
|
| `@jarenjs/studio/package.json` | metadata | — |
|
|
103
|
+
| `@jarenjs/studio/author` | JavaScript | declared |
|
|
104
|
+
| `@jarenjs/studio/export` | JavaScript | declared |
|
|
80
105
|
<!--/fact-->
|
|
81
106
|
|
|
82
107
|
## Install
|
package/dist/types/assemble.d.ts
CHANGED
|
@@ -3,24 +3,21 @@
|
|
|
3
3
|
* needs to decide reboot-vs-hot-update.
|
|
4
4
|
*
|
|
5
5
|
* `assembleArtifacts` composes the project's files into the runnable set.
|
|
6
|
-
*
|
|
7
|
-
* `
|
|
8
|
-
*
|
|
9
|
-
* composing separate `state` + `view` + `actions` files into ONE
|
|
10
|
-
* `jaren-app` document (the true HTML/CSS/JS split) — is the model's
|
|
11
|
-
* headline enhancement and layers on top without changing this contract.
|
|
6
|
+
* A runnable file can import named members from other project files;
|
|
7
|
+
* `sourceFiles` records the complete dependency chain. `state`/`data`
|
|
8
|
+
* files are inputs, not standalone artifacts.
|
|
12
9
|
*
|
|
13
10
|
* `classifyChange` is the load-bearing UX datum: a `state`-only edit must
|
|
14
11
|
* HOT-DISPATCH into a running app (no reboot, the user keeps scroll and
|
|
15
12
|
* inputs), while a `view`/`actions` change must reboot. It compares a
|
|
16
|
-
* STRUCTURAL key (
|
|
13
|
+
* STRUCTURAL key (all app members except `state`) via the suite's own
|
|
17
14
|
* `semanticKey` — the collision-free identity, not the memo-grade
|
|
18
15
|
* `contentKey` fingerprint: a classification decides whether a running
|
|
19
16
|
* app reboots, so a fingerprint collision would read a changed document
|
|
20
17
|
* as unchanged. The artifacts are parsed JSON, so the identity is total.
|
|
21
18
|
*/
|
|
22
19
|
/**
|
|
23
|
-
* Compose the project's files into runnable artifacts
|
|
20
|
+
* Compose the project's files into runnable artifacts, resolving imports.
|
|
24
21
|
* @param {any} project - a normalized project (from `parseProject`)
|
|
25
22
|
* @returns {{ artifacts: Array<{ name: string, kind: string, role: string,
|
|
26
23
|
* doc: any, sourceFiles: string[] }>, errors: Array<{ file: string, message: string }> }}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export declare const AUTHORABLE_KINDS: readonly string[];
|
|
2
|
+
/** @param {{ client: any, operators?: any, maxRepairs?: number }} options */
|
|
3
|
+
export declare function createStudioFileAuthor(options: {
|
|
4
|
+
client: any;
|
|
5
|
+
operators?: any;
|
|
6
|
+
maxRepairs?: number;
|
|
7
|
+
}): {
|
|
8
|
+
/** @param {{ project: any, name: string, kind?: string, prompt: string }} request
|
|
9
|
+
* @param {{ signal?: AbortSignal }} [hooks] */
|
|
10
|
+
author(request: {
|
|
11
|
+
project: any;
|
|
12
|
+
name: string;
|
|
13
|
+
kind?: string;
|
|
14
|
+
prompt: string;
|
|
15
|
+
}, hooks?: {
|
|
16
|
+
signal?: AbortSignal;
|
|
17
|
+
}): Promise<{
|
|
18
|
+
errors: any[];
|
|
19
|
+
raw: string;
|
|
20
|
+
attempts: number;
|
|
21
|
+
} | {
|
|
22
|
+
value: any;
|
|
23
|
+
raw: string;
|
|
24
|
+
attempts: number;
|
|
25
|
+
file: any;
|
|
26
|
+
}>;
|
|
27
|
+
};
|
|
@@ -83,7 +83,9 @@ export declare function createStudioComponent(options?: {
|
|
|
83
83
|
} | {
|
|
84
84
|
class?: undefined;
|
|
85
85
|
$if: ((string | (string | {
|
|
86
|
-
name:
|
|
86
|
+
name: {
|
|
87
|
+
$default: string[];
|
|
88
|
+
};
|
|
87
89
|
props: string;
|
|
88
90
|
})[] | {
|
|
89
91
|
class: string;
|
|
@@ -111,6 +113,33 @@ export declare function createStudioComponent(options?: {
|
|
|
111
113
|
})[];
|
|
112
114
|
$eq?: undefined;
|
|
113
115
|
})[];
|
|
116
|
+
})[] | (string | (string | {
|
|
117
|
+
class: string;
|
|
118
|
+
type: string;
|
|
119
|
+
'aria-pressed': {
|
|
120
|
+
$if: string[];
|
|
121
|
+
};
|
|
122
|
+
on: {
|
|
123
|
+
click: string;
|
|
124
|
+
};
|
|
125
|
+
})[] | (string | {
|
|
126
|
+
class: string;
|
|
127
|
+
type: string;
|
|
128
|
+
on: {
|
|
129
|
+
click: string;
|
|
130
|
+
};
|
|
131
|
+
})[] | (string | any[] | {
|
|
132
|
+
class: string;
|
|
133
|
+
role: string;
|
|
134
|
+
'aria-label': string;
|
|
135
|
+
})[] | (string | {
|
|
136
|
+
$apply: string;
|
|
137
|
+
}[] | (string | {
|
|
138
|
+
class: string;
|
|
139
|
+
})[] | {
|
|
140
|
+
class: string;
|
|
141
|
+
})[] | {
|
|
142
|
+
class: string;
|
|
114
143
|
})[] | (string | (string | {
|
|
115
144
|
class: string;
|
|
116
145
|
rows: number;
|
|
@@ -158,6 +187,21 @@ export declare function createStudioComponent(options?: {
|
|
|
158
187
|
role: string;
|
|
159
188
|
})[])[];
|
|
160
189
|
class?: undefined;
|
|
190
|
+
} | {
|
|
191
|
+
$if: (string | (string | {
|
|
192
|
+
class: string;
|
|
193
|
+
$if?: undefined;
|
|
194
|
+
} | {
|
|
195
|
+
$if: (string | {}[])[];
|
|
196
|
+
class?: undefined;
|
|
197
|
+
} | {
|
|
198
|
+
$if: (string | {}[])[];
|
|
199
|
+
class?: undefined;
|
|
200
|
+
} | {
|
|
201
|
+
$if: (string | {}[])[];
|
|
202
|
+
class?: undefined;
|
|
203
|
+
})[])[];
|
|
204
|
+
class?: undefined;
|
|
161
205
|
} | {
|
|
162
206
|
$if: (string | (string | {
|
|
163
207
|
$apply: string;
|
|
@@ -166,33 +210,6 @@ export declare function createStudioComponent(options?: {
|
|
|
166
210
|
role: string;
|
|
167
211
|
})[])[];
|
|
168
212
|
class?: undefined;
|
|
169
|
-
})[] | (string | (string | {
|
|
170
|
-
class: string;
|
|
171
|
-
type: string;
|
|
172
|
-
'aria-pressed': {
|
|
173
|
-
$if: string[];
|
|
174
|
-
};
|
|
175
|
-
on: {
|
|
176
|
-
click: string;
|
|
177
|
-
};
|
|
178
|
-
})[] | (string | {
|
|
179
|
-
class: string;
|
|
180
|
-
type: string;
|
|
181
|
-
on: {
|
|
182
|
-
click: string;
|
|
183
|
-
};
|
|
184
|
-
})[] | (string | any[] | {
|
|
185
|
-
class: string;
|
|
186
|
-
role: string;
|
|
187
|
-
'aria-label': string;
|
|
188
|
-
})[] | (string | {
|
|
189
|
-
$apply: string;
|
|
190
|
-
}[] | (string | {
|
|
191
|
-
class: string;
|
|
192
|
-
})[] | {
|
|
193
|
-
class: string;
|
|
194
|
-
})[] | {
|
|
195
|
-
class: string;
|
|
196
213
|
})[] | {
|
|
197
214
|
class: string;
|
|
198
215
|
'data-mode': string;
|
|
@@ -231,8 +248,8 @@ export declare function createStudioComponent(options?: {
|
|
|
231
248
|
};
|
|
232
249
|
};
|
|
233
250
|
} | {
|
|
234
|
-
class?: undefined;
|
|
235
251
|
type?: undefined;
|
|
252
|
+
class?: undefined;
|
|
236
253
|
title?: undefined;
|
|
237
254
|
on?: undefined;
|
|
238
255
|
$if: (string | (string | {
|
|
@@ -81,7 +81,9 @@ export declare const projectRules: ({
|
|
|
81
81
|
} | {
|
|
82
82
|
class?: undefined;
|
|
83
83
|
$if: ((string | (string | {
|
|
84
|
-
name:
|
|
84
|
+
name: {
|
|
85
|
+
$default: string[];
|
|
86
|
+
};
|
|
85
87
|
props: string;
|
|
86
88
|
})[] | {
|
|
87
89
|
class: string;
|
|
@@ -109,6 +111,33 @@ export declare const projectRules: ({
|
|
|
109
111
|
})[];
|
|
110
112
|
$eq?: undefined;
|
|
111
113
|
})[];
|
|
114
|
+
})[] | (string | (string | {
|
|
115
|
+
class: string;
|
|
116
|
+
type: string;
|
|
117
|
+
'aria-pressed': {
|
|
118
|
+
$if: string[];
|
|
119
|
+
};
|
|
120
|
+
on: {
|
|
121
|
+
click: string;
|
|
122
|
+
};
|
|
123
|
+
})[] | (string | {
|
|
124
|
+
class: string;
|
|
125
|
+
type: string;
|
|
126
|
+
on: {
|
|
127
|
+
click: string;
|
|
128
|
+
};
|
|
129
|
+
})[] | (string | any[] | {
|
|
130
|
+
class: string;
|
|
131
|
+
role: string;
|
|
132
|
+
'aria-label': string;
|
|
133
|
+
})[] | (string | {
|
|
134
|
+
$apply: string;
|
|
135
|
+
}[] | (string | {
|
|
136
|
+
class: string;
|
|
137
|
+
})[] | {
|
|
138
|
+
class: string;
|
|
139
|
+
})[] | {
|
|
140
|
+
class: string;
|
|
112
141
|
})[] | (string | (string | {
|
|
113
142
|
class: string;
|
|
114
143
|
rows: number;
|
|
@@ -156,6 +185,21 @@ export declare const projectRules: ({
|
|
|
156
185
|
role: string;
|
|
157
186
|
})[])[];
|
|
158
187
|
class?: undefined;
|
|
188
|
+
} | {
|
|
189
|
+
$if: (string | (string | {
|
|
190
|
+
class: string;
|
|
191
|
+
$if?: undefined;
|
|
192
|
+
} | {
|
|
193
|
+
$if: (string | {}[])[];
|
|
194
|
+
class?: undefined;
|
|
195
|
+
} | {
|
|
196
|
+
$if: (string | {}[])[];
|
|
197
|
+
class?: undefined;
|
|
198
|
+
} | {
|
|
199
|
+
$if: (string | {}[])[];
|
|
200
|
+
class?: undefined;
|
|
201
|
+
})[])[];
|
|
202
|
+
class?: undefined;
|
|
159
203
|
} | {
|
|
160
204
|
$if: (string | (string | {
|
|
161
205
|
$apply: string;
|
|
@@ -164,33 +208,6 @@ export declare const projectRules: ({
|
|
|
164
208
|
role: string;
|
|
165
209
|
})[])[];
|
|
166
210
|
class?: undefined;
|
|
167
|
-
})[] | (string | (string | {
|
|
168
|
-
class: string;
|
|
169
|
-
type: string;
|
|
170
|
-
'aria-pressed': {
|
|
171
|
-
$if: string[];
|
|
172
|
-
};
|
|
173
|
-
on: {
|
|
174
|
-
click: string;
|
|
175
|
-
};
|
|
176
|
-
})[] | (string | {
|
|
177
|
-
class: string;
|
|
178
|
-
type: string;
|
|
179
|
-
on: {
|
|
180
|
-
click: string;
|
|
181
|
-
};
|
|
182
|
-
})[] | (string | any[] | {
|
|
183
|
-
class: string;
|
|
184
|
-
role: string;
|
|
185
|
-
'aria-label': string;
|
|
186
|
-
})[] | (string | {
|
|
187
|
-
$apply: string;
|
|
188
|
-
}[] | (string | {
|
|
189
|
-
class: string;
|
|
190
|
-
})[] | {
|
|
191
|
-
class: string;
|
|
192
|
-
})[] | {
|
|
193
|
-
class: string;
|
|
194
211
|
})[] | {
|
|
195
212
|
class: string;
|
|
196
213
|
'data-mode': string;
|
package/dist/types/errors.d.ts
CHANGED
|
@@ -14,6 +14,7 @@ import { CodedError } from '@jarenjs/core/errors';
|
|
|
14
14
|
export declare const STUDIO_CODES: Readonly<{
|
|
15
15
|
JS0001: "the project document is invalid";
|
|
16
16
|
JS0002: "a file name is duplicated in the project";
|
|
17
|
+
JS0003: "a project file reference cannot be resolved";
|
|
17
18
|
}>;
|
|
18
19
|
/** A studio-envelope error. */
|
|
19
20
|
export declare class StudioError extends CodedError {
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/** ZIP method 0 (stored), UTF-8 names, fixed DOS epoch, no ZIP64.
|
|
2
|
+
* @param {Record<string, string | Uint8Array>} files @returns {Uint8Array} */
|
|
3
|
+
export declare function createProjectZip(files: Record<string, string | Uint8Array>): Uint8Array;
|
|
4
|
+
/** @param {any} project @param {Record<string, string | Uint8Array>} assets */
|
|
5
|
+
export declare function exportProject(project: any, assets: Record<string, string | Uint8Array>): Uint8Array<ArrayBufferLike>;
|
package/dist/types/index.d.ts
CHANGED
|
@@ -16,3 +16,5 @@ export { KINDS, LAYOUT_DEFAULT, parseProject, fileOf } from './project.js';
|
|
|
16
16
|
export { validateFile } from './validate.js';
|
|
17
17
|
export { assembleArtifacts, classifyChange, describe } from './assemble.js';
|
|
18
18
|
export { STUDIO_CODES, StudioError } from './errors.js';
|
|
19
|
+
export { resolveProjectFile, projectFileContext, renameProjectFile, writeProjectArtifact } from './resolve.js';
|
|
20
|
+
export { ADDABLE_KINDS, fileSkeleton } from './skeletons.js';
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/** Resolve one file and its transitive sources. Imported members must be
|
|
2
|
+
* absent locally; a typo, cycle or collision is a refusal, never a fallback.
|
|
3
|
+
* @param {any} project @param {string} name
|
|
4
|
+
* @returns {{ doc: any, sourceFiles: string[] }} */
|
|
5
|
+
export declare function resolveProjectFile(project: any, name: string): {
|
|
6
|
+
doc: any;
|
|
7
|
+
sourceFiles: string[];
|
|
8
|
+
};
|
|
9
|
+
/** Resolve a query/transform/validation input or a worker store route.
|
|
10
|
+
* Explicit references never fall back when broken. Multiple models require
|
|
11
|
+
* a choice; adding an unrelated model cannot silently reroute a query.
|
|
12
|
+
* @param {any} project @param {any} file
|
|
13
|
+
* @returns {{ input: any, model: any, collection: string | null }} */
|
|
14
|
+
export declare function projectFileContext(project: any, file: any): {
|
|
15
|
+
input: any;
|
|
16
|
+
model: any;
|
|
17
|
+
collection: string | null;
|
|
18
|
+
};
|
|
19
|
+
/** Rename references together with their target, preserving every other
|
|
20
|
+
* file member. A delete deliberately leaves references visibly broken.
|
|
21
|
+
* @param {any[]} files @param {string} before @param {string} after */
|
|
22
|
+
export declare function renameProjectFile(files: any[], before: string, after: string): any[];
|
|
23
|
+
/** Write an assembled artifact back into its source files. Imported
|
|
24
|
+
* members stay in their own files; conflicting writes to a shared source
|
|
25
|
+
* are refused atomically. Unchanged files keep their identity and text.
|
|
26
|
+
* @param {any} project @param {string} name @param {any} doc */
|
|
27
|
+
export declare function writeProjectArtifact(project: any, name: string, doc: any): any;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/** Creation kinds derive from the valid starter table and are shared by
|
|
2
|
+
* the component menu, website host and assistant. */
|
|
3
|
+
export declare const ADDABLE_KINDS: readonly string[];
|
|
4
|
+
/** The starter text for a freshly added file of `kind`, or null if the
|
|
5
|
+
* kind is not addable. */
|
|
6
|
+
export declare function fileSkeleton(kind: any): any;
|
package/dist/types/validate.d.ts
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* so host-registered operators ($npv, $sqrt) validate and a
|
|
12
12
|
* real error comes back as its own coded `JQ`/`JT` code with
|
|
13
13
|
* a docPath — the closed grammar would reject the operators;
|
|
14
|
-
* - `fsm` / `dag` / `model` → their
|
|
14
|
+
* - `fsm` / `dag` / `model` → their grammar plus compiler/planner checks;
|
|
15
15
|
* - `contract` → COMPILED by `compileContract`, so a refusal comes back
|
|
16
16
|
* as its stable `JC00xx` code with the docPath of the
|
|
17
17
|
* member at fault — richer than the grammar alone;
|
package/docs/PROJECT-FORMAT.md
CHANGED
|
@@ -39,8 +39,9 @@ strip reads.
|
|
|
39
39
|
| `query` | a query document | **compiled** by the engine with the operator registry |
|
|
40
40
|
| `state` / `data` | any JSON value (an input) | structural JSON only |
|
|
41
41
|
| `schema` | a JSON Schema | must be an object/boolean and compile |
|
|
42
|
-
| `fsm` / `dag` | a `jaren-fsm` / `jaren-dag` machine | its
|
|
43
|
-
| `model` | a `jaren-model` store definition |
|
|
42
|
+
| `fsm` / `dag` | a `jaren-fsm` / `jaren-dag` machine | its grammar and compiler; named tasks are checked without execution |
|
|
43
|
+
| `model` | a `jaren-model` store definition | its grammar, normalization and SQLite collection/entity planning |
|
|
44
|
+
| `contract` | a `jaren-contract` document | `compileContract`, with coded diagnostics |
|
|
44
45
|
|
|
45
46
|
**Why per-file, not one composed schema.** The published `jaren-query` /
|
|
46
47
|
`jaren-jslt` grammars are *closed* — their operator vocabulary is
|
|
@@ -56,15 +57,74 @@ design, not a compromise. A host embeds its own vocabulary with
|
|
|
56
57
|
|
|
57
58
|
## Assembly — files → runnable artifacts
|
|
58
59
|
|
|
59
|
-
`assembleArtifacts(project)`
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
60
|
+
`assembleArtifacts(project)` returns `{ artifacts, errors }`. Each runnable
|
|
61
|
+
file (`app`, `fsm`, `dag`, `model`, `jslt`, `query`, `schema`, `contract`)
|
|
62
|
+
produces `{ name, kind, role, doc, sourceFiles }`; `state`/`data` are inputs.
|
|
63
|
+
Assembly resolves JSON and references; `describe(project)` additionally
|
|
64
|
+
validates assembled documents and reports each file's errors.
|
|
65
|
+
|
|
66
|
+
A file can supply absent top-level members through `imports`, an object
|
|
67
|
+
mapping member names to exact project filenames. For example:
|
|
68
|
+
|
|
69
|
+
```json
|
|
70
|
+
{
|
|
71
|
+
"name": "app.json", "kind": "app", "text": "{}",
|
|
72
|
+
"imports": { "view": "app.view", "actions": "app.actions", "state": "app.state" }
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Each source's entire JSON value becomes the destination member. Sources may
|
|
77
|
+
themselves import members. The allowed destination members are:
|
|
78
|
+
|
|
79
|
+
| Destination kind | Importable members |
|
|
80
|
+
|---|---|
|
|
81
|
+
| `app` | `view`, `actions`, `state`, `subs` |
|
|
82
|
+
| `fsm` | `states`, `transitions`, `initial` |
|
|
83
|
+
| `dag` | `nodes`, `edges`, `output` |
|
|
84
|
+
| `model` | `collections`, `entities` |
|
|
85
|
+
|
|
86
|
+
`resolveProjectFile(project, name)` returns `{ doc, sourceFiles }`, with
|
|
87
|
+
dependencies in traversal order, deduplicated. Missing sources, cycles,
|
|
88
|
+
unsupported members and a member supplied both locally and by import raise
|
|
89
|
+
`JS0003`. Source files are never mutated. `renameProjectFile` updates all
|
|
90
|
+
references atomically. `writeProjectArtifact` writes edits back into their
|
|
91
|
+
source files, preserving untouched text and refusing conflicting writes to a
|
|
92
|
+
shared source. Deletion leaves dependent files with explicit reference errors.
|
|
93
|
+
|
|
94
|
+
The website keeps an app visible while editing a fragment directly imported
|
|
95
|
+
by exactly one app. Imported state changes hot-update that app; structural
|
|
96
|
+
changes reboot it. Ambiguous owners require selecting the intended app.
|
|
97
|
+
|
|
98
|
+
## Input and model routing
|
|
99
|
+
|
|
100
|
+
Optional file members `input`, `model` and `collection` select execution inputs.
|
|
101
|
+
`input` names a `data` or `state` file; absent it, pure runners use the first
|
|
102
|
+
`data` file, then the first `state` file, then JSON null. `model` explicitly
|
|
103
|
+
names a model file for a query. It never implicitly selects the first store.
|
|
104
|
+
`collection` chooses a collection; a model with exactly one collection can
|
|
105
|
+
omit it. `projectFileContext` resolves these references and refuses wrong
|
|
106
|
+
kinds or missing names. The IDE exposes selectors beside the editor.
|
|
107
|
+
|
|
108
|
+
The website runs collection models in private in-memory SQLite workers, one
|
|
109
|
+
owner per model filename. Queries referencing that model share its rows;
|
|
110
|
+
other models and the separate data page do not. Switching files stops the
|
|
111
|
+
view's live subscription but retains the worker. Committing a changed model
|
|
112
|
+
or seed recreates its store; deleting a model, replacing a project or
|
|
113
|
+
destroying the app releases its worker. Invalid drafts retain the committed
|
|
114
|
+
stage. Runtime rows are transient and are not saved or shared.
|
|
115
|
+
|
|
116
|
+
A model's **explicit** `input` is a seed object mapping collection names to
|
|
117
|
+
arrays of documents, inserted before the first query. No implicit data file
|
|
118
|
+
seeds a store. The stage supports inserts, deletes, query results, SQL plans
|
|
119
|
+
and live query results. Entity-only models validate and can be authored, but
|
|
120
|
+
the website's execution controls currently require a collection.
|
|
121
|
+
|
|
122
|
+
FSM and DAG files mount the Flow diagram editor, including palette,
|
|
123
|
+
inspector, undo/redo and run controls. Diagram edits write back through
|
|
124
|
+
assembly. FSM effects are recorded, not dispatched to host services; only
|
|
125
|
+
the editor's registered local DAG tasks execute. Teardown cancels pending
|
|
126
|
+
runs and ignores late completions. The standalone `#/flow` route remains
|
|
127
|
+
available using the same editor.
|
|
68
128
|
|
|
69
129
|
## `layout` is frozen
|
|
70
130
|
|
|
@@ -80,14 +140,25 @@ vertically in `top`; pointer cancellation restores the previous ratio.
|
|
|
80
140
|
**Download** exports the complete `jaren-project` envelope, including every
|
|
81
141
|
file and the active file/layout, and works for projects without an app.
|
|
82
142
|
**App JSON** separately exports the designated app document and reports
|
|
83
|
-
when none exists
|
|
143
|
+
when none exists, resolving any imported members first. **Offline ZIP**
|
|
144
|
+
exports a standalone runner, `project.json`, every original file's text, and
|
|
145
|
+
bundled runtime, fonts and SQLite assets. Unzip and serve the directory over
|
|
146
|
+
localhost (the included README gives a Python command); no package install
|
|
147
|
+
or internet connection is required. Runtime versions come from the exporting
|
|
148
|
+
build and are recorded in `runtime/versions.json`. Authored external asset
|
|
149
|
+
URLs remain external. Live rows and host credentials are excluded.
|
|
150
|
+
|
|
151
|
+
The headless `@jarenjs/studio/export` entry accepts the host's runtime asset
|
|
152
|
+
bytes and produces a deterministic ZIP. It refuses unsafe archive paths;
|
|
153
|
+
source filenames are represented in `project.json` and mapped to numbered
|
|
154
|
+
files, so arbitrary project names cannot escape the archive directory.
|
|
84
155
|
|
|
85
156
|
## `classifyChange` — reboot vs. hot-update
|
|
86
157
|
|
|
87
158
|
`classifyChange(prev, next)` reports, **per artifact**, whether a change
|
|
88
159
|
is `structural`, `state-only`, or `none`. A change of artifact kind is
|
|
89
160
|
structural even when the JSON text stays the same. It compares an app's
|
|
90
|
-
|
|
161
|
+
entire document except `state` (other artifacts' whole documents) via the
|
|
91
162
|
suite's collision-free `semanticKey`; a remaining document change is
|
|
92
163
|
`state-only`. Every filename, including `__proto__`, is an own member of
|
|
93
164
|
the result map.
|
|
@@ -98,13 +169,14 @@ widget, is deliberate.
|
|
|
98
169
|
|
|
99
170
|
## Errors
|
|
100
171
|
|
|
101
|
-
|
|
102
|
-
|
|
172
|
+
Envelope and reference operations raise coded `StudioError`s. `validateFile`
|
|
173
|
+
and `describe` report file problems as diagnostics.
|
|
103
174
|
|
|
104
175
|
| code | meaning |
|
|
105
176
|
|---|---|
|
|
106
177
|
| `JS0001` | the project document is invalid (bad JSON, or fails the envelope schema) |
|
|
107
178
|
| `JS0002` | a file name is duplicated in the project |
|
|
179
|
+
| `JS0003` | an import or execution reference cannot be resolved, or an artifact write conflicts |
|
|
108
180
|
|
|
109
181
|
## Status
|
|
110
182
|
|
|
@@ -114,13 +186,16 @@ debounced editor with its typing buffer, the run stage, the three layout
|
|
|
114
186
|
modes with a drag splitter, the phone pane switcher, save/load/share, and
|
|
115
187
|
an assistant that can list, read, write and run a project's files.
|
|
116
188
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
189
|
+
The creation menu and assistant share the engine's ten-kind vocabulary and
|
|
190
|
+
valid starter files. `@jarenjs/studio/author` uses one authoring profile per
|
|
191
|
+
file, then the full file validation gate with bounded repair rounds. The
|
|
192
|
+
website's `jaren_project_author` tool rejects stale publication if the project
|
|
193
|
+
changed during generation, returning the candidate for recovery. Generic
|
|
194
|
+
JSON/schema/contract files and imported destinations use broad JSON profiles;
|
|
195
|
+
their acceptance still depends on the full local validation gate. The exact
|
|
196
|
+
`jaren_project_write` tool remains available for supplied text.
|
|
197
|
+
|
|
123
198
|
The stage displays the nested app's latest boot/runtime failure and clears
|
|
124
|
-
it on restart.
|
|
125
|
-
|
|
126
|
-
|
|
199
|
+
it on restart. Remaining constraints live in
|
|
200
|
+
[ROADMAP.md](../../../docs/ROADMAP.md). The editor remains a plain
|
|
201
|
+
`<textarea>` with no syntax highlighting or imperative editor chrome.
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jarenjs/studio",
|
|
3
3
|
"private": false,
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.83.2",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/index.js",
|
|
7
7
|
"types": "./dist/types/index.d.ts",
|
|
@@ -17,7 +17,15 @@
|
|
|
17
17
|
},
|
|
18
18
|
"./schemas/*": "./schemas/*",
|
|
19
19
|
"./styles/studio.css": "./styles/studio.css",
|
|
20
|
-
"./package.json": "./package.json"
|
|
20
|
+
"./package.json": "./package.json",
|
|
21
|
+
"./author": {
|
|
22
|
+
"types": "./dist/types/author.d.ts",
|
|
23
|
+
"default": "./src/author.js"
|
|
24
|
+
},
|
|
25
|
+
"./export": {
|
|
26
|
+
"types": "./dist/types/export.d.ts",
|
|
27
|
+
"default": "./src/export.js"
|
|
28
|
+
}
|
|
21
29
|
},
|
|
22
30
|
"files": [
|
|
23
31
|
"dist/types/",
|
|
@@ -59,12 +67,13 @@
|
|
|
59
67
|
"prepack": "npm run build:types"
|
|
60
68
|
},
|
|
61
69
|
"dependencies": {
|
|
62
|
-
"@jarenjs/core": "^0.
|
|
63
|
-
"@jarenjs/validate": "^0.
|
|
64
|
-
"@jarenjs/json": "^0.
|
|
65
|
-
"@jarenjs/app": "^0.
|
|
66
|
-
"@jarenjs/flow": "^0.
|
|
67
|
-
"@jarenjs/db": "^0.
|
|
68
|
-
"@jarenjs/contract": "^0.
|
|
70
|
+
"@jarenjs/core": "^0.83.2",
|
|
71
|
+
"@jarenjs/validate": "^0.83.2",
|
|
72
|
+
"@jarenjs/json": "^0.83.2",
|
|
73
|
+
"@jarenjs/app": "^0.83.2",
|
|
74
|
+
"@jarenjs/flow": "^0.83.2",
|
|
75
|
+
"@jarenjs/db": "^0.83.2",
|
|
76
|
+
"@jarenjs/contract": "^0.83.2",
|
|
77
|
+
"@jarenjs/ai": "^0.83.2"
|
|
69
78
|
}
|
|
70
79
|
}
|