aktion-runtime 0.5.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.
Files changed (76) hide show
  1. package/README.md +1246 -0
  2. package/dist/aktion.iife.js +8431 -0
  3. package/dist/aktion.iife.js.map +1 -0
  4. package/dist/aktion.js +22594 -0
  5. package/dist/aktion.js.map +1 -0
  6. package/dist/aktion.umd.cjs +8431 -0
  7. package/dist/aktion.umd.cjs.map +1 -0
  8. package/dist/index.cjs +3 -0
  9. package/dist/index.d.ts +2 -0
  10. package/dist/index.js +5 -0
  11. package/dist/system_prompt.txt +1095 -0
  12. package/dist/system_prompt_chat.txt +404 -0
  13. package/dist/types/element.d.ts +175 -0
  14. package/dist/types/icons/index.d.ts +45 -0
  15. package/dist/types/index.d.ts +15 -0
  16. package/dist/types/language/builtins.d.ts +33 -0
  17. package/dist/types/language/components.d.ts +28 -0
  18. package/dist/types/language/grammar.d.ts +121 -0
  19. package/dist/types/language/index.d.ts +41 -0
  20. package/dist/types/language/snippets.d.ts +17 -0
  21. package/dist/types/library/components/_internal.d.ts +56 -0
  22. package/dist/types/library/components/advanced-charts.d.ts +6 -0
  23. package/dist/types/library/components/advanced-data.d.ts +6 -0
  24. package/dist/types/library/components/advanced-forms.d.ts +12 -0
  25. package/dist/types/library/components/advanced-patterns.d.ts +13 -0
  26. package/dist/types/library/components/charts.d.ts +5 -0
  27. package/dist/types/library/components/chat.d.ts +6 -0
  28. package/dist/types/library/components/content.d.ts +33 -0
  29. package/dist/types/library/components/data.d.ts +9 -0
  30. package/dist/types/library/components/editors.d.ts +5 -0
  31. package/dist/types/library/components/feedback.d.ts +14 -0
  32. package/dist/types/library/components/forms-shared.d.ts +7 -0
  33. package/dist/types/library/components/forms.d.ts +21 -0
  34. package/dist/types/library/components/helpers.d.ts +33 -0
  35. package/dist/types/library/components/layout.d.ts +20 -0
  36. package/dist/types/library/components/media.d.ts +7 -0
  37. package/dist/types/library/components/menu.d.ts +5 -0
  38. package/dist/types/library/components/navigation.d.ts +6 -0
  39. package/dist/types/library/components/new-components.d.ts +13 -0
  40. package/dist/types/library/components/patterns.d.ts +39 -0
  41. package/dist/types/library/components/router.d.ts +2 -0
  42. package/dist/types/library/components/theme.d.ts +2 -0
  43. package/dist/types/library/index.d.ts +5 -0
  44. package/dist/types/library/registry.d.ts +15 -0
  45. package/dist/types/library/types.d.ts +140 -0
  46. package/dist/types/library/utils.d.ts +73 -0
  47. package/dist/types/library/validate.d.ts +27 -0
  48. package/dist/types/parser/frontier.d.ts +65 -0
  49. package/dist/types/parser/index.d.ts +4 -0
  50. package/dist/types/parser/lexer.d.ts +46 -0
  51. package/dist/types/parser/parser.d.ts +2 -0
  52. package/dist/types/parser/types.d.ts +349 -0
  53. package/dist/types/prompt/generator.d.ts +33 -0
  54. package/dist/types/prompt/index.d.ts +1 -0
  55. package/dist/types/renderer/index.d.ts +1 -0
  56. package/dist/types/renderer/morph.d.ts +42 -0
  57. package/dist/types/renderer/renderer.d.ts +73 -0
  58. package/dist/types/runtime/builtins.d.ts +27 -0
  59. package/dist/types/runtime/console.d.ts +21 -0
  60. package/dist/types/runtime/effects.d.ts +69 -0
  61. package/dist/types/runtime/evaluator.d.ts +151 -0
  62. package/dist/types/runtime/http.d.ts +85 -0
  63. package/dist/types/runtime/i18n.d.ts +40 -0
  64. package/dist/types/runtime/index.d.ts +9 -0
  65. package/dist/types/runtime/router.d.ts +105 -0
  66. package/dist/types/runtime/state.d.ts +84 -0
  67. package/dist/types/runtime/storage.d.ts +50 -0
  68. package/dist/types/theme/index.d.ts +175 -0
  69. package/dist/types/theme/styles.d.ts +9 -0
  70. package/dist/types/tooling/codemod.d.ts +36 -0
  71. package/dist/types/tooling/delta.d.ts +74 -0
  72. package/dist/types/tooling/formatter.d.ts +8 -0
  73. package/dist/types/tooling/index.d.ts +29 -0
  74. package/dist/types/tooling/inspector.d.ts +49 -0
  75. package/dist/types/tooling/language-service.d.ts +57 -0
  76. package/package.json +63 -0
