@ariestools/aries-dapp-core 0.1.15 → 0.1.17

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 (44) hide show
  1. package/dist/bin/dappServer.mjs +77 -290
  2. package/dist/node/DappActor.d.ts +27 -23
  3. package/dist/node/DappActor.d.ts.map +1 -1
  4. package/dist/node/actor/types.d.ts +14 -28
  5. package/dist/node/actor/types.d.ts.map +1 -1
  6. package/dist/node/bin/loadReducer.d.ts +3 -1
  7. package/dist/node/bin/loadReducer.d.ts.map +1 -1
  8. package/dist/node/boot/bootDappActors.d.ts +4 -3
  9. package/dist/node/boot/bootDappActors.d.ts.map +1 -1
  10. package/dist/node/consumer.mjs.map +2 -2
  11. package/dist/node/index.d.ts +1 -2
  12. package/dist/node/index.d.ts.map +1 -1
  13. package/dist/node/index.mjs +51 -264
  14. package/dist/node/index.mjs.map +4 -4
  15. package/dist/node/providers/DappBucketStore.d.ts +3 -1
  16. package/dist/node/providers/DappBucketStore.d.ts.map +1 -1
  17. package/dist/node/providers/capabilities.d.ts +3 -1
  18. package/dist/node/providers/capabilities.d.ts.map +1 -1
  19. package/dist/node/providers/hashBytes.d.ts +3 -1
  20. package/dist/node/providers/hashBytes.d.ts.map +1 -1
  21. package/dist/node/providers/joinKey.d.ts +6 -2
  22. package/dist/node/providers/joinKey.d.ts.map +1 -1
  23. package/dist/node/providers/types.d.ts +21 -7
  24. package/dist/node/providers/types.d.ts.map +1 -1
  25. package/dist/node/publication/constants.d.ts +24 -8
  26. package/dist/node/publication/constants.d.ts.map +1 -1
  27. package/dist/node/publication/gc.d.ts +6 -2
  28. package/dist/node/publication/gc.d.ts.map +1 -1
  29. package/dist/node/publication/incremental.d.ts +9 -3
  30. package/dist/node/publication/incremental.d.ts.map +1 -1
  31. package/dist/node/publication/releases.d.ts +12 -4
  32. package/dist/node/publication/releases.d.ts.map +1 -1
  33. package/dist/node/publication/status.d.ts +3 -1
  34. package/dist/node/publication/status.d.ts.map +1 -1
  35. package/dist/node/publication/statusPatch.d.ts +9 -3
  36. package/dist/node/publication/statusPatch.d.ts.map +1 -1
  37. package/dist/node/publication/types.d.ts +42 -14
  38. package/dist/node/publication/types.d.ts.map +1 -1
  39. package/dist/node/reducer/DappReducer.d.ts +9 -3
  40. package/dist/node/reducer/DappReducer.d.ts.map +1 -1
  41. package/examples/countFactsReducer.mjs +3 -1
  42. package/package.json +17 -9
  43. package/dist/node/actor/AbstractActor.d.ts +0 -53
  44. package/dist/node/actor/AbstractActor.d.ts.map +0 -1
@@ -3,169 +3,17 @@ import { createRequire } from "node:module";
3
3
  import { existsSync, readFileSync } from "node:fs";
4
4
  import { homedir } from "node:os";
5
5
  import path from "node:path";
6
+ import { runActorsService } from "@ariestools/actor-cli";
6
7
  import { DAPP_BACKINGS, DAPP_BUCKETS, isDappBackingKind, resolveBacking, startDappServer } from "@ariestools/aries-dapp-serve";
7
- import { AbstractCreatable, ConsoleLogger, IdLogger, assertEx, creatable } from "@ariestools/sdk";
8
+ import { createNodeProcessHost } from "@ariestools/cli-kit-node";
9
+ import { ConsoleLogger, assertEx, creatable } from "@ariestools/sdk";
10
+ import { PeriodicActor } from "@ariestools/actor";
8
11
  import { DeleteObjectCommand, GetObjectCommand, HeadObjectCommand, ListObjectsV2Command, PutObjectCommand, S3Client } from "@aws-sdk/client-s3";
9
12
  import { pathToFileURL } from "node:url";
10
- //#region src/actor/AbstractActor.ts
11
- function createDeferred$1() {
12
- let resolve;
13
- let reject;
14
- const promise = new Promise((res, rej) => {
15
- resolve = res;
16
- reject = rej;
17
- });
18
- promise.catch(() => {});
19
- return {
20
- promise,
21
- reject,
22
- resolve
23
- };
24
- }
13
+ //#region src/providers/capabilities.ts
25
14
  /**
26
- * Lean, dapp-owned fork of the xl1 `ActorV3` pattern: the create/start/stop
27
- * lifecycle from `AbstractCreatable`, plus non-overlapping interval timers and
28
- * a readiness contract. It deliberately swaps the chain's
29
- * `ProviderFactoryLocator`/`LocatorConfig` machinery for the small
30
- * {@link DappProviderLocator} seam, so a dapp actor resolves providers by
31
- * moniker without dragging the chain protocol config model in.
32
- *
33
- * The locator is process-wide: the daemon builds it once and passes the same
34
- * instance to every actor via `params.locator` (see `bootDappActors`). When
35
- * this graduates into a shared cli/actor toolkit — and, later, xl1-protocol —
36
- * this base can re-adopt the real locator.
15
+ Thrown when a read-only capability wrapper receives a write.
37
16
  */
