memorio 4.9.35 → 5.1.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/AGENTS.md +3 -3
- package/README.md +95 -516
- package/SECURITY.md +159 -33
- package/SUMMARY.md +59 -45
- package/adr/001-state-proxy-model.md +95 -0
- package/adr/002-observer-semantics.md +179 -0
- package/adr/003-deep-mutation-semantics.md +128 -0
- package/adr/004-array-mutation-semantics.md +127 -0
- package/adr/005-scheduler-contract.md +148 -0
- package/adr/006-context-isolation.md +91 -0
- package/adr/007-mutation-records.md +117 -0
- package/adr/008-transactions.md +105 -0
- package/adr/009-history-model.md +109 -0
- package/adr/README.md +46 -0
- package/adr/template.md +48 -0
- package/bin/cli.js +68 -0
- package/examples/basic.ts +115 -115
- package/examples/browser-vanilla.html +358 -358
- package/examples/cache.ts +72 -72
- package/examples/cross-platform-guards.ts +57 -57
- package/examples/history.ts +104 -0
- package/examples/idb.ts +109 -109
- package/examples/multi-tenant-context.ts +44 -44
- package/examples/node-server.ts +308 -308
- package/examples/observer.ts +60 -60
- package/examples/platform.ts +115 -115
- package/examples/react-app.tsx +362 -362
- package/examples/react-observer.tsx +63 -63
- package/examples/semantic-memory.ts +60 -60
- package/examples/session-advanced.ts +91 -91
- package/examples/sqlite-batched-writes.ts +57 -57
- package/examples/state-advanced.ts +89 -89
- package/examples/store-advanced.ts +117 -117
- package/examples/sync.ts +90 -0
- package/examples/typed-and-schema.ts +102 -100
- package/examples/useObserver.tsx +140 -141
- package/global.cjs +5733 -0
- package/global.d.ts +8 -0
- package/global.js +5667 -0
- package/index.cjs +2202 -1041
- package/index.d.ts +2 -0
- package/index.js +2178 -1040
- package/llms.txt +113 -8
- package/markdown/AUDIT-REPORT.md +134 -0
- package/markdown/CACHE.md +191 -0
- package/markdown/DEVTOOLS.md +128 -0
- package/markdown/DISPATCH.md +176 -0
- package/markdown/HISTORY.md +198 -0
- package/markdown/IDB.md +177 -0
- package/markdown/IMPORT.md +152 -0
- package/markdown/INSPECT.md +122 -0
- package/markdown/LOGGER.md +153 -0
- package/markdown/MEMORY-ATTACHMENT.md +95 -0
- package/markdown/MEMORY.md +161 -0
- package/markdown/OBSERVER.md +208 -0
- package/markdown/PLATFORM.md +277 -0
- package/markdown/REDUX.md +54 -0
- package/markdown/SCHEMA.md +175 -0
- package/markdown/SESSION.md +164 -0
- package/markdown/SQLITE.md +189 -0
- package/markdown/STATE.md +159 -0
- package/markdown/STORE.md +170 -0
- package/markdown/SYNC.md +318 -0
- package/markdown/TYPED.md +164 -0
- package/markdown/USEOBSERVER.md +256 -0
- package/modules/redux.cjs +701 -177
- package/modules/redux.cjs.map +1 -1
- package/modules/redux.js +701 -177
- package/modules/redux.js.map +1 -1
- package/package.json +26 -4
- package/types/broadcast.d.ts +61 -0
- package/types/computed.d.ts +96 -0
- package/types/encryption.d.ts +129 -0
- package/types/env.d.ts +19 -9
- package/types/exports.d.ts +29 -0
- package/types/history.d.ts +13 -1
- package/types/memorio.d.ts +25 -6
- package/types/mutation.d.ts +75 -0
- package/types/security.d.ts +67 -0
- package/types/session.d.ts +23 -5
- package/types/store.d.ts +19 -3
- package/vsix/memorio.vsix +0 -0
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# ADR-008: Transactions
|
|
2
|
+
|
|
3
|
+
> **Status:** Accepted
|
|
4
|
+
> **Date:** 2026-09-12
|
|
5
|
+
|
|
6
|
+
## Context
|
|
7
|
+
|
|
8
|
+
Section 11 of the Memorio 5.x plan requires transactions to group
|
|
9
|
+
multiple mutations into one logical operation. The 5.0 codebase
|
|
10
|
+
implements `beginTransaction`, `commitTransaction`,
|
|
11
|
+
`abortTransaction`, `listTransactions`, `currentTransaction` in
|
|
12
|
+
`core/mutation/transaction.ts`. This ADR formalizes the semantics.
|
|
13
|
+
|
|
14
|
+
## Assumptions
|
|
15
|
+
|
|
16
|
+
- Mutations inside a transaction are tagged with the transaction ID
|
|
17
|
+
via `createMutation()` → `tagForTransaction()`.
|
|
18
|
+
- The transaction registry lives on `globalThis`
|
|
19
|
+
(`__memorio_transaction_registry__`) to survive module duplication.
|
|
20
|
+
- `internal.currentTransactionId` tracks the active transaction.
|
|
21
|
+
- `memorio.transaction(fn, opts)` is a convenience alias for
|
|
22
|
+
`beginTransaction`.
|
|
23
|
+
|
|
24
|
+
## Decision
|
|
25
|
+
|
|
26
|
+
### Transaction lifecycle
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
beginTransaction(source, message, metadata)
|
|
30
|
+
→ creates TransactionContext { id, startedAt, active: true }
|
|
31
|
+
→ sets internal.currentTransactionId = id
|
|
32
|
+
→ mutations tagged with id
|
|
33
|
+
|
|
34
|
+
commitTransaction()
|
|
35
|
+
→ marks context active: false, sets committedAt
|
|
36
|
+
→ clears internal.currentTransactionId
|
|
37
|
+
→ returns { id, mutations[], startedAt, committedAt, source, message, metadata }
|
|
38
|
+
|
|
39
|
+
abortTransaction()
|
|
40
|
+
→ rolls back all tagged mutations (applies inverse)
|
|
41
|
+
→ removes mutation IDs from undoStack (no redo push)
|
|
42
|
+
→ deletes from registry, clears currentTransactionId
|
|
43
|
+
→ returns the Transaction record
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Transaction ID generation
|
|
47
|
+
|
|
48
|
+
- Generated via `generateTransactionId()` → `tx_<encoded-hlc>`.
|
|
49
|
+
- Monotonically ordered within a node via HLC.
|
|
50
|
+
|
|
51
|
+
### Nested transactions
|
|
52
|
+
|
|
53
|
+
`beginTransaction` called while a transaction is already active
|
|
54
|
+
creates a **new** transaction context (with a new ID). The previous
|
|
55
|
+
transaction remains active in the registry - it is **not** suspended
|
|
56
|
+
or paused. `commitTransaction()` only commits the **most recently
|
|
57
|
+
started** active transaction.
|
|
58
|
+
|
|
59
|
+
This is a **flat namespace** model: transactions are independent, not
|
|
60
|
+
hierarchical. A mutation made after the inner `beginTransaction` is
|
|
61
|
+
tagged with the inner transaction's ID, not the outer.
|
|
62
|
+
|
|
63
|
+
> **Future:** A hierarchical model (with parentId) may be introduced.
|
|
64
|
+
> This ADR documents the current flat behavior.
|
|
65
|
+
|
|
66
|
+
### Rollback on abort
|
|
67
|
+
|
|
68
|
+
`abortTransaction` finds each tagged mutation in `undoStack` by its
|
|
69
|
+
record ID, removes it from the stack (without pushing to redo), and
|
|
70
|
+
applies the inverse (`_applyInverse`). The inverse writes go through
|
|
71
|
+
the Proxy with `historyEnabled = false` and `_recording = false`, so
|
|
72
|
+
they are not recorded.
|
|
73
|
+
|
|
74
|
+
### Transaction record immutability
|
|
75
|
+
|
|
76
|
+
Once committed or aborted, a transaction's `mutations` list is frozen
|
|
77
|
+
(immutable). The registry retains the context for
|
|
78
|
+
`listTransactions()` inspection, but `active` is `false`.
|
|
79
|
+
|
|
80
|
+
### Mutate inside a transaction
|
|
81
|
+
|
|
82
|
+
`memorio.mutate(path, value, { source })` inside a transaction:
|
|
83
|
+
1. Calls `createMutation(...)` which auto-tags with the active
|
|
84
|
+
transaction ID via `tagForTransaction()`.
|
|
85
|
+
2. Writes to state with `_recording = false` (no double recording).
|
|
86
|
+
3. Calls `recordMutation(mutation)` - the mutation is recorded in the
|
|
87
|
+
trace log AND tagged in the transaction.
|
|
88
|
+
|
|
89
|
+
## Consequences
|
|
90
|
+
|
|
91
|
+
- **Positive:** Mutations are grouped and attributable to a logical
|
|
92
|
+
operation - essential for explain() and impact() in Phase 4.
|
|
93
|
+
- **Positive:** `abortTransaction` provides atomic rollback - all
|
|
94
|
+
mutations are undone.
|
|
95
|
+
- **Positive:** Registry on `globalThis` survives module duplication.
|
|
96
|
+
- **Negative:** Nested transactions are flat (not hierarchical) -
|
|
97
|
+
the outer transaction is not aborted if the inner is aborted.
|
|
98
|
+
- **Negative:** Rollback via inverse application requires all
|
|
99
|
+
`before` values to be present in the MutationRecord - for
|
|
100
|
+
very large objects this is memory-intensive.
|
|
101
|
+
|
|
102
|
+
## Compliance tests
|
|
103
|
+
|
|
104
|
+
- `tests/vitest/tests/contracts/adr-008-transactions.test.ts`
|
|
105
|
+
- `tests/vitest/tests/mutation-engine.test.ts` (existing, §06-07)
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# ADR-009: History Model (Snapshot / Delta)
|
|
2
|
+
|
|
3
|
+
> **Status:** Proposed
|
|
4
|
+
> **Date:** 2026-09-12
|
|
5
|
+
|
|
6
|
+
## Context
|
|
7
|
+
|
|
8
|
+
Section 12 and Section 13 of the Memorio 5.x plan require an immutable,
|
|
9
|
+
Git-inspired history model with commits, snapshots, deltas, and undo/redo
|
|
10
|
+
as distinct concepts. The 4.7.3 baseline implements undo/redo on a
|
|
11
|
+
linear mutation stack (in `core/internal.ts` and
|
|
12
|
+
`functions/history/index.ts`). This ADR defines the upgrade path to
|
|
13
|
+
the full Commit → Snapshot → Delta model.
|
|
14
|
+
|
|
15
|
+
## Assumptions
|
|
16
|
+
|
|
17
|
+
- The current undo/redo stack stores flat `MutationRecord` entries.
|
|
18
|
+
- `enableHistory(true)` activates recording.
|
|
19
|
+
- `memorio.snapshot()` captures a deep clone of state.
|
|
20
|
+
- `memorio.trace()` returns the flat mutation log.
|
|
21
|
+
|
|
22
|
+
## Decision
|
|
23
|
+
|
|
24
|
+
### Current state (4.7.3 baseline)
|
|
25
|
+
|
|
26
|
+
- Mutations are stored as `MutationRecord[]` in `undoStack` and
|
|
27
|
+
`redoStack` on the singleton `internal` object.
|
|
28
|
+
- `undo()` pops from `undoStack`, pushes to `redoStack`, applies the
|
|
29
|
+
inverse to state.
|
|
30
|
+
- `redo()` pops from `redoStack`, pushes to `undoStack`, re-applies.
|
|
31
|
+
- `trace()` returns the full `mutations` log (trimmed to
|
|
32
|
+
`maxHistory`).
|
|
33
|
+
- No commit concept exists - every mutation is an individual entry.
|
|
34
|
+
|
|
35
|
+
### Target state (Memorio 5.0)
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
Commit (immutable, append-only)
|
|
39
|
+
├── parent: CommitId | null
|
|
40
|
+
├── patches: Patch[] (RFC 6902: add | remove | replace)
|
|
41
|
+
├── metadata: { source?, message?, actor?, timestamp, hlc }
|
|
42
|
+
└── snapshot?: SnapshotRef (materialized every N commits)
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
- **Commits** are the unit of history. `memorio.commit(message, fn)`
|
|
46
|
+
groups all mutations in `fn` into one commit.
|
|
47
|
+
- **Snapshots** are deep clones of state, materialized every
|
|
48
|
+
`snapshotInterval` commits (default: 100) to bound replay cost.
|
|
49
|
+
- **Deltas** are the `Patch[]` that transform a snapshot to the next
|
|
50
|
+
state. Only patches are stored between snapshots - never full
|
|
51
|
+
state copies.
|
|
52
|
+
- **Undo/Redo** operate at the commit level, not the individual
|
|
53
|
+
mutation level. Undoing a commit applies the inverse of every patch
|
|
54
|
+
in the commit.
|
|
55
|
+
|
|
56
|
+
### Migration path
|
|
57
|
+
|
|
58
|
+
1. **Phase 1 (this sprint):** Keep the existing flat mutation stack.
|
|
59
|
+
Document that `undo()`/`redo()` operate per-mutation, not per-commit.
|
|
60
|
+
Add `memorio.commit()` as a grouping mechanism without changing the
|
|
61
|
+
underlying stack.
|
|
62
|
+
2. **Phase 3:** Replace the flat stack with the Commit → Snapshot →
|
|
63
|
+
Delta model. `undo()`/`redo()` will operate per-commit.
|
|
64
|
+
|
|
65
|
+
### Undo vs. Revert (explicit distinction)
|
|
66
|
+
|
|
67
|
+
- **Undo** (`memorio.undo()`): Moves the current position backward in
|
|
68
|
+
the undo stack. The mutation is preserved on the redo stack.
|
|
69
|
+
- **Revert** (`memorio.history.revert(commitId)`): Creates a **new**
|
|
70
|
+
mutation that reverses a historical commit. The original commit
|
|
71
|
+
remains in history (immutable). This is a future Phase 3 feature.
|
|
72
|
+
|
|
73
|
+
### maxCommits and maxHistory
|
|
74
|
+
|
|
75
|
+
- `maxCommits` (default: 10,000): Maximum number of commit entries
|
|
76
|
+
retained. Older commits are trimmed (FIFO).
|
|
77
|
+
- `maxHistory` (default: 100): Maximum mutations per undo/redo stack
|
|
78
|
+
(legacy, applies to the current flat model).
|
|
79
|
+
|
|
80
|
+
### Replay safety
|
|
81
|
+
|
|
82
|
+
- Replay must be deterministic. Patches are pure (no closures, no
|
|
83
|
+
functions). `state.path = value` is the inverse of `delete
|
|
84
|
+
state.path` in a patch-based replay.
|
|
85
|
+
- External dependencies (Date.now, Math.random, crypto) must be
|
|
86
|
+
injected via a replay context to maintain determinism.
|
|
87
|
+
|
|
88
|
+
## Consequences
|
|
89
|
+
|
|
90
|
+
- **Positive:** Commits group mutations logically - essential for
|
|
91
|
+
explain(), business history, and audit trails.
|
|
92
|
+
- **Positive:** Snapshot/delta model bounds memory and replay cost.
|
|
93
|
+
- **Positive:** Undo and Revert are distinct operations - no
|
|
94
|
+
conflation.
|
|
95
|
+
- **Negative:** The current flat stack must be replaced in Phase 3,
|
|
96
|
+
which is a breaking change to `undo()`/`redo()` semantics
|
|
97
|
+
(per-mutation → per-commit).
|
|
98
|
+
- **Negative:** Snapshot materialization at intervals is a trade-off
|
|
99
|
+
between memory and CPU - defaults must be benchmark-driven.
|
|
100
|
+
|
|
101
|
+
## Compliance tests
|
|
102
|
+
|
|
103
|
+
- `tests/vitest/tests/contracts/adr-009-history.test.ts`
|
|
104
|
+
- `tests/vitest/tests/mutation-engine.test.ts` (existing, §04-07)
|
|
105
|
+
|
|
106
|
+
## Benchmarks
|
|
107
|
+
|
|
108
|
+
- `experimental/benchmarks/replay.bench.ts` - measures replay cost
|
|
109
|
+
with and without interval snapshots.
|
package/adr/README.md
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Architecture Decision Records (ADRs)
|
|
2
|
+
|
|
3
|
+
This directory contains Architecture Decision Records (ADRs) for the
|
|
4
|
+
**Memorio 5.x** "Application State Intelligence Runtime" initiative.
|
|
5
|
+
|
|
6
|
+
## Format
|
|
7
|
+
|
|
8
|
+
ADRs follow the [MADR](https://adr.github.io/) (Markdown Architectural
|
|
9
|
+
Decision Records) format. Each decision record answers four questions:
|
|
10
|
+
|
|
11
|
+
1. **Context** - What is the issue that we were dealing with when we
|
|
12
|
+
started thinking about it?
|
|
13
|
+
2. **Decision** - What is the change that we will make (that resolves
|
|
14
|
+
the issue)?
|
|
15
|
+
3. **Consequences** - What becomes easier or more difficult to do
|
|
16
|
+
because of this change?
|
|
17
|
+
|
|
18
|
+
## Numbering
|
|
19
|
+
|
|
20
|
+
| ADR | Title | Status |
|
|
21
|
+
|-----|-------|--------|
|
|
22
|
+
| [001](001-state-proxy-model.md) | State Proxy Model | Accepted |
|
|
23
|
+
| [002](002-observer-semantics.md) | Observer Semantics | Proposed |
|
|
24
|
+
| [003](003-deep-mutation-semantics.md) | Deep Mutation Semantics | Proposed |
|
|
25
|
+
| [004](004-array-mutation-semantics.md) | Array Mutation Semantics | Proposed |
|
|
26
|
+
| [005](005-scheduler-contract.md) | Scheduler Contract | Proposed |
|
|
27
|
+
| [006](006-context-isolation.md) | Context Isolation Model | Accepted |
|
|
28
|
+
| [007](007-mutation-records.md) | Mutation Records | Accepted |
|
|
29
|
+
| [008](008-transactions.md) | Transactions | Accepted |
|
|
30
|
+
| [009](009-history-model.md) | History Model (Snapshot/Delta) | Proposed |
|
|
31
|
+
|
|
32
|
+
## Lifecycle
|
|
33
|
+
|
|
34
|
+
New ADRs start as **Proposed**, move to **Accepted** when the decision
|
|
35
|
+
is implemented and tests pass, and become **Superseded** when a later
|
|
36
|
+
ADR supersedes them. A **Deprecated** status marks decisions that are no
|
|
37
|
+
longer relevant but kept for historical context.
|
|
38
|
+
|
|
39
|
+
## Compliance
|
|
40
|
+
|
|
41
|
+
Every ADR that defines a behavioral contract must have a corresponding
|
|
42
|
+
compliance test suite under `tests/vitest/tests/contracts/`. The test
|
|
43
|
+
file name mirrors the ADR number (e.g. `adr-004-arrays.test.ts`).
|
|
44
|
+
|
|
45
|
+
A release must not be published if any **Accepted** ADR has failing
|
|
46
|
+
compliance tests.
|
package/adr/template.md
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# ADR Template - MADR format
|
|
2
|
+
|
|
3
|
+
> **Status:** `{Proposed | Accepted | Superseded by [ADR-XXX](adr-XXX.md) | Deprecated}`
|
|
4
|
+
> **Date:** YYYY-MM-DD
|
|
5
|
+
|
|
6
|
+
## Context
|
|
7
|
+
|
|
8
|
+
> What is the issue that we were dealing with when we started thinking
|
|
9
|
+
> about it? What are the forces at play? Consider the unique constraints
|
|
10
|
+
> of this project - the need for deterministic, explainable state that
|
|
11
|
+
> remembers, understands, replays, and simulates application state.
|
|
12
|
+
|
|
13
|
+
## Assumptions
|
|
14
|
+
|
|
15
|
+
> List any assumptions the decision relies on (e.g. "state mutations are
|
|
16
|
+
> synchronous," "the Proxy target is always a plain object or array").
|
|
17
|
+
|
|
18
|
+
## Decision
|
|
19
|
+
|
|
20
|
+
> What is the change that we will make? Describe the chosen approach in
|
|
21
|
+
> detail. This section must be precise enough to serve as an implementation
|
|
22
|
+
> contract. Include:
|
|
23
|
+
>
|
|
24
|
+
> - The precise semantics (what happens, what does not happen)
|
|
25
|
+
> - Edge cases and error behavior
|
|
26
|
+
> - Performance characteristics
|
|
27
|
+
> - Backward-compatibility implications
|
|
28
|
+
|
|
29
|
+
## Consequences
|
|
30
|
+
|
|
31
|
+
> What becomes easier or more difficult to do because of this change?
|
|
32
|
+
> Consider:
|
|
33
|
+
>
|
|
34
|
+
> - **Positive** - benefits gained (e.g. improved developer experience,
|
|
35
|
+
> better performance, deterministic behavior)
|
|
36
|
+
> - **Negative** - trade-offs and drawbacks (e.g. loss of flexibility,
|
|
37
|
+
> migration complexity, runtime overhead)
|
|
38
|
+
> - **Testability** - how this decision is covered by compliance tests
|
|
39
|
+
|
|
40
|
+
## Compliance tests
|
|
41
|
+
|
|
42
|
+
> Reference the test file(s) that verify this contract. Every Accepted
|
|
43
|
+
> ADR must list at least one compliance test file path relative to the
|
|
44
|
+
> repository root.
|
|
45
|
+
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
File: _ADR_TITLE_PLACEHOLDER.md
|
package/bin/cli.js
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { spawnSync } from 'node:child_process';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import fs from 'node:fs';
|
|
5
|
+
import os from 'node:os';
|
|
6
|
+
import { fileURLToPath } from 'node:url';
|
|
7
|
+
|
|
8
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
9
|
+
|
|
10
|
+
const args = process.argv.slice(2);
|
|
11
|
+
const command = args[0];
|
|
12
|
+
|
|
13
|
+
if (command === 'install-extension') {
|
|
14
|
+
installExtension();
|
|
15
|
+
} else {
|
|
16
|
+
console.log('Usage: npx memorio install-extension');
|
|
17
|
+
process.exit(command ? 1 : 0);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function installExtension() {
|
|
21
|
+
const vsixPath = path.join(__dirname, '..', 'vsix', 'memorio.vsix');
|
|
22
|
+
|
|
23
|
+
if (!fs.existsSync(vsixPath)) {
|
|
24
|
+
console.error(`VSIX file not found at ${vsixPath}.`);
|
|
25
|
+
console.error('The npm package may be corrupted, or the build did not copy the .vsix into vsix/.');
|
|
26
|
+
process.exit(1);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const candidates = candidateBinaries();
|
|
30
|
+
const found = candidates.find((bin) => isAvailable(bin));
|
|
31
|
+
|
|
32
|
+
if (!found) {
|
|
33
|
+
console.error('No compatible editor found in PATH (tried: ' + candidates.join(', ') + ').');
|
|
34
|
+
console.error('Manual installation:');
|
|
35
|
+
console.error(' 1. Open your editor (VSCodium/VSCode)');
|
|
36
|
+
console.error(' 2. Command Palette -> "Extensions: Install from VSIX..."');
|
|
37
|
+
console.error(` 3. Select: ${vsixPath}`);
|
|
38
|
+
process.exit(1);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
console.log(`Editor detected: ${found}. Installing memorio extension...`);
|
|
42
|
+
const result = spawnSync(found, ['--install-extension', vsixPath], {
|
|
43
|
+
stdio: 'inherit',
|
|
44
|
+
shell: os.platform() === 'win32',
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
if (result.status !== 0) {
|
|
48
|
+
console.error('Installation failed. Try manually:');
|
|
49
|
+
console.error(` ${found} --install-extension "${vsixPath}"`);
|
|
50
|
+
process.exit(result.status || 1);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
console.log('Memorio extension installed successfully.');
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function candidateBinaries() {
|
|
57
|
+
const names = ['codium', 'vscodium', 'code', 'code-insiders'];
|
|
58
|
+
if (os.platform() === 'win32') {
|
|
59
|
+
return names.map((n) => `${n}.cmd`);
|
|
60
|
+
}
|
|
61
|
+
return names;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function isAvailable(bin) {
|
|
65
|
+
const checkCmd = os.platform() === 'win32' ? 'where' : 'which';
|
|
66
|
+
const result = spawnSync(checkCmd, [bin], { stdio: 'ignore', shell: true });
|
|
67
|
+
return result.status === 0;
|
|
68
|
+
}
|
package/examples/basic.ts
CHANGED
|
@@ -1,115 +1,115 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Memorio Basic Example
|
|
3
|
-
*
|
|
4
|
-
* This example shows the fundamental features of Memorio:
|
|
5
|
-
* - State management
|
|
6
|
-
* - Store (localStorage)
|
|
7
|
-
* - Session storage
|
|
8
|
-
* - Platform detection
|
|
9
|
-
*
|
|
10
|
-
* Run: npx ts-node examples/basic.ts
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
import 'memorio'
|
|
14
|
-
|
|
15
|
-
// ============================================
|
|
16
|
-
// PLATFORM DETECTION
|
|
17
|
-
// ============================================
|
|
18
|
-
|
|
19
|
-
console.debug('=== Platform Detection ===')
|
|
20
|
-
console.debug('Memorio version:', memorio.version)
|
|
21
|
-
|
|
22
|
-
// Check platform
|
|
23
|
-
if (memorio.isBrowser()) {
|
|
24
|
-
console.debug('Platform: Browser')
|
|
25
|
-
} else if (memorio.isNode()) {
|
|
26
|
-
console.debug('Platform: Node.js')
|
|
27
|
-
} else if (memorio.isDeno()) {
|
|
28
|
-
console.debug('Platform: Deno')
|
|
29
|
-
} else if (memorio.isEdge()) {
|
|
30
|
-
console.debug('Platform: Edge Worker')
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
// Get capabilities
|
|
34
|
-
const caps = memorio.getCapabilities()
|
|
35
|
-
console.debug('Capabilities:', {
|
|
36
|
-
platform: caps.platform,
|
|
37
|
-
hasLocalStorage: caps.hasLocalStorage,
|
|
38
|
-
hasSessionStorage: caps.hasSessionStorage,
|
|
39
|
-
hasIndexedDB: caps.hasIndexedDB
|
|
40
|
-
})
|
|
41
|
-
|
|
42
|
-
// ============================================
|
|
43
|
-
// STATE - In-memory reactive state
|
|
44
|
-
// ============================================
|
|
45
|
-
|
|
46
|
-
console.debug('\n=== State Management ===')
|
|
47
|
-
|
|
48
|
-
// Set some state values
|
|
49
|
-
state.name = 'Mario'
|
|
50
|
-
state.age = 30
|
|
51
|
-
state.isActive = true
|
|
52
|
-
state.profile = {
|
|
53
|
-
email: 'mario@example.com',
|
|
54
|
-
avatar: 'https://example.com/mario.png'
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// Get state values
|
|
58
|
-
console.debug('Name:', state.name)
|
|
59
|
-
console.debug('Age:', state.age)
|
|
60
|
-
console.debug('Profile:', state.profile)
|
|
61
|
-
|
|
62
|
-
// List all states
|
|
63
|
-
console.debug('All states:', state.list)
|
|
64
|
-
|
|
65
|
-
// ============================================
|
|
66
|
-
// STORE - Persistent localStorage
|
|
67
|
-
// ============================================
|
|
68
|
-
|
|
69
|
-
console.debug('\n=== Store (Persistent Storage) ===')
|
|
70
|
-
|
|
71
|
-
// Check persistence
|
|
72
|
-
console.debug('Is persistent:', store.isPersistent) // true in browser, false in Node.js/Deno
|
|
73
|
-
|
|
74
|
-
// Save to localStorage
|
|
75
|
-
store.set('username', 'mario')
|
|
76
|
-
store.set('preferences', { theme: 'dark', language: 'en' })
|
|
77
|
-
store.set('lastLogin', Date.now())
|
|
78
|
-
|
|
79
|
-
// Read from localStorage
|
|
80
|
-
console.debug('Username:', store.get('username'))
|
|
81
|
-
console.debug('Preferences:', store.get('preferences'))
|
|
82
|
-
|
|
83
|
-
// Get storage size
|
|
84
|
-
console.debug('Storage size:', store.size(), 'kilobytes')
|
|
85
|
-
|
|
86
|
-
// ============================================
|
|
87
|
-
// SESSION - Temporary session storage
|
|
88
|
-
// ============================================
|
|
89
|
-
|
|
90
|
-
console.debug('\n=== Session (Temporary Storage) ===')
|
|
91
|
-
|
|
92
|
-
// Check persistence
|
|
93
|
-
console.debug('Is persistent:', session.isPersistent) // true in browser, false in Node.js/Deno
|
|
94
|
-
|
|
95
|
-
// Save session data (cleared when tab closes)
|
|
96
|
-
session.set('token', 'abc123xyz')
|
|
97
|
-
session.set('userId', 42)
|
|
98
|
-
|
|
99
|
-
// Read session data
|
|
100
|
-
console.debug('Token:', session.get('token'))
|
|
101
|
-
console.debug('User ID:', session.get('userId'))
|
|
102
|
-
|
|
103
|
-
// ============================================
|
|
104
|
-
// CLEANUP
|
|
105
|
-
// ============================================
|
|
106
|
-
|
|
107
|
-
// Clear specific items
|
|
108
|
-
store.remove('username')
|
|
109
|
-
session.remove('token')
|
|
110
|
-
|
|
111
|
-
// Clear all
|
|
112
|
-
store.removeAll()
|
|
113
|
-
session.removeAll()
|
|
114
|
-
|
|
115
|
-
console.debug('\nExample complete!')
|
|
1
|
+
/**
|
|
2
|
+
* Memorio Basic Example
|
|
3
|
+
*
|
|
4
|
+
* This example shows the fundamental features of Memorio:
|
|
5
|
+
* - State management
|
|
6
|
+
* - Store (localStorage)
|
|
7
|
+
* - Session storage
|
|
8
|
+
* - Platform detection
|
|
9
|
+
*
|
|
10
|
+
* Run: npx ts-node examples/basic.ts
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { memorio, state, store, session } from 'memorio'
|
|
14
|
+
|
|
15
|
+
// ============================================
|
|
16
|
+
// PLATFORM DETECTION
|
|
17
|
+
// ============================================
|
|
18
|
+
|
|
19
|
+
console.debug('=== Platform Detection ===')
|
|
20
|
+
console.debug('Memorio version:', memorio.version)
|
|
21
|
+
|
|
22
|
+
// Check platform
|
|
23
|
+
if (memorio.isBrowser()) {
|
|
24
|
+
console.debug('Platform: Browser')
|
|
25
|
+
} else if (memorio.isNode()) {
|
|
26
|
+
console.debug('Platform: Node.js')
|
|
27
|
+
} else if (memorio.isDeno()) {
|
|
28
|
+
console.debug('Platform: Deno')
|
|
29
|
+
} else if (memorio.isEdge()) {
|
|
30
|
+
console.debug('Platform: Edge Worker')
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Get capabilities
|
|
34
|
+
const caps = memorio.getCapabilities()
|
|
35
|
+
console.debug('Capabilities:', {
|
|
36
|
+
platform: caps.platform,
|
|
37
|
+
hasLocalStorage: caps.hasLocalStorage,
|
|
38
|
+
hasSessionStorage: caps.hasSessionStorage,
|
|
39
|
+
hasIndexedDB: caps.hasIndexedDB
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
// ============================================
|
|
43
|
+
// STATE - In-memory reactive state
|
|
44
|
+
// ============================================
|
|
45
|
+
|
|
46
|
+
console.debug('\n=== State Management ===')
|
|
47
|
+
|
|
48
|
+
// Set some state values
|
|
49
|
+
state.name = 'Mario'
|
|
50
|
+
state.age = 30
|
|
51
|
+
state.isActive = true
|
|
52
|
+
state.profile = {
|
|
53
|
+
email: 'mario@example.com',
|
|
54
|
+
avatar: 'https://example.com/mario.png'
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Get state values
|
|
58
|
+
console.debug('Name:', state.name)
|
|
59
|
+
console.debug('Age:', state.age)
|
|
60
|
+
console.debug('Profile:', state.profile)
|
|
61
|
+
|
|
62
|
+
// List all states
|
|
63
|
+
console.debug('All states:', state.list)
|
|
64
|
+
|
|
65
|
+
// ============================================
|
|
66
|
+
// STORE - Persistent localStorage
|
|
67
|
+
// ============================================
|
|
68
|
+
|
|
69
|
+
console.debug('\n=== Store (Persistent Storage) ===')
|
|
70
|
+
|
|
71
|
+
// Check persistence
|
|
72
|
+
console.debug('Is persistent:', store.isPersistent) // true in browser, false in Node.js/Deno
|
|
73
|
+
|
|
74
|
+
// Save to localStorage
|
|
75
|
+
store.set('username', 'mario')
|
|
76
|
+
store.set('preferences', { theme: 'dark', language: 'en' })
|
|
77
|
+
store.set('lastLogin', Date.now())
|
|
78
|
+
|
|
79
|
+
// Read from localStorage
|
|
80
|
+
console.debug('Username:', store.get('username'))
|
|
81
|
+
console.debug('Preferences:', store.get('preferences'))
|
|
82
|
+
|
|
83
|
+
// Get storage size
|
|
84
|
+
console.debug('Storage size:', store.size(), 'kilobytes')
|
|
85
|
+
|
|
86
|
+
// ============================================
|
|
87
|
+
// SESSION - Temporary session storage
|
|
88
|
+
// ============================================
|
|
89
|
+
|
|
90
|
+
console.debug('\n=== Session (Temporary Storage) ===')
|
|
91
|
+
|
|
92
|
+
// Check persistence
|
|
93
|
+
console.debug('Is persistent:', session.isPersistent) // true in browser, false in Node.js/Deno
|
|
94
|
+
|
|
95
|
+
// Save session data (cleared when tab closes)
|
|
96
|
+
session.set('token', 'abc123xyz')
|
|
97
|
+
session.set('userId', 42)
|
|
98
|
+
|
|
99
|
+
// Read session data
|
|
100
|
+
console.debug('Token:', session.get('token'))
|
|
101
|
+
console.debug('User ID:', session.get('userId'))
|
|
102
|
+
|
|
103
|
+
// ============================================
|
|
104
|
+
// CLEANUP
|
|
105
|
+
// ============================================
|
|
106
|
+
|
|
107
|
+
// Clear specific items
|
|
108
|
+
store.remove('username')
|
|
109
|
+
session.remove('token')
|
|
110
|
+
|
|
111
|
+
// Clear all
|
|
112
|
+
store.removeAll()
|
|
113
|
+
session.removeAll()
|
|
114
|
+
|
|
115
|
+
console.debug('\nExample complete!')
|