@@ -0,0 +1,151 @@
1
+ import { Expression, Program, ComponentDeclaration, EffectDeclaration, ActionDeclaration } from '../parser/types.js';
2
+ import { StateStore } from './state.js';
3
+ import { HttpRuntime } from './http.js';
4
+ import { I18nRuntime } from './i18n.js';
5
+ import { ActionDeclRunner } from './effects.js';
6
+ import { Router } from './router.js';
7
+ import { ComponentLibrary } from '../library/types.js';
8
+ export interface ArgMeta {
9
+ /** Name of the `$variable` if this argument is a direct state reference. */
10
+ stateRef?: string;
11
+ }
12
+ export interface ComponentNode {
13
+ __kind: "Component";
14
+ /** Component name as written in Aktion. */
15
+ name: string;
16
+ /** Positional arguments after evaluation. */
17
+ args: unknown[];
18
+ /** Per-position metadata (state ref binding, etc.). */
19
+ argMeta: ArgMeta[];
20
+ /**
21
+ * Explicit `key:` override for content-addressed identity (§13). When
22
+ * present, the renderer uses this value as the suffix of the instance
23
+ * path instead of the source location — so reordering siblings keeps
24
+ * per-instance state attached to the right node.
25
+ */
26
+ explicitKey?: unknown;
27
+ /** Original AST for debugging/introspection. */
28
+ source?: {
29
+ line: number;
30
+ column: number;
31
+ };
32
+ }
33
+ export declare const isComponentNode: (value: unknown) => value is ComponentNode;
34
+ /**
35
+ * Lazy node produced when a user-declared `component Foo(p) { ... }` is
36
+ * called. The renderer expands these per-instance: each instance gets its
37
+ * own state-alias scope so two `Counter()` calls hold independent `$state`
38
+ * atoms (§7 — per-instance reactivity).
39
+ *
40
+ * The evaluator captures the call arguments + named slots eagerly; the
41
+ * body itself is evaluated at render-time once the instance key is known.
42
+ */
43
+ export interface UserComponentNode {
44
+ __kind: "UserComponent";
45
+ decl: ComponentDeclaration;
46
+ /** Positional argument values (already evaluated). */
47
+ positional: unknown[];
48
+ /** Named argument values (already evaluated), keyed by param/slot name. */
49
+ named: Record<string, unknown>;
50
+ /** Optional `key:` override the caller passed for stable instance identity. */
51
+ explicitKey?: unknown;
52
+ source?: {
53
+ line: number;
54
+ column: number;
55
+ };
56
+ }
57
+ export declare const isUserComponentNode: (value: unknown) => value is UserComponentNode;
58
+ export interface EvaluationContext {
59
+ state: StateStore;
60
+ /** Per-program scope for non-state assignments (refs to other lines). */
61
+ bindings: Map<string, () => unknown>;
62
+ /** Raw AST expressions for each top-level identifier. */
63
+ expressions: Map<string, Expression>;
64
+ /** Set of $variable names accessed during the current evaluation. */
65
+ trackedState: Set<string>;
66
+ /**
67
+ * Inline loop variables for expression `for` / `match`, router param
68
+ * bindings, lambda parameters, and component declaration parameters.
69
+ */
70
+ loopVars: Map<string, unknown>;
71
+ /**
72
+ * Per-instance state alias scope (§7). When a user-declared component
73
+ * body declares `$state n = 0`, the renderer pushes an alias frame so
74
+ * that the StateRef `n` reads/writes the per-instance key (e.g.
75
+ * `Counter@1:5#0:n`) rather than a shared global atom. The lookup walks
76
+ * from the top of the stack down — outer frames are still visible when
77
+ * not overridden.
78
+ */
79
+ stateAliases: Array<Map<string, string>>;
80
+ /** Optional router — exposed to the runtime for `_route_.path` / `params`. */
81
+ router?: Router;
82
+ /** Component library used to resolve trailing named-arg object literals. */
83
+ library?: ComponentLibrary;
84
+ /** Component declarations from the program (`component Foo() { ... }`). */
85
+ componentDecls: Map<string, ComponentDeclaration>;
86
+ /** Effect declarations (`effect [ ...deps ] { ... }`), keyed by auto-generated name. */
87
+ effectDecls: Map<string, EffectDeclaration>;
88
+ /** Action declarations (`action Foo() { ... }`). */
89
+ actionDecls: Map<string, ActionDeclaration>;
90
+ /** HTTP runtime (`http({...})` calls + interceptor configuration). */
91
+ http?: HttpRuntime;
92
+ /** Aktion 0.5 i18n runtime (`$i18n = i18n({...})` declaration + `t()` builtin). */
93
+ i18n?: I18nRuntime;
94
+ /** Aktion 0.5 action runner (`action Foo() optimistic { … }` invocations). */
95
+ actionRunner?: ActionDeclRunner;
96
+ /** Notify the host that something changed and a re-render is needed. */
97
+ notify?: () => void;
98
+ /**
99
+ * Optional executor for raw `js{ … }` blocks encountered inside an
100
+ * inline lambda. When set, evaluating a lambda whose body resolves to
101
+ * a `JsBlock` payload will invoke this with the captured body so
102
+ * `Button("Hi", action: () => { js{ alert("Hi") } })` actually runs
103
+ * the script instead of returning the deferred payload.
104
+ */
105
+ jsBlockExecutor?: (body: string, args?: Record<string, unknown>) => unknown;
106
+ }
107
+ /**
108
+ * Optional injectables for `createContext` — the host element passes its
109
+ * runtime singletons (HTTP, i18n, action runner) so endpoint use sites and
110
+ * action calls can resolve against them.
111
+ */
112
+ export interface CreateContextOptions {
113
+ router?: Router;
114
+ library?: ComponentLibrary;
115
+ http?: HttpRuntime;
116
+ i18n?: I18nRuntime;
117
+ actionRunner?: ActionDeclRunner;
118
+ notify?: () => void;
119
+ jsBlockExecutor?: (body: string, args?: Record<string, unknown>) => unknown;
120
+ }
121
+ /**
122
+ * Build a top-level evaluation context for a freshly parsed program.
123
+ */
124
+ export declare function createContext(state: StateStore, options?: CreateContextOptions): EvaluationContext;
125
+ /**
126
+ * Resolve a `$name` reference through the active per-instance alias
127
+ * stack. Returns the topmost binding or `name` itself when no alias is
128
+ * present. Exported so the action / effect runners can resolve writes
129
+ * the same way the evaluator resolves reads.
130
+ */
131
+ export declare function resolveStateAlias(ctx: EvaluationContext, name: string): string;
132
+ /**
133
+ * Plan a program: declare state variables, register HTTP endpoints, and
134
+ * build lazy bindings for every assignment so forward references resolve.
135
+ */
136
+ export declare function planProgram(program: Program, ctx: EvaluationContext): void;
137
+ export declare function evaluate(expr: Expression, ctx: EvaluationContext): unknown;
138
+ /**
139
+ * Evaluate a user-declared component body in a fresh per-instance scope.
140
+ * Called by the renderer once the stable instance key is known so
141
+ * `$state` declarations inside the body land in instance-private slots.
142
+ *
143
+ * `instanceKey` should be a deterministic string derived from the
144
+ * render-tree path (and/or the `key:` override) — it becomes the prefix
145
+ * for every per-instance state atom and effect / action declaration.
146
+ *
147
+ * Returns the body's last-expression value (typically a `ComponentNode`
148
+ * the renderer can hand to the library, or another `UserComponentNode`
149
+ * to expand recursively).
150
+ */
151
+ export declare function evaluateUserComponent(node: UserComponentNode, ctx: EvaluationContext, instanceKey: string): unknown;
@@ -0,0 +1,85 @@
1
+ import { EvaluationContext } from './evaluator.js';
2
+ export type HttpMethod = "GET" | "HEAD" | "OPTIONS" | "POST" | "PUT" | "PATCH" | "DELETE";
3
+ export interface HttpRequest {
4
+ url: string;
5
+ method: HttpMethod;
6
+ headers: Record<string, string>;
7
+ body?: unknown;
8
+ signal?: AbortSignal;
9
+ }
10
+ export interface HttpResponse {
11
+ status: number;
12
+ headers: Record<string, string>;
13
+ body: unknown;
14
+ }
15
+ export interface HttpInterceptors {
16
+ onRequest?: (request: HttpRequest) => HttpRequest | Promise<HttpRequest>;
17
+ onResponse?: (response: HttpResponse, retry: () => Promise<HttpResponse>) => HttpResponse | Promise<HttpResponse>;
18
+ onError?: (error: unknown, request: HttpRequest) => void;
19
+ }
20
+ export interface HttpDefaults {
21
+ baseUrl?: string;
22
+ headers?: Record<string, string>;
23
+ timeoutMs?: number;
24
+ retry?: {
25
+ count: number;
26
+ backoff?: "linear" | "exponential";
27
+ };
28
+ credentials?: RequestCredentials;
29
+ }
30
+ /** Reactive lifecycle of an `http({...})` resource. */
31
+ export type ResourceState = "idle" | "loading" | "data" | "error" | "stale";
32
+ /**
33
+ * Reactive bag returned by `http({...})`. Fields update in place as
34
+ * the request progresses; the runtime calls `notify()` so the next
35
+ * render observes the new values.
36
+ */
37
+ export interface EndpointResource {
38
+ state: ResourceState;
39
+ data: unknown;
40
+ error: unknown;
41
+ loading: boolean;
42
+ status?: number;
43
+ headers?: Record<string, string>;
44
+ lastUpdated?: number;
45
+ refetch: () => Promise<void>;
46
+ cancel: () => void;
47
+ }
48
+ /** Compatibility shim — subscription transports were removed in this version. */
49
+ export interface SubscriptionTransport {
50
+ open(url: string, opts: {
51
+ protocol?: string;
52
+ headers?: Record<string, string>;
53
+ }): {
54
+ onMessage(cb: (raw: unknown) => void): void;
55
+ onError(cb: (err: unknown) => void): void;
56
+ onClose(cb: () => void): void;
57
+ onOpen(cb: () => void): void;
58
+ send(payload: unknown): void;
59
+ close(): void;
60
+ };
61
+ }
62
+ export declare class HttpRuntime {
63
+ private interceptors;
64
+ private defaults;
65
+ setDefaults(defaults: HttpDefaults): void;
66
+ /** Merge new interceptors on top of any previously-registered ones. */
67
+ registerInterceptors(interceptors: HttpInterceptors): void;
68
+ /** Resolve a relative URL against the configured `baseUrl`. */
69
+ resolveUrl(url: string): string;
70
+ /**
71
+ * Issue a single HTTP request. Runs through `onRequest`/`onResponse`
72
+ * interceptors and surfaces a `retry()` one-shot inside `onResponse`.
73
+ * Honours `defaults.timeoutMs` via `AbortController`.
74
+ */
75
+ request(input: HttpRequest): Promise<HttpResponse>;
76
+ }
77
+ /**
78
+ * Run a single `http({...})` call and return the reactive resource bag.
79
+ *
80
+ * The bag mutates in place: `data`, `error`, `status`, `loading`,
81
+ * `headers`, `lastUpdated` update during the request lifecycle. The
82
+ * `refetch()` callback re-issues the original request; `cancel()`
83
+ * aborts the in-flight request (no-op when idle).
84
+ */
85
+ export declare function createHttpResource(config: unknown, ctx: EvaluationContext): EndpointResource;
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Aktion 0.5 i18n runtime — `$i18n` declaration + `t()` global builtin (§23).
3
+ *
4
+ * The runtime is intentionally tiny:
5
+ * - Holds the active locale, fallback locale, and message map.
6
+ * - `t(key, vars?)` looks up `key` (dot-paths supported, e.g. `"orders.title"`),
7
+ * falls back to the fallback locale's bundle, then to the bare key.
8
+ * - `vars?` are interpolated using `${name}` placeholders.
9
+ *
10
+ * Locale-aware formatting (`Money`, `Date`, `Number`, `Percent`,
11
+ * `RelativeTime`) is wired through `getLocale()` so library components
12
+ * can read the live value without each declaring it as a prop.
13
+ */
14
+ export interface I18nConfig {
15
+ locale: string;
16
+ messages: Record<string, unknown>;
17
+ fallback?: string;
18
+ /** Optional secondary message map for the fallback locale. */
19
+ fallbackMessages?: Record<string, unknown>;
20
+ }
21
+ export declare class I18nRuntime {
22
+ private locale;
23
+ private fallback;
24
+ private messages;
25
+ private fallbackMessages;
26
+ configure(config: I18nConfig): void;
27
+ /** Current active locale tag (e.g. `"en-US"`, `"de"`). */
28
+ getLocale(): string;
29
+ /** Snapshot of the configured fallback locale. */
30
+ getFallback(): string;
31
+ /**
32
+ * Translate a dot-pathed key, optionally interpolating `${name}` vars.
33
+ *
34
+ * Resolution order:
35
+ * 1. The active locale's message map.
36
+ * 2. The fallback locale's message map (if provided separately).
37
+ * 3. The bare key as a literal string.
38
+ */
39
+ t(key: string, vars?: Record<string, unknown>): string;
40
+ }
@@ -0,0 +1,9 @@
1
+ export * from './builtins.js';
2
+ export * from './state.js';
3
+ export * from './evaluator.js';
4
+ export * from './router.js';
5
+ export * from './http.js';
6
+ export * from './i18n.js';
7
+ export { storage, type CookieOptions, type StorageNamespace, type StorageRoot } from './storage.js';
8
+ export { consoleNs, type ConsoleNamespace } from './console.js';
9
+ export { EffectRunner, ActionDeclRunner, type EffectRunnerOptions, type ActionRunnerOptions, } from './effects.js';
@@ -0,0 +1,105 @@
1
+ /**
2
+ * Hash-based router for `<aktion-app>`.
3
+ *
4
+ * The router is owned by the host element and exposed to:
5
+ * - The evaluator (which special-cases `Routes(...)` to pick the matching
6
+ * `Route(path, content)` and inject path params as the loop variable
7
+ * `params`).
8
+ * - The renderer's helpers (so `NavLink(...)` can wire click handlers).
9
+ * - The action runner (`@Navigate("/path")` step).
10
+ *
11
+ * The wire format is hash-based — `#/page-name`. The router strips the leading
12
+ * `#` and any trailing `?…` query string before exposing the path. Navigating
13
+ * inside the component updates `window.location.hash`, and external hash
14
+ * changes (browser back/forward, direct URL edits) are picked up by the
15
+ * `hashchange` listener.
16
+ *
17
+ * The router is always started by the host element when it connects so that
18
+ * navigation works out of the box. In environments without a `window`
19
+ * (server-side rendering, tests) the router stays in "memory" mode:
20
+ * `navigate(...)` records the new path internally without touching the URL.
21
+ */
22
+ export type RouteParams = Record<string, string>;
23
+ export interface RouteMatch {
24
+ matched: boolean;
25
+ params: RouteParams;
26
+ /** True when the matched route is a wildcard (`*`) catch-all. */
27
+ wildcard?: boolean;
28
+ }
29
+ export interface RouteChangeDetail {
30
+ path: string;
31
+ previousPath: string | null;
32
+ source: "init" | "hashchange" | "navigate" | "external";
33
+ }
34
+ export type RouteListener = (detail: RouteChangeDetail) => void;
35
+ export interface RouterOptions {
36
+ /** Initial path when no hash is set. Defaults to `/`. */
37
+ defaultPath?: string;
38
+ }
39
+ /**
40
+ * Normalise an arbitrary string into a clean route path.
41
+ *
42
+ * readHashPath("") → "/"
43
+ * readHashPath("#") → "/"
44
+ * readHashPath("#/") → "/"
45
+ * readHashPath("#/about") → "/about"
46
+ * readHashPath("#about") → "/about"
47
+ * readHashPath("/foo/bar?x=1") → "/foo/bar"
48
+ * readHashPath("//foo///bar//") → "/foo/bar"
49
+ */
50
+ export declare function normalisePath(raw: string | null | undefined): string;
51
+ /**
52
+ * Match a route pattern against a concrete path. Patterns support:
53
+ * - literal segments: `/about`
54
+ * - parameter segments: `/users/:id`
55
+ * - wildcard catch-all: `*` (matches any path, params empty unless mixed)
56
+ * - mixed wildcard: `/docs/*` (matches everything under `/docs/`)
57
+ */
58
+ export declare function matchRoute(pattern: string, path: string): RouteMatch;
59
+ /**
60
+ * Singleton-per-element router. Owns the current path, listens for
61
+ * `hashchange` events when enabled, and notifies subscribers when the path
62
+ * changes for any reason.
63
+ */
64
+ export declare class Router {
65
+ private currentPath;
66
+ private currentParams;
67
+ private currentPattern;
68
+ private enabled;
69
+ private hashListener;
70
+ private listeners;
71
+ private readonly defaultPath;
72
+ /** True while we're updating `window.location.hash` ourselves — used to
73
+ * filter out the resulting `hashchange` echo. */
74
+ private settingHash;
75
+ constructor(options?: RouterOptions);
76
+ /**
77
+ * Attach the `hashchange` listener and synchronise from the current URL.
78
+ * Safe to call multiple times — it's idempotent.
79
+ */
80
+ start(): void;
81
+ /**
82
+ * Detach the `hashchange` listener. The current path stays as the last
83
+ * observed value so a follow-up `start()` resumes cleanly.
84
+ */
85
+ stop(): void;
86
+ getPath(): string;
87
+ getParams(): RouteParams;
88
+ /** Path pattern of the most recently matched `Route` (or null). */
89
+ getActivePattern(): string | null;
90
+ /**
91
+ * Called by `Routes(...)` after each render so we have the canonical
92
+ * pattern + params for the active page (used by `NavLink` to highlight the
93
+ * active link). The state store is NOT touched here.
94
+ */
95
+ setActiveMatch(pattern: string | null, params: RouteParams): void;
96
+ /**
97
+ * Navigate to the given path. When enabled, this updates the URL hash and
98
+ * relies on `hashchange` to notify listeners (so browser history works).
99
+ * When disabled, the navigation stays in-memory.
100
+ */
101
+ navigate(path: string): void;
102
+ subscribe(listener: RouteListener): () => void;
103
+ /** Replace the current path without going through `window.location`. */
104
+ private setPath;
105
+ }
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Lightweight reactive state container.
3
+ *
4
+ * Each `$variable` is tracked here. Components and queries subscribe to a
5
+ * specific set of state names; when any of them changes, their `notify`
6
+ * callback fires. There are no proxies or Symbols on the user-facing API,
7
+ * which keeps the surface small and predictable.
8
+ */
9
+ export type StateValue = unknown;
10
+ export type Subscriber = (changedNames: ReadonlySet<string>) => void;
11
+ /**
12
+ * Pluggable persistent storage adapter for `$$variable` declarations.
13
+ *
14
+ * The default implementation reads/writes JSON-encoded values to the host
15
+ * page's `localStorage`. Hosts (or tests) can swap it out via
16
+ * `StateStore.setPersistenceAdapter(...)` — useful for SSR shims or to
17
+ * scope storage per-element via a custom key prefix.
18
+ */
19
+ export interface PersistenceAdapter {
20
+ load(name: string): StateValue | undefined;
21
+ save(name: string, value: StateValue): void;
22
+ remove(name: string): void;
23
+ }
24
+ export declare class StateStore {
25
+ private values;
26
+ private defaults;
27
+ /** Persistent variable names — written to the adapter on every change. */
28
+ private persistent;
29
+ private persistenceAdapter;
30
+ private subscribers;
31
+ private pendingChanges;
32
+ private flushScheduled;
33
+ setPersistenceAdapter(adapter: PersistenceAdapter | null): void;
34
+ declare(name: string, defaultValue: StateValue): void;
35
+ /**
36
+ * Declare a persistent `$$variable`. The adapter is queried for an
37
+ * existing value; if one is found, it replaces the default. Otherwise
38
+ * the default is written back so the next mount reads the seeded value.
39
+ */
40
+ declarePersistent(name: string, defaultValue: StateValue): void;
41
+ isPersistent(name: string): boolean;
42
+ has(name: string): boolean;
43
+ get(name: string): StateValue;
44
+ set(name: string, value: StateValue): void;
45
+ /** Iterate over every (name, value) pair. Order is insertion order. */
46
+ entries(): IterableIterator<[string, StateValue]>;
47
+ /** Snapshot every (name, value) pair into a plain object. */
48
+ snapshot(): Record<string, StateValue>;
49
+ /**
50
+ * Aktion 0.5 §26 — resumability primitive. Restores
51
+ * every atom in `snapshot` *without* notifying subscribers, so the
52
+ * host can seed values before the runtime mounts (SSR hydration,
53
+ * URL-backed deep links, conversational continuity). Atoms that have
54
+ * not yet been `declare`d are still written so they show up the
55
+ * moment the program declares them.
56
+ *
57
+ * The persistence adapter is *not* consulted — hydration is
58
+ * authoritative. If the caller wants persisted reads to win, they
59
+ * should call `hydrate(snapshot)` before `declare(name, …)`.
60
+ */
61
+ hydrate(snapshot: Readonly<Record<string, StateValue>>): void;
62
+ reset(...names: string[]): void;
63
+ resetAll(): void;
64
+ /**
65
+ * Replace all state entries. Called when a fresh program is loaded.
66
+ *
67
+ * Also drops any pending change notifications: their names refer to the
68
+ * previous program's bindings, which no longer exist, and forwarding them
69
+ * to subscribers can fire queries / scripts that race against the new
70
+ * program's planning step.
71
+ */
72
+ rebind(declarations: Iterable<[string, StateValue]>): void;
73
+ subscribe(subscriber: Subscriber): () => void;
74
+ private scheduleFlush;
75
+ private flush;
76
+ }
77
+ /**
78
+ * Build a `PersistenceAdapter` backed by `window.localStorage` (or
79
+ * `sessionStorage`). The returned adapter namespaces each key by
80
+ * `keyPrefix` so two elements on the same page don't clobber one
81
+ * another's `$$variable` values. Returns `null` when no storage is
82
+ * available (SSR, sandboxed iframes, private mode in some browsers).
83
+ */
84
+ export declare function createLocalStorageAdapter(keyPrefix: string, storage: Storage | null): PersistenceAdapter | null;
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Browser storage namespace for Aktion.
3
+ *
4
+ * Exposes a single `storage` global that wraps three browser storage
5
+ * mechanisms — `localStorage`, `sessionStorage`, and document cookies —
6
+ * behind a uniform `set` / `get` / `remove` / `clear` API. Authors can
7
+ * reach for the default `localStorage` directly (`storage.set("k", "v")`)
8
+ * or namespace through `storage.local`, `storage.session`, or
9
+ * `storage.cookies`.
10
+ *
11
+ * Values that aren't strings round-trip through `JSON.stringify` /
12
+ * `JSON.parse`, so authors can persist arrays and objects without manual
13
+ * serialisation. Failures (quota exceeded, disabled storage, malformed
14
+ * JSON) are swallowed and reported via the return values rather than
15
+ * thrown — keeps streaming scripts robust in privacy / SSR contexts
16
+ * where the underlying APIs may be missing.
17
+ */
18
+ /** Options accepted by `storage.cookies.set` (mirrors the standard cookie attributes). */
19
+ export interface CookieOptions {
20
+ /** Days until expiry, or a Date instance for an absolute expiry. */
21
+ expires?: number | Date | string;
22
+ /** `Max-Age` in seconds — overrides `expires` when both are set. */
23
+ maxAge?: number;
24
+ /** Restrict cookie to the given path (defaults to `/`). */
25
+ path?: string;
26
+ /** Restrict cookie to the given domain. */
27
+ domain?: string;
28
+ /** Only send over HTTPS. */
29
+ secure?: boolean;
30
+ /** `SameSite` policy — `"Strict"`, `"Lax"`, or `"None"`. */
31
+ sameSite?: "Strict" | "Lax" | "None" | "strict" | "lax" | "none";
32
+ }
33
+ export interface StorageNamespace {
34
+ set: (key: string, value: unknown, options?: CookieOptions) => boolean;
35
+ get: (key: string) => unknown;
36
+ remove: (key: string, options?: CookieOptions) => boolean;
37
+ clear: () => boolean;
38
+ }
39
+ export interface StorageRoot extends StorageNamespace {
40
+ local: StorageNamespace;
41
+ session: StorageNamespace;
42
+ cookies: StorageNamespace;
43
+ }
44
+ /**
45
+ * The `storage` global exposed to Aktion programs. Default
46
+ * methods (`storage.set` / `storage.get` / `storage.remove` /
47
+ * `storage.clear`) delegate to `localStorage`; nested namespaces select
48
+ * a specific backend.
49
+ */
50
+ export declare const storage: StorageRoot;