@aelionsdk/sdk 0.1.0-beta.1

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 (60) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +63 -0
  3. package/dist/audio-controller.d.ts +25 -0
  4. package/dist/audio-controller.d.ts.map +1 -0
  5. package/dist/audio-controller.js +235 -0
  6. package/dist/audio-mastering.d.ts +27 -0
  7. package/dist/audio-mastering.d.ts.map +1 -0
  8. package/dist/audio-mastering.js +160 -0
  9. package/dist/composition.d.ts +75 -0
  10. package/dist/composition.d.ts.map +1 -0
  11. package/dist/composition.js +146 -0
  12. package/dist/default-schemas.d.ts +7 -0
  13. package/dist/default-schemas.d.ts.map +1 -0
  14. package/dist/default-schemas.js +18 -0
  15. package/dist/export-job.d.ts +22 -0
  16. package/dist/export-job.d.ts.map +1 -0
  17. package/dist/export-job.js +126 -0
  18. package/dist/extension-host.d.ts +90 -0
  19. package/dist/extension-host.d.ts.map +1 -0
  20. package/dist/extension-host.js +367 -0
  21. package/dist/index.d.ts +18 -0
  22. package/dist/index.d.ts.map +1 -0
  23. package/dist/index.js +19 -0
  24. package/dist/media-provider.d.ts +49 -0
  25. package/dist/media-provider.d.ts.map +1 -0
  26. package/dist/media-provider.js +388 -0
  27. package/dist/migration-materials.d.ts +10 -0
  28. package/dist/migration-materials.d.ts.map +1 -0
  29. package/dist/migration-materials.js +148 -0
  30. package/dist/migration.d.ts +109 -0
  31. package/dist/migration.d.ts.map +1 -0
  32. package/dist/migration.js +1232 -0
  33. package/dist/persistence.d.ts +73 -0
  34. package/dist/persistence.d.ts.map +1 -0
  35. package/dist/persistence.js +245 -0
  36. package/dist/player.d.ts +22 -0
  37. package/dist/player.d.ts.map +1 -0
  38. package/dist/player.js +522 -0
  39. package/dist/preview-controller.d.ts +62 -0
  40. package/dist/preview-controller.d.ts.map +1 -0
  41. package/dist/preview-controller.js +377 -0
  42. package/dist/preview-quality.d.ts +7 -0
  43. package/dist/preview-quality.d.ts.map +1 -0
  44. package/dist/preview-quality.js +8 -0
  45. package/dist/production-media-provider.d.ts +112 -0
  46. package/dist/production-media-provider.d.ts.map +1 -0
  47. package/dist/production-media-provider.js +749 -0
  48. package/dist/project-builder.d.ts +249 -0
  49. package/dist/project-builder.d.ts.map +1 -0
  50. package/dist/project-builder.js +953 -0
  51. package/dist/runtime-material-registry.d.ts +10 -0
  52. package/dist/runtime-material-registry.d.ts.map +1 -0
  53. package/dist/runtime-material-registry.js +23 -0
  54. package/dist/session.d.ts +29 -0
  55. package/dist/session.d.ts.map +1 -0
  56. package/dist/session.js +1114 -0
  57. package/dist/types.d.ts +392 -0
  58. package/dist/types.d.ts.map +1 -0
  59. package/dist/types.js +1 -0
  60. package/package.json +60 -0
