@jolly-pixel/asset-server 1.0.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE CHANGED
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2025 JollyPixel
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ MIT License
2
+
3
+ Copyright (c) 2025 JollyPixel
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,83 +1,83 @@
1
- <h1 align="center">
2
- asset-server
3
- </h1>
4
-
5
- <p align="center">
6
- Server-side asset storage, synchronization and catalog delivery
7
- </p>
8
-
9
- ## 💃 Getting Started
10
-
11
- Install the package with npm:
12
-
13
- ```bash
14
- $ npm i @jolly-pixel/asset-server
15
- ```
16
-
17
- `@jolly-pixel/asset-server` runs on the server. Browser code should use
18
- [`@jolly-pixel/asset`](../asset) for asset records and catalogs.
19
- Physical storage providers are supplied by
20
- [`@jolly-pixel/asset-source`](../asset-source).
21
-
22
- ## 👀 Usage example
23
-
24
- ```ts
25
- import * as EventStore from "@jolly-pixel/event-store";
26
- import { FilesystemAssetSource } from "@jolly-pixel/asset-source";
27
- import { Server } from "@jolly-pixel/network";
28
- import {
29
- createAssetBackend,
30
- textureAssetHandler
31
- } from "@jolly-pixel/asset-server";
32
-
33
- using eventStore = await EventStore.persistence.sqlite(
34
- "./assets/.jollypixel/events.db"
35
- );
36
-
37
- await using backend = await createAssetBackend({
38
- source: new FilesystemAssetSource("./assets"),
39
- eventStore,
40
- handlers: [textureAssetHandler()]
41
- });
42
-
43
- await using server = new Server({ eventStore });
44
- backend.attach(server);
45
- ```
46
-
47
- On startup, the backend catalogs files already present in `./assets`. Changes
48
- made through `backend.writer` are appended to the event store and written to
49
- the asset source. Changes made by external tools are detected and appended as
50
- system events.
51
-
52
- ## 📚 API
53
-
54
- - [`AssetBackend`](./docs/AssetBackend.md): setup, options and lifecycle
55
- - [`AssetWriter`](./docs/AssetWriter.md): create, update, rename and remove assets
56
- - [`AssetSource`](../asset-source/docs/AssetSource.md): in-memory and
57
- filesystem storage
58
- - [`Asset kinds`](./docs/AssetKinds.md): custom state, serialization and editing rooms
59
- - [`Catalog`](./docs/Catalog.md): catalog projection, network messages and HTTP access
60
- - [`Rooms`](./docs/Rooms.md): dynamic editing rooms and eviction
61
- - [`Sync`](./docs/Sync.md): lifecycle events, snapshots and reconciliation
62
-
63
- ## ✨ Contributors guide
64
-
65
- Read the [contributing guide][contributing] before submitting a change.
66
-
67
- Run these commands from the monorepo root:
68
-
69
- ```bash
70
- $ npm run test -w @jolly-pixel/asset-server
71
- $ npm run lint
72
- ```
73
-
74
- > [!CAUTION]
75
- > Include tests when adding a feature or fixing a bug.
76
-
77
- ## 📃 License
78
-
79
- MIT
80
-
81
- <!-- Reference-style links -->
82
-
83
- [contributing]: ../../CONTRIBUTING.md
1
+ <h1 align="center">
2
+ asset-server
3
+ </h1>
4
+
5
+ <p align="center">
6
+ Server-side asset storage, synchronization and catalog delivery
7
+ </p>
8
+
9
+ ## 💃 Getting Started
10
+
11
+ Install the package with npm:
12
+
13
+ ```bash
14
+ $ npm i @jolly-pixel/asset-server
15
+ ```
16
+
17
+ `@jolly-pixel/asset-server` runs on the server. Browser code should use
18
+ [`@jolly-pixel/asset`](../asset/README.md) for asset records and catalogs.
19
+ Physical storage providers are supplied by
20
+ [`@jolly-pixel/asset-source`](../asset-source/README.md).
21
+
22
+ ## 👀 Usage example
23
+
24
+ ```ts
25
+ import * as EventStore from "@jolly-pixel/event-store";
26
+ import { FilesystemAssetSource } from "@jolly-pixel/asset-source";
27
+ import { Server } from "@jolly-pixel/network";
28
+ import {
29
+ createAssetBackend,
30
+ textureAssetHandler
31
+ } from "@jolly-pixel/asset-server";
32
+
33
+ using eventStore = await EventStore.persistence.sqlite(
34
+ "./assets/.jollypixel/events.db"
35
+ );
36
+
37
+ await using backend = await createAssetBackend({
38
+ source: new FilesystemAssetSource("./assets"),
39
+ eventStore,
40
+ handlers: [textureAssetHandler()]
41
+ });
42
+
43
+ await using server = new Server({ eventStore });
44
+ backend.attach(server);
45
+ ```
46
+
47
+ On startup, the backend catalogs files already present in `./assets`. Changes
48
+ made through `backend.writer` are appended to the event store and written to
49
+ the asset source. Changes made by external tools are detected and appended as
50
+ system events.
51
+
52
+ ## 📚 API
53
+
54
+ - [`AssetBackend`](./docs/AssetBackend.md): setup, options and lifecycle
55
+ - [`AssetWriter`](./docs/AssetWriter.md): create, update, rename and remove assets
56
+ - [`AssetSource`](../asset-source/docs/AssetSource.md): in-memory and
57
+ filesystem storage
58
+ - [`Asset kinds`](./docs/AssetKinds.md): custom state, serialization and editing rooms
59
+ - [`Catalog`](./docs/Catalog.md): catalog projection, network messages and HTTP access
60
+ - [`Rooms`](./docs/Rooms.md): dynamic editing rooms and eviction
61
+ - [`Sync`](./docs/Sync.md): lifecycle events, snapshots and reconciliation
62
+
63
+ ## ✨ Contributors guide
64
+
65
+ Read the [contributing guide][contributing] before submitting a change.
66
+
67
+ Run these commands from the monorepo root:
68
+
69
+ ```bash
70
+ $ npm run test -w @jolly-pixel/asset-server
71
+ $ npm run lint
72
+ ```
73
+
74
+ > [!CAUTION]
75
+ > Include tests when adding a feature or fixing a bug.
76
+
77
+ ## 📃 License
78
+
79
+ MIT
80
+
81
+ <!-- Reference-style links -->
82
+
83
+ [contributing]: ../../CONTRIBUTING.md
@@ -31,7 +31,6 @@ export declare class CatalogExtension extends Extension {
31
31
  constructor(options: CatalogExtensionOptions);
32
32
  onClientConnect(client: ClientHandle, _identity: PeerMetadata, context: RoomContext): void;
33
33
  onClientDisconnect(clientId: string): void;
34
- onMessage(): void;
35
34
  dispose(): void;
36
35
  }
