@patterkit/runtime 0.12.1 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +15 -0
- package/dist/index.cjs +18 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +13 -2
- package/dist/index.d.ts +13 -2
- package/dist/index.js +18 -5
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -33,6 +33,21 @@ version number always means the same runtime behaviour. This package is versione
|
|
|
33
33
|
|
|
34
34
|
## [Unreleased]
|
|
35
35
|
|
|
36
|
+
## [0.13.0] - 2026-09-05
|
|
37
|
+
|
|
38
|
+
### Changed
|
|
39
|
+
|
|
40
|
+
- **A `writable: false` host declaration is the STORY's promise, and only the story's: the game
|
|
41
|
+
writes it.** `Engine.setProperty` / `Flow.setProperty` are the game's surfaces, so they now write a
|
|
42
|
+
read-only `@world` property whether it is self-backed or bound to a resolver; an effect that writes
|
|
43
|
+
one is refused exactly as before, with the same sentence. Until now the runtime refused every
|
|
44
|
+
caller alike, so a game could not advance its own clock through the engine and a Patterplay
|
|
45
|
+
coverage driver on such a property killed the run - which is how both this project and the
|
|
46
|
+
Storylet Engine found it, on the same day, in different content
|
|
47
|
+
(from-storylets/host-writes-to-read-only-world). The rule now lives in the shared kernel
|
|
48
|
+
(`@wildwinter/scoperegistry` ^0.6.0, an explicit host authority on `set`), so both products mean
|
|
49
|
+
the same thing by the flag.
|
|
50
|
+
|
|
36
51
|
## [0.12.1] - 2026-09-04
|
|
37
52
|
|
|
38
53
|
### Changed
|
package/dist/index.cjs
CHANGED
|
@@ -536,10 +536,16 @@ var Engine = class _Engine {
|
|
|
536
536
|
const { scope, name } = this.splitShared(ref);
|
|
537
537
|
return this.host.shared.get(scope, name);
|
|
538
538
|
}
|
|
539
|
-
/** Write a shared (`@patter` / foreign) property by ref. `@scene` refs are rejected (flow-level).
|
|
539
|
+
/** Write a shared (`@patter` / foreign) property by ref. `@scene` refs are rejected (flow-level).
|
|
540
|
+
*
|
|
541
|
+
* This is the GAME's surface, so it writes with host authority: a host-scope declaration's
|
|
542
|
+
* `writable: false` is the story's promise not to write the value, never a lock on the game that
|
|
543
|
+
* owns it. The story's own writes come through `Flow.runEffects`, which never claims it. (Ruled
|
|
544
|
+
* across the family 2026-09-05, after a Storylets venue clock and this project's coverage driver
|
|
545
|
+
* were each refused the one property they existed to move.) */
|
|
540
546
|
setProperty(ref, value) {
|
|
541
547
|
const { scope, name } = this.splitShared(ref);
|
|
542
|
-
this.host.shared.set(scope, name, value);
|
|
548
|
+
this.host.shared.set(scope, name, value, { host: true });
|
|
543
549
|
}
|
|
544
550
|
/** The shared `@patter` properties, for a live state inspector: each with its ref, type, current
|
|
545
551
|
* value, declared default (for reset), and enum options. Mirrors the Unity / Godot ports. */
|
|
@@ -1006,8 +1012,15 @@ var Flow = class {
|
|
|
1006
1012
|
if (scope === "scene") return this.sceneResolver.get(name);
|
|
1007
1013
|
return this.host.shared.get(scope, name);
|
|
1008
1014
|
}
|
|
1009
|
-
/** Write a property by ref (routed by scope, then by the property's `shared` flag).
|
|
1015
|
+
/** Write a property by ref (routed by scope, then by the property's `shared` flag). The GAME's
|
|
1016
|
+
* surface: it writes with host authority, so a `writable: false` host declaration does not refuse
|
|
1017
|
+
* it (see `Engine.setProperty`). The story's writes go through `writeProperty` instead. */
|
|
1010
1018
|
setProperty(ref, value) {
|
|
1019
|
+
this.writeProperty(ref, value, true);
|
|
1020
|
+
}
|
|
1021
|
+
/** The write itself. `host` says WHO is writing, which is the only thing `writable: false` cares
|
|
1022
|
+
* about: the story is refused, the game is not. */
|
|
1023
|
+
writeProperty(ref, value, host) {
|
|
1011
1024
|
const { scope, name } = this.splitRef(ref);
|
|
1012
1025
|
if (scope === "patter") {
|
|
1013
1026
|
this.patterResolver.set(name, value);
|
|
@@ -1015,7 +1028,7 @@ var Flow = class {
|
|
|
1015
1028
|
if (this.currentSceneId === null) throw new Error(`'${ref}': the flow has not entered a scene yet`);
|
|
1016
1029
|
this.sceneResolver.set(name, value);
|
|
1017
1030
|
} else {
|
|
1018
|
-
this.host.shared.set(scope, name, value);
|
|
1031
|
+
this.host.shared.set(scope, name, value, host ? { host: true } : void 0);
|
|
1019
1032
|
}
|
|
1020
1033
|
}
|
|
1021
1034
|
// -- Save / restore (engine-driven) --------------------------------------
|
|
@@ -1359,7 +1372,7 @@ var Flow = class {
|
|
|
1359
1372
|
for (const e of effects ?? []) {
|
|
1360
1373
|
const value = this.evalExpr(e.value);
|
|
1361
1374
|
const prev = this.host.logEnabled ? this.getProperty(e.target) : void 0;
|
|
1362
|
-
this.
|
|
1375
|
+
this.writeProperty(e.target, value, false);
|
|
1363
1376
|
this.emit({ type: "write", target: e.target, value, ...prev !== void 0 ? { prev } : {} });
|
|
1364
1377
|
}
|
|
1365
1378
|
}
|