@aelionsdk/material-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 +7 -0
  3. package/dist/bundled-schemas.d.ts +5 -0
  4. package/dist/bundled-schemas.d.ts.map +1 -0
  5. package/dist/bundled-schemas.js +3 -0
  6. package/dist/canonical.d.ts +6 -0
  7. package/dist/canonical.d.ts.map +1 -0
  8. package/dist/canonical.js +33 -0
  9. package/dist/catalog.d.ts +24 -0
  10. package/dist/catalog.d.ts.map +1 -0
  11. package/dist/catalog.js +47 -0
  12. package/dist/composition.d.ts +42 -0
  13. package/dist/composition.d.ts.map +1 -0
  14. package/dist/composition.js +169 -0
  15. package/dist/definition-builder.d.ts +48 -0
  16. package/dist/definition-builder.d.ts.map +1 -0
  17. package/dist/definition-builder.js +159 -0
  18. package/dist/graph-builder.d.ts +45 -0
  19. package/dist/graph-builder.d.ts.map +1 -0
  20. package/dist/graph-builder.js +125 -0
  21. package/dist/index.d.ts +15 -0
  22. package/dist/index.d.ts.map +1 -0
  23. package/dist/index.js +14 -0
  24. package/dist/lab.d.ts +48 -0
  25. package/dist/lab.d.ts.map +1 -0
  26. package/dist/lab.js +169 -0
  27. package/dist/migration.d.ts +22 -0
  28. package/dist/migration.d.ts.map +1 -0
  29. package/dist/migration.js +59 -0
  30. package/dist/package-limits.d.ts +30 -0
  31. package/dist/package-limits.d.ts.map +1 -0
  32. package/dist/package-limits.js +202 -0
  33. package/dist/package-shape.d.ts +6 -0
  34. package/dist/package-shape.d.ts.map +1 -0
  35. package/dist/package-shape.js +547 -0
  36. package/dist/package-snapshot.d.ts +5 -0
  37. package/dist/package-snapshot.d.ts.map +1 -0
  38. package/dist/package-snapshot.js +31 -0
  39. package/dist/package.d.ts +12 -0
  40. package/dist/package.d.ts.map +1 -0
  41. package/dist/package.js +244 -0
  42. package/dist/registry.d.ts +32 -0
  43. package/dist/registry.d.ts.map +1 -0
  44. package/dist/registry.js +150 -0
  45. package/dist/schema-validation.d.ts +4 -0
  46. package/dist/schema-validation.d.ts.map +1 -0
  47. package/dist/schema-validation.js +36 -0
  48. package/dist/security.d.ts +70 -0
  49. package/dist/security.d.ts.map +1 -0
  50. package/dist/security.js +161 -0
  51. package/dist/types.d.ts +245 -0
  52. package/dist/types.d.ts.map +1 -0
  53. package/dist/types.js +5 -0
  54. package/dist/validation.d.ts +6 -0
  55. package/dist/validation.d.ts.map +1 -0
  56. package/dist/validation.js +124 -0
  57. package/dist/zip.d.ts +4 -0
  58. package/dist/zip.d.ts.map +1 -0
  59. package/dist/zip.js +172 -0
  60. package/package.json +46 -0
