@jolly-pixel/asset-server 1.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.
Files changed (139) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +83 -0
  3. package/dist/catalog/CatalogExtension.d.ts +37 -0
  4. package/dist/catalog/CatalogExtension.d.ts.map +1 -0
  5. package/dist/catalog/CatalogExtension.js +82 -0
  6. package/dist/catalog/CatalogIdentitySidecar.d.ts +52 -0
  7. package/dist/catalog/CatalogIdentitySidecar.d.ts.map +1 -0
  8. package/dist/catalog/CatalogIdentitySidecar.js +132 -0
  9. package/dist/catalog/CatalogProjection.d.ts +32 -0
  10. package/dist/catalog/CatalogProjection.d.ts.map +1 -0
  11. package/dist/catalog/CatalogProjection.js +109 -0
  12. package/dist/catalog/httpHandler.d.ts +13 -0
  13. package/dist/catalog/httpHandler.d.ts.map +1 -0
  14. package/dist/catalog/httpHandler.js +27 -0
  15. package/dist/catalog/index.d.ts +9 -0
  16. package/dist/catalog/index.d.ts.map +1 -0
  17. package/dist/catalog/index.js +4 -0
  18. package/dist/constants.d.ts +9 -0
  19. package/dist/constants.d.ts.map +1 -0
  20. package/dist/constants.js +13 -0
  21. package/dist/createAssetBackend.d.ts +79 -0
  22. package/dist/createAssetBackend.d.ts.map +1 -0
  23. package/dist/createAssetBackend.js +146 -0
  24. package/dist/events/AssetEvents.d.ts +54 -0
  25. package/dist/events/AssetEvents.d.ts.map +1 -0
  26. package/dist/events/AssetEvents.js +102 -0
  27. package/dist/events/AssetEvents.schema.d.ts +111 -0
  28. package/dist/events/AssetEvents.schema.d.ts.map +1 -0
  29. package/dist/events/AssetEvents.schema.js +75 -0
  30. package/dist/events/index.d.ts +3 -0
  31. package/dist/events/index.d.ts.map +1 -0
  32. package/dist/events/index.js +1 -0
  33. package/dist/index.d.ts +13 -0
  34. package/dist/index.d.ts.map +1 -0
  35. package/dist/index.js +11 -0
  36. package/dist/kinds/AssetKindHandler.d.ts +38 -0
  37. package/dist/kinds/AssetKindHandler.d.ts.map +1 -0
  38. package/dist/kinds/AssetKindHandler.js +1 -0
  39. package/dist/kinds/AssetKindRegistry.d.ts +14 -0
  40. package/dist/kinds/AssetKindRegistry.d.ts.map +1 -0
  41. package/dist/kinds/AssetKindRegistry.js +52 -0
  42. package/dist/kinds/errors/UnknownAssetKindError.d.ts +5 -0
  43. package/dist/kinds/errors/UnknownAssetKindError.d.ts.map +1 -0
  44. package/dist/kinds/errors/UnknownAssetKindError.js +8 -0
  45. package/dist/kinds/errors/index.d.ts +2 -0
  46. package/dist/kinds/errors/index.d.ts.map +1 -0
  47. package/dist/kinds/errors/index.js +1 -0
  48. package/dist/kinds/handlers/binary.d.ts +10 -0
  49. package/dist/kinds/handlers/binary.d.ts.map +1 -0
  50. package/dist/kinds/handlers/binary.js +31 -0
  51. package/dist/kinds/handlers/index.d.ts +5 -0
  52. package/dist/kinds/handlers/index.d.ts.map +1 -0
  53. package/dist/kinds/handlers/index.js +2 -0
  54. package/dist/kinds/handlers/texture.d.ts +12 -0
  55. package/dist/kinds/handlers/texture.d.ts.map +1 -0
  56. package/dist/kinds/handlers/texture.js +27 -0
  57. package/dist/kinds/index.d.ts +5 -0
  58. package/dist/kinds/index.d.ts.map +1 -0
  59. package/dist/kinds/index.js +3 -0
  60. package/dist/logger.d.ts +4 -0
  61. package/dist/logger.d.ts.map +1 -0
  62. package/dist/logger.js +9 -0
  63. package/dist/plugins/vite.d.ts +36 -0
  64. package/dist/plugins/vite.d.ts.map +1 -0
  65. package/dist/plugins/vite.js +60 -0
  66. package/dist/rooms/AssetRoomExtension.d.ts +29 -0
  67. package/dist/rooms/AssetRoomExtension.d.ts.map +1 -0
  68. package/dist/rooms/AssetRoomExtension.js +50 -0
  69. package/dist/rooms/index.d.ts +5 -0
  70. package/dist/rooms/index.d.ts.map +1 -0
  71. package/dist/rooms/index.js +2 -0
  72. package/dist/rooms/registerAssetRooms.d.ts +21 -0
  73. package/dist/rooms/registerAssetRooms.d.ts.map +1 -0
  74. package/dist/rooms/registerAssetRooms.js +71 -0
  75. package/dist/static/contentTypes.d.ts +6 -0
  76. package/dist/static/contentTypes.d.ts.map +1 -0
  77. package/dist/static/contentTypes.js +27 -0
  78. package/dist/static/httpHandler.d.ts +24 -0
  79. package/dist/static/httpHandler.d.ts.map +1 -0
  80. package/dist/static/httpHandler.js +105 -0
  81. package/dist/static/index.d.ts +4 -0
  82. package/dist/static/index.d.ts.map +1 -0
  83. package/dist/static/index.js +2 -0
  84. package/dist/sync/AssetProjector.d.ts +33 -0
  85. package/dist/sync/AssetProjector.d.ts.map +1 -0
  86. package/dist/sync/AssetProjector.js +186 -0
  87. package/dist/sync/AssetStateStore.d.ts +28 -0
  88. package/dist/sync/AssetStateStore.d.ts.map +1 -0
  89. package/dist/sync/AssetStateStore.js +86 -0
  90. package/dist/sync/AssetWriter.d.ts +54 -0
  91. package/dist/sync/AssetWriter.d.ts.map +1 -0
  92. package/dist/sync/AssetWriter.js +149 -0
  93. package/dist/sync/ProjectionState.d.ts +33 -0
  94. package/dist/sync/ProjectionState.d.ts.map +1 -0
  95. package/dist/sync/ProjectionState.js +129 -0
  96. package/dist/sync/Reconciler.d.ts +36 -0
  97. package/dist/sync/Reconciler.d.ts.map +1 -0
  98. package/dist/sync/Reconciler.js +182 -0
  99. package/dist/sync/ReconciliationWatcher.d.ts +28 -0
  100. package/dist/sync/ReconciliationWatcher.d.ts.map +1 -0
  101. package/dist/sync/ReconciliationWatcher.js +86 -0
  102. package/dist/sync/SnapshotScheduler.d.ts +29 -0
  103. package/dist/sync/SnapshotScheduler.d.ts.map +1 -0
  104. package/dist/sync/SnapshotScheduler.js +136 -0
  105. package/dist/sync/foldProjection.d.ts +12 -0
  106. package/dist/sync/foldProjection.d.ts.map +1 -0
  107. package/dist/sync/foldProjection.js +32 -0
  108. package/dist/sync/index.d.ts +19 -0
  109. package/dist/sync/index.d.ts.map +1 -0
  110. package/dist/sync/index.js +9 -0
  111. package/dist/sync/matchRenames.d.ts +45 -0
  112. package/dist/sync/matchRenames.d.ts.map +1 -0
  113. package/dist/sync/matchRenames.js +85 -0
  114. package/dist/utils/TaskChain.d.ts +9 -0
  115. package/dist/utils/TaskChain.d.ts.map +1 -0
  116. package/dist/utils/TaskChain.js +14 -0
  117. package/dist/utils/contentHash.d.ts +2 -0
  118. package/dist/utils/contentHash.d.ts.map +1 -0
  119. package/dist/utils/contentHash.js +7 -0
  120. package/dist/utils/index.d.ts +3 -0
  121. package/dist/utils/index.d.ts.map +1 -0
  122. package/dist/utils/index.js +2 -0
  123. package/dist/workspace/createAssetWorkspace.d.ts +71 -0
  124. package/dist/workspace/createAssetWorkspace.d.ts.map +1 -0
  125. package/dist/workspace/createAssetWorkspace.js +72 -0
  126. package/dist/workspace/index.d.ts +5 -0
  127. package/dist/workspace/index.d.ts.map +1 -0
  128. package/dist/workspace/index.js +2 -0
  129. package/dist/workspace/seedAssetSource.d.ts +5 -0
  130. package/dist/workspace/seedAssetSource.d.ts.map +1 -0
  131. package/dist/workspace/seedAssetSource.js +20 -0
  132. package/docs/AssetBackend.md +73 -0
  133. package/docs/AssetKinds.md +204 -0
  134. package/docs/AssetWriter.md +62 -0
  135. package/docs/Catalog.md +71 -0
  136. package/docs/Rooms.md +70 -0
  137. package/docs/Sync.md +146 -0
  138. package/docs/Workspace.md +172 -0
  139. package/package.json +83 -0