37
36
  //# sourceMappingURL=CatalogExtension.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"CatalogExtension.d.ts","sourceRoot":"","sources":["../../src/catalog/CatalogExtension.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,SAAS,EAET,KAAK,YAAY,EACjB,KAAK,gBAAgB,EACrB,KAAK,YAAY,EAEjB,KAAK,WAAW,EACjB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAG5D,OAAO,KAAK,EACV,aAAa,EACb,iBAAiB,EAClB,MAAM,wBAAwB,CAAC;AAGhC,eAAO,MAAM,YAAY,kBAAkB,CAAC;AAE5C,eAAO,MAAM,gBAAgB,qBAAqB,CAAC;AACnD,eAAO,MAAM,eAAe,oBAAoB,CAAC;AAEjD,MAAM,MAAM,cAAc,GACtB;IAAE,IAAI,EAAE,OAAO,gBAAgB,CAAC;IAAC,QAAQ,EAAE,iBAAiB,CAAC;CAAE,GAC/D;IAAE,IAAI,EAAE,OAAO,eAAe,CAAC;IAAC,MAAM,EAAE,aAAa,CAAC;CAAE,CAAC;AAE7D,eAAO,MAAM,gBAAgB,EAAE,gBA+B9B,CAAC;AAEF,MAAM,WAAW,uBAAuB;IACtC,UAAU,EAAE,iBAAiB,CAAC;IAC9B;;;OAGG;IACH,EAAE,CAAC,EAAE,MAAM,CAAC;CACb;AAED;;GAEG;AACH,qBAAa,gBAAiB,SAAQ,SAAS;;IAC7C,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,mBAAgB;IAC7B,QAAQ,CAAC,SAAS,EAAE,gBAAgB,CAAoB;gBAQtD,OAAO,EAAE,uBAAuB;IAelC,eAAe,CACb,MAAM,EAAE,YAAY,EACpB,SAAS,EAAE,YAAY,EACvB,OAAO,EAAE,WAAW,GACnB,IAAI;IAUP,kBAAkB,CAChB,QAAQ,EAAE,MAAM,GACf,IAAI;IAOP,SAAS,IAAI,IAAI;IAIR,OAAO,IAAI,IAAI;CAQzB"}