package/dist/zip.js ADDED
@@ -0,0 +1,172 @@
1
+ import { addMaterialPackageBytes, materialPackageBudgetExceeded, materialUint8ArrayByteLength, resolveMaterialPackageByteLimits, validMaterialPackagePath, } from './package-limits.js';
2
+ const encoder = new TextEncoder();
3
+ const CRC_TABLE = new Uint32Array(256);
4
+ /* eslint-disable @typescript-eslint/unbound-method -- captured Map accessors are invoked with Reflect.apply */
5
+ const mapSizeGetter_ = Object.getOwnPropertyDescriptor(Map.prototype, 'size')?.get;
6
+ const mapEntries = Map.prototype.entries;
7
+ const typedArrayValues = Uint8Array.prototype.values;
8
+ /* eslint-enable @typescript-eslint/unbound-method */
9
+ if (mapSizeGetter_ === undefined)
10
+ throw new Error('Required Map size accessor is unavailable');
11
+ const mapSizeGetter = mapSizeGetter_;
12
+ function archiveMapSize(files) {
13
+ try {
14
+ return Number(Reflect.apply(mapSizeGetter, files, []));
15
+ }
16
+ catch {
17
+ throw new TypeError('MATERIAL_PACKAGE_INVALID: archive files must be a genuine Map');
18
+ }
19
+ }
20
+ function archiveMapEntries(files) {
21
+ try {
22
+ return Reflect.apply(mapEntries, files, []);
23
+ }
24
+ catch {
25
+ throw new TypeError('MATERIAL_PACKAGE_INVALID: archive files must be a genuine Map');
26
+ }
27
+ }
28
+ for (let index = 0; index < CRC_TABLE.length; index += 1) {
29
+ let value = index;
30
+ for (let bit = 0; bit < 8; bit += 1)
31
+ value = (value >>> 1) ^ (value & 1 ? 0xedb88320 : 0);
32
+ CRC_TABLE[index] = value >>> 0;
33
+ }
34
+ function crc32(data) {
35
+ let crc = 0xffffffff;
36
+ // Never dispatch through an instance Symbol.iterator. A genuine Uint8Array
37
+ // can still define an own iterator that yields forever and bypass every byte
38
+ // budget. The captured intrinsic iterates exactly the branded byte length.
39
+ const values = Reflect.apply(typedArrayValues, data, []);
40
+ for (const byte of values)
41
+ crc = ((crc >>> 8) ^ (CRC_TABLE[(crc ^ byte) & 0xff] ?? 0)) >>> 0;
42
+ return (crc ^ 0xffffffff) >>> 0;
43
+ }
44
+ function writeUint16(view, offset, value) {
45
+ view.setUint16(offset, value, true);
46
+ return offset + 2;
47
+ }
48
+ function writeUint32(view, offset, value) {
49
+ view.setUint32(offset, value, true);
50
+ return offset + 4;
51
+ }
52
+ function copyInto(output, offset, source, byteLength) {
53
+ output.set(source, offset);
54
+ return offset + byteLength;
55
+ }
56
+ function inspectArchiveFiles(files, options) {
57
+ const limits = resolveMaterialPackageByteLimits(options);
58
+ const fileCount = archiveMapSize(files);
59
+ if (!Number.isSafeInteger(fileCount) || fileCount < 0) {
60
+ throw new TypeError('MATERIAL_PACKAGE_INVALID: archive files has an invalid size');
61
+ }
62
+ if (fileCount > limits.maxFiles) {
63
+ throw new RangeError(`MATERIAL_PACKAGE_BUDGET_EXCEEDED: archive has ${fileCount} files; limit is ${limits.maxFiles}`);
64
+ }
65
+ const entries = [];
66
+ let packageBytes = 0;
67
+ let localBytes = 0;
68
+ let centralBytes = 0;
69
+ let inspectedFiles = 0;
70
+ for (const [path, data] of archiveMapEntries(files)) {
71
+ if (typeof path !== 'string' || !validMaterialPackagePath(path)) {
72
+ throw new TypeError('MATERIAL_PACKAGE_INVALID: unsafe ZIP path');
73
+ }
74
+ if (path === 'signature.json') {
75
+ throw new TypeError('MATERIAL_PACKAGE_INVALID: signature.json is a reserved payload path');
76
+ }
77
+ const byteLength = materialUint8ArrayByteLength(data, `archive file ${path}`);
78
+ const fileLimit = path === 'manifest.json' ? limits.maxManifestBytes : limits.maxFileBytes;
79
+ if (byteLength > fileLimit)
80
+ materialPackageBudgetExceeded(`file ${path}`, byteLength, fileLimit);
81
+ packageBytes = addMaterialPackageBytes(packageBytes, byteLength, `archive file ${path}`);
82
+ if (packageBytes > limits.maxPackageBytes) {
83
+ materialPackageBudgetExceeded('archive package files', packageBytes, limits.maxPackageBytes);
84
+ }
85
+ const name = encoder.encode(path);
86
+ if (name.byteLength > 0xffff) {
87
+ throw new RangeError(`MATERIAL_PACKAGE_INVALID: ZIP path is too long: ${path}`);
88
+ }
89
+ const localSize = addMaterialPackageBytes(30 + name.byteLength, byteLength, `ZIP file ${path}`);
90
+ const centralSize = 46 + name.byteLength;
91
+ const localOffset = localBytes;
92
+ localBytes = addMaterialPackageBytes(localBytes, localSize, 'ZIP local records');
93
+ centralBytes = addMaterialPackageBytes(centralBytes, centralSize, 'ZIP central records');
94
+ entries.push({
95
+ path,
96
+ data: data,
97
+ name,
98
+ byteLength,
99
+ checksum: crc32(data),
100
+ localOffset,
101
+ });
102
+ inspectedFiles += 1;
103
+ }
104
+ if (inspectedFiles !== fileCount) {
105
+ throw new TypeError('MATERIAL_PACKAGE_INVALID: archive files changed during inspection');
106
+ }
107
+ const archiveBytes = addMaterialPackageBytes(addMaterialPackageBytes(localBytes, centralBytes, 'ZIP records'), 22, 'ZIP archive');
108
+ if (archiveBytes > limits.maxArchiveBytes) {
109
+ materialPackageBudgetExceeded('archiveBytes', archiveBytes, limits.maxArchiveBytes);
110
+ }
111
+ if (localBytes > 0xffffffff || centralBytes > 0xffffffff) {
112
+ throw new RangeError('MATERIAL_PACKAGE_BUDGET_EXCEEDED: ZIP32 offset limit exceeded');
113
+ }
114
+ return { entries, archiveBytes };
115
+ }
116
+ /** Writes deterministic uncompressed ZIP bytes without platform metadata or variable timestamps. */
117
+ export function createDeterministicMaterialArchive(files, options = {}) {
118
+ // Compute every byte and reject the package before allocating its archive.
119
+ const { entries, archiveBytes } = inspectArchiveFiles(files, options);
120
+ const output = new Uint8Array(archiveBytes);
121
+ const view = new DataView(output.buffer);
122
+ let offset = 0;
123
+ for (const entry of entries) {
124
+ // UTF-8 names, no compression, fixed 1980-01-01 00:00 timestamp.
125
+ offset = writeUint32(view, offset, 0x04034b50);
126
+ offset = writeUint16(view, offset, 20);
127
+ offset = writeUint16(view, offset, 0x0800);
128
+ offset = writeUint16(view, offset, 0);
129
+ offset = writeUint16(view, offset, 0);
130
+ offset = writeUint16(view, offset, 0x0021);
131
+ offset = writeUint32(view, offset, entry.checksum);
132
+ offset = writeUint32(view, offset, entry.byteLength);
133
+ offset = writeUint32(view, offset, entry.byteLength);
134
+ offset = writeUint16(view, offset, entry.name.byteLength);
135
+ offset = writeUint16(view, offset, 0);
136
+ offset = copyInto(output, offset, entry.name, entry.name.byteLength);
137
+ offset = copyInto(output, offset, entry.data, entry.byteLength);
138
+ }
139
+ const centralOffset = offset;
140
+ for (const entry of entries) {
141
+ offset = writeUint32(view, offset, 0x02014b50);
142
+ offset = writeUint16(view, offset, 20);
143
+ offset = writeUint16(view, offset, 20);
144
+ offset = writeUint16(view, offset, 0x0800);
145
+ offset = writeUint16(view, offset, 0);
146
+ offset = writeUint16(view, offset, 0);
147
+ offset = writeUint16(view, offset, 0x0021);
148
+ offset = writeUint32(view, offset, entry.checksum);
149
+ offset = writeUint32(view, offset, entry.byteLength);
150
+ offset = writeUint32(view, offset, entry.byteLength);
151
+ offset = writeUint16(view, offset, entry.name.byteLength);
152
+ offset = writeUint16(view, offset, 0);
153
+ offset = writeUint16(view, offset, 0);
154
+ offset = writeUint16(view, offset, 0);
155
+ offset = writeUint16(view, offset, 0);
156
+ offset = writeUint32(view, offset, 0);
157
+ offset = writeUint32(view, offset, entry.localOffset);
158
+ offset = copyInto(output, offset, entry.name, entry.name.byteLength);
159
+ }
160
+ const centralBytes = offset - centralOffset;
161
+ offset = writeUint32(view, offset, 0x06054b50);
162
+ offset = writeUint16(view, offset, 0);
163
+ offset = writeUint16(view, offset, 0);
164
+ offset = writeUint16(view, offset, entries.length);
165
+ offset = writeUint16(view, offset, entries.length);
166
+ offset = writeUint32(view, offset, centralBytes);
167
+ offset = writeUint32(view, offset, centralOffset);
168
+ offset = writeUint16(view, offset, 0);
169
+ if (offset !== output.byteLength)
170
+ throw new Error('Material ZIP size accounting mismatch');
171
+ return output;
172
+ }
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "@aelionsdk/material-sdk",
3
+ "version": "0.1.0-beta.1",
4
+ "description": "Type-safe authoring, validation and packaging tools for Aelion materials",
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/FoyonaCZY/AelionSDK.git",
9
+ "directory": "packages/material-sdk"
10
+ },
11
+ "keywords": [
12
+ "aelion",
13
+ "material",
14
+ "shader",
15
+ "effects"
16
+ ],
17
+ "sideEffects": false,
18
+ "type": "module",
19
+ "exports": {
20
+ ".": {
21
+ "types": "./dist/index.d.ts",
22
+ "import": "./dist/index.js"
23
+ }
24
+ },
25
+ "files": [
26
+ "dist",
27
+ "!dist/.tsbuildinfo"
28
+ ],
29
+ "engines": {
30
+ "node": ">=20.19"
31
+ },
32
+ "publishConfig": {
33
+ "access": "public",
34
+ "provenance": true
35
+ },
36
+ "dependencies": {
37
+ "@aelionsdk/core": "0.1.0-beta.1",
38
+ "@aelionsdk/material-compiler": "0.1.0-beta.1",
39
+ "ajv": "8.17.1",
40
+ "ajv-formats": "3.0.1"
41
+ },
42
+ "scripts": {
43
+ "build": "tsc -b",
44
+ "typecheck": "tsc -b --pretty false"
45
+ }
46
+ }