@ariestools/aries-dapp-core 0.1.7

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/README.md ADDED
@@ -0,0 +1,38 @@
1
+ # @ariestools/aries-dapp-core
2
+
3
+ > **Dev only.** This is the compute half of the local `aries dapp` backend, a
4
+ > development fixture with no auth or metrics and memory-only storage. Not for
5
+ > production at this time.
6
+
7
+ The brains of a local dapp backend. It pairs with the storage server in
8
+ [`@ariestools/aries-dapp-serve`](../dapp-serve): the server holds three buckets
9
+ (`data`, `state`, `index`), and this package derives the mutable buckets from
10
+ the immutable one on an interval.
11
+
12
+ ## Pieces
13
+
14
+ - **`AbstractActor`** — a lean, dapp-owned fork of the xl1 `ActorV3` pattern:
15
+ the `create`/`start`/`stop` lifecycle plus non-overlapping interval timers
16
+ (`registerTimer`) and a readiness contract. It swaps the chain's
17
+ `ProviderFactoryLocator`/`LocatorConfig` machinery for the small
18
+ `DappProviderLocator` seam, so an actor resolves providers by moniker without
19
+ the chain protocol config model. Intended to graduate into a shared cli/actor
20
+ toolkit — and, later, xl1-protocol — where it can re-adopt the real locator.
21
+ - **`DappProviderLocator` / `createDappLocator`** — the **process-wide** service
22
+ locator, built once and shared across every actor (xl1-cli style). It
23
+ pre-registers an S3-backed `DappBucketStore` per bucket keyed by moniker.
24
+ - **`DappActor`** — resolves the three stores from the locator and drives its
25
+ `DappReducer` on an interval to keep `state`/`index` derived from `data`.
26
+ - **`DappReducer`** — the pluggable unit of dapp logic (`reduce({data, state,
27
+ index, logger})`). `noopReducer` is the default; supply a real one to derive.
28
+ - **`bootDappActors`** — creates and starts N actors against one shared locator.
29
+
30
+ ## Daemon
31
+
32
+ The composed daemon bin (`dist/bin/dappServer.mjs`) starts the storage server
33
+ and, in the same process, the locator and actors. `aries dapp up` spawns it.
34
+ Env config: `DAPP_PORT` (default 8801), `HOST` (default 127.0.0.1),
35
+ `DAPP_BACKING` (default `memory`), `DAPP_PUBLIC_HOST`, `DAPP_TLS_CERT`,
36
+ `DAPP_TLS_KEY`, and `DAPP_REDUCE_INTERVAL_MS` (default 5000). Under
37
+ `--ssl auto` the daemon exports the local CA via `NODE_EXTRA_CA_CERTS` so the
38
+ in-process S3 client trusts the HTTPS origin.
@@ -0,0 +1,389 @@
1
+ #!/usr/bin/env node
2
+ import { readFileSync } from "node:fs";
3
+ import { DAPP_BACKINGS, DAPP_BUCKETS, isDappBackingKind, resolveBacking, startDappServer } from "@ariestools/aries-dapp-serve";
4
+ import { AbstractCreatable, ConsoleLogger, IdLogger, assertEx, creatable } from "@ariestools/sdk";
5
+ import { GetObjectCommand, ListObjectsV2Command, PutObjectCommand, S3Client } from "@aws-sdk/client-s3";
6
+ //#region src/actor/AbstractActor.ts
7
+ function createDeferred() {
8
+ let resolve;
9
+ let reject;
10
+ return {
11
+ promise: new Promise((res, rej) => {
12
+ resolve = res;
13
+ reject = rej;
14
+ }),
15
+ reject,
16
+ resolve
17
+ };
18
+ }
19
+ /**
20
+ * Lean, dapp-owned fork of the xl1 `ActorV3` pattern: the create/start/stop
21
+ * lifecycle from `AbstractCreatable`, plus non-overlapping interval timers and
22
+ * a readiness contract. It deliberately swaps the chain's
23
+ * `ProviderFactoryLocator`/`LocatorConfig` machinery for the small
24
+ * {@link DappProviderLocator} seam, so a dapp actor resolves providers by
25
+ * moniker without dragging the chain protocol config model in.
26
+ *
27
+ * The locator is process-wide: the daemon builds it once and passes the same
28
+ * instance to every actor via `params.locator` (see `bootDappActors`). When
29
+ * this graduates into a shared cli/actor toolkit — and, later, xl1-protocol —
30
+ * this base can re-adopt the real locator.
31
+ */
32
+ var AbstractActor = class extends AbstractCreatable {
33
+ _intervals = /* @__PURE__ */ new Map();
34
+ _timeouts = /* @__PURE__ */ new Map();
35
+ _idLogger;
36
+ _inFlight = /* @__PURE__ */ new Map();
37
+ _readyDeferred = createDeferred();
38
+ _readyError;
39
+ _readyState = "pending";
40
+ get logger() {
41
+ this._idLogger ??= new IdLogger(assertEx(this.context.logger, () => `Logger is required in context for actor ${this.name}.`), () => this.name);
42
+ return this._idLogger;
43
+ }
44
+ get readyError() {
45
+ return this._readyError;
46
+ }
47
+ get readyState() {
48
+ return this._readyState;
49
+ }
50
+ get context() {
51
+ return this.locator.context;
52
+ }
53
+ get locator() {
54
+ return this.params.locator;
55
+ }
56
+ static async paramsHandler(params) {
57
+ const inParams = params ?? {};
58
+ const baseParams = await super.paramsHandler({
59
+ ...inParams,
60
+ name: inParams.name ?? "UnknownActor"
61
+ });
62
+ const locator = assertEx(inParams.locator, () => `params.locator is required for actor ${String(baseParams.name)}.`);
63
+ return {
64
+ ...baseParams,
65
+ locator
66
+ };
67
+ }
68
+ /**
69
+ * Register a recurring task. The interval only fires while the actor is
70
+ * `started`, and a run is skipped if the previous one is still in flight, so
71
+ * a slow pass can never stack on top of itself. Must be called from
72
+ * `startHandler` (guards on `starting` status), mirroring the xl1 actor.
73
+ */
74
+ registerTimer(timerName, callback, dueTimeMs, periodMs) {
75
+ if (this.status !== "starting") {
76
+ this.logger.warn(`Cannot register timer '${timerName}' because actor is not starting.`);
77
+ return;
78
+ }
79
+ const tick = () => {
80
+ if (this.status !== "started" || !this._intervals.has(timerName)) return;
81
+ if (this._inFlight.has(timerName)) {
82
+ this.logger.warn(`Skipping timer '${this.name}:${timerName}' because the previous run is still in flight.`);
83
+ return;
84
+ }
85
+ const run = (async () => {
86
+ const startTime = Date.now();
87
+ try {
88
+ await callback();
89
+ } catch (error) {
90
+ const err = error instanceof Error ? error : new Error(String(error));
91
+ this.logger.error(`Error in timer '${this.name}:${timerName}': ${err.message}`);
92
+ } finally {
93
+ const duration = Date.now() - startTime;
94
+ if (duration > periodMs) this.logger.warn(`Timer '${this.name}:${timerName}' took ${duration}ms, longer than its ${periodMs}ms period.`);
95
+ }
96
+ })();
97
+ this._inFlight.set(timerName, run.finally(() => {
98
+ this._inFlight.delete(timerName);
99
+ }));
100
+ };
101
+ const timeoutId = setTimeout(() => {
102
+ this._intervals.set(timerName, setInterval(tick, periodMs));
103
+ }, dueTimeMs);
104
+ this._timeouts.set(timerName, timeoutId);
105
+ }
106
+ /**
107
+ * Run the warm-pass once. Not driven automatically here (no orchestrator);
108
+ * a caller invokes it after `start()` if it wants `whenReady()` to resolve.
109
+ */
110
+ async runReadyHandler() {
111
+ if (this._readyState !== "pending") return;
112
+ try {
113
+ await this.readyHandler();
114
+ this._readyState = "ready";
115
+ this._readyDeferred.resolve();
116
+ } catch (error) {
117
+ const err = error instanceof Error ? error : new Error(String(error));
118
+ this._readyState = "failed";
119
+ this._readyError = err;
120
+ this._readyDeferred.reject(err);
121
+ throw err;
122
+ }
123
+ }
124
+ async stopHandler() {
125
+ await super.stopHandler();
126
+ for (const timeoutRef of this._timeouts.values()) clearTimeout(timeoutRef);
127
+ this._timeouts.clear();
128
+ for (const intervalRef of this._intervals.values()) clearInterval(intervalRef);
129
+ this._intervals.clear();
130
+ await Promise.allSettled(this._inFlight.values());
131
+ this._inFlight.clear();
132
+ }
133
+ async whenReady() {
134
+ await this._readyDeferred.promise;
135
+ }
136
+ /** Override to prove the actor can do useful work. Default: no-op. */
137
+ async readyHandler() {}
138
+ };
139
+ //#endregion
140
+ //#region src/providers/monikers.ts
141
+ /**
142
+ * Provider monikers for the three dapp buckets. An actor declares these in its
143
+ * `static dependencies` and resolves them from the locator at create time.
144
+ */
145
+ const DappDataStoreMoniker = "DappDataStore";
146
+ const DappStateStoreMoniker = "DappStateStore";
147
+ const DappIndexStoreMoniker = "DappIndexStore";
148
+ //#endregion
149
+ //#region \0@oxc-project+runtime@0.140.0/helpers/esm/decorate.js
150
+ function __decorate(decorators, target, key, desc) {
151
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
152
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
153
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
154
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
155
+ }
156
+ //#endregion
157
+ //#region src/DappActor.ts
158
+ const DEFAULT_REDUCE_INTERVAL_MS = 5e3;
159
+ const DEFAULT_FIRST_RUN_DELAY_MS = 2e3;
160
+ let DappActor = class DappActor extends AbstractActor {
161
+ static dependencies = [
162
+ DappDataStoreMoniker,
163
+ DappStateStoreMoniker,
164
+ DappIndexStoreMoniker
165
+ ];
166
+ _data;
167
+ _index;
168
+ _state;
169
+ async createHandler() {
170
+ await super.createHandler();
171
+ this._data = await this.locator.getInstance(DappDataStoreMoniker);
172
+ this._state = await this.locator.getInstance(DappStateStoreMoniker);
173
+ this._index = await this.locator.getInstance(DappIndexStoreMoniker);
174
+ }
175
+ async startHandler() {
176
+ await super.startHandler();
177
+ const interval = this.params.reduceIntervalMs ?? DEFAULT_REDUCE_INTERVAL_MS;
178
+ const firstRunDelay = this.params.firstRunDelayMs ?? DEFAULT_FIRST_RUN_DELAY_MS;
179
+ this.registerTimer("DappReduce", async () => {
180
+ await this.runReducePass();
181
+ }, firstRunDelay, interval);
182
+ this.logger.info(`DappActor started: reducer '${this.params.reducer.name}' every ${interval}ms`);
183
+ }
184
+ async runReducePass() {
185
+ await this.params.reducer.reduce({
186
+ data: this._data,
187
+ index: this._index,
188
+ logger: this.logger,
189
+ state: this._state
190
+ });
191
+ }
192
+ };
193
+ DappActor = __decorate([creatable()], DappActor);
194
+ //#endregion
195
+ //#region src/boot/bootDappActors.ts
196
+ /**
197
+ * Creates and starts one {@link DappActor} per spec, all sharing the single
198
+ * process-wide locator. Returns them so the caller can stop them on shutdown.
199
+ */
200
+ async function bootDappActors(locator, specs) {
201
+ const actors = [];
202
+ for (const spec of specs) {
203
+ const params = {
204
+ locator,
205
+ name: spec.name,
206
+ reducer: spec.reducer,
207
+ ...spec.reduceIntervalMs !== void 0 && { reduceIntervalMs: spec.reduceIntervalMs }
208
+ };
209
+ const actor = await DappActor.create(params);
210
+ await actor.start();
211
+ actors.push(actor);
212
+ }
213
+ return actors;
214
+ }
215
+ //#endregion
216
+ //#region src/providers/DappBucketStore.ts
217
+ const DEFAULT_CREDENTIAL = "S3RVER";
218
+ function isNotFound(error) {
219
+ const name = error.name;
220
+ return name === "NoSuchKey" || name === "NotFound";
221
+ }
222
+ /**
223
+ * S3-backed {@link DappBucketStore} pointed at the local dapp server. Uses
224
+ * path-style addressing so `/{bucket}/{key}` resolves as a subfolder of the
225
+ * one origin. Under `--ssl auto` the server speaks HTTPS with a locally
226
+ * trusted certificate; the daemon exports its CA via `NODE_EXTRA_CA_CERTS`, so
227
+ * this client trusts it without any per-request handler configuration.
228
+ */
229
+ function createS3BucketStore(options) {
230
+ const { bucket } = options;
231
+ const client = new S3Client({
232
+ endpoint: options.endpoint,
233
+ region: "us-east-1",
234
+ forcePathStyle: true,
235
+ credentials: {
236
+ accessKeyId: options.accessKeyId ?? DEFAULT_CREDENTIAL,
237
+ secretAccessKey: options.secretAccessKey ?? DEFAULT_CREDENTIAL
238
+ }
239
+ });
240
+ return {
241
+ bucket,
242
+ async get(key) {
243
+ try {
244
+ return await (await client.send(new GetObjectCommand({
245
+ Bucket: bucket,
246
+ Key: key
247
+ }))).Body?.transformToByteArray();
248
+ } catch (error) {
249
+ if (isNotFound(error)) return void 0;
250
+ throw error;
251
+ }
252
+ },
253
+ async put(key, body) {
254
+ await client.send(new PutObjectCommand({
255
+ Bucket: bucket,
256
+ Key: key,
257
+ Body: body
258
+ }));
259
+ },
260
+ async list(prefix) {
261
+ const keys = [];
262
+ let token;
263
+ do {
264
+ const response = await client.send(new ListObjectsV2Command({
265
+ Bucket: bucket,
266
+ Prefix: prefix,
267
+ ContinuationToken: token
268
+ }));
269
+ for (const item of response.Contents ?? []) if (item.Key !== void 0) keys.push(item.Key);
270
+ token = response.IsTruncated === true ? response.NextContinuationToken : void 0;
271
+ } while (token !== void 0);
272
+ return keys;
273
+ }
274
+ };
275
+ }
276
+ //#endregion
277
+ //#region src/locator/createDappLocator.ts
278
+ /**
279
+ * Builds the process-wide locator: one instance, shared across every actor
280
+ * (xl1-cli style). It pre-registers an S3-backed store per bucket keyed by
281
+ * moniker; extra providers can be `register`ed before actors are created.
282
+ */
283
+ function createDappLocator(options) {
284
+ const logger = options.logger ?? new ConsoleLogger();
285
+ const bucketOptions = {
286
+ endpoint: options.endpoint,
287
+ ...options.accessKeyId !== void 0 && { accessKeyId: options.accessKeyId },
288
+ ...options.secretAccessKey !== void 0 && { secretAccessKey: options.secretAccessKey }
289
+ };
290
+ const instances = /* @__PURE__ */ new Map([
291
+ [DappDataStoreMoniker, createS3BucketStore({
292
+ ...bucketOptions,
293
+ bucket: "data"
294
+ })],
295
+ [DappStateStoreMoniker, createS3BucketStore({
296
+ ...bucketOptions,
297
+ bucket: "state"
298
+ })],
299
+ [DappIndexStoreMoniker, createS3BucketStore({
300
+ ...bucketOptions,
301
+ bucket: "index"
302
+ })]
303
+ ]);
304
+ return {
305
+ context: { logger },
306
+ has(moniker) {
307
+ return instances.has(moniker);
308
+ },
309
+ register(moniker, instance) {
310
+ instances.set(moniker, instance);
311
+ },
312
+ async getInstance(moniker) {
313
+ const found = instances.get(moniker);
314
+ if (found === void 0) throw new Error(`No provider registered for moniker "${moniker}"`);
315
+ return found;
316
+ },
317
+ async tryGetInstance(moniker) {
318
+ return instances.get(moniker);
319
+ }
320
+ };
321
+ }
322
+ //#endregion
323
+ //#region src/reducer/DappReducer.ts
324
+ /**
325
+ * Default reducer: does nothing. The harness runs the full timer/provider
326
+ * spine with this in place; supply a real reducer to derive `state` and
327
+ * `index` from `data`.
328
+ */
329
+ const noopReducer = {
330
+ name: "noop",
331
+ async reduce() {}
332
+ };
333
+ //#endregion
334
+ //#region src/bin/dappServer.ts
335
+ /**
336
+ * Composed dapp daemon: boots the S3-compatible storage server (from
337
+ * `@ariestools/aries-dapp-serve`) and, in the same process, a shared
338
+ * process-wide locator plus the DappActor(s) that derive `state`/`index` from
339
+ * `data` on an interval. Spawned by `aries dapp up`.
340
+ */
341
+ const PORT = Number(process.env.DAPP_PORT ?? 8801);
342
+ const HOST = process.env.HOST ?? "127.0.0.1";
343
+ const BACKING = process.env.DAPP_BACKING ?? "memory";
344
+ const PUBLIC_HOST = process.env.DAPP_PUBLIC_HOST;
345
+ const TLS_CERT_PATH = process.env.DAPP_TLS_CERT;
346
+ const TLS_KEY_PATH = process.env.DAPP_TLS_KEY;
347
+ const REDUCE_INTERVAL_MS = Number(process.env.DAPP_REDUCE_INTERVAL_MS ?? 5e3);
348
+ async function main() {
349
+ if (!isDappBackingKind(BACKING)) throw new Error(`Unsupported DAPP_BACKING '${BACKING}' (supported: ${DAPP_BACKINGS.join(", ")})`);
350
+ if (TLS_CERT_PATH === void 0 !== (TLS_KEY_PATH === void 0)) throw new Error("DAPP_TLS_CERT and DAPP_TLS_KEY must be provided together");
351
+ const backing = resolveBacking(BACKING);
352
+ const server = await startDappServer({
353
+ backing,
354
+ host: HOST,
355
+ port: PORT,
356
+ publicHost: PUBLIC_HOST,
357
+ tls: TLS_CERT_PATH === void 0 || TLS_KEY_PATH === void 0 ? void 0 : {
358
+ cert: readFileSync(TLS_CERT_PATH),
359
+ key: readFileSync(TLS_KEY_PATH)
360
+ }
361
+ });
362
+ const logger = new ConsoleLogger();
363
+ const actors = await bootDappActors(createDappLocator({
364
+ endpoint: server.baseUrl,
365
+ logger
366
+ }), [{
367
+ name: "DappActor",
368
+ reducer: noopReducer,
369
+ reduceIntervalMs: REDUCE_INTERVAL_MS
370
+ }]);
371
+ console.log(`dapp server listening at ${server.baseUrl}\n` + DAPP_BUCKETS.map((bucket) => ` /${bucket.padEnd(5)} ${server.baseUrl}/${bucket}`).join("\n") + `\nbacking: ${backing.description} — ${backing.directory}\nactors: ${actors.length} (reducer '${noopReducer.name}', every ${REDUCE_INTERVAL_MS}ms)`);
372
+ const shutdown = async () => {
373
+ for (const actor of actors) await actor.stop();
374
+ await server.close();
375
+ process.exit(0);
376
+ };
377
+ process.on("SIGINT", () => {
378
+ shutdown();
379
+ });
380
+ process.on("SIGTERM", () => {
381
+ shutdown();
382
+ });
383
+ }
384
+ main().catch((error) => {
385
+ console.error(error);
386
+ process.exit(1);
387
+ });
388
+ //#endregion
389
+ export {};
@@ -0,0 +1,26 @@
1
+ import { AbstractActor } from './actor/AbstractActor.ts';
2
+ import type { ActorParams } from './actor/types.ts';
3
+ import type { DappBucketStore } from './providers/DappBucketStore.ts';
4
+ 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
+ reduceIntervalMs?: number;
9
+ reducer: DappReducer;
10
+ }
11
+ /**
12
+ * The stock dapp actor: resolves the three bucket stores from the shared
13
+ * locator, then drives its reducer on an interval to keep `state` and `index`
14
+ * derived from `data`. Multiple actors (each with its own reducer) can share
15
+ * one locator; this is the default single-reducer instance the daemon boots.
16
+ */
17
+ export declare class DappActor extends AbstractActor<DappActorParams> {
18
+ static readonly dependencies: readonly ["DappDataStore", "DappStateStore", "DappIndexStore"];
19
+ protected _data: DappBucketStore;
20
+ protected _index: DappBucketStore;
21
+ protected _state: DappBucketStore;
22
+ createHandler(): Promise<void>;
23
+ protected startHandler(): Promise<void>;
24
+ private runReducePass;
25
+ }
26
+ //# sourceMappingURL=DappActor.d.ts.map
@@ -0,0 +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,eAAe,EAAE,MAAM,gCAAgC,CAAA;AAIrE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAA;AAE3D,MAAM,WAAW,eAAgB,SAAQ,WAAW;IAClD,8DAA8D;IAC9D,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,OAAO,EAAE,WAAW,CAAA;CACrB;AAKD;;;;;GAKG;AACH,qBACa,SAAU,SAAQ,aAAa,CAAC,eAAe,CAAC;IAC3D,MAAM,CAAC,QAAQ,CAAC,YAAY,iEAIlB;IAEV,SAAS,CAAC,KAAK,EAAG,eAAe,CAAA;IACjC,SAAS,CAAC,MAAM,EAAG,eAAe,CAAA;IAClC,SAAS,CAAC,MAAM,EAAG,eAAe,CAAA;IAEnB,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;cAOpB,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;YAUxC,aAAa;CAQ5B"}
@@ -0,0 +1,48 @@
1
+ import type { CreatableInstance, Logger } from '@ariestools/sdk';
2
+ import { AbstractCreatable } from '@ariestools/sdk';
3
+ import type { ActorParams, DappContext, DappProviderLocator, ReadyState } from './types.ts';
4
+ /**
5
+ * Lean, dapp-owned fork of the xl1 `ActorV3` pattern: the create/start/stop
6
+ * lifecycle from `AbstractCreatable`, plus non-overlapping interval timers and
7
+ * a readiness contract. It deliberately swaps the chain's
8
+ * `ProviderFactoryLocator`/`LocatorConfig` machinery for the small
9
+ * {@link DappProviderLocator} seam, so a dapp actor resolves providers by
10
+ * moniker without dragging the chain protocol config model in.
11
+ *
12
+ * The locator is process-wide: the daemon builds it once and passes the same
13
+ * instance to every actor via `params.locator` (see `bootDappActors`). When
14
+ * this graduates into a shared cli/actor toolkit — and, later, xl1-protocol —
15
+ * this base can re-adopt the real locator.
16
+ */
17
+ export declare abstract class AbstractActor<TParams extends ActorParams = ActorParams> extends AbstractCreatable<TParams> {
18
+ protected readonly _intervals: Map<string, NodeJS.Timeout>;
19
+ protected readonly _timeouts: Map<string, NodeJS.Timeout>;
20
+ private _idLogger?;
21
+ private readonly _inFlight;
22
+ private readonly _readyDeferred;
23
+ private _readyError?;
24
+ private _readyState;
25
+ get logger(): Logger;
26
+ get readyError(): Error | undefined;
27
+ get readyState(): ReadyState;
28
+ protected get context(): DappContext;
29
+ protected get locator(): DappProviderLocator;
30
+ static paramsHandler<T extends CreatableInstance>(params?: Partial<T['params']>): Promise<T['params']>;
31
+ /**
32
+ * Register a recurring task. The interval only fires while the actor is
33
+ * `started`, and a run is skipped if the previous one is still in flight, so
34
+ * a slow pass can never stack on top of itself. Must be called from
35
+ * `startHandler` (guards on `starting` status), mirroring the xl1 actor.
36
+ */
37
+ registerTimer(timerName: string, callback: () => Promise<void>, dueTimeMs: number, periodMs: number): void;
38
+ /**
39
+ * Run the warm-pass once. Not driven automatically here (no orchestrator);
40
+ * a caller invokes it after `start()` if it wants `whenReady()` to resolve.
41
+ */
42
+ runReadyHandler(): Promise<void>;
43
+ stopHandler(): Promise<void>;
44
+ whenReady(): Promise<void>;
45
+ /** Override to prove the actor can do useful work. Default: no-op. */
46
+ protected readyHandler(): Promise<void>;
47
+ }
48
+ //# sourceMappingURL=AbstractActor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AbstractActor.d.ts","sourceRoot":"","sources":["../../../src/actor/AbstractActor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAA;AAChE,OAAO,EACL,iBAAiB,EAClB,MAAM,iBAAiB,CAAA;AAExB,OAAO,KAAK,EACV,WAAW,EAAE,WAAW,EAAE,mBAAmB,EAAE,UAAU,EAC1D,MAAM,YAAY,CAAA;AAoBnB;;;;;;;;;;;;GAYG;AACH,8BAAsB,aAAa,CAAC,OAAO,SAAS,WAAW,GAAG,WAAW,CAAE,SAAQ,iBAAiB,CAAC,OAAO,CAAC;IAC/G,SAAS,CAAC,QAAQ,CAAC,UAAU,8BAAoC;IACjE,SAAS,CAAC,QAAQ,CAAC,SAAS,8BAAoC;IAEhE,OAAO,CAAC,SAAS,CAAC,CAAQ;IAC1B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAmC;IAC7D,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAyB;IACxD,OAAO,CAAC,WAAW,CAAC,CAAO;IAC3B,OAAO,CAAC,WAAW,CAAwB;IAE3C,IAAa,MAAM,IAAI,MAAM,CAM5B;IAED,IAAI,UAAU,IAAI,KAAK,GAAG,SAAS,CAElC;IAED,IAAI,UAAU,IAAI,UAAU,CAE3B;IAED,SAAS,KAAK,OAAO,IAAI,WAAW,CAEnC;IAED,SAAS,KAAK,OAAO,IAAI,mBAAmB,CAE3C;WAEqB,aAAa,CAAC,CAAC,SAAS,iBAAiB,EAAE,MAAM,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;IAOrH;;;;;OAKG;IACH,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;IAmC1G;;;OAGG;IACG,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;IAevB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;IAUrC,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;IAIhC,sEAAsE;cACtD,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;CAG9C"}
@@ -0,0 +1,30 @@
1
+ import type { CreatableParams, Logger } from '@ariestools/sdk';
2
+ /** Identifier a provider is registered and resolved under in the locator. */
3
+ export type DappMoniker = string;
4
+ export type ReadyState = 'pending' | 'ready' | 'failed';
5
+ /**
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.
9
+ */
10
+ export interface DappContext {
11
+ logger: Logger;
12
+ }
13
+ /**
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`).
18
+ */
19
+ export interface DappProviderLocator {
20
+ readonly context: DappContext;
21
+ getInstance<T>(moniker: DappMoniker): Promise<T>;
22
+ has(moniker: DappMoniker): boolean;
23
+ register(moniker: DappMoniker, instance: unknown): void;
24
+ tryGetInstance<T>(moniker: DappMoniker): Promise<T | undefined>;
25
+ }
26
+ /** Base params every dapp actor takes: the shared, process-wide locator. */
27
+ export interface ActorParams extends CreatableParams {
28
+ locator: DappProviderLocator;
29
+ }
30
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +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,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;CAC7B"}
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Composed dapp daemon: boots the S3-compatible storage server (from
4
+ * `@ariestools/aries-dapp-serve`) and, in the same process, a shared
5
+ * process-wide locator plus the DappActor(s) that derive `state`/`index` from
6
+ * `data` on an interval. Spawned by `aries dapp up`.
7
+ */
8
+ export {};
9
+ //# sourceMappingURL=dappServer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dappServer.d.ts","sourceRoot":"","sources":["../../../src/bin/dappServer.ts"],"names":[],"mappings":";AAEA;;;;;GAKG"}
@@ -0,0 +1,14 @@
1
+ import type { DappProviderLocator } from '../actor/types.ts';
2
+ import { DappActor } from '../DappActor.ts';
3
+ import type { DappReducer } from '../reducer/DappReducer.ts';
4
+ export interface DappActorSpec {
5
+ name: string;
6
+ reduceIntervalMs?: number;
7
+ reducer: DappReducer;
8
+ }
9
+ /**
10
+ * Creates and starts one {@link DappActor} per spec, all sharing the single
11
+ * process-wide locator. Returns them so the caller can stop them on shutdown.
12
+ */
13
+ export declare function bootDappActors(locator: DappProviderLocator, specs: readonly DappActorSpec[]): Promise<DappActor[]>;
14
+ //# sourceMappingURL=bootDappActors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bootDappActors.d.ts","sourceRoot":"","sources":["../../../src/boot/bootDappActors.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAA;AAE5D,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAC3C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAA;AAE5D,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAA;IACZ,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,OAAO,EAAE,WAAW,CAAA;CACrB;AAED;;;GAGG;AACH,wBAAsB,cAAc,CAClC,OAAO,EAAE,mBAAmB,EAC5B,KAAK,EAAE,SAAS,aAAa,EAAE,GAC9B,OAAO,CAAC,SAAS,EAAE,CAAC,CActB"}
@@ -0,0 +1,14 @@
1
+ export { AbstractActor } from './actor/AbstractActor.ts';
2
+ export type { ActorParams, DappContext, DappMoniker, DappProviderLocator, ReadyState, } from './actor/types.ts';
3
+ export type { DappActorSpec } from './boot/bootDappActors.ts';
4
+ export { bootDappActors } from './boot/bootDappActors.ts';
5
+ export type { DappActorParams } from './DappActor.ts';
6
+ export { DappActor } from './DappActor.ts';
7
+ export type { CreateDappLocatorOptions } from './locator/createDappLocator.ts';
8
+ export { createDappLocator } from './locator/createDappLocator.ts';
9
+ export type { DappBucketStore, S3DappBucketStoreOptions } from './providers/DappBucketStore.ts';
10
+ export { createS3BucketStore } from './providers/DappBucketStore.ts';
11
+ export { DappDataStoreMoniker, DappIndexStoreMoniker, DappStateStoreMoniker, } from './providers/monikers.ts';
12
+ export type { DappReduceContext, DappReducer } from './reducer/DappReducer.ts';
13
+ export { noopReducer } from './reducer/DappReducer.ts';
14
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAA;AACxD,YAAY,EACV,WAAW,EAAE,WAAW,EAAE,WAAW,EAAE,mBAAmB,EAAE,UAAU,GACvE,MAAM,kBAAkB,CAAA;AACzB,YAAY,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAA;AAC7D,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAA;AACzD,YAAY,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAA;AACrD,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAC1C,YAAY,EAAE,wBAAwB,EAAE,MAAM,gCAAgC,CAAA;AAC9E,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAA;AAClE,YAAY,EAAE,eAAe,EAAE,wBAAwB,EAAE,MAAM,gCAAgC,CAAA;AAC/F,OAAO,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAA;AACpE,OAAO,EACL,oBAAoB,EAAE,qBAAqB,EAAE,qBAAqB,GACnE,MAAM,yBAAyB,CAAA;AAChC,YAAY,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAA;AAC9E,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAA"}
@@ -0,0 +1,318 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
4
+ var __decorateClass = (decorators, target, key, kind) => {
5
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
6
+ for (var i = decorators.length - 1, decorator; i >= 0; i--)
7
+ if (decorator = decorators[i])
8
+ result = (kind ? decorator(target, key, result) : decorator(result)) || result;
9
+ if (kind && result) __defProp(target, key, result);
10
+ return result;
11
+ };
12
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
13
+
14
+ // src/actor/AbstractActor.ts
15
+ import {
16
+ AbstractCreatable,
17
+ assertEx,
18
+ IdLogger
19
+ } from "@ariestools/sdk";
20
+ function createDeferred() {
21
+ let resolve;
22
+ let reject;
23
+ const promise = new Promise((res, rej) => {
24
+ resolve = res;
25
+ reject = rej;
26
+ });
27
+ return {
28
+ promise,
29
+ reject,
30
+ resolve
31
+ };
32
+ }
33
+ var AbstractActor = class extends AbstractCreatable {
34
+ _intervals = /* @__PURE__ */ new Map();
35
+ _timeouts = /* @__PURE__ */ new Map();
36
+ _idLogger;
37
+ _inFlight = /* @__PURE__ */ new Map();
38
+ _readyDeferred = createDeferred();
39
+ _readyError;
40
+ _readyState = "pending";
41
+ get logger() {
42
+ this._idLogger ??= new IdLogger(
43
+ assertEx(this.context.logger, () => `Logger is required in context for actor ${this.name}.`),
44
+ () => this.name
45
+ );
46
+ return this._idLogger;
47
+ }
48
+ get readyError() {
49
+ return this._readyError;
50
+ }
51
+ get readyState() {
52
+ return this._readyState;
53
+ }
54
+ get context() {
55
+ return this.locator.context;
56
+ }
57
+ get locator() {
58
+ return this.params.locator;
59
+ }
60
+ static async paramsHandler(params) {
61
+ const inParams = params ?? {};
62
+ const baseParams = await super.paramsHandler({ ...inParams, name: inParams.name ?? "UnknownActor" });
63
+ const locator = assertEx(inParams.locator, () => `params.locator is required for actor ${String(baseParams.name)}.`);
64
+ return { ...baseParams, locator };
65
+ }
66
+ /**
67
+ * Register a recurring task. The interval only fires while the actor is
68
+ * `started`, and a run is skipped if the previous one is still in flight, so
69
+ * a slow pass can never stack on top of itself. Must be called from
70
+ * `startHandler` (guards on `starting` status), mirroring the xl1 actor.
71
+ */
72
+ registerTimer(timerName, callback, dueTimeMs, periodMs) {
73
+ if (this.status !== "starting") {
74
+ this.logger.warn(`Cannot register timer '${timerName}' because actor is not starting.`);
75
+ return;
76
+ }
77
+ const tick = () => {
78
+ if (this.status !== "started" || !this._intervals.has(timerName)) return;
79
+ if (this._inFlight.has(timerName)) {
80
+ this.logger.warn(`Skipping timer '${this.name}:${timerName}' because the previous run is still in flight.`);
81
+ return;
82
+ }
83
+ const run = (async () => {
84
+ const startTime = Date.now();
85
+ try {
86
+ await callback();
87
+ } catch (error) {
88
+ const err = error instanceof Error ? error : new Error(String(error));
89
+ this.logger.error(`Error in timer '${this.name}:${timerName}': ${err.message}`);
90
+ } finally {
91
+ const duration = Date.now() - startTime;
92
+ if (duration > periodMs) {
93
+ this.logger.warn(`Timer '${this.name}:${timerName}' took ${duration}ms, longer than its ${periodMs}ms period.`);
94
+ }
95
+ }
96
+ })();
97
+ this._inFlight.set(timerName, run.finally(() => {
98
+ this._inFlight.delete(timerName);
99
+ }));
100
+ };
101
+ const timeoutId = setTimeout(() => {
102
+ this._intervals.set(timerName, setInterval(tick, periodMs));
103
+ }, dueTimeMs);
104
+ this._timeouts.set(timerName, timeoutId);
105
+ }
106
+ /**
107
+ * Run the warm-pass once. Not driven automatically here (no orchestrator);
108
+ * a caller invokes it after `start()` if it wants `whenReady()` to resolve.
109
+ */
110
+ async runReadyHandler() {
111
+ if (this._readyState !== "pending") return;
112
+ try {
113
+ await this.readyHandler();
114
+ this._readyState = "ready";
115
+ this._readyDeferred.resolve();
116
+ } catch (error) {
117
+ const err = error instanceof Error ? error : new Error(String(error));
118
+ this._readyState = "failed";
119
+ this._readyError = err;
120
+ this._readyDeferred.reject(err);
121
+ throw err;
122
+ }
123
+ }
124
+ async stopHandler() {
125
+ await super.stopHandler();
126
+ for (const timeoutRef of this._timeouts.values()) clearTimeout(timeoutRef);
127
+ this._timeouts.clear();
128
+ for (const intervalRef of this._intervals.values()) clearInterval(intervalRef);
129
+ this._intervals.clear();
130
+ await Promise.allSettled(this._inFlight.values());
131
+ this._inFlight.clear();
132
+ }
133
+ async whenReady() {
134
+ await this._readyDeferred.promise;
135
+ }
136
+ /** Override to prove the actor can do useful work. Default: no-op. */
137
+ async readyHandler() {
138
+ }
139
+ };
140
+
141
+ // src/DappActor.ts
142
+ import { creatable } from "@ariestools/sdk";
143
+
144
+ // src/providers/monikers.ts
145
+ var DappDataStoreMoniker = "DappDataStore";
146
+ var DappStateStoreMoniker = "DappStateStore";
147
+ var DappIndexStoreMoniker = "DappIndexStore";
148
+
149
+ // src/DappActor.ts
150
+ var DEFAULT_REDUCE_INTERVAL_MS = 5e3;
151
+ var DEFAULT_FIRST_RUN_DELAY_MS = 2e3;
152
+ var DappActor = class extends AbstractActor {
153
+ _data;
154
+ _index;
155
+ _state;
156
+ async createHandler() {
157
+ await super.createHandler();
158
+ this._data = await this.locator.getInstance(DappDataStoreMoniker);
159
+ this._state = await this.locator.getInstance(DappStateStoreMoniker);
160
+ this._index = await this.locator.getInstance(DappIndexStoreMoniker);
161
+ }
162
+ async startHandler() {
163
+ await super.startHandler();
164
+ const interval = this.params.reduceIntervalMs ?? DEFAULT_REDUCE_INTERVAL_MS;
165
+ const firstRunDelay = this.params.firstRunDelayMs ?? DEFAULT_FIRST_RUN_DELAY_MS;
166
+ this.registerTimer("DappReduce", async () => {
167
+ await this.runReducePass();
168
+ }, firstRunDelay, interval);
169
+ this.logger.info(`DappActor started: reducer '${this.params.reducer.name}' every ${interval}ms`);
170
+ }
171
+ async runReducePass() {
172
+ await this.params.reducer.reduce({
173
+ data: this._data,
174
+ index: this._index,
175
+ logger: this.logger,
176
+ state: this._state
177
+ });
178
+ }
179
+ };
180
+ __publicField(DappActor, "dependencies", [
181
+ DappDataStoreMoniker,
182
+ DappStateStoreMoniker,
183
+ DappIndexStoreMoniker
184
+ ]);
185
+ DappActor = __decorateClass([
186
+ creatable()
187
+ ], DappActor);
188
+
189
+ // src/boot/bootDappActors.ts
190
+ async function bootDappActors(locator, specs) {
191
+ const actors = [];
192
+ for (const spec of specs) {
193
+ const params = {
194
+ locator,
195
+ name: spec.name,
196
+ reducer: spec.reducer,
197
+ ...spec.reduceIntervalMs !== void 0 && { reduceIntervalMs: spec.reduceIntervalMs }
198
+ };
199
+ const actor = await DappActor.create(params);
200
+ await actor.start();
201
+ actors.push(actor);
202
+ }
203
+ return actors;
204
+ }
205
+
206
+ // src/locator/createDappLocator.ts
207
+ import { ConsoleLogger } from "@ariestools/sdk";
208
+
209
+ // src/providers/DappBucketStore.ts
210
+ import {
211
+ GetObjectCommand,
212
+ ListObjectsV2Command,
213
+ PutObjectCommand,
214
+ S3Client
215
+ } from "@aws-sdk/client-s3";
216
+ var DEFAULT_CREDENTIAL = "S3RVER";
217
+ function isNotFound(error) {
218
+ const name = error.name;
219
+ return name === "NoSuchKey" || name === "NotFound";
220
+ }
221
+ function createS3BucketStore(options) {
222
+ const { bucket } = options;
223
+ const client = new S3Client({
224
+ endpoint: options.endpoint,
225
+ region: "us-east-1",
226
+ forcePathStyle: true,
227
+ credentials: {
228
+ accessKeyId: options.accessKeyId ?? DEFAULT_CREDENTIAL,
229
+ secretAccessKey: options.secretAccessKey ?? DEFAULT_CREDENTIAL
230
+ }
231
+ });
232
+ return {
233
+ bucket,
234
+ async get(key) {
235
+ try {
236
+ const response = await client.send(new GetObjectCommand({ Bucket: bucket, Key: key }));
237
+ return await response.Body?.transformToByteArray();
238
+ } catch (error) {
239
+ if (isNotFound(error)) return void 0;
240
+ throw error;
241
+ }
242
+ },
243
+ async put(key, body) {
244
+ await client.send(new PutObjectCommand({
245
+ Bucket: bucket,
246
+ Key: key,
247
+ Body: body
248
+ }));
249
+ },
250
+ async list(prefix) {
251
+ const keys = [];
252
+ let token;
253
+ do {
254
+ const response = await client.send(new ListObjectsV2Command({
255
+ Bucket: bucket,
256
+ Prefix: prefix,
257
+ ContinuationToken: token
258
+ }));
259
+ for (const item of response.Contents ?? []) {
260
+ if (item.Key !== void 0) keys.push(item.Key);
261
+ }
262
+ token = response.IsTruncated === true ? response.NextContinuationToken : void 0;
263
+ } while (token !== void 0);
264
+ return keys;
265
+ }
266
+ };
267
+ }
268
+
269
+ // src/locator/createDappLocator.ts
270
+ function createDappLocator(options) {
271
+ const logger = options.logger ?? new ConsoleLogger();
272
+ const bucketOptions = {
273
+ endpoint: options.endpoint,
274
+ ...options.accessKeyId !== void 0 && { accessKeyId: options.accessKeyId },
275
+ ...options.secretAccessKey !== void 0 && { secretAccessKey: options.secretAccessKey }
276
+ };
277
+ const instances = /* @__PURE__ */ new Map([
278
+ [DappDataStoreMoniker, createS3BucketStore({ ...bucketOptions, bucket: "data" })],
279
+ [DappStateStoreMoniker, createS3BucketStore({ ...bucketOptions, bucket: "state" })],
280
+ [DappIndexStoreMoniker, createS3BucketStore({ ...bucketOptions, bucket: "index" })]
281
+ ]);
282
+ return {
283
+ context: { logger },
284
+ has(moniker) {
285
+ return instances.has(moniker);
286
+ },
287
+ register(moniker, instance) {
288
+ instances.set(moniker, instance);
289
+ },
290
+ async getInstance(moniker) {
291
+ const found = instances.get(moniker);
292
+ if (found === void 0) throw new Error(`No provider registered for moniker "${moniker}"`);
293
+ return found;
294
+ },
295
+ async tryGetInstance(moniker) {
296
+ return instances.get(moniker);
297
+ }
298
+ };
299
+ }
300
+
301
+ // src/reducer/DappReducer.ts
302
+ var noopReducer = {
303
+ name: "noop",
304
+ async reduce() {
305
+ }
306
+ };
307
+ export {
308
+ AbstractActor,
309
+ DappActor,
310
+ DappDataStoreMoniker,
311
+ DappIndexStoreMoniker,
312
+ DappStateStoreMoniker,
313
+ bootDappActors,
314
+ createDappLocator,
315
+ createS3BucketStore,
316
+ noopReducer
317
+ };
318
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/actor/AbstractActor.ts", "../../src/DappActor.ts", "../../src/providers/monikers.ts", "../../src/boot/bootDappActors.ts", "../../src/locator/createDappLocator.ts", "../../src/providers/DappBucketStore.ts", "../../src/reducer/DappReducer.ts"],
4
+ "sourcesContent": ["import type { CreatableInstance, Logger } from '@ariestools/sdk'\nimport {\n AbstractCreatable, assertEx, IdLogger,\n} from '@ariestools/sdk'\n\nimport type {\n ActorParams, DappContext, DappProviderLocator, ReadyState,\n} from './types.ts'\n\ninterface Deferred<T> {\n promise: Promise<T>\n reject: (reason: unknown) => void\n resolve: (value: T) => void\n}\n\nfunction createDeferred<T>(): Deferred<T> {\n let resolve!: (value: T) => void\n let reject!: (reason: unknown) => void\n const promise = new Promise<T>((res, rej) => {\n resolve = res\n reject = rej\n })\n return {\n promise, reject, resolve,\n }\n}\n\n/**\n * Lean, dapp-owned fork of the xl1 `ActorV3` pattern: the create/start/stop\n * lifecycle from `AbstractCreatable`, plus non-overlapping interval timers and\n * a readiness contract. It deliberately swaps the chain's\n * `ProviderFactoryLocator`/`LocatorConfig` machinery for the small\n * {@link DappProviderLocator} seam, so a dapp actor resolves providers by\n * moniker without dragging the chain protocol config model in.\n *\n * The locator is process-wide: the daemon builds it once and passes the same\n * instance to every actor via `params.locator` (see `bootDappActors`). When\n * this graduates into a shared cli/actor toolkit \u2014 and, later, xl1-protocol \u2014\n * this base can re-adopt the real locator.\n */\nexport abstract class AbstractActor<TParams extends ActorParams = ActorParams> extends AbstractCreatable<TParams> {\n protected readonly _intervals = new Map<string, NodeJS.Timeout>()\n protected readonly _timeouts = new Map<string, NodeJS.Timeout>()\n\n private _idLogger?: Logger\n private readonly _inFlight = new Map<string, Promise<void>>()\n private readonly _readyDeferred = createDeferred<void>()\n private _readyError?: Error\n private _readyState: ReadyState = 'pending'\n\n override get logger(): Logger {\n this._idLogger ??= new IdLogger(\n assertEx(this.context.logger, () => `Logger is required in context for actor ${this.name}.`),\n () => this.name,\n )\n return this._idLogger\n }\n\n get readyError(): Error | undefined {\n return this._readyError\n }\n\n get readyState(): ReadyState {\n return this._readyState\n }\n\n protected get context(): DappContext {\n return this.locator.context\n }\n\n protected get locator(): DappProviderLocator {\n return this.params.locator\n }\n\n static override async paramsHandler<T extends CreatableInstance>(params?: Partial<T['params']>): Promise<T['params']> {\n const inParams = (params ?? {}) as Partial<T['params']> & { locator?: DappProviderLocator }\n const baseParams = await super.paramsHandler({ ...inParams, name: inParams.name ?? 'UnknownActor' }) as T['params']\n const locator = assertEx(inParams.locator, () => `params.locator is required for actor ${String(baseParams.name)}.`)\n return { ...baseParams, locator }\n }\n\n /**\n * Register a recurring task. The interval only fires while the actor is\n * `started`, and a run is skipped if the previous one is still in flight, so\n * a slow pass can never stack on top of itself. Must be called from\n * `startHandler` (guards on `starting` status), mirroring the xl1 actor.\n */\n registerTimer(timerName: string, callback: () => Promise<void>, dueTimeMs: number, periodMs: number): void {\n if (this.status !== 'starting') {\n this.logger.warn(`Cannot register timer '${timerName}' because actor is not starting.`)\n return\n }\n const tick = (): void => {\n if (this.status !== 'started' || !this._intervals.has(timerName)) return\n if (this._inFlight.has(timerName)) {\n this.logger.warn(`Skipping timer '${this.name}:${timerName}' because the previous run is still in flight.`)\n return\n }\n const run = (async (): Promise<void> => {\n const startTime = Date.now()\n try {\n await callback()\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error))\n this.logger.error(`Error in timer '${this.name}:${timerName}': ${err.message}`)\n } finally {\n const duration = Date.now() - startTime\n if (duration > periodMs) {\n this.logger.warn(`Timer '${this.name}:${timerName}' took ${duration}ms, longer than its ${periodMs}ms period.`)\n }\n }\n })()\n this._inFlight.set(timerName, run.finally(() => {\n this._inFlight.delete(timerName)\n }))\n }\n const timeoutId = setTimeout(() => {\n this._intervals.set(timerName, setInterval(tick, periodMs))\n }, dueTimeMs)\n this._timeouts.set(timerName, timeoutId)\n }\n\n /**\n * Run the warm-pass once. Not driven automatically here (no orchestrator);\n * a caller invokes it after `start()` if it wants `whenReady()` to resolve.\n */\n async runReadyHandler(): Promise<void> {\n if (this._readyState !== 'pending') return\n try {\n await this.readyHandler()\n this._readyState = 'ready'\n this._readyDeferred.resolve()\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error))\n this._readyState = 'failed'\n this._readyError = err\n this._readyDeferred.reject(err)\n throw err\n }\n }\n\n override async stopHandler(): Promise<void> {\n await super.stopHandler()\n for (const timeoutRef of this._timeouts.values()) clearTimeout(timeoutRef)\n this._timeouts.clear()\n for (const intervalRef of this._intervals.values()) clearInterval(intervalRef)\n this._intervals.clear()\n await Promise.allSettled(this._inFlight.values())\n this._inFlight.clear()\n }\n\n async whenReady(): Promise<void> {\n await this._readyDeferred.promise\n }\n\n /** Override to prove the actor can do useful work. Default: no-op. */\n protected async readyHandler(): Promise<void> {\n // no-op by default\n }\n}\n", "import { creatable } from '@ariestools/sdk'\n\nimport { AbstractActor } from './actor/AbstractActor.ts'\nimport type { ActorParams } from './actor/types.ts'\nimport type { DappBucketStore } from './providers/DappBucketStore.ts'\nimport {\n DappDataStoreMoniker, DappIndexStoreMoniker, DappStateStoreMoniker,\n} from './providers/monikers.ts'\nimport type { DappReducer } from './reducer/DappReducer.ts'\n\nexport interface DappActorParams extends ActorParams {\n /** Delay before the first reduce pass. Defaults to 2000ms. */\n firstRunDelayMs?: number\n reduceIntervalMs?: number\n reducer: DappReducer\n}\n\nconst DEFAULT_REDUCE_INTERVAL_MS = 5000\nconst DEFAULT_FIRST_RUN_DELAY_MS = 2000\n\n/**\n * The stock dapp actor: resolves the three bucket stores from the shared\n * locator, then drives its reducer on an interval to keep `state` and `index`\n * derived from `data`. Multiple actors (each with its own reducer) can share\n * one locator; this is the default single-reducer instance the daemon boots.\n */\n@creatable()\nexport class DappActor extends AbstractActor<DappActorParams> {\n static readonly dependencies = [\n DappDataStoreMoniker,\n DappStateStoreMoniker,\n DappIndexStoreMoniker,\n ] as const\n\n protected _data!: DappBucketStore\n protected _index!: DappBucketStore\n protected _state!: DappBucketStore\n\n override async createHandler(): Promise<void> {\n await super.createHandler()\n this._data = await this.locator.getInstance<DappBucketStore>(DappDataStoreMoniker)\n this._state = await this.locator.getInstance<DappBucketStore>(DappStateStoreMoniker)\n this._index = await this.locator.getInstance<DappBucketStore>(DappIndexStoreMoniker)\n }\n\n protected override async startHandler(): Promise<void> {\n await super.startHandler()\n const interval = this.params.reduceIntervalMs ?? DEFAULT_REDUCE_INTERVAL_MS\n const firstRunDelay = this.params.firstRunDelayMs ?? DEFAULT_FIRST_RUN_DELAY_MS\n this.registerTimer('DappReduce', async () => {\n await this.runReducePass()\n }, firstRunDelay, interval)\n this.logger.info(`DappActor started: reducer '${this.params.reducer.name}' every ${interval}ms`)\n }\n\n private async runReducePass(): Promise<void> {\n await this.params.reducer.reduce({\n data: this._data,\n index: this._index,\n logger: this.logger,\n state: this._state,\n })\n }\n}\n", "/**\n * Provider monikers for the three dapp buckets. An actor declares these in its\n * `static dependencies` and resolves them from the locator at create time.\n */\nexport const DappDataStoreMoniker = 'DappDataStore' as const\nexport const DappStateStoreMoniker = 'DappStateStore' as const\nexport const DappIndexStoreMoniker = 'DappIndexStore' as const\n", "import type { CreatableName } from '@ariestools/sdk'\n\nimport type { DappProviderLocator } from '../actor/types.ts'\nimport type { DappActorParams } from '../DappActor.ts'\nimport { DappActor } from '../DappActor.ts'\nimport type { DappReducer } from '../reducer/DappReducer.ts'\n\nexport interface DappActorSpec {\n name: string\n reduceIntervalMs?: number\n reducer: DappReducer\n}\n\n/**\n * Creates and starts one {@link DappActor} per spec, all sharing the single\n * process-wide locator. Returns them so the caller can stop them on shutdown.\n */\nexport async function bootDappActors(\n locator: DappProviderLocator,\n specs: readonly DappActorSpec[],\n): Promise<DappActor[]> {\n const actors: DappActor[] = []\n for (const spec of specs) {\n const params: Partial<DappActorParams> = {\n locator,\n name: spec.name as CreatableName,\n reducer: spec.reducer,\n ...(spec.reduceIntervalMs !== undefined && { reduceIntervalMs: spec.reduceIntervalMs }),\n }\n const actor = await DappActor.create(params)\n await actor.start()\n actors.push(actor)\n }\n return actors\n}\n", "import type { Logger } from '@ariestools/sdk'\nimport { ConsoleLogger } from '@ariestools/sdk'\n\nimport type { DappMoniker, DappProviderLocator } from '../actor/types.ts'\nimport { createS3BucketStore } from '../providers/DappBucketStore.ts'\nimport {\n DappDataStoreMoniker, DappIndexStoreMoniker, DappStateStoreMoniker,\n} from '../providers/monikers.ts'\n\nexport interface CreateDappLocatorOptions {\n accessKeyId?: string\n /** Origin the dapp server listens on, e.g. `http://127.0.0.1:8801`. */\n endpoint: string\n logger?: Logger\n secretAccessKey?: string\n}\n\n/**\n * Builds the process-wide locator: one instance, shared across every actor\n * (xl1-cli style). It pre-registers an S3-backed store per bucket keyed by\n * moniker; extra providers can be `register`ed before actors are created.\n */\nexport function createDappLocator(options: CreateDappLocatorOptions): DappProviderLocator {\n const logger = options.logger ?? new ConsoleLogger()\n const bucketOptions = {\n endpoint: options.endpoint,\n ...(options.accessKeyId !== undefined && { accessKeyId: options.accessKeyId }),\n ...(options.secretAccessKey !== undefined && { secretAccessKey: options.secretAccessKey }),\n }\n const instances = new Map<DappMoniker, unknown>([\n [DappDataStoreMoniker, createS3BucketStore({ ...bucketOptions, bucket: 'data' })],\n [DappStateStoreMoniker, createS3BucketStore({ ...bucketOptions, bucket: 'state' })],\n [DappIndexStoreMoniker, createS3BucketStore({ ...bucketOptions, bucket: 'index' })],\n ])\n return {\n context: { logger },\n has(moniker: DappMoniker): boolean {\n return instances.has(moniker)\n },\n register(moniker: DappMoniker, instance: unknown): void {\n instances.set(moniker, instance)\n },\n async getInstance<T>(moniker: DappMoniker): Promise<T> {\n const found = instances.get(moniker)\n if (found === undefined) throw new Error(`No provider registered for moniker \"${moniker}\"`)\n return found as T\n },\n async tryGetInstance<T>(moniker: DappMoniker): Promise<T | undefined> {\n return instances.get(moniker) as T | undefined\n },\n }\n}\n", "import type { DappBucket } from '@ariestools/aries-dapp-serve'\nimport {\n GetObjectCommand, ListObjectsV2Command, PutObjectCommand, S3Client,\n} from '@aws-sdk/client-s3'\n\n/**\n * A provider over one dapp bucket. `data` is the immutable source of truth\n * (read-only in practice); `state` and `index` are the derived buckets a\n * reducer writes. The interface is intentionally tiny \u2014 reducers compose the\n * richer read/derive/write logic on top of these primitives.\n */\nexport interface DappBucketStore {\n readonly bucket: DappBucket\n get(key: string): Promise<Uint8Array | undefined>\n list(prefix?: string): Promise<string[]>\n put(key: string, body: string | Uint8Array): Promise<void>\n}\n\nexport interface S3DappBucketStoreOptions {\n accessKeyId?: string\n bucket: DappBucket\n /** Origin the dapp server listens on, e.g. `http://127.0.0.1:8801`. */\n endpoint: string\n secretAccessKey?: string\n}\n\nconst DEFAULT_CREDENTIAL = 'S3RVER'\n\nfunction isNotFound(error: unknown): boolean {\n const name = (error as { name?: string }).name\n return name === 'NoSuchKey' || name === 'NotFound'\n}\n\n/**\n * S3-backed {@link DappBucketStore} pointed at the local dapp server. Uses\n * path-style addressing so `/{bucket}/{key}` resolves as a subfolder of the\n * one origin. Under `--ssl auto` the server speaks HTTPS with a locally\n * trusted certificate; the daemon exports its CA via `NODE_EXTRA_CA_CERTS`, so\n * this client trusts it without any per-request handler configuration.\n */\nexport function createS3BucketStore(options: S3DappBucketStoreOptions): DappBucketStore {\n const { bucket } = options\n const client = new S3Client({\n endpoint: options.endpoint,\n region: 'us-east-1',\n forcePathStyle: true,\n credentials: {\n accessKeyId: options.accessKeyId ?? DEFAULT_CREDENTIAL,\n secretAccessKey: options.secretAccessKey ?? DEFAULT_CREDENTIAL,\n },\n })\n return {\n bucket,\n async get(key: string): Promise<Uint8Array | undefined> {\n try {\n const response = await client.send(new GetObjectCommand({ Bucket: bucket, Key: key }))\n return await response.Body?.transformToByteArray()\n } catch (error) {\n if (isNotFound(error)) return undefined\n throw error\n }\n },\n async put(key: string, body: string | Uint8Array): Promise<void> {\n await client.send(new PutObjectCommand({\n Bucket: bucket, Key: key, Body: body,\n }))\n },\n async list(prefix?: string): Promise<string[]> {\n const keys: string[] = []\n let token: string | undefined\n do {\n const response = await client.send(new ListObjectsV2Command({\n Bucket: bucket,\n Prefix: prefix,\n ContinuationToken: token,\n }))\n for (const item of response.Contents ?? []) {\n if (item.Key !== undefined) keys.push(item.Key)\n }\n token = response.IsTruncated === true ? response.NextContinuationToken : undefined\n } while (token !== undefined)\n return keys\n },\n }\n}\n", "import type { Logger } from '@ariestools/sdk'\n\nimport type { DappBucketStore } from '../providers/DappBucketStore.ts'\n\n/** What a reducer is handed each pass: the three bucket stores plus a logger. */\nexport interface DappReduceContext {\n /** Immutable source of truth. */\n data: DappBucketStore\n /** Derived, query-optimized views. */\n index: DappBucketStore\n logger: Logger\n /** Derived current view. */\n state: DappBucketStore\n}\n\n/**\n * The pluggable unit of dapp logic. The DappActor timer calls `reduce` on an\n * interval; an implementation reads the immutable `data` bucket and rebuilds\n * `state` and `index`. Passes should be idempotent and resume from a watermark\n * so a slow or interrupted pass is safe to repeat.\n */\nexport interface DappReducer {\n readonly name: string\n reduce(context: DappReduceContext): Promise<void>\n}\n\n/**\n * Default reducer: does nothing. The harness runs the full timer/provider\n * spine with this in place; supply a real reducer to derive `state` and\n * `index` from `data`.\n */\nexport const noopReducer: DappReducer = {\n name: 'noop',\n async reduce(): Promise<void> {\n // no-op: the spine runs, no derivation happens\n },\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;AACA;AAAA,EACE;AAAA,EAAmB;AAAA,EAAU;AAAA,OACxB;AAYP,SAAS,iBAAiC;AACxC,MAAI;AACJ,MAAI;AACJ,QAAM,UAAU,IAAI,QAAW,CAAC,KAAK,QAAQ;AAC3C,cAAU;AACV,aAAS;AAAA,EACX,CAAC;AACD,SAAO;AAAA,IACL;AAAA,IAAS;AAAA,IAAQ;AAAA,EACnB;AACF;AAeO,IAAe,gBAAf,cAAgF,kBAA2B;AAAA,EAC7F,aAAa,oBAAI,IAA4B;AAAA,EAC7C,YAAY,oBAAI,IAA4B;AAAA,EAEvD;AAAA,EACS,YAAY,oBAAI,IAA2B;AAAA,EAC3C,iBAAiB,eAAqB;AAAA,EAC/C;AAAA,EACA,cAA0B;AAAA,EAElC,IAAa,SAAiB;AAC5B,SAAK,cAAc,IAAI;AAAA,MACrB,SAAS,KAAK,QAAQ,QAAQ,MAAM,2CAA2C,KAAK,IAAI,GAAG;AAAA,MAC3F,MAAM,KAAK;AAAA,IACb;AACA,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,IAAI,aAAgC;AAClC,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,IAAI,aAAyB;AAC3B,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,IAAc,UAAuB;AACnC,WAAO,KAAK,QAAQ;AAAA,EACtB;AAAA,EAEA,IAAc,UAA+B;AAC3C,WAAO,KAAK,OAAO;AAAA,EACrB;AAAA,EAEA,aAAsB,cAA2C,QAAqD;AACpH,UAAM,WAAY,UAAU,CAAC;AAC7B,UAAM,aAAa,MAAM,MAAM,cAAc,EAAE,GAAG,UAAU,MAAM,SAAS,QAAQ,eAAe,CAAC;AACnG,UAAM,UAAU,SAAS,SAAS,SAAS,MAAM,wCAAwC,OAAO,WAAW,IAAI,CAAC,GAAG;AACnH,WAAO,EAAE,GAAG,YAAY,QAAQ;AAAA,EAClC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,cAAc,WAAmB,UAA+B,WAAmB,UAAwB;AACzG,QAAI,KAAK,WAAW,YAAY;AAC9B,WAAK,OAAO,KAAK,0BAA0B,SAAS,kCAAkC;AACtF;AAAA,IACF;AACA,UAAM,OAAO,MAAY;AACvB,UAAI,KAAK,WAAW,aAAa,CAAC,KAAK,WAAW,IAAI,SAAS,EAAG;AAClE,UAAI,KAAK,UAAU,IAAI,SAAS,GAAG;AACjC,aAAK,OAAO,KAAK,mBAAmB,KAAK,IAAI,IAAI,SAAS,gDAAgD;AAC1G;AAAA,MACF;AACA,YAAM,OAAO,YAA2B;AACtC,cAAM,YAAY,KAAK,IAAI;AAC3B,YAAI;AACF,gBAAM,SAAS;AAAA,QACjB,SAAS,OAAO;AACd,gBAAM,MAAM,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC;AACpE,eAAK,OAAO,MAAM,mBAAmB,KAAK,IAAI,IAAI,SAAS,MAAM,IAAI,OAAO,EAAE;AAAA,QAChF,UAAE;AACA,gBAAM,WAAW,KAAK,IAAI,IAAI;AAC9B,cAAI,WAAW,UAAU;AACvB,iBAAK,OAAO,KAAK,UAAU,KAAK,IAAI,IAAI,SAAS,UAAU,QAAQ,uBAAuB,QAAQ,YAAY;AAAA,UAChH;AAAA,QACF;AAAA,MACF,GAAG;AACH,WAAK,UAAU,IAAI,WAAW,IAAI,QAAQ,MAAM;AAC9C,aAAK,UAAU,OAAO,SAAS;AAAA,MACjC,CAAC,CAAC;AAAA,IACJ;AACA,UAAM,YAAY,WAAW,MAAM;AACjC,WAAK,WAAW,IAAI,WAAW,YAAY,MAAM,QAAQ,CAAC;AAAA,IAC5D,GAAG,SAAS;AACZ,SAAK,UAAU,IAAI,WAAW,SAAS;AAAA,EACzC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,kBAAiC;AACrC,QAAI,KAAK,gBAAgB,UAAW;AACpC,QAAI;AACF,YAAM,KAAK,aAAa;AACxB,WAAK,cAAc;AACnB,WAAK,eAAe,QAAQ;AAAA,IAC9B,SAAS,OAAO;AACd,YAAM,MAAM,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC;AACpE,WAAK,cAAc;AACnB,WAAK,cAAc;AACnB,WAAK,eAAe,OAAO,GAAG;AAC9B,YAAM;AAAA,IACR;AAAA,EACF;AAAA,EAEA,MAAe,cAA6B;AAC1C,UAAM,MAAM,YAAY;AACxB,eAAW,cAAc,KAAK,UAAU,OAAO,EAAG,cAAa,UAAU;AACzE,SAAK,UAAU,MAAM;AACrB,eAAW,eAAe,KAAK,WAAW,OAAO,EAAG,eAAc,WAAW;AAC7E,SAAK,WAAW,MAAM;AACtB,UAAM,QAAQ,WAAW,KAAK,UAAU,OAAO,CAAC;AAChD,SAAK,UAAU,MAAM;AAAA,EACvB;AAAA,EAEA,MAAM,YAA2B;AAC/B,UAAM,KAAK,eAAe;AAAA,EAC5B;AAAA;AAAA,EAGA,MAAgB,eAA8B;AAAA,EAE9C;AACF;;;AC/JA,SAAS,iBAAiB;;;ACInB,IAAM,uBAAuB;AAC7B,IAAM,wBAAwB;AAC9B,IAAM,wBAAwB;;;ADWrC,IAAM,6BAA6B;AACnC,IAAM,6BAA6B;AAS5B,IAAM,YAAN,cAAwB,cAA+B;AAAA,EAOlD;AAAA,EACA;AAAA,EACA;AAAA,EAEV,MAAe,gBAA+B;AAC5C,UAAM,MAAM,cAAc;AAC1B,SAAK,QAAQ,MAAM,KAAK,QAAQ,YAA6B,oBAAoB;AACjF,SAAK,SAAS,MAAM,KAAK,QAAQ,YAA6B,qBAAqB;AACnF,SAAK,SAAS,MAAM,KAAK,QAAQ,YAA6B,qBAAqB;AAAA,EACrF;AAAA,EAEA,MAAyB,eAA8B;AACrD,UAAM,MAAM,aAAa;AACzB,UAAM,WAAW,KAAK,OAAO,oBAAoB;AACjD,UAAM,gBAAgB,KAAK,OAAO,mBAAmB;AACrD,SAAK,cAAc,cAAc,YAAY;AAC3C,YAAM,KAAK,cAAc;AAAA,IAC3B,GAAG,eAAe,QAAQ;AAC1B,SAAK,OAAO,KAAK,+BAA+B,KAAK,OAAO,QAAQ,IAAI,WAAW,QAAQ,IAAI;AAAA,EACjG;AAAA,EAEA,MAAc,gBAA+B;AAC3C,UAAM,KAAK,OAAO,QAAQ,OAAO;AAAA,MAC/B,MAAM,KAAK;AAAA,MACX,OAAO,KAAK;AAAA,MACZ,QAAQ,KAAK;AAAA,MACb,OAAO,KAAK;AAAA,IACd,CAAC;AAAA,EACH;AACF;AAnCE,cADW,WACK,gBAAe;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AACF;AALW,YAAN;AAAA,EADN,UAAU;AAAA,GACE;;;AEVb,eAAsB,eACpB,SACA,OACsB;AACtB,QAAM,SAAsB,CAAC;AAC7B,aAAW,QAAQ,OAAO;AACxB,UAAM,SAAmC;AAAA,MACvC;AAAA,MACA,MAAM,KAAK;AAAA,MACX,SAAS,KAAK;AAAA,MACd,GAAI,KAAK,qBAAqB,UAAa,EAAE,kBAAkB,KAAK,iBAAiB;AAAA,IACvF;AACA,UAAM,QAAQ,MAAM,UAAU,OAAO,MAAM;AAC3C,UAAM,MAAM,MAAM;AAClB,WAAO,KAAK,KAAK;AAAA,EACnB;AACA,SAAO;AACT;;;ACjCA,SAAS,qBAAqB;;;ACA9B;AAAA,EACE;AAAA,EAAkB;AAAA,EAAsB;AAAA,EAAkB;AAAA,OACrD;AAuBP,IAAM,qBAAqB;AAE3B,SAAS,WAAW,OAAyB;AAC3C,QAAM,OAAQ,MAA4B;AAC1C,SAAO,SAAS,eAAe,SAAS;AAC1C;AASO,SAAS,oBAAoB,SAAoD;AACtF,QAAM,EAAE,OAAO,IAAI;AACnB,QAAM,SAAS,IAAI,SAAS;AAAA,IAC1B,UAAU,QAAQ;AAAA,IAClB,QAAQ;AAAA,IACR,gBAAgB;AAAA,IAChB,aAAa;AAAA,MACX,aAAa,QAAQ,eAAe;AAAA,MACpC,iBAAiB,QAAQ,mBAAmB;AAAA,IAC9C;AAAA,EACF,CAAC;AACD,SAAO;AAAA,IACL;AAAA,IACA,MAAM,IAAI,KAA8C;AACtD,UAAI;AACF,cAAM,WAAW,MAAM,OAAO,KAAK,IAAI,iBAAiB,EAAE,QAAQ,QAAQ,KAAK,IAAI,CAAC,CAAC;AACrF,eAAO,MAAM,SAAS,MAAM,qBAAqB;AAAA,MACnD,SAAS,OAAO;AACd,YAAI,WAAW,KAAK,EAAG,QAAO;AAC9B,cAAM;AAAA,MACR;AAAA,IACF;AAAA,IACA,MAAM,IAAI,KAAa,MAA0C;AAC/D,YAAM,OAAO,KAAK,IAAI,iBAAiB;AAAA,QACrC,QAAQ;AAAA,QAAQ,KAAK;AAAA,QAAK,MAAM;AAAA,MAClC,CAAC,CAAC;AAAA,IACJ;AAAA,IACA,MAAM,KAAK,QAAoC;AAC7C,YAAM,OAAiB,CAAC;AACxB,UAAI;AACJ,SAAG;AACD,cAAM,WAAW,MAAM,OAAO,KAAK,IAAI,qBAAqB;AAAA,UAC1D,QAAQ;AAAA,UACR,QAAQ;AAAA,UACR,mBAAmB;AAAA,QACrB,CAAC,CAAC;AACF,mBAAW,QAAQ,SAAS,YAAY,CAAC,GAAG;AAC1C,cAAI,KAAK,QAAQ,OAAW,MAAK,KAAK,KAAK,GAAG;AAAA,QAChD;AACA,gBAAQ,SAAS,gBAAgB,OAAO,SAAS,wBAAwB;AAAA,MAC3E,SAAS,UAAU;AACnB,aAAO;AAAA,IACT;AAAA,EACF;AACF;;;AD9DO,SAAS,kBAAkB,SAAwD;AACxF,QAAM,SAAS,QAAQ,UAAU,IAAI,cAAc;AACnD,QAAM,gBAAgB;AAAA,IACpB,UAAU,QAAQ;AAAA,IAClB,GAAI,QAAQ,gBAAgB,UAAa,EAAE,aAAa,QAAQ,YAAY;AAAA,IAC5E,GAAI,QAAQ,oBAAoB,UAAa,EAAE,iBAAiB,QAAQ,gBAAgB;AAAA,EAC1F;AACA,QAAM,YAAY,oBAAI,IAA0B;AAAA,IAC9C,CAAC,sBAAsB,oBAAoB,EAAE,GAAG,eAAe,QAAQ,OAAO,CAAC,CAAC;AAAA,IAChF,CAAC,uBAAuB,oBAAoB,EAAE,GAAG,eAAe,QAAQ,QAAQ,CAAC,CAAC;AAAA,IAClF,CAAC,uBAAuB,oBAAoB,EAAE,GAAG,eAAe,QAAQ,QAAQ,CAAC,CAAC;AAAA,EACpF,CAAC;AACD,SAAO;AAAA,IACL,SAAS,EAAE,OAAO;AAAA,IAClB,IAAI,SAA+B;AACjC,aAAO,UAAU,IAAI,OAAO;AAAA,IAC9B;AAAA,IACA,SAAS,SAAsB,UAAyB;AACtD,gBAAU,IAAI,SAAS,QAAQ;AAAA,IACjC;AAAA,IACA,MAAM,YAAe,SAAkC;AACrD,YAAM,QAAQ,UAAU,IAAI,OAAO;AACnC,UAAI,UAAU,OAAW,OAAM,IAAI,MAAM,uCAAuC,OAAO,GAAG;AAC1F,aAAO;AAAA,IACT;AAAA,IACA,MAAM,eAAkB,SAA8C;AACpE,aAAO,UAAU,IAAI,OAAO;AAAA,IAC9B;AAAA,EACF;AACF;;;AEpBO,IAAM,cAA2B;AAAA,EACtC,MAAM;AAAA,EACN,MAAM,SAAwB;AAAA,EAE9B;AACF;",
6
+ "names": []
7
+ }
@@ -0,0 +1,16 @@
1
+ import type { Logger } from '@ariestools/sdk';
2
+ import type { DappProviderLocator } from '../actor/types.ts';
3
+ export interface CreateDappLocatorOptions {
4
+ accessKeyId?: string;
5
+ /** Origin the dapp server listens on, e.g. `http://127.0.0.1:8801`. */
6
+ endpoint: string;
7
+ logger?: Logger;
8
+ secretAccessKey?: string;
9
+ }
10
+ /**
11
+ * Builds the process-wide locator: one instance, shared across every actor
12
+ * (xl1-cli style). It pre-registers an S3-backed store per bucket keyed by
13
+ * moniker; extra providers can be `register`ed before actors are created.
14
+ */
15
+ export declare function createDappLocator(options: CreateDappLocatorOptions): DappProviderLocator;
16
+ //# sourceMappingURL=createDappLocator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createDappLocator.d.ts","sourceRoot":"","sources":["../../../src/locator/createDappLocator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAA;AAG7C,OAAO,KAAK,EAAe,mBAAmB,EAAE,MAAM,mBAAmB,CAAA;AAMzE,MAAM,WAAW,wBAAwB;IACvC,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,uEAAuE;IACvE,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,eAAe,CAAC,EAAE,MAAM,CAAA;CACzB;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,wBAAwB,GAAG,mBAAmB,CA6BxF"}
@@ -0,0 +1,29 @@
1
+ import type { DappBucket } from '@ariestools/aries-dapp-serve';
2
+ /**
3
+ * A provider over one dapp bucket. `data` is the immutable source of truth
4
+ * (read-only in practice); `state` and `index` are the derived buckets a
5
+ * reducer writes. The interface is intentionally tiny — reducers compose the
6
+ * richer read/derive/write logic on top of these primitives.
7
+ */
8
+ export interface DappBucketStore {
9
+ readonly bucket: DappBucket;
10
+ get(key: string): Promise<Uint8Array | undefined>;
11
+ list(prefix?: string): Promise<string[]>;
12
+ put(key: string, body: string | Uint8Array): Promise<void>;
13
+ }
14
+ export interface S3DappBucketStoreOptions {
15
+ accessKeyId?: string;
16
+ bucket: DappBucket;
17
+ /** Origin the dapp server listens on, e.g. `http://127.0.0.1:8801`. */
18
+ endpoint: string;
19
+ secretAccessKey?: string;
20
+ }
21
+ /**
22
+ * S3-backed {@link DappBucketStore} pointed at the local dapp server. Uses
23
+ * path-style addressing so `/{bucket}/{key}` resolves as a subfolder of the
24
+ * one origin. Under `--ssl auto` the server speaks HTTPS with a locally
25
+ * trusted certificate; the daemon exports its CA via `NODE_EXTRA_CA_CERTS`, so
26
+ * this client trusts it without any per-request handler configuration.
27
+ */
28
+ export declare function createS3BucketStore(options: S3DappBucketStoreOptions): DappBucketStore;
29
+ //# sourceMappingURL=DappBucketStore.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DappBucketStore.d.ts","sourceRoot":"","sources":["../../../src/providers/DappBucketStore.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAA;AAK9D;;;;;GAKG;AACH,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAA;IAC3B,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,CAAA;IACjD,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAA;IACxC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CAC3D;AAED,MAAM,WAAW,wBAAwB;IACvC,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,MAAM,EAAE,UAAU,CAAA;IAClB,uEAAuE;IACvE,QAAQ,EAAE,MAAM,CAAA;IAChB,eAAe,CAAC,EAAE,MAAM,CAAA;CACzB;AASD;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,wBAAwB,GAAG,eAAe,CA4CtF"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Provider monikers for the three dapp buckets. An actor declares these in its
3
+ * `static dependencies` and resolves them from the locator at create time.
4
+ */
5
+ export declare const DappDataStoreMoniker: "DappDataStore";
6
+ export declare const DappStateStoreMoniker: "DappStateStore";
7
+ export declare const DappIndexStoreMoniker: "DappIndexStore";
8
+ //# sourceMappingURL=monikers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"monikers.d.ts","sourceRoot":"","sources":["../../../src/providers/monikers.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,eAAO,MAAM,oBAAoB,EAAG,eAAwB,CAAA;AAC5D,eAAO,MAAM,qBAAqB,EAAG,gBAAyB,CAAA;AAC9D,eAAO,MAAM,qBAAqB,EAAG,gBAAyB,CAAA"}
@@ -0,0 +1,29 @@
1
+ import type { Logger } from '@ariestools/sdk';
2
+ import type { DappBucketStore } from '../providers/DappBucketStore.ts';
3
+ /** What a reducer is handed each pass: the three bucket stores plus a logger. */
4
+ export interface DappReduceContext {
5
+ /** Immutable source of truth. */
6
+ data: DappBucketStore;
7
+ /** Derived, query-optimized views. */
8
+ index: DappBucketStore;
9
+ logger: Logger;
10
+ /** Derived current view. */
11
+ state: DappBucketStore;
12
+ }
13
+ /**
14
+ * The pluggable unit of dapp logic. The DappActor timer calls `reduce` on an
15
+ * interval; an implementation reads the immutable `data` bucket and rebuilds
16
+ * `state` and `index`. Passes should be idempotent and resume from a watermark
17
+ * so a slow or interrupted pass is safe to repeat.
18
+ */
19
+ export interface DappReducer {
20
+ readonly name: string;
21
+ reduce(context: DappReduceContext): Promise<void>;
22
+ }
23
+ /**
24
+ * Default reducer: does nothing. The harness runs the full timer/provider
25
+ * spine with this in place; supply a real reducer to derive `state` and
26
+ * `index` from `data`.
27
+ */
28
+ export declare const noopReducer: DappReducer;
29
+ //# sourceMappingURL=DappReducer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DappReducer.d.ts","sourceRoot":"","sources":["../../../src/reducer/DappReducer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAA;AAE7C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAA;AAEtE,iFAAiF;AACjF,MAAM,WAAW,iBAAiB;IAChC,iCAAiC;IACjC,IAAI,EAAE,eAAe,CAAA;IACrB,sCAAsC;IACtC,KAAK,EAAE,eAAe,CAAA;IACtB,MAAM,EAAE,MAAM,CAAA;IACd,4BAA4B;IAC5B,KAAK,EAAE,eAAe,CAAA;CACvB;AAED;;;;;GAKG;AACH,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,MAAM,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CAClD;AAED;;;;GAIG;AACH,eAAO,MAAM,WAAW,EAAE,WAKzB,CAAA"}
package/package.json ADDED
@@ -0,0 +1,62 @@
1
+ {
2
+ "name": "@ariestools/aries-dapp-core",
3
+ "version": "0.1.7",
4
+ "description": "Aries dapp backend core: the DappActor (forked xl1 actor pattern), process-wide provider locator, pluggable reducer, and the composed daemon that runs the storage server plus actors",
5
+ "keywords": [
6
+ "ariestools",
7
+ "xl1",
8
+ "xyo",
9
+ "dapp",
10
+ "actor",
11
+ "typescript"
12
+ ],
13
+ "homepage": "https://ariestools.ai",
14
+ "license": "LGPL-3.0-only",
15
+ "author": {
16
+ "name": "Arie Trouw",
17
+ "email": "support@ariestools.ai",
18
+ "url": "https://ariestools.ai"
19
+ },
20
+ "sideEffects": false,
21
+ "type": "module",
22
+ "exports": {
23
+ ".": {
24
+ "types": "./dist/node/index.d.ts",
25
+ "default": "./dist/node/index.mjs"
26
+ },
27
+ "./package.json": "./package.json"
28
+ },
29
+ "bin": {
30
+ "aries-dapp-server": "dist/bin/dappServer.mjs"
31
+ },
32
+ "files": [
33
+ "dist",
34
+ "README.md"
35
+ ],
36
+ "publishConfig": {
37
+ "access": "public"
38
+ },
39
+ "dependencies": {
40
+ "@ariestools/sdk": "~8.1.1",
41
+ "@aws-sdk/client-s3": "~3.1090.0",
42
+ "tslib": "~2.8.1",
43
+ "@ariestools/aries-dapp-serve": "~0.1.7"
44
+ },
45
+ "devDependencies": {
46
+ "@ariestools/toolchain": "~8.7.16",
47
+ "@ariestools/tsconfig": "~8.7.16",
48
+ "@opentelemetry/api": "~1.9.1",
49
+ "@types/node": "~26.1.1",
50
+ "rolldown": "~1.2.0",
51
+ "typescript": "~6.0.3",
52
+ "vite": "~8.1.5",
53
+ "vitest": "~4.1.10"
54
+ },
55
+ "engines": {
56
+ "node": ">=18.17.1"
57
+ },
58
+ "engineStrict": true,
59
+ "scripts": {
60
+ "package-compile": "package-compile-only && rolldown -c rolldown.config.ts"
61
+ }
62
+ }