@markless/core 0.1.0 → 0.2.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.
@@ -0,0 +1,38 @@
1
+ # Markless agent playbook
2
+
3
+ Use this file as the guidance for the installed `@markless/core` version in the current project. Markless compiles `.tsrx` authoring into fine-grained DOM work; it does not use a virtual DOM or hydrate by rerunning component bodies in the browser.
4
+
5
+ ## Authoring
6
+
7
+ - Import the public authoring APIs (`state`, `computed`, `element`, `shared`, and `storage`) from `@markless/core`. Keep reactive component authoring in `.tsrx` files.
8
+ - Declare mutable state with `state(...)`, derived values with `computed(...)`, and update state with ordinary assignment. Do not introduce hooks, an effects system, or a client component rerender path.
9
+ - Persist reactive state with `storage(fallback)`. It reads and writes like ordinary state — reading the binding returns the value; assigning to it persists to `localStorage` (v1: strings only) and sets a `data-<key>` attribute on `<html>` for no-flash CSS. The compiler seeds the value before the framework wakes, so first paint is correct with no double read. By default the persistence key is **derived from the binding identifier**, namespaced: `let theme = storage('light')` persists under `markless:theme` (attr `data-markless-theme`). The derived key is a stable compile-time literal, so minification never changes it — but **renaming the binding changes the key and orphans existing users' saved data**. For anything you ship to real users, **pin an explicit key**, which is used verbatim and is rename-proof: `let theme = storage('theme', 'light')` persists under `theme`. Use derived keys for local/prototype state; pin explicit keys for durable user data. (A build-time rename-drift guard that warns when a derived key disappears is a planned fast-follow — see the framework's storage-ergonomics notes.)
10
+ - Use `element()` handles and `attach` behaviors for element lifetime work. Return cleanup from an attachment when it owns resources.
11
+ - Treat event arguments as native events. Inspect `event.target`; a deferred handler must not depend on `event.currentTarget` remaining populated.
12
+ - Prefer build diagnostics over guesses. If the compiler rejects an authored shape, change that shape instead of suppressing the gate.
13
+ - In tests, wait for an observable DOM result. A graph flush is not necessarily a DOM commit barrier.
14
+
15
+ ## Run the project doctor
16
+
17
+ Run the app's `doctor` package script first for environment, dependency, and production-build failures. Follow the concrete failing check, then run the consuming application's own checks; framework package tests alone do not prove that an application still works.
18
+
19
+ ## Analyzer and Witness evidence
20
+
21
+ Use the public exports from `@markless/analyzer` and, for browser collection, `@markless/analyzer/playwright`. Let the application own its route/action policy, budgets, and persisted receipts. Import validators, invariant identifiers, debug-channel sentinels, schemas, and report helpers from the analyzer package rather than copying their values.
22
+
23
+ Use analyzer results beside existing application assertions until they prove equivalent coverage. Convert Witness outcomes with `createWitnessVerdict`, then combine them through the analyzer's public verdict-report helpers. A missing or incompatible evidence source is a collection failure, not a passing result.
24
+
25
+ ## Inspect the live debug channel
26
+
27
+ Use a debug-enabled development build and inspect `window.__MARKLESS_DEBUG__` in the running page. For a failed interaction, call its public `explainInteraction(element, eventType)` method on the actual DOM element before inferring a cause from source. Inspect the channel's public container and lifecycle data when the explanation points to ownership or disposal.
28
+
29
+ Do not copy channel protocol strings or configuration constants into application tooling. Import analyzer-owned facts from `@markless/analyzer`, and use the public debug surface exposed by the installed runtime.
30
+
31
+ ## Diagnose resume failures
32
+
33
+ 1. Reproduce against a production build as well as development.
34
+ 2. Run the doctor and fix version skew or build failures first.
35
+ 3. Use the analyzer's public payload-wiring and locator-resolution collectors to compare served payload claims, runtime registrations, and resolved DOM targets.
36
+ 4. Use the preload-integrity and request-window helpers for code that arrives too late, and the debug-strip evaluator to distinguish debug-enabled evidence from an unflagged production artifact.
37
+ 5. When testing explicit resume entry points, import the public resume helpers from `@markless/core` or its documented runtime entry points. Do not invent hydration or rerender as a recovery path.
38
+ 6. Preserve the smallest failing application case and its receipts, then run that application's checks after the fix.
package/dist/index.d.ts CHANGED
@@ -9,7 +9,7 @@ type SharedScope = 'request' | 'container' | 'page';
9
9
  type SharedOptions = {
10
10
  readonly scope: SharedScope;
11
11
  };