38
- var AbstractActor = class extends AbstractCreatable {
39
- _intervals = /* @__PURE__ */ new Map();
40
- _timeouts = /* @__PURE__ */ new Map();
41
- _abortController = new AbortController();
42
- _idLogger;
43
- _inFlight = /* @__PURE__ */ new Map();
44
- _readyDeferred = createDeferred$1();
45
- _readyError;
46
- _readyState = "pending";
47
- get logger() {
48
- this._idLogger ??= new IdLogger(assertEx(this.context.logger, () => `Logger is required in context for actor ${this.name}.`), () => this.name);
49
- return this._idLogger;
50
- }
51
- get readyError() {
52
- return this._readyError;
53
- }
54
- get readyState() {
55
- return this._readyState;
56
- }
57
- get context() {
58
- return this.locator.context;
59
- }
60
- get locator() {
61
- return this.params.locator;
62
- }
63
- /** Abort signal cancelled when the actor stops (or is replaced on restart). */
64
- get signal() {
65
- return this._abortController.signal;
66
- }
67
- static async paramsHandler(params) {
68
- const inParams = params ?? {};
69
- const baseParams = await super.paramsHandler({
70
- ...inParams,
71
- name: inParams.name ?? "UnknownActor"
72
- });
73
- const locator = assertEx(inParams.locator, () => `params.locator is required for actor ${String(baseParams.name)}.`);
74
- return {
75
- ...baseParams,
76
- locator
77
- };
78
- }
79
- /** Override to prove the actor can do useful work. Default: no-op. */
80
- async readyHandler() {}
81
- /**
82
- * Register a recurring task. The first invocation fires after `dueTimeMs`
83
- * (the documented first-run delay); subsequent invocations fire every
84
- * `periodMs` while the actor is `started`. A run is skipped if the previous
85
- * one is still in flight, so a slow pass can never stack on top of itself.
86
- * Must be called from `startHandler` (guards on `starting` status).
87
- */
88
- registerTimer(timerName, callback, dueTimeMs, periodMs) {
89
- if (this.status !== "starting") {
90
- this.logger.warn(`Cannot register timer '${timerName}' because actor is not starting.`);
91
- return;
92
- }
93
- const tick = () => {
94
- if (this.status !== "started") return;
95
- if (this._inFlight.has(timerName)) {
96
- this.logger.warn(`Skipping timer '${this.name}:${timerName}' because the previous run is still in flight.`);
97
- return;
98
- }
99
- const run = (async () => {
100
- const startTime = Date.now();
101
- try {
102
- await callback();
103
- } catch (error) {
104
- const err = error instanceof Error ? error : new Error(String(error));
105
- this.logger.error(`Error in timer '${this.name}:${timerName}': ${err.message}`);
106
- } finally {
107
- const duration = Date.now() - startTime;
108
- if (duration > periodMs) this.logger.warn(`Timer '${this.name}:${timerName}' took ${duration}ms, longer than its ${periodMs}ms period.`);
109
- }
110
- })();
111
- this._inFlight.set(timerName, run.finally(() => {
112
- this._inFlight.delete(timerName);
113
- }));
114
- };
115
- const timeoutId = setTimeout(() => {
116
- if (this.status !== "started") return;
117
- this._intervals.set(timerName, setInterval(tick, periodMs));
118
- tick();
119
- }, dueTimeMs);
120
- this._timeouts.set(timerName, timeoutId);
121
- }
122
- /**
123
- * Run the warm-pass once. The standard boot path invokes this after
124
- * `start()` so readiness either resolves or rejects.
125
- */
126
- async runReadyHandler() {
127
- if (this._readyState !== "pending") return;
128
- try {
129
- await this.readyHandler();
130
- this._readyState = "ready";
131
- this._readyDeferred.resolve();
132
- } catch (error) {
133
- const err = error instanceof Error ? error : new Error(String(error));
134
- this._readyState = "failed";
135
- this._readyError = err;
136
- this._readyDeferred.reject(err);
137
- throw err;
138
- }
139
- }
140
- async startHandler() {
141
- if (this._abortController.signal.aborted) this._abortController = new AbortController();
142
- await super.startHandler();
143
- }
144
- async stopHandler() {
145
- await super.stopHandler();
146
- this._abortController.abort();
147
- for (const timeoutRef of this._timeouts.values()) clearTimeout(timeoutRef);
148
- this._timeouts.clear();
149
- for (const intervalRef of this._intervals.values()) clearInterval(intervalRef);
150
- this._intervals.clear();
151
- const inFlight = [...this._inFlight.values()];
152
- this._inFlight.clear();
153
- const timeoutMs = this.params.shutdownTimeoutMs;
154
- if (timeoutMs === void 0) {
155
- await Promise.allSettled(inFlight);
156
- return;
157
- }
158
- await Promise.race([Promise.allSettled(inFlight), new Promise((resolve) => {
159
- setTimeout(resolve, timeoutMs);
160
- })]);
161
- }
162
- async whenReady() {
163
- await this._readyDeferred.promise;
164
- }
165
- };
166
- //#endregion
167
- //#region src/providers/capabilities.ts
168
- /** Thrown when a read-only capability wrapper receives a write. */
169
17
  var ReadOnlyStoreError = class extends Error {
170
18
  name = "ReadOnlyStoreError";
171
19
  constructor(role, operation = "put") {
@@ -222,10 +70,14 @@ const DappStateStoreMoniker = "DappStateStore";
222
70
  const DappIndexStoreMoniker = "DappIndexStore";
223
71
  //#endregion
224
72
  //#region src/publication/constants.ts
225
- /** Well-known relative keys published by the coherent generation protocol. */
73
+ /**
74
+ Well-known relative keys published by the coherent generation protocol.
75
+ */
226
76
  const HEAD_KEY = "head.json";
227
77
  const STATUS_KEY = "status.json";
228
- /** CDN caching: mutable head and status objects that must revalidate. */
78
+ /**
79
+ CDN caching: mutable head and status objects that must revalidate.
80
+ */
229
81
  const CACHE_CONTROL_REVALIDATE = "public, max-age=0, must-revalidate";
230
82
  const INDEXER_STATUS_SCHEMA = "network.aries.dapp.indexer.status";
231
83
  //#endregion
@@ -290,7 +142,9 @@ const PROGRESS_KEYS = [
290
142
  "generation",
291
143
  "generationRoot"
292
144
  ];
293
- /** Carry forward durable progress fields from a prior status object. */
145
+ /**
146
+ Carry forward durable progress fields from a prior status object.
147
+ */
294
148
  function priorProgressFields(prior) {
295
149
  if (prior === void 0) return {};
296
150
  return {
@@ -298,7 +152,9 @@ function priorProgressFields(prior) {
298
152
  ...prior.lastSuccessAt !== void 0 && { lastSuccessAt: prior.lastSuccessAt }
299
153
  };
300
154
  }
301
- /** Build success status fields from reduce progress, falling back to prior. */
155
+ /**
156
+ Build success status fields from reduce progress, falling back to prior.
157
+ */
302
158
  function successStatusFields(progress, prior, now) {
303
159
  const fromProgress = progress === void 0 ? {} : pickDefined(progress, PROGRESS_KEYS);
304
160
  const generation = progress?.generation ?? prior?.generation;
@@ -313,7 +169,9 @@ function successStatusFields(progress, prior, now) {
313
169
  ...prior?.lastErrorAt !== void 0 && { lastErrorAt: prior.lastErrorAt }
314
170
  };
315
171
  }
316
- /** Build failure status fields while preserving prior checkpoint progress. */
172
+ /**
173
+ Build failure status fields while preserving prior checkpoint progress.
174
+ */
317
175
  function failureStatusFields(prior, consecutiveFailures, error, now) {
318
176
  return {
319
177
  consecutiveFailures,
@@ -323,7 +181,7 @@ function failureStatusFields(prior, consecutiveFailures, error, now) {
323
181
  };
324
182
  }
325
183
  //#endregion
326
- //#region \0@oxc-project+runtime@0.140.0/helpers/esm/decorate.js
184
+ //#region \0@oxc-project+runtime@0.143.0/helpers/esm/decorate.js
327
185
  function __decorate(decorators, target, key, desc) {
328
186
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
329
187
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
@@ -333,22 +191,6 @@ function __decorate(decorators, target, key, desc) {
333
191
  //#endregion
334
192
  //#region src/DappActor.ts
335
193
  const DEFAULT_REDUCE_INTERVAL_MS = 5e3;
336
- const DEFAULT_FIRST_RUN_DELAY_MS = 2e3;
337
- const REDUCE_TIMER = "DappReduce";
338
- function createDeferred() {
339
- let resolve;
340
- let reject;
341
- const promise = new Promise((res, rej) => {
342
- resolve = res;
343
- reject = rej;
344
- });
345
- promise.catch(() => {});
346
- return {
347
- promise,
348
- reject,
349
- resolve
350
- };
351
- }
352
194
  function withDefaultGenerationRoot(result) {
353
195
  if (result === void 0) return;
354
196
  if (result.generation === void 0 || result.generationRoot !== void 0) return result;
@@ -357,7 +199,7 @@ function withDefaultGenerationRoot(result) {
357
199
  generationRoot: HEAD_KEY
358
200
  };
359
201
  }
360
- let DappActor = class DappActor extends AbstractActor {
202
+ let DappActor = class DappActor extends PeriodicActor {
361
203
  static dependencies = [
362
204
  DappDataStoreMoniker,
363
205
  DappStateStoreMoniker,
@@ -366,12 +208,17 @@ let DappActor = class DappActor extends AbstractActor {
366
208
  _data;
367
209
  _index;
368
210
  _state;
369
- _consecutiveFailures = 0;
370
- _firstPass = createDeferred();
371
- _firstPassSettled = false;
372
- /** Consecutive reduce failures since the last success. */
373
- get consecutiveFailures() {
374
- return this._consecutiveFailures;
211
+ /**
212
+ Dapp actors require a logger in the locator context (see {@link DappContext}).
213
+ */
214
+ get logger() {
215
+ return assertEx(super.logger, () => `Logger is required in context for actor ${this.name}.`);
216
+ }
217
+ /**
218
+ Reduce cadence: `reduceIntervalMs` names the interval in dapp configs.
219
+ */
220
+ get intervalMs() {
221
+ return this.params.reduceIntervalMs ?? DEFAULT_REDUCE_INTERVAL_MS;
375
222
  }
376
223
  async createHandler() {
377
224
  await super.createHandler();
@@ -380,21 +227,27 @@ let DappActor = class DappActor extends AbstractActor {
380
227
  this._state = await this.locator.getInstance(DappStateStoreMoniker);
381
228
  this._index = await this.locator.getInstance(DappIndexStoreMoniker);
382
229
  }
383
- async readyHandler() {
384
- await this._firstPass.promise;
385
- }
386
230
  async startHandler() {
387
231
  await super.startHandler();
388
- const interval = this.params.reduceIntervalMs ?? DEFAULT_REDUCE_INTERVAL_MS;
389
- const firstRunDelay = this.params.firstRunDelayMs ?? DEFAULT_FIRST_RUN_DELAY_MS;
390
- this.registerTimer(REDUCE_TIMER, async () => {
391
- await this.runReducePass();
392
- }, firstRunDelay, interval);
393
- this.logger.info(`DappActor started: reducer '${this.params.reducer.name}' every ${interval}ms (first run in ${firstRunDelay}ms)`);
232
+ this.logger.info(`DappActor started: reducer '${this.params.reducer.name}' every ${this.intervalMs}ms (first run in ${this.firstRunDelayMs}ms)`);
233
+ }
234
+ /**
235
+ Failure side-channel: publish durable failure status (count already incremented).
236
+ */
237
+ async onPassError(error) {
238
+ await this.safePublishStatus(void 0, error);
394
239
  }
395
- async stopHandler() {
396
- this.settleFirstPass(/* @__PURE__ */ new Error("Actor stopped before first reduce pass completed"));
397
- await super.stopHandler();
240
+ async runPass({ signal }) {
241
+ const result = await this.params.reducer.reduce({
242
+ data: this._data,
243
+ index: this._index,
244
+ logger: this.logger,
245
+ signal,
246
+ state: this._state
247
+ });
248
+ if (signal.aborted) return;
249
+ const progress = withDefaultGenerationRoot(result === void 0 ? void 0 : result);
250
+ await this.safePublishStatus(progress);
398
251
  }
399
252
  async publishStatusFromProgress(progress, error) {
400
253
  if (this.params.publishStatus === false) return;
@@ -405,40 +258,9 @@ let DappActor = class DappActor extends AbstractActor {
405
258
  prior = void 0;
406
259
  }
407
260
  const now = (/* @__PURE__ */ new Date()).toISOString();
408
- const fields = error === void 0 ? successStatusFields(progress, prior, now) : failureStatusFields(prior, this._consecutiveFailures, error, now);
261
+ const fields = error === void 0 ? successStatusFields(progress, prior, now) : failureStatusFields(prior, this.consecutiveFailures, error, now);
409
262
  await writeIndexerStatus(this._state, fields);
410
263
  }
411
- async runReducePass() {
412
- const signal = this.signal;
413
- try {
414
- const result = await this.params.reducer.reduce({
415
- data: this._data,
416
- index: this._index,
417
- logger: this.logger,
418
- signal,
419
- state: this._state
420
- });
421
- if (signal.aborted) return;
422
- const progress = withDefaultGenerationRoot(result === void 0 ? void 0 : result);
423
- this._consecutiveFailures = 0;
424
- await this.safePublishStatus(progress);
425
- this.settleFirstPass();
426
- } catch (error) {
427
- if (signal.aborted) return;
428
- const err = error instanceof Error ? error : new Error(String(error));
429
- this._consecutiveFailures += 1;
430
- await this.safePublishStatus(void 0, err);
431
- this.settleFirstPass(err);
432
- this.logger.error(`Error in reduce pass for '${this.params.reducer.name}': ${err.message}`);
433
- const max = this.params.maxConsecutiveFailures;
434
- if (max !== void 0 && this._consecutiveFailures >= max) {
435
- this.logger.error(`Reducer '${this.params.reducer.name}' failed ${this._consecutiveFailures} consecutive times; stopping actor`);
436
- setTimeout(() => {
437
- this.stop();
438
- }, 0);
439
- }
440
- }
441
- }
442
264
  async safePublishStatus(progress, error) {
443
265
  try {
444
266
  await this.publishStatusFromProgress(progress, error);
@@ -446,50 +268,9 @@ let DappActor = class DappActor extends AbstractActor {
446
268
  this.logger.error(`Failed to publish indexer status: ${String(statusError)}`);
447
269
  }
448
270
  }
449
- settleFirstPass(error) {
450
- if (this._firstPassSettled) return;
451
- this._firstPassSettled = true;
452
- if (error === void 0) this._firstPass.resolve();
453
- else this._firstPass.reject(error);
454
- }
455
271
  };
456
272
  DappActor = __decorate([creatable()], DappActor);
457
273
  //#endregion
458
- //#region src/boot/bootDappActors.ts
459
- /**
460
- * Creates and starts one {@link DappActor} per spec, all sharing the single
461
- * process-wide locator. On partial failure, actors already started are stopped
462
- * before the error is rethrown. Returns them so the caller can stop them on
463
- * shutdown.
464
- */
465
- async function bootDappActors(locator, specs) {
466
- const actors = [];
467
- try {
468
- for (const spec of specs) {
469
- const params = {
470
- locator,
471
- name: spec.name,
472
- reducer: spec.reducer,
473
- ...spec.reduceIntervalMs !== void 0 && { reduceIntervalMs: spec.reduceIntervalMs },
474
- ...spec.firstRunDelayMs !== void 0 && { firstRunDelayMs: spec.firstRunDelayMs },
475
- ...spec.maxConsecutiveFailures !== void 0 && { maxConsecutiveFailures: spec.maxConsecutiveFailures },
476
- ...spec.publishStatus !== void 0 && { publishStatus: spec.publishStatus },
477
- ...spec.shutdownTimeoutMs !== void 0 && { shutdownTimeoutMs: spec.shutdownTimeoutMs }
478
- };
479
- const actor = await DappActor.create(params);
480
- await actor.start();
481
- actors.push(actor);
482
- if (spec.runReady !== false) await actor.runReadyHandler();
483
- }
484
- return actors;
485
- } catch (error) {
486
- for (const actor of [...actors].reverse()) try {
487
- await actor.stop();
488
- } catch {}
489
- throw error;
490
- }
491
- }
492
- //#endregion
493
274
  //#region src/providers/errors.ts
494
275
  /**
495
276
  * Thrown when a conditional put fails (object already exists under
@@ -517,7 +298,9 @@ function joinKey(prefix, relativeKey) {
517
298
  if (cleanKey.length === 0) return cleanPrefix;
518
299
  return `${cleanPrefix}/${cleanKey}`;
519
300
  }
520
- /** Strip a role prefix from a physical key, returning the relative key. */
301
+ /**
302
+ Strip a role prefix from a physical key, returning the relative key.
303
+ */
521
304
  function stripPrefix(prefix, physicalKey) {
522
305
  const cleanPrefix = prefix.replaceAll(/^\/+|\/+$/g, "");
523
306
  if (cleanPrefix.length === 0) return physicalKey;
@@ -526,7 +309,9 @@ function stripPrefix(prefix, physicalKey) {
526
309
  if (physicalKey.startsWith(withSlash)) return physicalKey.slice(withSlash.length);
527
310
  return physicalKey;
528
311
  }
529
- /** Normalize an optional public base URL (no trailing slash). */
312
+ /**
313
+ Normalize an optional public base URL (no trailing slash).
314
+ */
530
315
  function normalizePublicBaseUrl(url) {
531
316
  if (url === void 0 || url.length === 0) return void 0;
532
317
  return url.replace(/\/+$/, "");
@@ -942,28 +727,30 @@ async function main() {
942
727
  });
943
728
  process.env.DAPP_PUBLICATION_SAFETY ??= "unfenced";
944
729
  process.env.DAPP_ENDPOINT ??= server.baseUrl;
945
- const actors = await bootDappActors(locator, [{
730
+ const actors = [await DappActor.create({
731
+ firstRunDelayMs: FIRST_RUN_DELAY_MS,
732
+ locator,
946
733
  name: "DappActor",
947
- reducer,
734
+ publishStatus: reducer.name !== "noop",
948
735
  reduceIntervalMs: REDUCE_INTERVAL_MS,
949
- firstRunDelayMs: FIRST_RUN_DELAY_MS,
950
- publishStatus: reducer.name !== "noop"
951
- }]);
736
+ reducer
737
+ })];
952
738
  const versionSuffix = reducer.version === void 0 ? "" : `@${reducer.version}`;
953
739
  const reducerLine = REDUCER_SPEC === void 0 ? "\nreducer: noop (pass DAPP_REDUCER / --reducer for real logic)" : `\nreducer: ${REDUCER_SPEC}`;
954
- console.log(`[dev-only] dapp server listening at ${server.baseUrl}\n` + DAPP_BUCKETS.map((bucket) => ` /${bucket.padEnd(5)} ${server.baseUrl}/${bucket}`).join("\n") + `\nbacking: ${backing.description}\nactors: ${actors.length} (reducer '${reducer.name}'${versionSuffix}, every ${REDUCE_INTERVAL_MS}ms)` + reducerLine);
955
- const shutdown = async () => {
956
- for (const actor of actors) await actor.stop();
740
+ const banner = `[dev-only] dapp server listening at ${server.baseUrl}\n` + DAPP_BUCKETS.map((bucket) => ` /${bucket.padEnd(5)} ${server.baseUrl}/${bucket}`).join("\n") + `\nbacking: ${backing.description}\nactors: ${actors.length} (reducer '${reducer.name}'${versionSuffix}, every ${REDUCE_INTERVAL_MS}ms)` + reducerLine;
741
+ const processHost = createNodeProcessHost({ signals: ["SIGINT", "SIGTERM"] });
742
+ try {
743
+ await runActorsService(processHost, {
744
+ actors,
745
+ onReady: () => {
746
+ console.log(banner);
747
+ },
748
+ supervisor: "parallel"
749
+ });
750
+ } finally {
957
751
  locator.destroy();
958
752
  await server.close();
959
- process.exit(0);
960
- };
961
- process.on("SIGINT", () => {
962
- shutdown();
963
- });
964
- process.on("SIGTERM", () => {
965
- shutdown();
966
- });
753
+ }
967
754
  }
968
755
  main().catch((error) => {
969
756
  console.error(error);
@@ -1,47 +1,51 @@
1
- import { AbstractActor } from './actor/AbstractActor.ts';
2
- import type { ActorParams } from './actor/types.ts';
1
+ import type { PeriodicActorParams, PeriodicPassContext } from '@ariestools/actor';
2
+ import { PeriodicActor } from '@ariestools/actor';
3
+ import type { Logger } from '@ariestools/sdk';
4
+ import type { DappProviderLocator } from './actor/types.ts';
3
5
  import type { DappObjectReader, DappObjectWriter } from './providers/capabilities.ts';
4
6
  import type { DappReducer } from './reducer/DappReducer.ts';
5
- export interface DappActorParams extends ActorParams {
6
- /** Delay before the first reduce pass. Defaults to 2000ms. */
7
- firstRunDelayMs?: number;
8
- /**
9
- * When set, after this many consecutive reduce failures the actor stops so a
10
- * supervisor can restart the process.
11
- */
12
- maxConsecutiveFailures?: number;
7
+ export interface DappActorParams extends PeriodicActorParams<DappProviderLocator> {
13
8
  /**
14
9
  * When true (default), publish durable indexer status to the state store
15
10
  * after each reduce pass (success or failure).
16
11
  */
17
12
  publishStatus?: boolean;
13
+ /**
14
+ Period between reduce passes. Defaults to 5000ms.
15
+ */
18
16
  reduceIntervalMs?: number;
19
17
  reducer: DappReducer;
20
18
  }
21
19
  /**
22
20
  * The stock dapp actor: resolves the three bucket stores from the shared
23
21
  * locator, then drives its reducer on an interval to keep `state` and `index`
24
- * derived from authoritative input. Multiple actors (each with its own
25
- * reducer) can share one locator; this is the default single-reducer instance
26
- * the local daemon boots.
22
+ * derived from authoritative input. The loop policies (first-pass-gated
23
+ * readiness, non-overlap, consecutive-failure self-stop) come from
24
+ * `PeriodicActor`; this class contributes the reduce pass and durable status
25
+ * publication. Multiple actors (each with its own reducer) can share one
26
+ * locator; this is the default single-reducer instance the local daemon boots.
27
27
  */
28
- export declare class DappActor extends AbstractActor<DappActorParams> {
28
+ export declare class DappActor extends PeriodicActor<DappActorParams> {
29
29
  static readonly dependencies: readonly ["DappDataStore", "DappStateStore", "DappIndexStore"];
30
30
  protected _data: DappObjectReader;
31
31
  protected _index: DappObjectWriter;
32
32
  protected _state: DappObjectWriter;
33
- private _consecutiveFailures;
34
- private readonly _firstPass;
35
- private _firstPassSettled;
36
- /** Consecutive reduce failures since the last success. */
37
- get consecutiveFailures(): number;
33
+ /**
34
+ Dapp actors require a logger in the locator context (see {@link DappContext}).
35
+ */
36
+ get logger(): Logger;
37
+ /**
38
+ Reduce cadence: `reduceIntervalMs` names the interval in dapp configs.
39
+ */
40
+ protected get intervalMs(): number;
38
41
  createHandler(): Promise<void>;
39
- readyHandler(): Promise<void>;
40
42
  startHandler(): Promise<void>;
41
- stopHandler(): Promise<void>;
43
+ /**
44
+ Failure side-channel: publish durable failure status (count already incremented).
45
+ */
46
+ protected onPassError(error: Error): Promise<void>;
47
+ protected runPass({ signal }: PeriodicPassContext): Promise<void>;
42
48
  private publishStatusFromProgress;
43
- private runReducePass;
44
49
  private safePublishStatus;
45
- private settleFirstPass;
46
50
  }
47
51
  //# sourceMappingURL=DappActor.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"DappActor.d.ts","sourceRoot":"","sources":["../../src/DappActor.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAA;AACxD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AACnD,OAAO,KAAK,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAA;AASrF,OAAO,KAAK,EAAsB,WAAW,EAAE,MAAM,0BAA0B,CAAA;AAE/E,MAAM,WAAW,eAAgB,SAAQ,WAAW;IAClD,8DAA8D;IAC9D,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB;;;OAGG;IACH,sBAAsB,CAAC,EAAE,MAAM,CAAA;IAC/B;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,OAAO,EAAE,WAAW,CAAA;CACrB;AAmCD;;;;;;GAMG;AACH,qBACa,SAAU,SAAQ,aAAa,CAAC,eAAe,CAAC;IAC3D,MAAM,CAAC,QAAQ,CAAC,YAAY,iEAIlB;IAEV,SAAS,CAAC,KAAK,EAAG,gBAAgB,CAAA;IAClC,SAAS,CAAC,MAAM,EAAG,gBAAgB,CAAA;IACnC,SAAS,CAAC,MAAM,EAAG,gBAAgB,CAAA;IAEnC,OAAO,CAAC,oBAAoB,CAAI;IAChC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAyB;IACpD,OAAO,CAAC,iBAAiB,CAAQ;IAEjC,0DAA0D;IAC1D,IAAI,mBAAmB,IAAI,MAAM,CAEhC;IAEc,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;IAS9B,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;IAI7B,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;IAa7B,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;YAK7B,yBAAyB;YAkBzB,aAAa;YA8Cb,iBAAiB;IAW/B,OAAO,CAAC,eAAe;CAMxB"}
1
+ {"version":3,"file":"DappActor.d.ts","sourceRoot":"","sources":["../../src/DappActor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAA;AACjF,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AACjD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAA;AAG7C,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAA;AAC3D,OAAO,KAAK,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAA;AASrF,OAAO,KAAK,EAAsB,WAAW,EAAE,MAAM,0BAA0B,CAAA;AAE/E,MAAM,WAAW,eAAgB,SAAQ,mBAAmB,CAAC,mBAAmB,CAAC;IAC/E;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB;;MAEE;IACF,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,OAAO,EAAE,WAAW,CAAA;CACrB;AAYD;;;;;;;;GAQG;AACH,qBACa,SAAU,SAAQ,aAAa,CAAC,eAAe,CAAC;IAC3D,MAAM,CAAC,QAAQ,CAAC,YAAY,iEAIlB;IAEV,SAAS,CAAC,KAAK,EAAG,gBAAgB,CAAA;IAClC,SAAS,CAAC,MAAM,EAAG,gBAAgB,CAAA;IACnC,SAAS,CAAC,MAAM,EAAG,gBAAgB,CAAA;IAEnC;;MAEE;IACF,IAAa,MAAM,IAAI,MAAM,CAE5B;IAED;;MAEE;IACF,cAAuB,UAAU,IAAI,MAAM,CAE1C;IAEc,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;IAS9B,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;IAQ5C;;MAEE;cACuB,WAAW,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC;cAIxC,OAAO,CAAC,EAAE,MAAM,EAAE,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;YAclE,yBAAyB;YAkBzB,iBAAiB;CAUhC"}
@@ -1,37 +1,23 @@
1
- import type { CreatableParams, Logger } from '@ariestools/sdk';
2
- /** Identifier a provider is registered and resolved under in the locator. */
1
+ import type { ActorContext, InstanceLocator, OwnedLocator, RegistrableLocator } from '@ariestools/actor-model';
2
+ import type { Logger } from '@ariestools/sdk';
3
+ /**
4
+ Identifier a provider is registered and resolved under in the locator.
5
+ */
3
6
  export type DappMoniker = string;
4
- export type ReadyState = 'pending' | 'ready' | 'failed';
5
7
  /**
6
- * The shared context carried by the process-wide locator. Kept intentionally
7
- * minimal a `logger` is all an actor requires. Telemetry (meter/tracer) can
8
- * be added here when the base graduates into the shared cli/actor toolkit.
8
+ * The shared context carried by the process-wide locator. A `logger` is
9
+ * required for dapp actors; telemetry providers and a status reporter are
10
+ * available via the inherited {@link ActorContext} fields when wired.
9
11
  */
10
- export interface DappContext {
12
+ export interface DappContext extends ActorContext {
11
13
  logger: Logger;
12
14
  }
13
15
  /**
14
- * Small service-locator seam an actor uses to resolve its providers by moniker.
15
- * A dapp-owned stand-in for the chain's `ProviderFactoryLocatorInstance` that
16
- * avoids the chain `LocatorConfig`/protocol coupling. The daemon builds one and
17
- * shares the same instance across every actor (see `bootDappActors`).
16
+ * The dapp locator contract: the actor-kit locator seam carrying the dapp
17
+ * context, with registration, ownership, and a `has` probe. The daemon builds
18
+ * one and shares the same instance across every actor (see `bootDappActors`).
18
19
  */
19
- export interface DappProviderLocator {
20
- readonly context: DappContext;
21
- /** Release owned resources (e.g. an S3 client constructed by the locator). */
22
- destroy(): void;
23
- getInstance<T>(moniker: DappMoniker): Promise<T>;
20
+ export type DappProviderLocator = InstanceLocator<DappContext> & OwnedLocator & RegistrableLocator & {
24
21
  has(moniker: DappMoniker): boolean;
25
- register(moniker: DappMoniker, instance: unknown): void;
26
- tryGetInstance<T>(moniker: DappMoniker): Promise<T | undefined>;
27
- }
28
- /** Base params every dapp actor takes: the shared, process-wide locator. */
29
- export interface ActorParams extends CreatableParams {
30
- locator: DappProviderLocator;
31
- /**
32
- * Max time to wait for in-flight timer work on stop after aborting the
33
- * signal. When omitted, stop waits until in-flight work settles.
34
- */
35
- shutdownTimeoutMs?: number;
36
- }
22
+ };
37
23
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/actor/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAA;AAE9D,6EAA6E;AAC7E,MAAM,MAAM,WAAW,GAAG,MAAM,CAAA;AAEhC,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,OAAO,GAAG,QAAQ,CAAA;AAEvD;;;;GAIG;AACH,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAA;CACf;AAED;;;;;GAKG;AACH,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAA;IAC7B,8EAA8E;IAC9E,OAAO,IAAI,IAAI,CAAA;IACf,WAAW,CAAC,CAAC,EAAE,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,CAAC,CAAC,CAAA;IAChD,GAAG,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAA;IAClC,QAAQ,CAAC,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,OAAO,GAAG,IAAI,CAAA;IACvD,cAAc,CAAC,CAAC,EAAE,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC,CAAA;CAChE;AAED,4EAA4E;AAC5E,MAAM,WAAW,WAAY,SAAQ,eAAe;IAClD,OAAO,EAAE,mBAAmB,CAAA;IAC5B;;;OAGG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAA;CAC3B"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/actor/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,YAAY,EACZ,eAAe,EACf,YAAY,EACZ,kBAAkB,EACnB,MAAM,yBAAyB,CAAA;AAChC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAA;AAE7C;;EAEE;AACF,MAAM,MAAM,WAAW,GAAG,MAAM,CAAA;AAEhC;;;;GAIG;AACH,MAAM,WAAW,WAAY,SAAQ,YAAY;IAC/C,MAAM,EAAE,MAAM,CAAA;CACf;AAED;;;;GAIG;AACH,MAAM,MAAM,mBAAmB,GAAG,eAAe,CAAC,WAAW,CAAC,GAAG,YAAY,GAAG,kBAAkB,GAAG;IACnG,GAAG,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAA;CACnC,CAAA"}
@@ -5,7 +5,9 @@ export interface LoadReducerOptions {
5
5
  * Defaults to trying `reducer`, then `default`.
6
6
  */
7
7
  exportName?: string;
8
- /** Absolute or relative path to a `.mjs` file, or a resolvable package export. */
8
+ /**
9
+ Absolute or relative path to a `.mjs` file, or a resolvable package export.
10
+ */
9
11
  spec: string;
10
12
  }
11
13
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"loadReducer.d.ts","sourceRoot":"","sources":["../../../src/bin/loadReducer.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAA;AAI5D,MAAM,WAAW,kBAAkB;IACjC;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,kFAAkF;IAClF,IAAI,EAAE,MAAM,CAAA;CACb;AA6DD;;;;GAIG;AACH,wBAAsB,WAAW,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,WAAW,CAAC,CAOnF"}
1
+ {"version":3,"file":"loadReducer.d.ts","sourceRoot":"","sources":["../../../src/bin/loadReducer.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAA;AAI5D,MAAM,WAAW,kBAAkB;IACjC;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB;;MAEE;IACF,IAAI,EAAE,MAAM,CAAA;CACb;AA6DD;;;;GAIG;AACH,wBAAsB,WAAW,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,WAAW,CAAC,CAOnF"}
@@ -17,9 +17,10 @@ export interface DappActorSpec {
17
17
  }
18
18
  /**
19
19
  * Creates and starts one {@link DappActor} per spec, all sharing the single
20
- * process-wide locator. On partial failure, actors already started are stopped
21
- * before the error is rethrown. Returns them so the caller can stop them on
22
- * shutdown.
20
+ * process-wide locator. A thin wrapper over actor-kit's `bootActors`: on
21
+ * partial failure, actors already started are stopped (with shutdown
22
+ * fallback) before the error is rethrown. Returns them so the caller can
23
+ * stop them on shutdown.
23
24
  */
24
25
  export declare function bootDappActors(locator: DappProviderLocator, specs: readonly DappActorSpec[]): Promise<DappActor[]>;
25
26
  //# sourceMappingURL=bootDappActors.d.ts.map