1
+ {"version":3,"file":"CatalogExtension.d.ts","sourceRoot":"","sources":["../../src/catalog/CatalogExtension.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,SAAS,EAET,KAAK,YAAY,EACjB,KAAK,gBAAgB,EACrB,KAAK,YAAY,EAEjB,KAAK,WAAW,EACjB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAG5D,OAAO,KAAK,EACV,aAAa,EACb,iBAAiB,EAClB,MAAM,wBAAwB,CAAC;AAGhC,eAAO,MAAM,YAAY,kBAAkB,CAAC;AAE5C,eAAO,MAAM,gBAAgB,qBAAqB,CAAC;AACnD,eAAO,MAAM,eAAe,oBAAoB,CAAC;AAEjD,MAAM,MAAM,cAAc,GACtB;IAAE,IAAI,EAAE,OAAO,gBAAgB,CAAC;IAAC,QAAQ,EAAE,iBAAiB,CAAC;CAAE,GAC/D;IAAE,IAAI,EAAE,OAAO,eAAe,CAAC;IAAC,MAAM,EAAE,aAAa,CAAC;CAAE,CAAC;AAE7D,eAAO,MAAM,gBAAgB,EAAE,gBA+B9B,CAAC;AAEF,MAAM,WAAW,uBAAuB;IACtC,UAAU,EAAE,iBAAiB,CAAC;IAC9B;;;OAGG;IACH,EAAE,CAAC,EAAE,MAAM,CAAC;CACb;AAED;;GAEG;AACH,qBAAa,gBAAiB,SAAQ,SAAS;;IAC7C,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,mBAAgB;IAC7B,QAAQ,CAAC,SAAS,EAAE,gBAAgB,CAAoB;gBAQtD,OAAO,EAAE,uBAAuB;IAezB,eAAe,CACtB,MAAM,EAAE,YAAY,EACpB,SAAS,EAAE,YAAY,EACvB,OAAO,EAAE,WAAW,GACnB,IAAI;IAUE,kBAAkB,CACzB,QAAQ,EAAE,MAAM,GACf,IAAI;IAOE,OAAO,IAAI,IAAI;CAQzB"}
@@ -71,9 +71,6 @@ export class CatalogExtension extends Extension {
71
71
  this.#broadcast = null;
72
72
  }
73
73
  }
