@arcote.tech/arc-adapter-db-sqlite-wasm 0.5.1 → 0.5.5
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/dist/index.js +188 -63
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1401,6 +1401,9 @@ class AuthAdapter {
|
|
|
1401
1401
|
localStorage.removeItem(TOKEN_PREFIX + scope);
|
|
1402
1402
|
}
|
|
1403
1403
|
}
|
|
1404
|
+
setDecoded(decoded, scope = "default") {
|
|
1405
|
+
this.scopes.set(scope, { raw: "", decoded });
|
|
1406
|
+
}
|
|
1404
1407
|
loadPersisted() {
|
|
1405
1408
|
if (!hasLocalStorage())
|
|
1406
1409
|
return;
|
|
@@ -1598,7 +1601,8 @@ class EventWire {
|
|
|
1598
1601
|
localId: e.localId,
|
|
1599
1602
|
type: e.type,
|
|
1600
1603
|
payload: e.payload,
|
|
1601
|
-
createdAt: e.createdAt
|
|
1604
|
+
createdAt: e.createdAt,
|
|
1605
|
+
authContext: e.authContext
|
|
1602
1606
|
}))
|
|
1603
1607
|
}));
|
|
1604
1608
|
}
|
|
@@ -1755,11 +1759,13 @@ class LocalEventPublisher {
|
|
|
1755
1759
|
}
|
|
1756
1760
|
async publish(event) {
|
|
1757
1761
|
const allChanges = [];
|
|
1762
|
+
const eventAuthContext = event.authContext ?? null;
|
|
1758
1763
|
const storedEvent = {
|
|
1759
1764
|
_id: event.id,
|
|
1760
1765
|
type: event.type,
|
|
1761
1766
|
payload: JSON.stringify(event.payload),
|
|
1762
|
-
createdAt: event.createdAt.toISOString()
|
|
1767
|
+
createdAt: event.createdAt.toISOString(),
|
|
1768
|
+
authContext: eventAuthContext ? JSON.stringify(eventAuthContext) : null
|
|
1763
1769
|
};
|
|
1764
1770
|
allChanges.push({
|
|
1765
1771
|
store: EVENT_TABLES.events,
|
|
@@ -2439,6 +2445,109 @@ class ArcObject extends ArcAbstract {
|
|
|
2439
2445
|
return new ArcObject(partialShape);
|
|
2440
2446
|
}
|
|
2441
2447
|
}
|
|
2448
|
+
class DataStorage {
|
|
2449
|
+
async commitChanges(changes) {
|
|
2450
|
+
await Promise.all(changes.map(({ store, changes: changes2 }) => this.getStore(store).applyChanges(changes2)));
|
|
2451
|
+
}
|
|
2452
|
+
}
|
|
2453
|
+
|
|
2454
|
+
class ScopedStore {
|
|
2455
|
+
#inner;
|
|
2456
|
+
#restrictions;
|
|
2457
|
+
#canWrite;
|
|
2458
|
+
#storeName;
|
|
2459
|
+
constructor(inner, restrictions, canWrite) {
|
|
2460
|
+
this.#inner = inner;
|
|
2461
|
+
this.#restrictions = restrictions;
|
|
2462
|
+
this.#canWrite = canWrite;
|
|
2463
|
+
this.#storeName = inner.storeName;
|
|
2464
|
+
}
|
|
2465
|
+
get storeName() {
|
|
2466
|
+
return this.#storeName;
|
|
2467
|
+
}
|
|
2468
|
+
async find(options, listener) {
|
|
2469
|
+
const restricted = this.#applyReadRestrictions(options);
|
|
2470
|
+
return this.#inner.find(restricted, listener);
|
|
2471
|
+
}
|
|
2472
|
+
async set(item) {
|
|
2473
|
+
this.#assertWriteAccess();
|
|
2474
|
+
this.#validateScopeFields(item);
|
|
2475
|
+
return this.#inner.set(item);
|
|
2476
|
+
}
|
|
2477
|
+
async remove(id) {
|
|
2478
|
+
this.#assertWriteAccess();
|
|
2479
|
+
return this.#inner.remove(id);
|
|
2480
|
+
}
|
|
2481
|
+
async modify(id, data) {
|
|
2482
|
+
this.#assertWriteAccess();
|
|
2483
|
+
this.#validateScopeFields(data);
|
|
2484
|
+
return this.#inner.modify(id, data);
|
|
2485
|
+
}
|
|
2486
|
+
async applyChanges(changes) {
|
|
2487
|
+
this.#assertWriteAccess();
|
|
2488
|
+
for (const change of changes) {
|
|
2489
|
+
if (change.type === "set") {
|
|
2490
|
+
this.#validateScopeFields(change.data);
|
|
2491
|
+
} else if (change.type === "modify") {
|
|
2492
|
+
this.#validateScopeFields(change.data);
|
|
2493
|
+
}
|
|
2494
|
+
}
|
|
2495
|
+
return this.#inner.applyChanges(changes);
|
|
2496
|
+
}
|
|
2497
|
+
unsubscribe(listener) {
|
|
2498
|
+
this.#inner.unsubscribe(listener);
|
|
2499
|
+
}
|
|
2500
|
+
#applyReadRestrictions(options) {
|
|
2501
|
+
if (Object.keys(this.#restrictions).length === 0) {
|
|
2502
|
+
return options ?? {};
|
|
2503
|
+
}
|
|
2504
|
+
return {
|
|
2505
|
+
...options,
|
|
2506
|
+
where: { ...options?.where ?? {}, ...this.#restrictions }
|
|
2507
|
+
};
|
|
2508
|
+
}
|
|
2509
|
+
#assertWriteAccess() {
|
|
2510
|
+
if (!this.#canWrite) {
|
|
2511
|
+
throw new Error(`Scope violation: write access denied to store "${this.#storeName}" (read-only)`);
|
|
2512
|
+
}
|
|
2513
|
+
}
|
|
2514
|
+
#validateScopeFields(data) {
|
|
2515
|
+
for (const [key, value] of Object.entries(this.#restrictions)) {
|
|
2516
|
+
if (key in data && data[key] !== value) {
|
|
2517
|
+
throw new Error(`Scope violation: field "${key}" must be "${value}", got "${data[key]}" in store "${this.#storeName}"`);
|
|
2518
|
+
}
|
|
2519
|
+
}
|
|
2520
|
+
}
|
|
2521
|
+
}
|
|
2522
|
+
|
|
2523
|
+
class ScopedDataStorage extends DataStorage {
|
|
2524
|
+
#inner;
|
|
2525
|
+
#allowedStores;
|
|
2526
|
+
#restrictions;
|
|
2527
|
+
constructor(inner, allowedStores, restrictions) {
|
|
2528
|
+
super();
|
|
2529
|
+
this.#inner = inner;
|
|
2530
|
+
this.#allowedStores = allowedStores;
|
|
2531
|
+
this.#restrictions = restrictions;
|
|
2532
|
+
}
|
|
2533
|
+
getStore(storeName) {
|
|
2534
|
+
const permission = this.#allowedStores.get(storeName);
|
|
2535
|
+
if (!permission) {
|
|
2536
|
+
throw new Error(`Scope violation: access denied to store "${storeName}" (not declared in query/mutate)`);
|
|
2537
|
+
}
|
|
2538
|
+
const inner = this.#inner.getStore(storeName);
|
|
2539
|
+
return new ScopedStore(inner, this.#restrictions, permission === "read-write");
|
|
2540
|
+
}
|
|
2541
|
+
fork() {
|
|
2542
|
+
return this.#inner.fork();
|
|
2543
|
+
}
|
|
2544
|
+
getReadTransaction() {
|
|
2545
|
+
return this.#inner.getReadTransaction();
|
|
2546
|
+
}
|
|
2547
|
+
getReadWriteTransaction() {
|
|
2548
|
+
return this.#inner.getReadWriteTransaction();
|
|
2549
|
+
}
|
|
2550
|
+
}
|
|
2442
2551
|
class ArcPrimitive extends ArcAbstract {
|
|
2443
2552
|
serialize(value) {
|
|
2444
2553
|
return value;
|
|
@@ -2623,6 +2732,54 @@ class ArcContextElement extends ArcFragmentBase {
|
|
|
2623
2732
|
return this._seeds;
|
|
2624
2733
|
}
|
|
2625
2734
|
}
|
|
2735
|
+
function buildElementContext(queryElements, mutationElements, adapters) {
|
|
2736
|
+
const queryMap = new Map;
|
|
2737
|
+
const mutateMap = new Map;
|
|
2738
|
+
const queryProps = {};
|
|
2739
|
+
for (const element of queryElements) {
|
|
2740
|
+
if (element.queryContext) {
|
|
2741
|
+
const ctx = element.queryContext(adapters);
|
|
2742
|
+
queryProps[element.name] = ctx;
|
|
2743
|
+
queryMap.set(element, ctx);
|
|
2744
|
+
}
|
|
2745
|
+
}
|
|
2746
|
+
const mutateProps = {};
|
|
2747
|
+
for (const element of mutationElements) {
|
|
2748
|
+
if (element.mutateContext) {
|
|
2749
|
+
const ctx = element.mutateContext(adapters);
|
|
2750
|
+
mutateProps[element.name] = ctx;
|
|
2751
|
+
mutateMap.set(element, ctx);
|
|
2752
|
+
}
|
|
2753
|
+
}
|
|
2754
|
+
const queryFn = (element) => {
|
|
2755
|
+
const cached = queryMap.get(element);
|
|
2756
|
+
if (cached)
|
|
2757
|
+
return cached;
|
|
2758
|
+
if (element.queryContext) {
|
|
2759
|
+
const ctx = element.queryContext(adapters);
|
|
2760
|
+
queryMap.set(element, ctx);
|
|
2761
|
+
return ctx;
|
|
2762
|
+
}
|
|
2763
|
+
throw new Error(`Element "${element.name}" has no queryContext`);
|
|
2764
|
+
};
|
|
2765
|
+
Object.assign(queryFn, queryProps);
|
|
2766
|
+
const mutateFn = (element) => {
|
|
2767
|
+
const cached = mutateMap.get(element);
|
|
2768
|
+
if (cached)
|
|
2769
|
+
return cached;
|
|
2770
|
+
if (element.mutateContext) {
|
|
2771
|
+
const ctx = element.mutateContext(adapters);
|
|
2772
|
+
mutateMap.set(element, ctx);
|
|
2773
|
+
return ctx;
|
|
2774
|
+
}
|
|
2775
|
+
throw new Error(`Element "${element.name}" has no mutateContext`);
|
|
2776
|
+
};
|
|
2777
|
+
Object.assign(mutateFn, mutateProps);
|
|
2778
|
+
return {
|
|
2779
|
+
query: queryFn,
|
|
2780
|
+
mutate: mutateFn
|
|
2781
|
+
};
|
|
2782
|
+
}
|
|
2626
2783
|
|
|
2627
2784
|
class ArcBoolean extends ArcPrimitive {
|
|
2628
2785
|
hasToBeTrue() {
|
|
@@ -2746,11 +2903,14 @@ class ArcEvent extends ArcContextElement {
|
|
|
2746
2903
|
if (!adapters.eventPublisher) {
|
|
2747
2904
|
throw new Error(`Event "${this.data.name}" cannot be emitted: no eventPublisher adapter available`);
|
|
2748
2905
|
}
|
|
2906
|
+
const decoded = adapters.authAdapter?.getDecoded() ?? null;
|
|
2907
|
+
const authContext = decoded ? { tokenName: decoded.tokenName, params: decoded.params } : null;
|
|
2749
2908
|
const event = {
|
|
2750
2909
|
type: this.data.name,
|
|
2751
2910
|
payload,
|
|
2752
2911
|
id: this.eventId.generate(),
|
|
2753
|
-
createdAt: new Date
|
|
2912
|
+
createdAt: new Date,
|
|
2913
|
+
authContext
|
|
2754
2914
|
};
|
|
2755
2915
|
await adapters.eventPublisher.publish(event);
|
|
2756
2916
|
}
|
|
@@ -2826,55 +2986,6 @@ class ArcEvent extends ArcContextElement {
|
|
|
2826
2986
|
return ArcEvent.sharedDatabaseStoreSchema();
|
|
2827
2987
|
}
|
|
2828
2988
|
}
|
|
2829
|
-
function buildElementContext(queryElements, mutationElements, adapters) {
|
|
2830
|
-
const queryMap = new Map;
|
|
2831
|
-
const mutateMap = new Map;
|
|
2832
|
-
const queryProps = {};
|
|
2833
|
-
for (const element of queryElements) {
|
|
2834
|
-
if (element.queryContext) {
|
|
2835
|
-
const ctx = element.queryContext(adapters);
|
|
2836
|
-
queryProps[element.name] = ctx;
|
|
2837
|
-
queryMap.set(element, ctx);
|
|
2838
|
-
}
|
|
2839
|
-
}
|
|
2840
|
-
const mutateProps = {};
|
|
2841
|
-
for (const element of mutationElements) {
|
|
2842
|
-
if (element.mutateContext) {
|
|
2843
|
-
const ctx = element.mutateContext(adapters);
|
|
2844
|
-
mutateProps[element.name] = ctx;
|
|
2845
|
-
mutateMap.set(element, ctx);
|
|
2846
|
-
}
|
|
2847
|
-
}
|
|
2848
|
-
const queryFn = (element) => {
|
|
2849
|
-
const cached = queryMap.get(element);
|
|
2850
|
-
if (cached)
|
|
2851
|
-
return cached;
|
|
2852
|
-
if (element.queryContext) {
|
|
2853
|
-
const ctx = element.queryContext(adapters);
|
|
2854
|
-
queryMap.set(element, ctx);
|
|
2855
|
-
return ctx;
|
|
2856
|
-
}
|
|
2857
|
-
throw new Error(`Element "${element.name}" has no queryContext`);
|
|
2858
|
-
};
|
|
2859
|
-
Object.assign(queryFn, queryProps);
|
|
2860
|
-
const mutateFn = (element) => {
|
|
2861
|
-
const cached = mutateMap.get(element);
|
|
2862
|
-
if (cached)
|
|
2863
|
-
return cached;
|
|
2864
|
-
if (element.mutateContext) {
|
|
2865
|
-
const ctx = element.mutateContext(adapters);
|
|
2866
|
-
mutateMap.set(element, ctx);
|
|
2867
|
-
return ctx;
|
|
2868
|
-
}
|
|
2869
|
-
throw new Error(`Element "${element.name}" has no mutateContext`);
|
|
2870
|
-
};
|
|
2871
|
-
Object.assign(mutateFn, mutateProps);
|
|
2872
|
-
return {
|
|
2873
|
-
query: queryFn,
|
|
2874
|
-
mutate: mutateFn
|
|
2875
|
-
};
|
|
2876
|
-
}
|
|
2877
|
-
|
|
2878
2989
|
class ArcFunction {
|
|
2879
2990
|
data;
|
|
2880
2991
|
constructor(data) {
|
|
@@ -2991,11 +3102,14 @@ class AggregateBase {
|
|
|
2991
3102
|
if (!adapters.eventPublisher) {
|
|
2992
3103
|
throw new Error(`Cannot emit event "${arcEvent.name}": no eventPublisher adapter available`);
|
|
2993
3104
|
}
|
|
3105
|
+
const decoded = adapters.authAdapter?.getDecoded() ?? null;
|
|
3106
|
+
const authContext = decoded ? { tokenName: decoded.tokenName, params: decoded.params } : null;
|
|
2994
3107
|
const eventInstance = {
|
|
2995
3108
|
type: arcEvent.name,
|
|
2996
3109
|
payload,
|
|
2997
3110
|
id: `${Date.now()}_${Math.random().toString(36).slice(2)}`,
|
|
2998
|
-
createdAt: new Date
|
|
3111
|
+
createdAt: new Date,
|
|
3112
|
+
authContext
|
|
2999
3113
|
};
|
|
3000
3114
|
await adapters.eventPublisher.publish(eventInstance);
|
|
3001
3115
|
}
|
|
@@ -3191,9 +3305,10 @@ class ArcListener extends ArcContextElement {
|
|
|
3191
3305
|
async handleEvent(event2, adapters) {
|
|
3192
3306
|
if (!this.data.handler)
|
|
3193
3307
|
return;
|
|
3194
|
-
const
|
|
3195
|
-
|
|
3196
|
-
|
|
3308
|
+
const scopedAdapters = this.buildScopedAdapters(event2, adapters);
|
|
3309
|
+
const context2 = this.#fn.buildContext(scopedAdapters);
|
|
3310
|
+
if (scopedAdapters.authAdapter) {
|
|
3311
|
+
const decoded = scopedAdapters.authAdapter.getDecoded();
|
|
3197
3312
|
if (decoded) {
|
|
3198
3313
|
context2.$auth = {
|
|
3199
3314
|
params: decoded.params,
|
|
@@ -3209,6 +3324,21 @@ class ArcListener extends ArcContextElement {
|
|
|
3209
3324
|
await this.data.handler(context2, event2);
|
|
3210
3325
|
}
|
|
3211
3326
|
}
|
|
3327
|
+
buildScopedAdapters(event2, adapters) {
|
|
3328
|
+
if (adapters.authAdapter?.isAuthenticated()) {
|
|
3329
|
+
return adapters;
|
|
3330
|
+
}
|
|
3331
|
+
const authContext = event2.authContext;
|
|
3332
|
+
if (!authContext) {
|
|
3333
|
+
return adapters;
|
|
3334
|
+
}
|
|
3335
|
+
const scopedAuth = new AuthAdapter;
|
|
3336
|
+
scopedAuth.setDecoded({
|
|
3337
|
+
tokenName: authContext.tokenName,
|
|
3338
|
+
params: authContext.params
|
|
3339
|
+
});
|
|
3340
|
+
return { ...adapters, authAdapter: scopedAuth };
|
|
3341
|
+
}
|
|
3212
3342
|
destroy() {
|
|
3213
3343
|
for (const unsubscribe of this.unsubscribers) {
|
|
3214
3344
|
unsubscribe();
|
|
@@ -3313,12 +3443,6 @@ class ArcRoute extends ArcContextElement {
|
|
|
3313
3443
|
return context2;
|
|
3314
3444
|
}
|
|
3315
3445
|
}
|
|
3316
|
-
class DataStorage {
|
|
3317
|
-
async commitChanges(changes) {
|
|
3318
|
-
await Promise.all(changes.map(({ store, changes: changes2 }) => this.getStore(store).applyChanges(changes2)));
|
|
3319
|
-
}
|
|
3320
|
-
}
|
|
3321
|
-
|
|
3322
3446
|
class StoreState {
|
|
3323
3447
|
storeName;
|
|
3324
3448
|
dataStorage;
|
|
@@ -4339,7 +4463,8 @@ class StreamingEventPublisher {
|
|
|
4339
4463
|
localId: event3.id,
|
|
4340
4464
|
type: event3.type,
|
|
4341
4465
|
payload: event3.payload,
|
|
4342
|
-
createdAt: event3.createdAt.toISOString()
|
|
4466
|
+
createdAt: event3.createdAt.toISOString(),
|
|
4467
|
+
authContext: event3.authContext ?? null
|
|
4343
4468
|
}
|
|
4344
4469
|
]);
|
|
4345
4470
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@arcote.tech/arc-adapter-db-sqlite-wasm",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.5",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"dev": "bun build ./src/index.ts ./src/worker.ts --outdir ./dist --target browser --format esm --watch"
|
|
24
24
|
},
|
|
25
25
|
"peerDependencies": {
|
|
26
|
-
"@arcote.tech/arc": "^0.5.
|
|
26
|
+
"@arcote.tech/arc": "^0.5.5",
|
|
27
27
|
"@sqlite.org/sqlite-wasm": "^3.46.0-build1"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|