@arcote.tech/arc-adapter-db-sqlite 0.4.7 → 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 (2) hide show
  1. package/dist/index.js +464 -3
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  // src/bun-sqlite.ts
2
2
  import { Database } from "bun:sqlite";
3
3
 
4
- // ../../../../node_modules/mutative/dist/mutative.esm.mjs
4
+ // ../../../../node_modules/.bun/mutative@1.3.0/node_modules/mutative/dist/mutative.esm.mjs
5
5
  var Operation = {
6
6
  Remove: "remove",
7
7
  Replace: "replace",
@@ -1357,14 +1357,23 @@ var TOKEN_PREFIX = "arc:token:";
1357
1357
  function hasLocalStorage() {
1358
1358
  return typeof localStorage !== "undefined";
1359
1359
  }
1360
+ function notifyTokenChange(scope) {
1361
+ if (typeof window !== "undefined") {
1362
+ queueMicrotask(() => {
1363
+ window.dispatchEvent(new CustomEvent("arc:token-change", { detail: { scope } }));
1364
+ });
1365
+ }
1366
+ }
1360
1367
 
1361
1368
  class AuthAdapter {
1362
1369
  scopes = new Map;
1363
1370
  setToken(token, scope = "default") {
1364
1371
  if (!token) {
1365
1372
  this.scopes.delete(scope);
1366
- if (hasLocalStorage())
1373
+ if (hasLocalStorage()) {
1367
1374
  localStorage.removeItem(TOKEN_PREFIX + scope);
1375
+ notifyTokenChange(scope);
1376
+ }
1368
1377
  return;
1369
1378
  }
1370
1379
  try {
@@ -1385,8 +1394,10 @@ class AuthAdapter {
1385
1394
  exp: payload.exp
1386
1395
  }
1387
1396
  });
1388
- if (hasLocalStorage())
1397
+ if (hasLocalStorage()) {
1389
1398
  localStorage.setItem(TOKEN_PREFIX + scope, token);
1399
+ notifyTokenChange(scope);
1400
+ }
1390
1401
  } catch {
1391
1402
  this.scopes.delete(scope);
1392
1403
  if (hasLocalStorage())
@@ -2818,6 +2829,147 @@ class ArcEvent extends ArcContextElement {
2818
2829
  return ArcEvent.sharedDatabaseStoreSchema();
2819
2830
  }
2820
2831
  }
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
+ class ArcFunction {
2882
+ data;
2883
+ constructor(data) {
2884
+ this.data = data;
2885
+ }
2886
+ withParams(schema) {
2887
+ return new ArcFunction({
2888
+ ...this.data,
2889
+ params: schema instanceof ArcObject ? schema : new ArcObject(schema)
2890
+ });
2891
+ }
2892
+ withResult(schema) {
2893
+ return new ArcFunction({
2894
+ ...this.data,
2895
+ result: schema instanceof ArcObject ? schema : new ArcObject(schema)
2896
+ });
2897
+ }
2898
+ query(elements) {
2899
+ return new ArcFunction({
2900
+ ...this.data,
2901
+ queryElements: elements
2902
+ });
2903
+ }
2904
+ mutate(elements) {
2905
+ return new ArcFunction({
2906
+ ...this.data,
2907
+ mutationElements: elements
2908
+ });
2909
+ }
2910
+ protectedBy(token, check) {
2911
+ const existingProtections = this.data.protections || [];
2912
+ return new ArcFunction({
2913
+ ...this.data,
2914
+ protections: [...existingProtections, { token, check }]
2915
+ });
2916
+ }
2917
+ description(desc) {
2918
+ return new ArcFunction({
2919
+ ...this.data,
2920
+ description: desc
2921
+ });
2922
+ }
2923
+ handle(handler) {
2924
+ return new ArcFunction({
2925
+ ...this.data,
2926
+ handler
2927
+ });
2928
+ }
2929
+ get isPublic() {
2930
+ return !this.hasProtections;
2931
+ }
2932
+ get hasProtections() {
2933
+ return (this.data.protections?.length ?? 0) > 0;
2934
+ }
2935
+ get protections() {
2936
+ return this.data.protections || [];
2937
+ }
2938
+ get handler() {
2939
+ return this.data.handler;
2940
+ }
2941
+ get params() {
2942
+ return this.data.params;
2943
+ }
2944
+ get result() {
2945
+ return this.data.result;
2946
+ }
2947
+ async verifyProtections(tokens) {
2948
+ if (!this.data.protections || this.data.protections.length === 0) {
2949
+ return true;
2950
+ }
2951
+ for (const protection of this.data.protections) {
2952
+ const tokenInstance = tokens.find((t) => t.getTokenDefinition() === protection.token);
2953
+ if (!tokenInstance) {
2954
+ return false;
2955
+ }
2956
+ const result = await protection.check(tokenInstance);
2957
+ if (result === false) {
2958
+ return false;
2959
+ }
2960
+ }
2961
+ return true;
2962
+ }
2963
+ buildContext(adapters) {
2964
+ return buildElementContext(this.data.queryElements || [], this.data.mutationElements || [], adapters);
2965
+ }
2966
+ toJsonSchema() {
2967
+ return {
2968
+ params: this.data.params?.toJsonSchema?.() ?? null,
2969
+ result: this.data.result?.toJsonSchema?.() ?? null
2970
+ };
2971
+ }
2972
+ }
2821
2973
  class AggregateBase {
2822
2974
  value;
2823
2975
  _id;
@@ -2855,6 +3007,315 @@ class AggregateBase {
2855
3007
  return result;
2856
3008
  }
2857
3009
  }
3010
+ class ArcCommand extends ArcContextElement {
3011
+ data;
3012
+ #fn;
3013
+ constructor(data, fn) {
3014
+ super(data.name);
3015
+ this.data = data;
3016
+ this.#fn = fn ?? new ArcFunction({
3017
+ params: data.params,
3018
+ result: null,
3019
+ queryElements: data.queryElements,
3020
+ mutationElements: data.mutationElements,
3021
+ protections: data.protections || [],
3022
+ handler: data.handler ?? null,
3023
+ description: data.description
3024
+ });
3025
+ }
3026
+ description(description) {
3027
+ const newFn = this.#fn.description(description);
3028
+ return new ArcCommand({ ...this.data, description }, newFn);
3029
+ }
3030
+ get isPublic() {
3031
+ return this.#fn.isPublic;
3032
+ }
3033
+ query(elements) {
3034
+ const newFn = this.#fn.query(elements);
3035
+ return new ArcCommand({ ...this.data, queryElements: elements }, newFn);
3036
+ }
3037
+ mutate(elements) {
3038
+ const newFn = this.#fn.mutate(elements);
3039
+ return new ArcCommand({ ...this.data, mutationElements: elements }, newFn);
3040
+ }
3041
+ withParams(schema) {
3042
+ const newFn = this.#fn.withParams(schema);
3043
+ return new ArcCommand({
3044
+ ...this.data,
3045
+ params: schema instanceof ArcObject ? schema : new ArcObject(schema)
3046
+ }, newFn);
3047
+ }
3048
+ withResult(...schemas) {
3049
+ return new ArcCommand({ ...this.data, results: schemas }, this.#fn);
3050
+ }
3051
+ handle(handler) {
3052
+ const newFn = new ArcFunction({
3053
+ ...this.#fn.data,
3054
+ handler
3055
+ });
3056
+ return new ArcCommand({ ...this.data, handler }, newFn);
3057
+ }
3058
+ protectBy(token, check) {
3059
+ const newFn = this.#fn.protectedBy(token, check);
3060
+ const existingProtections = this.data.protections || [];
3061
+ return new ArcCommand({
3062
+ ...this.data,
3063
+ protections: [...existingProtections, { token, check }]
3064
+ }, newFn);
3065
+ }
3066
+ get hasProtections() {
3067
+ return this.#fn.hasProtections;
3068
+ }
3069
+ get protections() {
3070
+ return this.#fn.protections;
3071
+ }
3072
+ async verifyProtections(tokens) {
3073
+ return this.#fn.verifyProtections(tokens);
3074
+ }
3075
+ async init(environment, adapters) {
3076
+ if (environment === "server" && this.data.handler && adapters.commandWire?.registerCommandHandler) {
3077
+ adapters.commandWire.registerCommandHandler(this.data.name, async (params) => {
3078
+ const executeFunc = this.mutateContext(adapters);
3079
+ return await executeFunc(params);
3080
+ });
3081
+ }
3082
+ }
3083
+ mutateContext(adapters) {
3084
+ const executeFunc = async (params) => {
3085
+ if (this.data.handler) {
3086
+ return await this.executeLocally(params, adapters);
3087
+ }
3088
+ if (!adapters.commandWire) {
3089
+ throw new Error(`Command "${this.data.name}" has no handler and no commandWire adapter available for remote execution`);
3090
+ }
3091
+ return await adapters.commandWire.executeCommand(this.data.name, params);
3092
+ };
3093
+ return Object.assign(executeFunc, { params: this.data.params });
3094
+ }
3095
+ async executeLocally(params, adapters) {
3096
+ if (!this.data.handler) {
3097
+ throw new Error(`Command "${this.data.name}" has no handler`);
3098
+ }
3099
+ const context2 = this.buildCommandContext(adapters);
3100
+ return await this.data.handler(context2, params);
3101
+ }
3102
+ buildCommandContext(adapters) {
3103
+ const context2 = this.#fn.buildContext(adapters);
3104
+ if (this.#fn.hasProtections && adapters.authAdapter) {
3105
+ const decoded = adapters.authAdapter.getDecoded();
3106
+ if (decoded) {
3107
+ context2.$auth = {
3108
+ params: decoded.params,
3109
+ tokenName: decoded.tokenName
3110
+ };
3111
+ } else {
3112
+ throw new Error(`Command "${this.data.name}" requires authentication but no valid token found`);
3113
+ }
3114
+ }
3115
+ return context2;
3116
+ }
3117
+ toJsonSchema() {
3118
+ const parametersSchema = this.data.params ? this.data.params.toJsonSchema?.() ?? {
3119
+ type: "object",
3120
+ properties: {}
3121
+ } : { type: "object", properties: {} };
3122
+ return {
3123
+ type: "function",
3124
+ name: this.data.name,
3125
+ description: this.data.description ?? undefined,
3126
+ parameters: parametersSchema,
3127
+ strict: true
3128
+ };
3129
+ }
3130
+ }
3131
+ class ArcListener extends ArcContextElement {
3132
+ data;
3133
+ #fn;
3134
+ unsubscribers = [];
3135
+ constructor(data, fn) {
3136
+ super(data.name);
3137
+ this.data = data;
3138
+ this.#fn = fn ?? new ArcFunction({
3139
+ params: null,
3140
+ result: null,
3141
+ queryElements: data.queryElements,
3142
+ mutationElements: data.mutationElements,
3143
+ protections: [],
3144
+ handler: null,
3145
+ description: data.description
3146
+ });
3147
+ }
3148
+ description(description) {
3149
+ const newFn = this.#fn.description(description);
3150
+ return new ArcListener({ ...this.data, description }, newFn);
3151
+ }
3152
+ listenTo(events) {
3153
+ return new ArcListener({ ...this.data, eventElements: events }, this.#fn);
3154
+ }
3155
+ query(elements) {
3156
+ const newFn = this.#fn.query(elements);
3157
+ return new ArcListener({ ...this.data, queryElements: elements }, newFn);
3158
+ }
3159
+ mutate(elements) {
3160
+ const newFn = this.#fn.mutate(elements);
3161
+ return new ArcListener({ ...this.data, mutationElements: elements }, newFn);
3162
+ }
3163
+ async() {
3164
+ return new ArcListener({ ...this.data, isAsync: true }, this.#fn);
3165
+ }
3166
+ handle(handler) {
3167
+ return new ArcListener({ ...this.data, handler }, this.#fn);
3168
+ }
3169
+ get eventElements() {
3170
+ return this.data.eventElements || [];
3171
+ }
3172
+ get isAsync() {
3173
+ return this.data.isAsync;
3174
+ }
3175
+ async init(environment, adapters) {
3176
+ if (environment !== "server") {
3177
+ return;
3178
+ }
3179
+ if (!this.data.handler) {
3180
+ console.warn(`Listener "${this.data.name}" has no handler`);
3181
+ return;
3182
+ }
3183
+ if (!adapters.eventPublisher) {
3184
+ console.warn(`Listener "${this.data.name}" cannot subscribe: no eventPublisher adapter`);
3185
+ return;
3186
+ }
3187
+ for (const eventElement of this.data.eventElements) {
3188
+ const unsubscribe = adapters.eventPublisher.subscribe(eventElement.name, async (event2) => {
3189
+ await this.handleEvent(event2, adapters);
3190
+ });
3191
+ this.unsubscribers.push(unsubscribe);
3192
+ }
3193
+ }
3194
+ async handleEvent(event2, adapters) {
3195
+ if (!this.data.handler)
3196
+ return;
3197
+ const context2 = this.#fn.buildContext(adapters);
3198
+ if (adapters.authAdapter) {
3199
+ const decoded = adapters.authAdapter.getDecoded();
3200
+ if (decoded) {
3201
+ context2.$auth = {
3202
+ params: decoded.params,
3203
+ tokenName: decoded.tokenName
3204
+ };
3205
+ }
3206
+ }
3207
+ if (this.data.isAsync) {
3208
+ Promise.resolve(this.data.handler(context2, event2)).catch((error) => {
3209
+ console.error(`Async listener "${this.data.name}" error:`, error);
3210
+ });
3211
+ } else {
3212
+ await this.data.handler(context2, event2);
3213
+ }
3214
+ }
3215
+ destroy() {
3216
+ for (const unsubscribe of this.unsubscribers) {
3217
+ unsubscribe();
3218
+ }
3219
+ this.unsubscribers = [];
3220
+ }
3221
+ }
3222
+ class ArcRoute extends ArcContextElement {
3223
+ data;
3224
+ #fn;
3225
+ constructor(data, fn) {
3226
+ super(data.name);
3227
+ this.data = data;
3228
+ this.#fn = fn ?? new ArcFunction({
3229
+ params: null,
3230
+ result: null,
3231
+ queryElements: data.queryElements,
3232
+ mutationElements: data.mutationElements,
3233
+ protections: data.protections || [],
3234
+ handler: null,
3235
+ description: data.description
3236
+ });
3237
+ }
3238
+ description(description) {
3239
+ const newFn = this.#fn.description(description);
3240
+ return new ArcRoute({ ...this.data, description }, newFn);
3241
+ }
3242
+ path(path) {
3243
+ return new ArcRoute({ ...this.data, path }, this.#fn);
3244
+ }
3245
+ public() {
3246
+ return new ArcRoute({ ...this.data, isPublic: true }, this.#fn);
3247
+ }
3248
+ query(elements) {
3249
+ const newFn = this.#fn.query(elements);
3250
+ return new ArcRoute({ ...this.data, queryElements: elements }, newFn);
3251
+ }
3252
+ mutate(elements) {
3253
+ const newFn = this.#fn.mutate(elements);
3254
+ return new ArcRoute({ ...this.data, mutationElements: elements }, newFn);
3255
+ }
3256
+ protectBy(token, check) {
3257
+ const newFn = this.#fn.protectedBy(token, check);
3258
+ const existingProtections = this.data.protections || [];
3259
+ return new ArcRoute({
3260
+ ...this.data,
3261
+ protections: [...existingProtections, { token, check }]
3262
+ }, newFn);
3263
+ }
3264
+ handle(handlers) {
3265
+ return new ArcRoute({ ...this.data, handlers }, this.#fn);
3266
+ }
3267
+ get routePath() {
3268
+ return this.data.path || `/${this.data.name}`;
3269
+ }
3270
+ get fullPath() {
3271
+ return `/route${this.routePath}`;
3272
+ }
3273
+ get isPublic() {
3274
+ return this.data.isPublic;
3275
+ }
3276
+ get hasProtections() {
3277
+ return this.#fn.hasProtections;
3278
+ }
3279
+ get protections() {
3280
+ return this.data.protections || [];
3281
+ }
3282
+ getHandler(method) {
3283
+ return this.data.handlers?.[method];
3284
+ }
3285
+ matchesPath(pathname) {
3286
+ const routePath = this.fullPath;
3287
+ const routeParts = routePath.split("/").filter(Boolean);
3288
+ const pathParts = pathname.split("/").filter(Boolean);
3289
+ if (routeParts.length !== pathParts.length) {
3290
+ return { matches: false, params: {} };
3291
+ }
3292
+ const params = {};
3293
+ for (let i = 0;i < routeParts.length; i++) {
3294
+ const routePart = routeParts[i];
3295
+ const pathPart = pathParts[i];
3296
+ if (routePart.startsWith(":")) {
3297
+ const paramName = routePart.slice(1);
3298
+ params[paramName] = pathPart;
3299
+ } else if (routePart !== pathPart) {
3300
+ return { matches: false, params: {} };
3301
+ }
3302
+ }
3303
+ return { matches: true, params };
3304
+ }
3305
+ async verifyProtections(tokens) {
3306
+ if (this.data.isPublic) {
3307
+ return true;
3308
+ }
3309
+ return this.#fn.verifyProtections(tokens);
3310
+ }
3311
+ buildContext(adapters, authParams) {
3312
+ const context2 = this.#fn.buildContext(adapters);
3313
+ if (authParams) {
3314
+ context2.$auth = authParams;
3315
+ }
3316
+ return context2;
3317
+ }
3318
+ }
2858
3319
  class DataStorage {
2859
3320
  async commitChanges(changes) {
2860
3321
  await Promise.all(changes.map(({ store, changes: changes2 }) => this.getStore(store).applyChanges(changes2)));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arcote.tech/arc-adapter-db-sqlite",
3
- "version": "0.4.7",
3
+ "version": "0.5.0",
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.4.7"
23
+ "@arcote.tech/arc": "^0.5.0"
24
24
  },
25
25
  "devDependencies": {
26
26
  "typescript": "^5.0.0"