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