74
- onMessage() {
75
- return void 0;
76
- }
77
74
  dispose() {
78
75
  this.#projection.off("changed", this.#onChanged);
79
76
  this.#members.clear();
package/dist/constants.js CHANGED
@@ -5,9 +5,9 @@ export const IDENTITY_SIDECAR_PATH = `${STATE_DIRECTORY}/assets.json`;
5
5
  export const PROJECTION_STATE_PATH = `${STATE_DIRECTORY}/state.json`;
6
6
  export const STATE_GITIGNORE_PATH = `${STATE_DIRECTORY}/.gitignore`;
7
7
  export const EVENTS_DB_PATH = `${STATE_DIRECTORY}/events.db`;
8
- export const STATE_GITIGNORE_CONTENT = `state.json
9
- events.db
10
- events.db-journal
11
- events.db-wal
8
+ export const STATE_GITIGNORE_CONTENT = `state.json
9
+ events.db
10
+ events.db-journal
11
+ events.db-wal
12
12
  `;
13
13
  export const ASSET_EVENT_PREFIX = "asset.";
@@ -23,7 +23,6 @@ export declare class AssetRoomExtension<TCommand = unknown> extends network.Exte
23
23
  readonly protocols: network.MessageProtocols;
24
24
  constructor(binding: AssetRoomBinding, protocol: AssetLiveProtocol<TCommand>);
25
25
  onClientConnect(client: network.ClientHandle): void;
26
- onClientDisconnect(): void;
27
26
  onMessage(clientId: string, payload: unknown, context: network.RoomContext): Promise<void>;
28
27
  }
29
28
  //# sourceMappingURL=AssetRoomExtension.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"AssetRoomExtension.d.ts","sourceRoot":"","sources":["../../src/rooms/AssetRoomExtension.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,OAAO,MAAM,sBAAsB,CAAC;AAGhD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAErE,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,gBAAgB,CAAC,QAAQ,GAAG,OAAO;IAClD,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC;IAC3B,MAAM,CAAC,IAAI,IAAI,CAAC;CACjB;AAED,MAAM,WAAW,iBAAiB,CAAC,QAAQ,GAAG,OAAO;IACnD,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC,gBAAgB,CAAC;IAE7C,KAAK,CACH,OAAO,EAAE,OAAO,GACf,QAAQ,GAAG,IAAI,CAAC;IAEnB,QAAQ,IAAI,OAAO,CAAC;IAEpB,SAAS,CACP,OAAO,EAAE,QAAQ,EACjB,QAAQ,EAAE,MAAM,GACf,gBAAgB,CAAC,QAAQ,CAAC,GAAG,IAAI,CAAC;IAErC,SAAS,CAAC,CACR,OAAO,EAAE,QAAQ,GAChB,gBAAgB,CAAC;CACrB;AAED,qBAAa,kBAAkB,CAC7B,QAAQ,GAAG,OAAO,CAClB,SAAQ,OAAO,CAAC,SAAS;;IACzB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC,gBAAgB,CAAC;gBAM3C,OAAO,EAAE,gBAAgB,EACzB,QAAQ,EAAE,iBAAiB,CAAC,QAAQ,CAAC;IAWvC,eAAe,CACb,MAAM,EAAE,OAAO,CAAC,YAAY,GAC3B,IAAI;IAOP,kBAAkB,IAAI,IAAI;IAIpB,SAAS,CACb,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,OAAO,CAAC,WAAW,GAC3B,OAAO,CAAC,IAAI,CAAC;CA6BjB"}
1
+ {"version":3,"file":"AssetRoomExtension.d.ts","sourceRoot":"","sources":["../../src/rooms/AssetRoomExtension.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,OAAO,MAAM,sBAAsB,CAAC;AAGhD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAErE,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,gBAAgB,CAAC,QAAQ,GAAG,OAAO;IAClD,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC;IAC3B,MAAM,CAAC,IAAI,IAAI,CAAC;CACjB;AAED,MAAM,WAAW,iBAAiB,CAAC,QAAQ,GAAG,OAAO;IACnD,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC,gBAAgB,CAAC;IAE7C,KAAK,CACH,OAAO,EAAE,OAAO,GACf,QAAQ,GAAG,IAAI,CAAC;IAEnB,QAAQ,IAAI,OAAO,CAAC;IAEpB,SAAS,CACP,OAAO,EAAE,QAAQ,EACjB,QAAQ,EAAE,MAAM,GACf,gBAAgB,CAAC,QAAQ,CAAC,GAAG,IAAI,CAAC;IAErC,SAAS,CAAC,CACR,OAAO,EAAE,QAAQ,GAChB,gBAAgB,CAAC;CACrB;AAED,qBAAa,kBAAkB,CAC7B,QAAQ,GAAG,OAAO,CAClB,SAAQ,OAAO,CAAC,SAAS;;IACzB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC,gBAAgB,CAAC;gBAM3C,OAAO,EAAE,gBAAgB,EACzB,QAAQ,EAAE,iBAAiB,CAAC,QAAQ,CAAC;IAW9B,eAAe,CACtB,MAAM,EAAE,OAAO,CAAC,YAAY,GAC3B,IAAI;IAOQ,SAAS,CACtB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,OAAO,CAAC,WAAW,GAC3B,OAAO,CAAC,IAAI,CAAC;CA6BjB"}
@@ -20,9 +20,6 @@ export class AssetRoomExtension extends network.Extension {
20
20
  data: this.#protocol.snapshot()
21
21
  });
22
22
  }
23
- onClientDisconnect() {
24
- return void 0;
25
- }
26
23
  async onMessage(clientId, payload, context) {
27
24
  const command = this.#protocol.parse(payload);
28
25
  if (command === null) {
@@ -1,73 +1,73 @@
1
- # AssetBackend
2
-
3
- `createAssetBackend` connects an `AssetSource` to an event store and starts
4
- catalog projection, filesystem reconciliation and snapshot scheduling.
5
-
6
- ```ts
7
- createAssetBackend(options: AssetBackendOptions): Promise<AssetBackend>
8
- ```
9
-
10
- ## Options
11
-
12
- | Option | Default | Description |
13
- |---|---|---|
14
- | `source` | required | Physical asset storage. |
15
- | `eventStore` | required | Event store used for asset and domain events. |
16
- | `handlers` | `[]` | Asset kind handlers. Unmatched paths use `binary`. |
17
- | `snapshot` | `2_000` / `30_000` ms | Default quiet and maximum snapshot delays. |
18
- | `reconcileOnStart` | `true` | Scan the source when the backend starts. |
19
- | `watch` | `true` | Watch sources that implement `watch()`. |
20
- | `reconcileDebounce` | `200` ms | Quiet period before external changes are scanned. |
21
- | `logger` | silent | A `loglayer` logger. |
22
-
23
- A handler may override either default snapshot delay. See
24
- [Asset kinds](./AssetKinds.md#snapshot-policy).
25
-
26
- ## Returned backend
27
-
28
- ```ts
29
- interface AssetBackend extends AsyncDisposable {
30
- readonly source: AssetSource;
31
- readonly eventStore: EventStore;
32
- readonly kinds: AssetKindRegistry;
33
- readonly writer: AssetWriter;
34
- readonly catalog: CatalogProjection;
35
-
36
- flush(assetId?: string): Promise<void>;
37
- attach(server: Server, options?: { graceMs?: number }): () => void;
38
- close(): Promise<void>;
39
- }
40
- ```
41
-
42
- Use [`writer`](./AssetWriter.md) for asset mutations. `flush(assetId?)` waits
43
- for pending snapshots and source writes for one asset, or for every pending
44
- asset when the ID is omitted.
45
-
46
- `attach(server)` registers the `asset-catalog` room and installs the dynamic
47
- asset-room resolver. Its callback clears the resolver. Existing rooms and the
48
- catalog room remain owned by the `Server` until `server.close()`.
49
-
50
- Close the server before the backend so active asset rooms can flush while the
51
- backend is still running. `close()` stops watching, flushes pending work and
52
- releases backend subscriptions. It does not close the injected server or event
53
- store. `[Symbol.asyncDispose]` calls `close()`.
54
-
55
- The returned object also exposes `internals` for tests and hosts that need to
56
- drive an individual stage. Normal application code should use `writer`,
57
- `catalog`, `flush()` and `attach()`.
58
-
59
- ## Workspace files
60
-
61
- `createAssetBackend` manages these files under the source root:
62
-
63
- ```text
64
- .jollypixel/
65
- assets.json
66
- state.json
67
- .gitignore
68
- ```
69
-
70
- Commit `assets.json` so paths keep the same asset IDs when a checkout has no
71
- local event log. `state.json` stores machine-local projection positions and is
72
- ignored by the generated `.gitignore`. The host chooses where the event store
73
- is persisted.
1
+ # AssetBackend
2
+
3
+ `createAssetBackend` connects an `AssetSource` to an event store and starts
4
+ catalog projection, filesystem reconciliation and snapshot scheduling.
5
+
6
+ ```ts
7
+ createAssetBackend(options: AssetBackendOptions): Promise<AssetBackend>
8
+ ```
9
+
10
+ ## Options
11
+
12
+ | Option | Default | Description |
13
+ |---|---|---|
14
+ | `source` | required | Physical asset storage. |
15
+ | `eventStore` | required | Event store used for asset and domain events. |
16
+ | `handlers` | `[]` | Asset kind handlers. Unmatched paths use `binary`. |
17
+ | `snapshot` | `2_000` / `30_000` ms | Default quiet and maximum snapshot delays. |
18
+ | `reconcileOnStart` | `true` | Scan the source when the backend starts. |
19
+ | `watch` | `true` | Watch sources that implement `watch()`. |
20
+ | `reconcileDebounce` | `200` ms | Quiet period before external changes are scanned. |
21
+ | `logger` | silent | A `loglayer` logger. |
22
+
23
+ A handler may override either default snapshot delay. See
24
+ [Asset kinds](./AssetKinds.md#snapshot-policy).
25
+
26
+ ## Returned backend
27
+
28
+ ```ts
29
+ interface AssetBackend extends AsyncDisposable {
30
+ readonly source: AssetSource;
31
+ readonly eventStore: EventStore;
32
+ readonly kinds: AssetKindRegistry;
33
+ readonly writer: AssetWriter;
34
+ readonly catalog: CatalogProjection;
35
+
36
+ flush(assetId?: string): Promise<void>;
37
+ attach(server: Server, options?: { graceMs?: number }): () => void;
38
+ close(): Promise<void>;
39
+ }
40
+ ```
41
+
42
+ Use [`writer`](./AssetWriter.md) for asset mutations. `flush(assetId?)` waits
43
+ for pending snapshots and source writes for one asset, or for every pending
44
+ asset when the ID is omitted.
45
+
46
+ `attach(server)` registers the `asset-catalog` room and installs the dynamic
47
+ asset-room resolver. Its callback clears the resolver. Existing rooms and the
48
+ catalog room remain owned by the `Server` until `server.close()`.
49
+
50
+ Close the server before the backend so active asset rooms can flush while the
51
+ backend is still running. `close()` stops watching, flushes pending work and
52
+ releases backend subscriptions. It does not close the injected server or event
53
+ store. `[Symbol.asyncDispose]` calls `close()`.
54
+
55
+ The returned object also exposes `internals` for tests and hosts that need to
56
+ drive an individual stage. Normal application code should use `writer`,
57
+ `catalog`, `flush()` and `attach()`.
58
+
59
+ ## Workspace files
60
+
61
+ `createAssetBackend` manages these files under the source root:
62
+
63
+ ```text
64
+ .jollypixel/
65
+ assets.json
66
+ state.json
67
+ .gitignore
68
+ ```
69
+
70
+ Commit `assets.json` so paths keep the same asset IDs when a checkout has no
71
+ local event log. `state.json` stores machine-local projection positions and is
72
+ ignored by the generated `.gitignore`. The host chooses where the event store
73
+ is persisted.