@@ -0,0 +1,79 @@
1
+ import type * as EventStore from "@jolly-pixel/event-store";
2
+ import type { Server } from "@jolly-pixel/network";
3
+ import type { AssetSource } from "@jolly-pixel/asset-source";
4
+ import type { AssetEventDataMap } from "./events/AssetEvents.ts";
5
+ import { CatalogIdentitySidecar } from "./catalog/CatalogIdentitySidecar.ts";
6
+ import { AssetKindRegistry } from "./kinds/AssetKindRegistry.ts";
7
+ import type { AssetKindHandler, SnapshotPolicy } from "./kinds/AssetKindHandler.ts";
8
+ import { ProjectionState } from "./sync/ProjectionState.ts";
9
+ import { AssetProjector } from "./sync/AssetProjector.ts";
10
+ import { AssetStateStore } from "./sync/AssetStateStore.ts";
11
+ import { AssetWriter } from "./sync/AssetWriter.ts";
12
+ import { SnapshotScheduler } from "./sync/SnapshotScheduler.ts";
13
+ import { Reconciler } from "./sync/Reconciler.ts";
14
+ import { ReconciliationWatcher } from "./sync/ReconciliationWatcher.ts";
15
+ import { CatalogProjection } from "./catalog/CatalogProjection.ts";
16
+ import { CatalogExtension } from "./catalog/CatalogExtension.ts";
17
+ import { type Logger } from "./logger.ts";
18
+ export interface AssetBackendOptions {
19
+ source: AssetSource;
20
+ eventStore: EventStore.TypedEventStore<AssetEventDataMap>;
21
+ /**
22
+ * Kind handlers. The built-in `binary` fallback is always present and
23
+ * claims whatever these do not.
24
+ */
25
+ handlers?: AssetKindHandler[];
26
+ /**
27
+ * Default snapshot cadence, overridable per kind.
28
+ */
29
+ snapshot?: SnapshotPolicy;
30
+ /**
31
+ * Reconcile the physical store on startup.
32
+ * @default true
33
+ */
34
+ reconcileOnStart?: boolean;
35
+ /**
36
+ * Watch the source for external changes, when it supports it.
37
+ * @default true
38
+ */
39
+ watch?: boolean;
40
+ /**
41
+ * Quiet period, in milliseconds, before filesystem notifications become
42
+ * one reconciliation pass.
43
+ */
44
+ reconcileDebounce?: number;
45
+ logger?: Logger;
46
+ }
47
+ /**
48
+ * Internal stages exposed to tests, tooling, and hosts.
49
+ *
50
+ * They stay outside `AssetBackend` because their shapes are not public API.
51
+ */
52
+ export interface AssetBackendInternals {
53
+ readonly identity: CatalogIdentitySidecar;
54
+ readonly state: ProjectionState;
55
+ readonly projector: AssetProjector;
56
+ readonly states: AssetStateStore;
57
+ readonly scheduler: SnapshotScheduler;
58
+ readonly reconciler: Reconciler;
59
+ readonly watcher: ReconciliationWatcher;
60
+ readonly catalogExtension: CatalogExtension;
61
+ }
62
+ export interface AssetBackend extends AsyncDisposable {
63
+ readonly source: AssetSource;
64
+ readonly eventStore: EventStore.TypedEventStore<AssetEventDataMap>;
65
+ readonly kinds: AssetKindRegistry;
66
+ readonly writer: AssetWriter;
67
+ readonly catalog: CatalogProjection;
68
+ readonly internals: AssetBackendInternals;
69
+ flush(assetId?: string): Promise<void>;
70
+ attach(server: Server, options?: {
71
+ graceMs?: number;
72
+ }): () => void;
73
+ close(): Promise<void>;
74
+ }
75
+ /**
76
+ * Assembles the asset backend and starts projections in dependency order.
77
+ */
78
+ export declare function createAssetBackend(options: AssetBackendOptions): Promise<AssetBackend>;
79
+ //# sourceMappingURL=createAssetBackend.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createAssetBackend.d.ts","sourceRoot":"","sources":["../src/createAssetBackend.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,UAAU,MAAM,0BAA0B,CAAC;AAC5D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AACnD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAO7D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AACjE,OAAO,EAAE,sBAAsB,EAAE,MAAM,qCAAqC,CAAC;AAC7E,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,KAAK,EACV,gBAAgB,EAChB,cAAc,EACf,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,EAAE,qBAAqB,EAAE,MAAM,iCAAiC,CAAC;AACxE,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAEjE,OAAO,EAEL,KAAK,MAAM,EACZ,MAAM,aAAa,CAAC;AAErB,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,WAAW,CAAC;IACpB,UAAU,EAAE,UAAU,CAAC,eAAe,CAAC,iBAAiB,CAAC,CAAC;IAC1D;;;OAGG;IACH,QAAQ,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAC9B;;OAEG;IACH,QAAQ,CAAC,EAAE,cAAc,CAAC;IAC1B;;;OAGG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B;;;OAGG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB;;;OAGG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;GAIG;AACH,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,QAAQ,EAAE,sBAAsB,CAAC;IAC1C,QAAQ,CAAC,KAAK,EAAE,eAAe,CAAC;IAChC,QAAQ,CAAC,SAAS,EAAE,cAAc,CAAC;IACnC,QAAQ,CAAC,MAAM,EAAE,eAAe,CAAC;IACjC,QAAQ,CAAC,SAAS,EAAE,iBAAiB,CAAC;IACtC,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;IAChC,QAAQ,CAAC,OAAO,EAAE,qBAAqB,CAAC;IACxC,QAAQ,CAAC,gBAAgB,EAAE,gBAAgB,CAAC;CAC7C;AAED,MAAM,WAAW,YAAa,SAAQ,eAAe;IACnD,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAC7B,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC,eAAe,CAAC,iBAAiB,CAAC,CAAC;IACnE,QAAQ,CAAC,KAAK,EAAE,iBAAiB,CAAC;IAClC,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAC7B,QAAQ,CAAC,OAAO,EAAE,iBAAiB,CAAC;IACpC,QAAQ,CAAC,SAAS,EAAE,qBAAqB,CAAC;IAE1C,KAAK,CACH,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC,CAAC;IAEjB,MAAM,CACJ,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC;KAAE,GAC9B,MAAM,IAAI,CAAC;IAEd,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,YAAY,CAAC,CAuIvB"}
@@ -0,0 +1,146 @@
1
+ // Import Internal Dependencies
2
+ import { STATE_GITIGNORE_CONTENT, STATE_GITIGNORE_PATH } from "./constants.js";
3
+ import { CatalogIdentitySidecar } from "./catalog/CatalogIdentitySidecar.js";
4
+ import { AssetKindRegistry } from "./kinds/AssetKindRegistry.js";
5
+ import { ProjectionState } from "./sync/ProjectionState.js";
6
+ import { AssetProjector } from "./sync/AssetProjector.js";
7
+ import { AssetStateStore } from "./sync/AssetStateStore.js";
8
+ import { AssetWriter } from "./sync/AssetWriter.js";
9
+ import { SnapshotScheduler } from "./sync/SnapshotScheduler.js";
10
+ import { Reconciler } from "./sync/Reconciler.js";
11
+ import { ReconciliationWatcher } from "./sync/ReconciliationWatcher.js";
12
+ import { CatalogProjection } from "./catalog/CatalogProjection.js";
13
+ import { CatalogExtension } from "./catalog/CatalogExtension.js";
14
+ import { registerAssetRooms } from "./rooms/registerAssetRooms.js";
15
+ import { silentLogger } from "./logger.js";
16
+ /**
17
+ * Assembles the asset backend and starts projections in dependency order.
18
+ */
19
+ export async function createAssetBackend(options) {
20
+ const { source, eventStore, handlers = [], snapshot, reconcileOnStart = true, watch = true, reconcileDebounce, logger = silentLogger() } = options;
21
+ const kinds = new AssetKindRegistry(handlers);
22
+ await ensureGitignore(source);
23
+ const state = await ProjectionState.load(source, logger);
24
+ const projector = new AssetProjector({
25
+ source,
26
+ eventStore,
27
+ state,
28
+ logger
29
+ });
30
+ projector.load();
31
+ projector.start();
32
+ const states = new AssetStateStore({
33
+ eventStore,
34
+ kinds
35
+ });
36
+ states.start();
37
+ const scheduler = new SnapshotScheduler({
38
+ eventStore,
39
+ states,
40
+ projector,
41
+ snapshot,
42
+ logger
43
+ });
44
+ scheduler.start();
45
+ const identity = await CatalogIdentitySidecar.load(source, logger);
46
+ const writer = new AssetWriter({
47
+ eventStore,
48
+ kinds,
49
+ projector,
50
+ identity,
51
+ source,
52
+ logger
53
+ });
54
+ const reconciler = new Reconciler({
55
+ source,
56
+ projector,
57
+ writer,
58
+ kinds,
59
+ logger
60
+ });
61
+ const watcher = new ReconciliationWatcher({
62
+ source,
63
+ reconciler,
64
+ debounce: reconcileDebounce,
65
+ logger
66
+ });
67
+ const catalog = new CatalogProjection({ eventStore });
68
+ if (reconcileOnStart) {
69
+ (await reconciler.reconcile()).orTee((error) => logger
70
+ .withMetadata({ reason: error.message })
71
+ .error("initial reconciliation failed"));
72
+ await projector.flush();
73
+ }
74
+ catalog.load();
75
+ catalog.start();
76
+ const catalogExtension = new CatalogExtension({
77
+ projection: catalog
78
+ });
79
+ if (watch) {
80
+ watcher.start();
81
+ }
82
+ const backend = {
83
+ source,
84
+ eventStore,
85
+ kinds,
86
+ writer,
87
+ catalog,
88
+ internals: {
89
+ identity,
90
+ state,
91
+ projector,
92
+ states,
93
+ scheduler,
94
+ reconciler,
95
+ watcher,
96
+ catalogExtension
97
+ },
98
+ async flush(assetId) {
99
+ await scheduler.flush(assetId);
100
+ await projector.flush(assetId);
101
+ },
102
+ attach(server, attachOptions = {}) {
103
+ server.register(catalogExtension);
104
+ return registerAssetRooms({
105
+ server,
106
+ kinds,
107
+ catalog,
108
+ states,
109
+ projector,
110
+ scheduler,
111
+ graceMs: attachOptions.graceMs,
112
+ logger
113
+ });
114
+ },
115
+ async close() {
116
+ await watcher.close();
117
+ await scheduler.close();
118
+ await projector.close();
119
+ states.close();
120
+ catalogExtension.dispose();
121
+ catalog.close();
122
+ },
123
+ async [Symbol.asyncDispose]() {
124
+ await backend.close();
125
+ }
126
+ };
127
+ return backend;
128
+ }
129
+ async function ensureGitignore(source) {
130
+ try {
131
+ await source.read(STATE_GITIGNORE_PATH);
132
+ return;
133
+ }
134
+ catch (error) {
135
+ if (!isNotFound(error)) {
136
+ return;
137
+ }
138
+ }
139
+ await source.write(STATE_GITIGNORE_PATH, new TextEncoder().encode(STATE_GITIGNORE_CONTENT));
140
+ }
141
+ function isNotFound(error) {
142
+ return typeof error === "object" &&
143
+ error !== null &&
144
+ "code" in error &&
145
+ error.code === "ENOENT";
146
+ }
@@ -0,0 +1,54 @@
1
+ import type * as EventStore from "@jolly-pixel/event-store";
2
+ import { type Result } from "@openally/result";
3
+ import { type Infer, type ValidationError } from "ata-validator";
4
+ import { assetContentSchema, assetDeletedDataSchema, assetRenamedDataSchema, assetWriteDataSchema } from "./AssetEvents.schema.ts";
5
+ export declare const ASSET_CREATED: "asset.created";
6
+ export declare const ASSET_UPDATED: "asset.updated";
7
+ export declare const ASSET_RENAMED: "asset.renamed";
8
+ export declare const ASSET_DELETED: "asset.deleted";
9
+ export type AssetEventType = typeof ASSET_CREATED | typeof ASSET_UPDATED | typeof ASSET_RENAMED | typeof ASSET_DELETED;
10
+ export declare const ASSET_CHECKPOINT_EVENT_TYPES: readonly AssetEventType[];
11
+ export type AssetContent = Infer<typeof assetContentSchema>;
12
+ export type AssetInlineContent = Extract<AssetContent, {
13
+ type: "inline";
14
+ }>;
15
+ /**
16
+ * Shared payload for create and update events.
17
+ */
18
+ export type AssetWriteData = Readonly<Omit<Infer<typeof assetWriteDataSchema>, "content"> & {
19
+ content: AssetInlineContent;
20
+ }>;
21
+ export type AssetCreatedData = AssetWriteData;
22
+ export type AssetUpdatedData = AssetWriteData;
23
+ export type AssetRenamedData = Readonly<Infer<typeof assetRenamedDataSchema>>;
24
+ export type AssetDeletedData = Readonly<Infer<typeof assetDeletedDataSchema>>;
25
+ export type AssetEventData = AssetWriteData | AssetRenamedData | AssetDeletedData;
26
+ export type AssetEventDataMap = {
27
+ [ASSET_CREATED]: AssetCreatedData;
28
+ [ASSET_UPDATED]: AssetUpdatedData;
29
+ [ASSET_RENAMED]: AssetRenamedData;
30
+ [ASSET_DELETED]: AssetDeletedData;
31
+ };
32
+ export type AssetEvent = EventStore.TypedEvent<AssetEventDataMap>;
33
+ /**
34
+ * Why an event on an asset stream did not yield an asset event.
35
+ *
36
+ * `foreign` means the event belongs to another domain and is none of our
37
+ * business. `malformed` and `unsupported` both mean an asset event we cannot
38
+ * project, and are worth reporting.
39
+ */
40
+ export type AssetEventRejection = {
41
+ reason: "foreign";
42
+ } | {
43
+ reason: "malformed";
44
+ errors: readonly ValidationError[];
45
+ } | {
46
+ reason: "unsupported";
47
+ detail: string;
48
+ };
49
+ export declare function isAssetEventType(eventType: string): boolean;
50
+ export declare function parseAssetEvent(event: EventStore.Event): Result<AssetEvent, AssetEventRejection>;
51
+ export declare function describeRejection(rejection: AssetEventRejection): string;
52
+ export declare function encodeContent(data: Uint8Array): AssetInlineContent;
53
+ export declare function decodeContent(content: AssetInlineContent): Uint8Array;
54
+ //# sourceMappingURL=AssetEvents.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AssetEvents.d.ts","sourceRoot":"","sources":["../../src/events/AssetEvents.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,KAAK,UAAU,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAGL,KAAK,MAAM,EACZ,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAEL,KAAK,KAAK,EACV,KAAK,eAAe,EACrB,MAAM,eAAe,CAAC;AAGvB,OAAO,EACL,kBAAkB,EAClB,sBAAsB,EACtB,sBAAsB,EACtB,oBAAoB,EACrB,MAAM,yBAAyB,CAAC;AAkBjC,eAAO,MAAM,aAAa,iBAA0C,CAAC;AACrE,eAAO,MAAM,aAAa,iBAA0C,CAAC;AACrE,eAAO,MAAM,aAAa,iBAA0C,CAAC;AACrE,eAAO,MAAM,aAAa,iBAA0C,CAAC;AAErE,MAAM,MAAM,cAAc,GACtB,OAAO,aAAa,GACpB,OAAO,aAAa,GACpB,OAAO,aAAa,GACpB,OAAO,aAAa,CAAC;AAEzB,eAAO,MAAM,4BAA4B,EAAE,SAAS,cAAc,EAIjE,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAE5D,MAAM,MAAM,kBAAkB,GAAG,OAAO,CACtC,YAAY,EACZ;IAAE,IAAI,EAAE,QAAQ,CAAC;CAAE,CACpB,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG,QAAQ,CACjC,IAAI,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,EAAE,SAAS,CAAC,GACnD;IAAE,OAAO,EAAE,kBAAkB,CAAC;CAAE,CACnC,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG,cAAc,CAAC;AAC9C,MAAM,MAAM,gBAAgB,GAAG,cAAc,CAAC;AAE9C,MAAM,MAAM,gBAAgB,GAAG,QAAQ,CACrC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CACrC,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG,QAAQ,CACrC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CACrC,CAAC;AAEF,MAAM,MAAM,cAAc,GACtB,cAAc,GACd,gBAAgB,GAChB,gBAAgB,CAAC;AAErB,MAAM,MAAM,iBAAiB,GAAG;IAC9B,CAAC,aAAa,CAAC,EAAE,gBAAgB,CAAC;IAClC,CAAC,aAAa,CAAC,EAAE,gBAAgB,CAAC;IAClC,CAAC,aAAa,CAAC,EAAE,gBAAgB,CAAC;IAClC,CAAC,aAAa,CAAC,EAAE,gBAAgB,CAAC;CACnC,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG,UAAU,CAAC,UAAU,CAAC,iBAAiB,CAAC,CAAC;AAElE;;;;;;GAMG;AACH,MAAM,MAAM,mBAAmB,GAC3B;IAAE,MAAM,EAAE,SAAS,CAAC;CAAE,GACtB;IAAE,MAAM,EAAE,WAAW,CAAC;IAAC,MAAM,EAAE,SAAS,eAAe,EAAE,CAAC;CAAE,GAC5D;IAAE,MAAM,EAAE,aAAa,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;CAAE,CAAC;AAE/C,wBAAgB,gBAAgB,CAC9B,SAAS,EAAE,MAAM,GAChB,OAAO,CAET;AAED,wBAAgB,eAAe,CAC7B,KAAK,EAAE,UAAU,CAAC,KAAK,GACtB,MAAM,CAAC,UAAU,EAAE,mBAAmB,CAAC,CA8BzC;AAED,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,mBAAmB,GAC7B,MAAM,CAWR;AAsCD,wBAAgB,aAAa,CAC3B,IAAI,EAAE,UAAU,GACf,kBAAkB,CAUpB;AAED,wBAAgB,aAAa,CAC3B,OAAO,EAAE,kBAAkB,GAC1B,UAAU,CAIZ"}
@@ -0,0 +1,102 @@
1
+ // Import Node.js Dependencies
2
+ import { Buffer } from "node:buffer";
3
+ import { Err, Ok } from "@openally/result";
4
+ import { Validator } from "ata-validator";
5
+ // Import Internal Dependencies
6
+ import { assetContentSchema, assetDeletedDataSchema, assetRenamedDataSchema, assetWriteDataSchema } from "./AssetEvents.schema.js";
7
+ import { ASSET_EVENT_PREFIX } from "../constants.js";
8
+ // CONSTANTS
9
+ const kValidatorOptions = { useDefaults: false };
10
+ const kWriteDataValidator = new Validator(assetWriteDataSchema, kValidatorOptions);
11
+ const kRenamedDataValidator = new Validator(assetRenamedDataSchema, kValidatorOptions);
12
+ const kDeletedDataValidator = new Validator(assetDeletedDataSchema, kValidatorOptions);
13
+ export const ASSET_CREATED = `${ASSET_EVENT_PREFIX}created`;
14
+ export const ASSET_UPDATED = `${ASSET_EVENT_PREFIX}updated`;
15
+ export const ASSET_RENAMED = `${ASSET_EVENT_PREFIX}renamed`;
16
+ export const ASSET_DELETED = `${ASSET_EVENT_PREFIX}deleted`;
17
+ export const ASSET_CHECKPOINT_EVENT_TYPES = [
18
+ ASSET_CREATED,
19
+ ASSET_UPDATED,
20
+ ASSET_DELETED
21
+ ];
22
+ export function isAssetEventType(eventType) {
23
+ return eventType.startsWith(ASSET_EVENT_PREFIX);
24
+ }
25
+ export function parseAssetEvent(event) {
26
+ switch (event.eventType) {
27
+ case ASSET_CREATED:
28
+ case ASSET_UPDATED:
29
+ return parseWriteEvent(event.eventType, event);
30
+ case ASSET_RENAMED: {
31
+ const result = kRenamedDataValidator.validate(event.eventData);
32
+ return result.valid ?
33
+ Ok({
34
+ ...event,
35
+ eventType: ASSET_RENAMED,
36
+ eventData: result.data
37
+ }) :
38
+ Err(malformed(result.errors));
39
+ }
40
+ case ASSET_DELETED: {
41
+ const result = kDeletedDataValidator.validate(event.eventData);
42
+ return result.valid ?
43
+ Ok({
44
+ ...event,
45
+ eventType: ASSET_DELETED,
46
+ eventData: result.data
47
+ }) :
48
+ Err(malformed(result.errors));
49
+ }
50
+ default:
51
+ return Err({ reason: "foreign" });
52
+ }
53
+ }
54
+ export function describeRejection(rejection) {
55
+ switch (rejection.reason) {
56
+ case "foreign":
57
+ return "event belongs to another domain";
58
+ case "unsupported":
59
+ return rejection.detail;
60
+ default:
61
+ return rejection.errors
62
+ .map((error) => `${error.instancePath || "/"} ${error.message}`)
63
+ .join("; ");
64
+ }
65
+ }
66
+ function parseWriteEvent(eventType, event) {
67
+ const result = kWriteDataValidator.validate(event.eventData);
68
+ if (!result.valid) {
69
+ return Err(malformed(result.errors));
70
+ }
71
+ const { content } = result.data;
72
+ if (content.type !== "inline") {
73
+ return Err({
74
+ reason: "unsupported",
75
+ detail: "content references are not supported yet"
76
+ });
77
+ }
78
+ return Ok({
79
+ ...event,
80
+ eventType,
81
+ eventData: {
82
+ ...result.data,
83
+ content
84
+ }
85
+ });
86
+ }
87
+ function malformed(errors) {
88
+ return {
89
+ reason: "malformed",
90
+ errors
91
+ };
92
+ }
93
+ export function encodeContent(data) {
94
+ return {
95
+ type: "inline",
96
+ encoding: "base64",
97
+ data: Buffer.from(data.buffer, data.byteOffset, data.byteLength).toString("base64")
98
+ };
99
+ }
100
+ export function decodeContent(content) {
101
+ return new Uint8Array(Buffer.from(content.data, "base64"));
102
+ }
@@ -0,0 +1,111 @@
1
+ export declare const assetContentSchema: {
2
+ readonly oneOf: readonly [{
3
+ readonly type: "object";
4
+ readonly properties: {
5
+ readonly type: {
6
+ readonly const: "inline";
7
+ };
8
+ readonly encoding: {
9
+ readonly const: "base64";
10
+ };
11
+ readonly data: {
12
+ readonly type: "string";
13
+ };
14
+ };
15
+ readonly required: readonly ["type", "encoding", "data"];
16
+ }, {
17
+ readonly type: "object";
18
+ readonly properties: {
19
+ readonly type: {
20
+ readonly const: "ref";
21
+ };
22
+ readonly hash: {
23
+ readonly type: "string";
24
+ };
25
+ readonly size: {
26
+ readonly type: "number";
27
+ };
28
+ };
29
+ readonly required: readonly ["type", "hash", "size"];
30
+ }];
31
+ };
32
+ export declare const assetWriteDataSchema: {
33
+ readonly type: "object";
34
+ readonly properties: {
35
+ readonly path: {
36
+ readonly type: "string";
37
+ };
38
+ readonly kind: {
39
+ readonly type: "string";
40
+ };
41
+ readonly hash: {
42
+ readonly type: "string";
43
+ };
44
+ readonly size: {
45
+ readonly type: "number";
46
+ };
47
+ readonly content: {
48
+ readonly oneOf: readonly [{
49
+ readonly type: "object";
50
+ readonly properties: {
51
+ readonly type: {
52
+ readonly const: "inline";
53
+ };
54
+ readonly encoding: {
55
+ readonly const: "base64";
56
+ };
57
+ readonly data: {
58
+ readonly type: "string";
59
+ };
60
+ };
61
+ readonly required: readonly ["type", "encoding", "data"];
62
+ }, {
63
+ readonly type: "object";
64
+ readonly properties: {
65
+ readonly type: {
66
+ readonly const: "ref";
67
+ };
68
+ readonly hash: {
69
+ readonly type: "string";
70
+ };
71
+ readonly size: {
72
+ readonly type: "number";
73
+ };
74
+ };
75
+ readonly required: readonly ["type", "hash", "size"];
76
+ }];
77
+ };
78
+ };
79
+ readonly required: readonly ["path", "kind", "hash", "size", "content"];
80
+ };
81
+ export declare const assetRenamedDataSchema: {
82
+ readonly type: "object";
83
+ readonly properties: {
84
+ readonly from: {
85
+ readonly type: "string";
86
+ };
87
+ readonly to: {
88
+ readonly type: "string";
89
+ };
90
+ readonly kind: {
91
+ readonly type: "string";
92
+ };
93
+ readonly hash: {
94
+ readonly type: "string";
95
+ };
96
+ };
97
+ readonly required: readonly ["from", "to", "kind", "hash"];
98
+ };
99
+ export declare const assetDeletedDataSchema: {
100
+ readonly type: "object";
101
+ readonly properties: {
102
+ readonly path: {
103
+ readonly type: "string";
104
+ };
105
+ readonly kind: {
106
+ readonly type: "string";
107
+ };
108
+ };
109
+ readonly required: readonly ["path", "kind"];
110
+ };
111
+ //# sourceMappingURL=AssetEvents.schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AssetEvents.schema.d.ts","sourceRoot":"","sources":["../../src/events/AssetEvents.schema.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6B7B,CAAC;AAEH,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgB/B,CAAC;AAEH,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;CAcjC,CAAC;AAEH,eAAO,MAAM,sBAAsB;;;;;;;;;;;CAUjC,CAAC"}
@@ -0,0 +1,75 @@
1
+ // Import Third-party Dependencies
2
+ import { defineSchema } from "ata-validator";
3
+ export const assetContentSchema = defineSchema({
4
+ oneOf: [
5
+ {
6
+ type: "object",
7
+ properties: {
8
+ type: { const: "inline" },
9
+ encoding: { const: "base64" },
10
+ data: { type: "string" }
11
+ },
12
+ required: [
13
+ "type",
14
+ "encoding",
15
+ "data"
16
+ ]
17
+ },
18
+ {
19
+ type: "object",
20
+ properties: {
21
+ type: { const: "ref" },
22
+ hash: { type: "string" },
23
+ size: { type: "number" }
24
+ },
25
+ required: [
26
+ "type",
27
+ "hash",
28
+ "size"
29
+ ]
30
+ }
31
+ ]
32
+ });
33
+ export const assetWriteDataSchema = defineSchema({
34
+ type: "object",
35
+ properties: {
36
+ path: { type: "string" },
37
+ kind: { type: "string" },
38
+ hash: { type: "string" },
39
+ size: { type: "number" },
40
+ content: assetContentSchema
41
+ },
42
+ required: [
43
+ "path",
44
+ "kind",
45
+ "hash",
46
+ "size",
47
+ "content"
48
+ ]
49
+ });
50
+ export const assetRenamedDataSchema = defineSchema({
51
+ type: "object",
52
+ properties: {
53
+ from: { type: "string" },
54
+ to: { type: "string" },
55
+ kind: { type: "string" },
56
+ hash: { type: "string" }
57
+ },
58
+ required: [
59
+ "from",
60
+ "to",
61
+ "kind",
62
+ "hash"
63
+ ]
64
+ });
65
+ export const assetDeletedDataSchema = defineSchema({
66
+ type: "object",
67
+ properties: {
68
+ path: { type: "string" },
69
+ kind: { type: "string" }
70
+ },
71
+ required: [
72
+ "path",
73
+ "kind"
74
+ ]
75
+ });
@@ -0,0 +1,3 @@
1
+ export { ASSET_CHECKPOINT_EVENT_TYPES, ASSET_CREATED, ASSET_DELETED, ASSET_RENAMED, ASSET_UPDATED, decodeContent, describeRejection, encodeContent, isAssetEventType, parseAssetEvent } from "./AssetEvents.ts";
2
+ export type { AssetContent, AssetCreatedData, AssetDeletedData, AssetEvent, AssetEventData, AssetEventDataMap, AssetEventRejection, AssetEventType, AssetInlineContent, AssetRenamedData, AssetUpdatedData, AssetWriteData } from "./AssetEvents.ts";
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/events/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,4BAA4B,EAC5B,aAAa,EACb,aAAa,EACb,aAAa,EACb,aAAa,EACb,aAAa,EACb,iBAAiB,EACjB,aAAa,EACb,gBAAgB,EAChB,eAAe,EAChB,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EACV,YAAY,EACZ,gBAAgB,EAChB,gBAAgB,EAChB,UAAU,EACV,cAAc,EACd,iBAAiB,EACjB,mBAAmB,EACnB,cAAc,EACd,kBAAkB,EAClB,gBAAgB,EAChB,gBAAgB,EAChB,cAAc,EACf,MAAM,kBAAkB,CAAC"}
@@ -0,0 +1 @@
1
+ export { ASSET_CHECKPOINT_EVENT_TYPES, ASSET_CREATED, ASSET_DELETED, ASSET_RENAMED, ASSET_UPDATED, decodeContent, describeRejection, encodeContent, isAssetEventType, parseAssetEvent } from "./AssetEvents.js";
@@ -0,0 +1,13 @@
1
+ export * from "./utils/index.ts";
2
+ export * from "./kinds/index.ts";
3
+ export * from "./events/index.ts";
4
+ export * from "./sync/index.ts";
5
+ export * from "./catalog/index.ts";
6
+ export * from "./rooms/index.ts";
7
+ export * from "./static/index.ts";
8
+ export * from "./workspace/index.ts";
9
+ export { createAssetBackend } from "./createAssetBackend.ts";
10
+ export type { AssetBackend, AssetBackendInternals, AssetBackendOptions } from "./createAssetBackend.ts";
11
+ export { silentLogger, type Logger } from "./logger.ts";
12
+ export { ASSET_EVENT_PREFIX, EVENTS_DB_PATH, IDENTITY_SIDECAR_PATH, PROJECTION_STATE_PATH, STATE_DIRECTORY, STATE_GITIGNORE_PATH } from "./constants.ts";
13
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAChC,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,sBAAsB,CAAC;AACrC,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,YAAY,EACV,YAAY,EACZ,qBAAqB,EACrB,mBAAmB,EACpB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,YAAY,EACZ,KAAK,MAAM,EACZ,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,kBAAkB,EAClB,cAAc,EACd,qBAAqB,EACrB,qBAAqB,EACrB,eAAe,EACf,oBAAoB,EACrB,MAAM,gBAAgB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,11 @@
1
+ export * from "./utils/index.js";
2
+ export * from "./kinds/index.js";
3
+ export * from "./events/index.js";
4
+ export * from "./sync/index.js";
5
+ export * from "./catalog/index.js";
6
+ export * from "./rooms/index.js";
7
+ export * from "./static/index.js";
8
+ export * from "./workspace/index.js";
9
+ export { createAssetBackend } from "./createAssetBackend.js";
10
+ export { silentLogger } from "./logger.js";
11
+ export { ASSET_EVENT_PREFIX, EVENTS_DB_PATH, IDENTITY_SIDECAR_PATH, PROJECTION_STATE_PATH, STATE_DIRECTORY, STATE_GITIGNORE_PATH } from "./constants.js";
@@ -0,0 +1,38 @@
1
+ import type * as EventStore from "@jolly-pixel/event-store";
2
+ import type { Extension } from "@jolly-pixel/network";
3
+ import type { AssetLiveProtocol } from "../rooms/AssetRoomExtension.ts";
4
+ export interface SnapshotPolicy {
5
+ /**
6
+ * Quiet period, in milliseconds, after the last event for an asset.
7
+ * `0` snapshots as soon as the current task yields.
8
+ * @default 2_000
9
+ */
10
+ delay?: number;
11
+ /**
12
+ * Upper bound, in milliseconds, between the first unsnapshotted event and
13
+ * its snapshot. Bounds data loss while an asset is edited continuously.
14
+ * @default 30_000
15
+ */
16
+ maxDelay?: number;
17
+ }
18
+ export interface AssetRoomBinding<TState = unknown> {
19
+ readonly assetId: string;
20
+ readonly kind: string;
21
+ readonly roomId: string;
22
+ readonly state: TState;
23
+ }
24
+ /**
25
+ * Folds an asset event stream and serializes its projected state.
26
+ */
27
+ export interface AssetKindHandler<TState = unknown, TCommand = unknown> {
28
+ readonly kind: string;
29
+ readonly match: readonly string[];
30
+ readonly snapshot?: SnapshotPolicy;
31
+ readonly contentTypes?: Readonly<Record<string, string>>;
32
+ create(assetId: string): TState;
33
+ apply(state: TState, event: EventStore.Event): void;
34
+ serialize(state: TState): Promise<Uint8Array>;
35
+ live?(binding: AssetRoomBinding<TState>): AssetLiveProtocol<TCommand>;
36
+ createExtension?(binding: AssetRoomBinding<TState>): Extension;
37
+ }
38
+ //# sourceMappingURL=AssetKindHandler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AssetKindHandler.d.ts","sourceRoot":"","sources":["../../src/kinds/AssetKindHandler.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,UAAU,MAAM,0BAA0B,CAAC;AAC5D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAGtD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AAExE,MAAM,WAAW,cAAc;IAC7B;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,gBAAgB,CAAC,MAAM,GAAG,OAAO;IAChD,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB,CAC/B,MAAM,GAAG,OAAO,EAChB,QAAQ,GAAG,OAAO;IAElB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,QAAQ,CAAC,QAAQ,CAAC,EAAE,cAAc,CAAC;IACnC,QAAQ,CAAC,YAAY,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAEzD,MAAM,CACJ,OAAO,EAAE,MAAM,GACd,MAAM,CAAC;IAEV,KAAK,CACH,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,UAAU,CAAC,KAAK,GACtB,IAAI,CAAC;IAER,SAAS,CACP,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,UAAU,CAAC,CAAC;IAEvB,IAAI,CAAC,CACH,OAAO,EAAE,gBAAgB,CAAC,MAAM,CAAC,GAChC,iBAAiB,CAAC,QAAQ,CAAC,CAAC;IAE/B,eAAe,CAAC,CACd,OAAO,EAAE,gBAAgB,CAAC,MAAM,CAAC,GAChC,SAAS,CAAC;CACd"}
@@ -0,0 +1 @@
1
+ export {};