@kontsedal/olas-core 0.0.4 → 0.0.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.cjs +4 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.mts +2 -2
- package/dist/index.mjs +2 -2
- package/dist/{root-BBSlzvJ2.mjs → root-DqWolle_.mjs} +160 -6
- package/dist/root-DqWolle_.mjs.map +1 -0
- package/dist/{root-CoafhkTg.cjs → root-lBp7qziQ.cjs} +177 -5
- package/dist/root-lBp7qziQ.cjs.map +1 -0
- package/dist/testing.cjs +1 -1
- package/dist/testing.d.cts +1 -1
- package/dist/testing.d.mts +1 -1
- package/dist/testing.mjs +1 -1
- package/dist/{types-BCf2nB2N.d.mts → types-BH1o6nYa.d.mts} +129 -4
- package/dist/{types-BCf2nB2N.d.mts.map → types-BH1o6nYa.d.mts.map} +1 -1
- package/dist/{types-Ijeun3qo.d.cts → types-C4Vtkxbn.d.cts} +129 -4
- package/dist/{types-Ijeun3qo.d.cts.map → types-C4Vtkxbn.d.cts.map} +1 -1
- package/package.json +1 -1
- package/src/controller/instance.ts +11 -1
- package/src/index.ts +11 -2
- package/src/query/client.ts +36 -0
- package/src/query/mutation.ts +178 -1
- package/src/query/plugin.ts +91 -1
- package/dist/root-BBSlzvJ2.mjs.map +0 -1
- package/dist/root-CoafhkTg.cjs.map +0 -1
|
@@ -978,6 +978,25 @@ function registerQueryById(queryId, query) {
|
|
|
978
978
|
function lookupRegisteredQuery(queryId) {
|
|
979
979
|
return queryRegistry.get(queryId);
|
|
980
980
|
}
|
|
981
|
+
const mutationRegistry = /* @__PURE__ */ new Map();
|
|
982
|
+
/** Register a mutation by its `mutationId`. Internal — called from `defineMutation`. */
|
|
983
|
+
function registerMutationById(mutationId, entry) {
|
|
984
|
+
mutationRegistry.set(mutationId, entry);
|
|
985
|
+
}
|
|
986
|
+
/**
|
|
987
|
+
* Look up a registered mutation by id. Returns `undefined` when no
|
|
988
|
+
* mutation with that id has been defined — typical when a queue entry
|
|
989
|
+
* references a mutation whose module hasn't been imported (e.g. a
|
|
990
|
+
* code-split route boundary). The plugin should leave such entries in
|
|
991
|
+
* place and retry once the module loads.
|
|
992
|
+
*/
|
|
993
|
+
function lookupRegisteredMutation(mutationId) {
|
|
994
|
+
return mutationRegistry.get(mutationId);
|
|
995
|
+
}
|
|
996
|
+
/** Test-only — drop a registered mutation. Not exported from the package. */
|
|
997
|
+
function _unregisterMutationById(mutationId) {
|
|
998
|
+
mutationRegistry.delete(mutationId);
|
|
999
|
+
}
|
|
981
1000
|
//#endregion
|
|
982
1001
|
//#region src/query/client.ts
|
|
983
1002
|
const DEFAULT_GC_TIME = 5 * 6e4;
|
|
@@ -1342,6 +1361,26 @@ var QueryClient = class {
|
|
|
1342
1361
|
this.callPlugin(() => cb.call(plugin, event));
|
|
1343
1362
|
}
|
|
1344
1363
|
}
|
|
1364
|
+
/**
|
|
1365
|
+
* Fan out a `MutationEnqueueEvent` to every installed plugin. Called from
|
|
1366
|
+
* `MutationImpl.executeRun` when `spec.persist === true`. Plugins use this
|
|
1367
|
+
* to write the run to durable storage; the queue replays on reload. SPEC §13.3.
|
|
1368
|
+
*/
|
|
1369
|
+
emitMutationEnqueue(event) {
|
|
1370
|
+
if (this.plugins.length === 0) return;
|
|
1371
|
+
for (const plugin of this.plugins) if (plugin.onMutationEnqueue) {
|
|
1372
|
+
const cb = plugin.onMutationEnqueue;
|
|
1373
|
+
this.callPlugin(() => cb.call(plugin, event));
|
|
1374
|
+
}
|
|
1375
|
+
}
|
|
1376
|
+
/** Fan out a `MutationSettleEvent` to every installed plugin. SPEC §13.3. */
|
|
1377
|
+
emitMutationSettle(event) {
|
|
1378
|
+
if (this.plugins.length === 0) return;
|
|
1379
|
+
for (const plugin of this.plugins) if (plugin.onMutationSettle) {
|
|
1380
|
+
const cb = plugin.onMutationSettle;
|
|
1381
|
+
this.callPlugin(() => cb.call(plugin, event));
|
|
1382
|
+
}
|
|
1383
|
+
}
|
|
1345
1384
|
/** Resolve `queryId → live entry-map keys`. Empty array when unknown. */
|
|
1346
1385
|
subscribedKeysFor(queryId) {
|
|
1347
1386
|
const query = lookupRegisteredQuery(queryId);
|
|
@@ -2784,12 +2823,52 @@ function arraysEqual(a, b) {
|
|
|
2784
2823
|
}
|
|
2785
2824
|
//#endregion
|
|
2786
2825
|
//#region src/query/mutation.ts
|
|
2826
|
+
/**
|
|
2827
|
+
* Register a persistable mutation at module scope. Returns the spec
|
|
2828
|
+
* unchanged (with a `__olas: 'mutation'` brand) so consumers can pass it
|
|
2829
|
+
* to `ctx.mutation(...)`, optionally spreading per-controller hooks on
|
|
2830
|
+
* top:
|
|
2831
|
+
*
|
|
2832
|
+
* ```ts
|
|
2833
|
+
* // module-scope
|
|
2834
|
+
* export const createOrder = defineMutation({
|
|
2835
|
+
* mutationId: 'order/create',
|
|
2836
|
+
* mutate: async (vars: OrderInput, { signal }) => api.createOrder(vars, { signal }),
|
|
2837
|
+
* })
|
|
2838
|
+
*
|
|
2839
|
+
* // controller
|
|
2840
|
+
* const m = ctx.mutation({
|
|
2841
|
+
* ...createOrder,
|
|
2842
|
+
* onSuccess: () => toast('Order placed'),
|
|
2843
|
+
* })
|
|
2844
|
+
* ```
|
|
2845
|
+
*
|
|
2846
|
+
* The `mutate` function MUST NOT close over controller-instance state — on
|
|
2847
|
+
* replay there is no controller. Module-level dependencies (a shared `api`
|
|
2848
|
+
* client, etc.) are fine.
|
|
2849
|
+
*/
|
|
2850
|
+
function defineMutation(spec) {
|
|
2851
|
+
if (typeof spec.mutationId !== "string" || spec.mutationId.length === 0) throw new Error("[olas] defineMutation requires a non-empty `mutationId`.");
|
|
2852
|
+
const persistSpec = {
|
|
2853
|
+
...spec,
|
|
2854
|
+
persist: spec.persist ?? true
|
|
2855
|
+
};
|
|
2856
|
+
registerMutationById(spec.mutationId, {
|
|
2857
|
+
mutationId: spec.mutationId,
|
|
2858
|
+
mutate: spec.mutate
|
|
2859
|
+
});
|
|
2860
|
+
return Object.assign(persistSpec, {
|
|
2861
|
+
__olas: "mutation",
|
|
2862
|
+
mutationId: spec.mutationId
|
|
2863
|
+
});
|
|
2864
|
+
}
|
|
2787
2865
|
var MutationImpl = class {
|
|
2788
2866
|
spec;
|
|
2789
2867
|
onError;
|
|
2790
2868
|
controllerPath;
|
|
2791
2869
|
inflightCounter;
|
|
2792
2870
|
devtools;
|
|
2871
|
+
lifecycle;
|
|
2793
2872
|
data = signal(void 0);
|
|
2794
2873
|
error = signal(void 0);
|
|
2795
2874
|
isPending = signal(false);
|
|
@@ -2798,12 +2877,21 @@ var MutationImpl = class {
|
|
|
2798
2877
|
serialQueue = [];
|
|
2799
2878
|
serialActive = false;
|
|
2800
2879
|
disposed = false;
|
|
2801
|
-
constructor(spec, onError, controllerPath, inflightCounter, devtools) {
|
|
2880
|
+
constructor(spec, onError, controllerPath, inflightCounter, devtools, lifecycle) {
|
|
2802
2881
|
this.spec = spec;
|
|
2803
2882
|
this.onError = onError;
|
|
2804
2883
|
this.controllerPath = controllerPath;
|
|
2805
2884
|
this.inflightCounter = inflightCounter;
|
|
2806
2885
|
this.devtools = devtools;
|
|
2886
|
+
this.lifecycle = lifecycle;
|
|
2887
|
+
}
|
|
2888
|
+
/**
|
|
2889
|
+
* True iff this mutation should emit persistable-lifecycle events.
|
|
2890
|
+
* Validated at construction time (in `createMutation`) so any malformed
|
|
2891
|
+
* `persist: true`-without-`mutationId` config surfaces early.
|
|
2892
|
+
*/
|
|
2893
|
+
get isPersistable() {
|
|
2894
|
+
return this.spec.persist === true && this.lifecycle !== void 0;
|
|
2807
2895
|
}
|
|
2808
2896
|
emit(event) {}
|
|
2809
2897
|
run = ((vars = void 0) => {
|
|
@@ -2867,10 +2955,30 @@ var MutationImpl = class {
|
|
|
2867
2955
|
this.isPending.set(true);
|
|
2868
2956
|
this.lastVariables.set(vars);
|
|
2869
2957
|
});
|
|
2958
|
+
const runId = this.isPersistable ? makeRunId() : "";
|
|
2959
|
+
const mutationId = this.spec.mutationId;
|
|
2960
|
+
if (this.isPersistable && mutationId !== void 0) try {
|
|
2961
|
+
this.lifecycle?.emitEnqueue({
|
|
2962
|
+
mutationId,
|
|
2963
|
+
runId,
|
|
2964
|
+
variables: vars,
|
|
2965
|
+
attempt: 0
|
|
2966
|
+
});
|
|
2967
|
+
} catch (err) {
|
|
2968
|
+
dispatchError(this.onError, err, {
|
|
2969
|
+
kind: "plugin",
|
|
2970
|
+
controllerPath: this.controllerPath
|
|
2971
|
+
});
|
|
2972
|
+
}
|
|
2870
2973
|
try {
|
|
2871
2974
|
const result = await raceAbort(this.runWithRetry(vars, abort.signal), abort.signal);
|
|
2872
2975
|
if (abort.signal.aborted || this.disposed) {
|
|
2873
2976
|
snapshot?.rollback();
|
|
2977
|
+
if (this.isPersistable && mutationId !== void 0) this.safeEmitSettle({
|
|
2978
|
+
mutationId,
|
|
2979
|
+
runId,
|
|
2980
|
+
outcome: "cancelled"
|
|
2981
|
+
});
|
|
2874
2982
|
throw new DOMException("Superseded", "AbortError");
|
|
2875
2983
|
}
|
|
2876
2984
|
batch(() => {
|
|
@@ -2880,16 +2988,32 @@ var MutationImpl = class {
|
|
|
2880
2988
|
this.safeCall(() => this.spec.onSuccess?.(result, vars), "mutation");
|
|
2881
2989
|
snapshot?.finalize();
|
|
2882
2990
|
this.safeCall(() => this.spec.onSettled?.(result, void 0, vars), "mutation");
|
|
2991
|
+
if (this.isPersistable && mutationId !== void 0) this.safeEmitSettle({
|
|
2992
|
+
mutationId,
|
|
2993
|
+
runId,
|
|
2994
|
+
outcome: "success"
|
|
2995
|
+
});
|
|
2883
2996
|
return result;
|
|
2884
2997
|
} catch (err) {
|
|
2885
2998
|
if (isAbortError(err) || abort.signal.aborted) {
|
|
2886
2999
|
snapshot?.rollback();
|
|
3000
|
+
if (this.isPersistable && mutationId !== void 0) this.safeEmitSettle({
|
|
3001
|
+
mutationId,
|
|
3002
|
+
runId,
|
|
3003
|
+
outcome: "cancelled"
|
|
3004
|
+
});
|
|
2887
3005
|
throw err;
|
|
2888
3006
|
}
|
|
2889
3007
|
this.error.set(err);
|
|
2890
3008
|
this.safeCall(() => this.spec.onError?.(err, vars, snapshot), "mutation");
|
|
2891
3009
|
snapshot?.rollback();
|
|
2892
3010
|
this.safeCall(() => this.spec.onSettled?.(void 0, err, vars), "mutation");
|
|
3011
|
+
if (this.isPersistable && mutationId !== void 0) this.safeEmitSettle({
|
|
3012
|
+
mutationId,
|
|
3013
|
+
runId,
|
|
3014
|
+
outcome: "error",
|
|
3015
|
+
error: err
|
|
3016
|
+
});
|
|
2893
3017
|
throw err;
|
|
2894
3018
|
} finally {
|
|
2895
3019
|
this.inflight.delete(handle);
|
|
@@ -2897,6 +3021,16 @@ var MutationImpl = class {
|
|
|
2897
3021
|
if (this.inflight.size === 0) this.isPending.set(false);
|
|
2898
3022
|
}
|
|
2899
3023
|
}
|
|
3024
|
+
safeEmitSettle(event) {
|
|
3025
|
+
try {
|
|
3026
|
+
this.lifecycle?.emitSettle(event);
|
|
3027
|
+
} catch (err) {
|
|
3028
|
+
dispatchError(this.onError, err, {
|
|
3029
|
+
kind: "plugin",
|
|
3030
|
+
controllerPath: this.controllerPath
|
|
3031
|
+
});
|
|
3032
|
+
}
|
|
3033
|
+
}
|
|
2900
3034
|
wrapSnapshot(raw) {
|
|
2901
3035
|
let consumed = false;
|
|
2902
3036
|
return {
|
|
@@ -2960,8 +3094,24 @@ var MutationImpl = class {
|
|
|
2960
3094
|
this.serialQueue.length = 0;
|
|
2961
3095
|
}
|
|
2962
3096
|
};
|
|
2963
|
-
function createMutation(spec, onError, controllerPath, inflightCounter, devtools) {
|
|
2964
|
-
|
|
3097
|
+
function createMutation(spec, onError, controllerPath, inflightCounter, devtools, lifecycle) {
|
|
3098
|
+
if (spec.persist === true) {
|
|
3099
|
+
if (typeof spec.mutationId !== "string" || spec.mutationId.length === 0) throw new Error("[olas] ctx.mutation({ persist: true, ... }) requires a non-empty `mutationId`.");
|
|
3100
|
+
}
|
|
3101
|
+
return new MutationImpl(spec, onError, controllerPath, inflightCounter, devtools, lifecycle);
|
|
3102
|
+
}
|
|
3103
|
+
/**
|
|
3104
|
+
* Generate a unique-enough run id for the persistable-mutation lifecycle.
|
|
3105
|
+
* Uses `crypto.randomUUID` where available (Node 19+, modern browsers),
|
|
3106
|
+
* with a timestamp+random fallback for older runtimes. Collisions only
|
|
3107
|
+
* affect dedup at the plugin layer, not correctness, so the fallback's
|
|
3108
|
+
* weakness is acceptable.
|
|
3109
|
+
*/
|
|
3110
|
+
function makeRunId() {
|
|
3111
|
+
const g = globalThis;
|
|
3112
|
+
if (typeof g.crypto?.randomUUID === "function") return g.crypto.randomUUID();
|
|
3113
|
+
const rand = Math.random().toString(36).slice(2, 12);
|
|
3114
|
+
return `${Date.now().toString(36)}-${rand}`;
|
|
2965
3115
|
}
|
|
2966
3116
|
/**
|
|
2967
3117
|
* Race a promise against an AbortSignal. If the signal fires before the
|
|
@@ -3497,7 +3647,11 @@ var ControllerInstance = class ControllerInstance {
|
|
|
3497
3647
|
return handle.subscription;
|
|
3498
3648
|
},
|
|
3499
3649
|
mutation(spec) {
|
|
3500
|
-
const
|
|
3650
|
+
const queryClient = self.rootShared.queryClient;
|
|
3651
|
+
const m = createMutation(spec, self.rootShared.onError, self.path, queryClient.mutationsInflight$, self.rootShared.devtools, spec.persist === true ? {
|
|
3652
|
+
emitEnqueue: (ev) => queryClient.emitMutationEnqueue(ev),
|
|
3653
|
+
emitSettle: (ev) => queryClient.emitMutationSettle(ev)
|
|
3654
|
+
} : void 0);
|
|
3501
3655
|
self.entries.push({
|
|
3502
3656
|
kind: "cleanup",
|
|
3503
3657
|
dispose: () => m.dispose()
|
|
@@ -4099,6 +4253,12 @@ function createRoot(def, options) {
|
|
|
4099
4253
|
return createRootWithProps(def, void 0, options);
|
|
4100
4254
|
}
|
|
4101
4255
|
//#endregion
|
|
4256
|
+
Object.defineProperty(exports, "_unregisterMutationById", {
|
|
4257
|
+
enumerable: true,
|
|
4258
|
+
get: function() {
|
|
4259
|
+
return _unregisterMutationById;
|
|
4260
|
+
}
|
|
4261
|
+
});
|
|
4102
4262
|
Object.defineProperty(exports, "batch", {
|
|
4103
4263
|
enumerable: true,
|
|
4104
4264
|
get: function() {
|
|
@@ -4141,6 +4301,12 @@ Object.defineProperty(exports, "defineController", {
|
|
|
4141
4301
|
return defineController;
|
|
4142
4302
|
}
|
|
4143
4303
|
});
|
|
4304
|
+
Object.defineProperty(exports, "defineMutation", {
|
|
4305
|
+
enumerable: true,
|
|
4306
|
+
get: function() {
|
|
4307
|
+
return defineMutation;
|
|
4308
|
+
}
|
|
4309
|
+
});
|
|
4144
4310
|
Object.defineProperty(exports, "effect", {
|
|
4145
4311
|
enumerable: true,
|
|
4146
4312
|
get: function() {
|
|
@@ -4153,6 +4319,12 @@ Object.defineProperty(exports, "isAbortError", {
|
|
|
4153
4319
|
return isAbortError;
|
|
4154
4320
|
}
|
|
4155
4321
|
});
|
|
4322
|
+
Object.defineProperty(exports, "lookupRegisteredMutation", {
|
|
4323
|
+
enumerable: true,
|
|
4324
|
+
get: function() {
|
|
4325
|
+
return lookupRegisteredMutation;
|
|
4326
|
+
}
|
|
4327
|
+
});
|
|
4156
4328
|
Object.defineProperty(exports, "lookupRegisteredQuery", {
|
|
4157
4329
|
enumerable: true,
|
|
4158
4330
|
get: function() {
|
|
@@ -4184,4 +4356,4 @@ Object.defineProperty(exports, "untracked", {
|
|
|
4184
4356
|
}
|
|
4185
4357
|
});
|
|
4186
4358
|
|
|
4187
|
-
//# sourceMappingURL=root-
|
|
4359
|
+
//# sourceMappingURL=root-lBp7qziQ.cjs.map
|