@@ -0,0 +1,73 @@
1
+ import { type AelionProject } from '@aelionsdk/project-schema';
2
+ import type { AelionSessionApi } from './types.js';
3
+ export declare const PROJECT_REVISION_RECORD_VERSION: "aelion.project-revision/1";
4
+ export interface ProjectRevisionRecord {
5
+ readonly version: typeof PROJECT_REVISION_RECORD_VERSION;
6
+ readonly projectId: string;
7
+ /** Monotonic store generation; unlike Session revision, this survives reloads. */
8
+ readonly generation: number;
9
+ /** Transaction revision that triggered this snapshot inside its source Session. */
10
+ readonly sourceRevision: string;
11
+ readonly savedAtEpochMs: number;
12
+ readonly canonicalProject: string;
13
+ readonly contentHash: string;
14
+ }
15
+ export interface ProjectRevisionStore {
16
+ loadLatest(projectId: string): Promise<ProjectRevisionRecord | null>;
17
+ /**
18
+ * Atomically keeps the record with the greatest generation.
19
+ * Implementations must not replace a newer record with a stale write.
20
+ */
21
+ saveLatest(record: ProjectRevisionRecord): Promise<void>;
22
+ remove(projectId: string): Promise<void>;
23
+ }
24
+ export declare class MemoryProjectRevisionStore implements ProjectRevisionStore {
25
+ #private;
26
+ loadLatest(projectId: string): Promise<ProjectRevisionRecord | null>;
27
+ saveLatest(record: ProjectRevisionRecord): Promise<void>;
28
+ remove(projectId: string): Promise<void>;
29
+ }
30
+ export interface IndexedDbProjectRevisionStoreOptions {
31
+ readonly databaseName?: string;
32
+ }
33
+ /** Browser persistence with an atomic stale-generation guard. */
34
+ export declare class IndexedDbProjectRevisionStore implements ProjectRevisionStore {
35
+ #private;
36
+ constructor(options?: IndexedDbProjectRevisionStoreOptions);
37
+ loadLatest(projectId: string): Promise<ProjectRevisionRecord | null>;
38
+ saveLatest(record: ProjectRevisionRecord): Promise<void>;
39
+ remove(projectId: string): Promise<void>;
40
+ }
41
+ export interface ProjectPersistenceOptions {
42
+ readonly debounceMs?: number;
43
+ readonly saveInitial?: boolean;
44
+ readonly onError?: (error: unknown) => void;
45
+ readonly now?: () => number;
46
+ }
47
+ export interface ProjectPersistenceSnapshot {
48
+ readonly projectId: string;
49
+ readonly pendingRevision: bigint | null;
50
+ readonly lastSavedRevision: bigint | null;
51
+ readonly generation: number;
52
+ readonly disposed: boolean;
53
+ readonly error: unknown;
54
+ }
55
+ /**
56
+ * Serializes immutable Project snapshots in revision order. Call `flush` before
57
+ * navigation when durability matters; `dispose` also flushes the trailing edit.
58
+ */
59
+ export declare class ProjectPersistenceController {
60
+ #private;
61
+ private constructor();
62
+ static attach(session: AelionSessionApi, store: ProjectRevisionStore, options?: ProjectPersistenceOptions): Promise<ProjectPersistenceController>;
63
+ getSnapshot(): ProjectPersistenceSnapshot;
64
+ flush(): Promise<void>;
65
+ dispose(): Promise<void>;
66
+ }
67
+ export interface RestoredProjectRevision {
68
+ readonly record: ProjectRevisionRecord;
69
+ readonly project: Readonly<AelionProject>;
70
+ }
71
+ /** Verifies the canonical content hash before loading a stored Project. */
72
+ export declare function restoreLatestProject(session: AelionSessionApi, store: ProjectRevisionStore, projectId: string): Promise<RestoredProjectRevision | null>;
73
+ //# sourceMappingURL=persistence.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"persistence.d.ts","sourceRoot":"","sources":["../src/persistence.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,245 @@
1
+ import { canonicalHash, canonicalStringify } from '@aelionsdk/project-schema';
2
+ export const PROJECT_REVISION_RECORD_VERSION = 'aelion.project-revision/1';
3
+ function cloneRecord(record) {
4
+ return structuredClone(record);
5
+ }
6
+ function assertRecord(value, projectId) {
7
+ if (value === null || typeof value !== 'object' || Array.isArray(value)) {
8
+ throw new TypeError('Invalid Aelion Project revision record');
9
+ }
10
+ const record = value;
11
+ if (record.version !== PROJECT_REVISION_RECORD_VERSION ||
12
+ typeof record.projectId !== 'string' ||
13
+ (projectId !== undefined && record.projectId !== projectId) ||
14
+ typeof record.generation !== 'number' ||
15
+ !Number.isSafeInteger(record.generation) ||
16
+ record.generation < 0 ||
17
+ typeof record.sourceRevision !== 'string' ||
18
+ !/^(0|[1-9]\d*)$/u.test(record.sourceRevision) ||
19
+ typeof record.savedAtEpochMs !== 'number' ||
20
+ !Number.isFinite(record.savedAtEpochMs) ||
21
+ typeof record.canonicalProject !== 'string' ||
22
+ record.canonicalProject.length === 0 ||
23
+ typeof record.contentHash !== 'string' ||
24
+ record.contentHash.length === 0) {
25
+ throw new TypeError('Invalid Aelion Project revision record');
26
+ }
27
+ }
28
+ function persistenceError(value) {
29
+ return value instanceof Error ? value : new Error('Project persistence failed', { cause: value });
30
+ }
31
+ export class MemoryProjectRevisionStore {
32
+ #records = new Map();
33
+ loadLatest(projectId) {
34
+ const record = this.#records.get(projectId);
35
+ return Promise.resolve(record === undefined ? null : cloneRecord(record));
36
+ }
37
+ saveLatest(record) {
38
+ assertRecord(record);
39
+ const current = this.#records.get(record.projectId);
40
+ if (current === undefined || record.generation > current.generation) {
41
+ this.#records.set(record.projectId, cloneRecord(record));
42
+ }
43
+ return Promise.resolve();
44
+ }
45
+ remove(projectId) {
46
+ this.#records.delete(projectId);
47
+ return Promise.resolve();
48
+ }
49
+ }
50
+ function requestResult(request) {
51
+ return new Promise((resolve, reject) => {
52
+ request.onsuccess = () => resolve(request.result);
53
+ request.onerror = () => reject(request.error ?? new Error('IndexedDB request failed'));
54
+ });
55
+ }
56
+ function transactionComplete(transaction) {
57
+ return new Promise((resolve, reject) => {
58
+ transaction.oncomplete = () => resolve();
59
+ transaction.onabort = () => reject(transaction.error ?? new DOMException('IndexedDB transaction aborted', 'AbortError'));
60
+ transaction.onerror = () => reject(transaction.error ?? new Error('IndexedDB transaction failed'));
61
+ });
62
+ }
63
+ /** Browser persistence with an atomic stale-generation guard. */
64
+ export class IndexedDbProjectRevisionStore {
65
+ #database;
66
+ constructor(options = {}) {
67
+ if (typeof indexedDB === 'undefined') {
68
+ throw new Error('IndexedDB is unavailable in this environment');
69
+ }
70
+ const request = indexedDB.open(options.databaseName ?? 'aelion-projects', 1);
71
+ request.onupgradeneeded = () => {
72
+ if (!request.result.objectStoreNames.contains('project-revisions')) {
73
+ request.result.createObjectStore('project-revisions', { keyPath: 'projectId' });
74
+ }
75
+ };
76
+ this.#database = requestResult(request);
77
+ }
78
+ async loadLatest(projectId) {
79
+ const database = await this.#database;
80
+ const transaction = database.transaction('project-revisions', 'readonly');
81
+ const value = await requestResult(transaction.objectStore('project-revisions').get(projectId));
82
+ await transactionComplete(transaction);
83
+ if (value === undefined)
84
+ return null;
85
+ assertRecord(value, projectId);
86
+ return cloneRecord(value);
87
+ }
88
+ async saveLatest(record) {
89
+ assertRecord(record);
90
+ const database = await this.#database;
91
+ const transaction = database.transaction('project-revisions', 'readwrite');
92
+ const store = transaction.objectStore('project-revisions');
93
+ const current = await requestResult(store.get(record.projectId));
94
+ if (current !== undefined)
95
+ assertRecord(current, record.projectId);
96
+ if (current === undefined || record.generation > current.generation) {
97
+ store.put(cloneRecord(record));
98
+ }
99
+ await transactionComplete(transaction);
100
+ }
101
+ async remove(projectId) {
102
+ const database = await this.#database;
103
+ const transaction = database.transaction('project-revisions', 'readwrite');
104
+ transaction.objectStore('project-revisions').delete(projectId);
105
+ await transactionComplete(transaction);
106
+ }
107
+ }
108
+ /**
109
+ * Serializes immutable Project snapshots in revision order. Call `flush` before
110
+ * navigation when durability matters; `dispose` also flushes the trailing edit.
111
+ */
112
+ export class ProjectPersistenceController {
113
+ #session;
114
+ #store;
115
+ #projectId;
116
+ #debounceMs;
117
+ #onError;
118
+ #now;
119
+ #unsubscribe;
120
+ #pending;
121
+ #timer;
122
+ #tail = Promise.resolve();
123
+ #generation;
124
+ #lastSavedRevision = null;
125
+ #error;
126
+ #disposed = false;
127
+ constructor(session, store, projectId, generation, options) {
128
+ this.#session = session;
129
+ this.#store = store;
130
+ this.#projectId = projectId;
131
+ this.#generation = generation;
132
+ this.#debounceMs = options.debounceMs ?? 250;
133
+ if (!Number.isFinite(this.#debounceMs) || this.#debounceMs < 0) {
134
+ throw new RangeError('debounceMs must be a non-negative finite number');
135
+ }
136
+ this.#onError = options.onError;
137
+ this.#now = options.now ?? Date.now;
138
+ this.#unsubscribe = session.subscribe('project-changed', event => {
139
+ this.#schedule(event.commit.revision);
140
+ });
141
+ if (options.saveInitial ?? true) {
142
+ const revision = session.revision;
143
+ if (revision !== null)
144
+ this.#schedule(revision);
145
+ }
146
+ }
147
+ static async attach(session, store, options = {}) {
148
+ const project = session.getSnapshot().project;
149
+ if (project === null)
150
+ throw new Error('Load an Aelion Project before attaching persistence');
151
+ const latest = await store.loadLatest(project.projectId);
152
+ return new ProjectPersistenceController(session, store, project.projectId, latest?.generation ?? 0, options);
153
+ }
154
+ getSnapshot() {
155
+ return {
156
+ projectId: this.#projectId,
157
+ pendingRevision: this.#pending?.sourceRevision ?? null,
158
+ lastSavedRevision: this.#lastSavedRevision,
159
+ generation: this.#generation,
160
+ disposed: this.#disposed,
161
+ error: this.#error,
162
+ };
163
+ }
164
+ async flush() {
165
+ this.#enqueuePending();
166
+ await this.#tail;
167
+ if (this.#error !== undefined)
168
+ throw persistenceError(this.#error);
169
+ }
170
+ async dispose() {
171
+ if (this.#disposed)
172
+ return;
173
+ this.#disposed = true;
174
+ this.#unsubscribe();
175
+ await this.flush();
176
+ }
177
+ #schedule(revision) {
178
+ if (this.#disposed)
179
+ return;
180
+ const project = this.#session.getSnapshot().project;
181
+ if (project === null || project.projectId !== this.#projectId) {
182
+ const error = new Error('Persistence controller cannot follow a different Project');
183
+ this.#error = error;
184
+ this.#onError?.(error);
185
+ return;
186
+ }
187
+ this.#pending = {
188
+ project: structuredClone(project),
189
+ sourceRevision: revision,
190
+ };
191
+ if (this.#timer !== undefined)
192
+ clearTimeout(this.#timer);
193
+ this.#timer = setTimeout(() => this.#enqueuePending(), this.#debounceMs);
194
+ }
195
+ #enqueuePending() {
196
+ if (this.#timer !== undefined) {
197
+ clearTimeout(this.#timer);
198
+ this.#timer = undefined;
199
+ }
200
+ const pending = this.#pending;
201
+ if (pending === undefined)
202
+ return;
203
+ this.#pending = undefined;
204
+ const generation = this.#generation + 1;
205
+ this.#generation = generation;
206
+ this.#tail = this.#tail.then(async () => {
207
+ try {
208
+ const canonicalProject = canonicalStringify(pending.project);
209
+ const contentHash = await canonicalHash(pending.project);
210
+ await this.#store.saveLatest({
211
+ version: PROJECT_REVISION_RECORD_VERSION,
212
+ projectId: this.#projectId,
213
+ generation,
214
+ sourceRevision: pending.sourceRevision.toString(),
215
+ savedAtEpochMs: this.#now(),
216
+ canonicalProject,
217
+ contentHash,
218
+ });
219
+ this.#lastSavedRevision = pending.sourceRevision;
220
+ this.#error = undefined;
221
+ }
222
+ catch (error) {
223
+ this.#error = error;
224
+ this.#onError?.(error);
225
+ }
226
+ });
227
+ }
228
+ }
229
+ /** Verifies the canonical content hash before loading a stored Project. */
230
+ export async function restoreLatestProject(session, store, projectId) {
231
+ const record = await store.loadLatest(projectId);
232
+ if (record === null)
233
+ return null;
234
+ assertRecord(record, projectId);
235
+ const parsed = JSON.parse(record.canonicalProject);
236
+ const contentHash = await canonicalHash(parsed);
237
+ if (contentHash !== record.contentHash) {
238
+ throw new Error(`Stored Aelion Project ${projectId} failed its content-hash check`);
239
+ }
240
+ await session.loadProject(parsed);
241
+ const project = session.getSnapshot().project;
242
+ if (project === null)
243
+ throw new Error('Restored Project did not enter the Session');
244
+ return { record, project };
245
+ }
@@ -0,0 +1,22 @@
1
+ import type { ChangeSet } from '@aelionsdk/transaction';
2
+ import type { AelionSession } from './session.js';
3
+ import type { AelionPlayerApi, AelionPlayerFrame, AelionPlayerStats, AelionPlayerState, AelionRuntimeAssets } from './types.js';
4
+ type RuntimeErrorListener = (error: unknown) => void;
5
+ export declare class AelionPlayer implements AelionPlayerApi {
6
+ #private;
7
+ constructor(session: AelionSession, onRuntimeError?: RuntimeErrorListener, runtimeAssets?: AelionRuntimeAssets);
8
+ get state(): AelionPlayerState;
9
+ get currentTimeUs(): number;
10
+ play(): Promise<void>;
11
+ pause(): Promise<void>;
12
+ seek(timeUs: number): Promise<void>;
13
+ scrub(timeUs: number): Promise<import("@aelionsdk/renderer-worker").RenderIrFrameResult>;
14
+ setPreviewQuality(options: Parameters<AelionPlayerApi['setPreviewQuality']>[0]): void;
15
+ getStats(): AelionPlayerStats;
16
+ subscribe(listener: (frame: AelionPlayerFrame) => void): () => void;
17
+ invalidate(changeSet: ChangeSet): void;
18
+ reset(): Promise<void>;
19
+ dispose(): Promise<void>;
20
+ }
21
+ export {};
22
+ //# sourceMappingURL=player.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"player.d.ts","sourceRoot":"","sources":["../src/player.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAExD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAElD,OAAO,KAAK,EACV,eAAe,EACf,iBAAiB,EACjB,iBAAiB,EAEjB,iBAAiB,EACjB,mBAAmB,EACpB,MAAM,YAAY,CAAC;AAIpB,KAAK,oBAAoB,GAAG,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;AAiBrD,qBAAa,YAAa,YAAW,eAAe;;gBA2BhD,OAAO,EAAE,aAAa,EACtB,cAAc,CAAC,EAAE,oBAAoB,EACrC,aAAa,CAAC,EAAE,mBAAmB;IAOrC,IAAW,KAAK,IAAI,iBAAiB,CAEpC;IAED,IAAW,aAAa,IAAI,MAAM,CAKjC;IAEY,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IA+BrB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAWtB,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAkCzC,KAAK,CAAC,MAAM,EAAE,MAAM;IAIpB,iBAAiB,CAAC,OAAO,EAAE,UAAU,CAAC,eAAe,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI;IAOrF,QAAQ,IAAI,iBAAiB;IAwD7B,SAAS,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,GAAG,MAAM,IAAI;IASnE,UAAU,CAAC,SAAS,EAAE,SAAS,GAAG,IAAI;IAahC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAa5B,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CAsShC"}