12
- type FrameworkApiName = 'state' | 'computed' | 'element' | 'shared';
12
+ type FrameworkApiName = 'state' | 'computed' | 'element' | 'shared' | 'storage';
13
13
  type FrameworkApiRuntimeDiagnostic = {
14
14
  readonly code: 'MARKLESS_FRAMEWORK_API_RUNTIME_CALL';
15
15
  readonly severity: 'error';
@@ -41,5 +41,6 @@ declare function computed<T>(derive: () => T): AsyncComputedValue<T>;
41
41
  declare function element<T extends Element = Element>(): ElementHandle<T>;
42
42
  type SharedDefinition<T> = () => T;
43
43
  declare function shared<T>(create: () => T, options?: SharedOptions): SharedDefinition<T>;
44
+ declare function storage(key: string, fallback: string): string;
44
45
  //#endregion
45
- export { type AsyncComputedValue, type CsrRenderArtifact, type CsrRenderContainer, type CsrRenderOptions, type CsrRenderOutput, type CsrRenderable, type ElementHandle, type FrameworkApiName, type FrameworkApiRuntimeDiagnostic, FrameworkApiRuntimeError, type RenderTarget, type RenderToStringOptions, type ResumePayloadDocumentInput, type ResumePayloadScriptsInput, type ResumePayloadScriptsResult, type SharedDefinition, type SharedOptions, type SharedScope, type SsrRenderArtifact, type SsrRenderOutput, type SsrRenderable, computed, element, render, renderToString, resumeFromPayloadDocument, resumeFromPayloadScripts, shared, state };
46
+ export { type AsyncComputedValue, type CsrRenderArtifact, type CsrRenderContainer, type CsrRenderOptions, type CsrRenderOutput, type CsrRenderable, type ElementHandle, type FrameworkApiName, type FrameworkApiRuntimeDiagnostic, FrameworkApiRuntimeError, type RenderTarget, type RenderToStringOptions, type ResumePayloadDocumentInput, type ResumePayloadScriptsInput, type ResumePayloadScriptsResult, type SharedDefinition, type SharedOptions, type SharedScope, type SsrRenderArtifact, type SsrRenderOutput, type SsrRenderable, computed, element, render, renderToString, resumeFromPayloadDocument, resumeFromPayloadScripts, shared, state, storage };
package/dist/index.js CHANGED
@@ -31,6 +31,9 @@ function element() {
31
31
  function shared(create, options) {
32
32
  return frameworkApi("shared", create, options);
33
33
  }
34
+ function storage(key, fallback) {
35
+ return frameworkApi("storage", key, fallback);
36
+ }
34
37
  function frameworkApi(name, ..._args) {
35
38
  throw new FrameworkApiRuntimeError(name);
36
39
  }
@@ -38,4 +41,4 @@ function frameworkApiRuntimeMessage(name) {
38
41
  return `markless ${name}() must be compiled from a .tsrx file before it can run.`;
39
42
  }
40
43
  //#endregion
41
- export { FrameworkApiRuntimeError, computed, element, render, renderToString, resumeFromPayloadDocument, resumeFromPayloadScripts, shared, state };
44
+ export { FrameworkApiRuntimeError, computed, element, render, renderToString, resumeFromPayloadDocument, resumeFromPayloadScripts, shared, state, storage };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@markless/core",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Markless core authoring APIs: resumable TSRX apps with no hydration and no VDOM.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -8,9 +8,10 @@
8
8
  "url": "git+https://github.com/markless-dev/markless.git",
9
9
  "directory": "packages/core"
10
10
  },
11
- "publishConfig": {
12
- "access": "public"
13
- },
11
+ "files": [
12
+ "agent",
13
+ "dist"
14
+ ],
14
15
  "type": "module",
15
16
  "sideEffects": false,
16
17
  "exports": {
@@ -103,13 +104,14 @@
103
104
  "default": "./dist/vite.js"
104
105
  }
105
106
  },
107
+ "publishConfig": {
108
+ "access": "public",
109
+ "provenance": true
110
+ },
106
111
  "dependencies": {
107
- "@markless/bundler": "0.1.0",
108
- "@markless/router": "0.1.0",
109
- "@markless/web": "0.1.0"
112
+ "@markless/router": "0.2.0",
113
+ "@markless/bundler": "0.2.0",
114
+ "@markless/web": "0.2.0"
110
115
  },
111
- "files": [
112
- "dist"
113
- ],
114
116
  "scripts": {}
115
117
  }