@smallpen/core 0.1.0-alpha.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.
package/package.json ADDED
@@ -0,0 +1,18 @@
1
+ {
2
+ "name": "@smallpen/core",
3
+ "version": "0.1.0-alpha.1",
4
+ "publishConfig": {
5
+ "access": "public"
6
+ },
7
+ "type": "module",
8
+ "exports": "./src/index.mjs",
9
+ "files": [
10
+ "src"
11
+ ],
12
+ "sideEffects": false,
13
+ "repository": {
14
+ "type": "git",
15
+ "url": "git+https://github.com/SmallRaw/SmallPen.git",
16
+ "directory": "smallpen/packages/core"
17
+ }
18
+ }
@@ -0,0 +1,64 @@
1
+ const encoder = new TextEncoder();
2
+
3
+ async function sha256(value) {
4
+ const subtle = globalThis.crypto?.subtle;
5
+ if (!subtle) {
6
+ throw new Error("SmallPen Core requires the Web Crypto SHA-256 API");
7
+ }
8
+ const bytes =
9
+ typeof value === "string"
10
+ ? encoder.encode(value)
11
+ : value instanceof Uint8Array
12
+ ? value
13
+ : null;
14
+ if (!bytes) {
15
+ throw new TypeError("SmallPen SHA-256 input must be a string or Uint8Array");
16
+ }
17
+ return new Uint8Array(await subtle.digest("SHA-256", bytes));
18
+ }
19
+
20
+ function hex(bytes) {
21
+ return [...bytes].map((byte) => byte.toString(16).padStart(2, "0")).join("");
22
+ }
23
+
24
+ function normalizeCanonicalValue(value) {
25
+ if (Array.isArray(value)) return value.map(normalizeCanonicalValue);
26
+ if (value !== null && typeof value === "object") {
27
+ return Object.fromEntries(
28
+ Object.entries(value)
29
+ .filter(([, entryValue]) => entryValue !== undefined)
30
+ .sort(([left], [right]) => left.localeCompare(right))
31
+ .map(([key, entryValue]) => [key, normalizeCanonicalValue(entryValue)]),
32
+ );
33
+ }
34
+ return value;
35
+ }
36
+
37
+ export function canonicalJSON(value) {
38
+ return JSON.stringify(normalizeCanonicalValue(value), null, 2) + "\n";
39
+ }
40
+
41
+ export async function sha256Hex(value) {
42
+ return hex(await sha256(value));
43
+ }
44
+
45
+ export async function hashCanonicalFiles(files) {
46
+ let source = "";
47
+ for (const [path, contents] of [...files.entries()].sort(([left], [right]) =>
48
+ left.localeCompare(right),
49
+ )) {
50
+ source += `${path}\0${contents}\0`;
51
+ }
52
+ return hex(await sha256(source));
53
+ }
54
+
55
+ export async function stableRuntimeUuid(packageId, kind, stableId) {
56
+ const bytes = (await sha256(`${packageId}\0${kind}\0${stableId}`)).slice(
57
+ 0,
58
+ 16,
59
+ );
60
+ bytes[6] = (bytes[6] & 0x0f) | 0x50;
61
+ bytes[8] = (bytes[8] & 0x3f) | 0x80;
62
+ const value = hex(bytes);
63
+ return `${value.slice(0, 8)}-${value.slice(8, 12)}-${value.slice(12, 16)}-${value.slice(16, 20)}-${value.slice(20)}`;
64
+ }
@@ -0,0 +1,495 @@
1
+ function deepFreeze(value) {
2
+ for (const child of Object.values(value)) {
3
+ if (child && typeof child === "object") deepFreeze(child);
4
+ }
5
+ return Object.freeze(value);
6
+ }
7
+
8
+ export const SMALLPEN_FORMAT_CAPABILITIES = deepFreeze({
9
+ canonicalPackage: {
10
+ entryKinds: [
11
+ "assets",
12
+ "components",
13
+ "contexts",
14
+ "requirements",
15
+ "scenarios",
16
+ "screens",
17
+ "tokens",
18
+ ],
19
+ nodeTypes: [
20
+ "COMPONENT",
21
+ "COMPONENT_SET",
22
+ "ELLIPSE",
23
+ "FRAME",
24
+ "GROUP",
25
+ "IMAGE",
26
+ "INSTANCE",
27
+ "PATH",
28
+ "RECTANGLE",
29
+ "TEXT",
30
+ ],
31
+ assetLibraryModel: "local-colors-fonts-typographies-media",
32
+ binaryBlobModel: "sha256-addressed",
33
+ customFontModel: "families-variants-woff",
34
+ componentCanonicalModel: "component-sets-sparse-variants",
35
+ dependencyModel:
36
+ "one-foundation-plus-multiple-local-or-url-library-sources",
37
+ contextModel: "finite-axes-defaults-profiles",
38
+ effectiveTokenResolution:
39
+ "product-first-specificity-then-foundation-fallback",
40
+ fontImportConversion: "sfnt-to-woff",
41
+ fontImportTypes: ["font/otf", "font/ttf", "font/woff"],
42
+ repairChoices: [
43
+ "choose-foundation",
44
+ "recreate-product-asset",
45
+ "remove-dependent-usage",
46
+ "retarget-reference",
47
+ ],
48
+ presentationRootForms: ["legacy-single", "forest"],
49
+ requirementModel: "requirements-links-flows-annotations",
50
+ textModel: "blocks-runs",
51
+ scenarioModel: "finite-declarative-actions",
52
+ screenModel: "base-plus-independent-presentations",
53
+ tokenCanonicalModel: "dtcg-smallpen-extension",
54
+ tokenBindingFields: [
55
+ "cornerRadius",
56
+ "shadow",
57
+ "blur",
58
+ "backgroundBlur",
59
+ "fill",
60
+ "fills.N",
61
+ "fontFamily",
62
+ "fontSize",
63
+ "fontWeight",
64
+ "height",
65
+ "itemSpacing",
66
+ "opacity",
67
+ "paddingBottom",
68
+ "paddingLeft",
69
+ "paddingRight",
70
+ "paddingTop",
71
+ "strokeWidth",
72
+ "typography",
73
+ "width",
74
+ ],
75
+ tokenLibraryModel: "ordered-sets-themes",
76
+ tokenTypes: [
77
+ "boolean",
78
+ "border-radius",
79
+ "color",
80
+ "dimensions",
81
+ "font-family",
82
+ "font-size",
83
+ "font-weight",
84
+ "letter-spacing",
85
+ "number",
86
+ "opacity",
87
+ "other",
88
+ "rotation",
89
+ "shadow",
90
+ "sizing",
91
+ "spacing",
92
+ "string",
93
+ "stroke-width",
94
+ "text-case",
95
+ "text-decoration",
96
+ "typography",
97
+ ],
98
+ },
99
+ canonicalWrite: {
100
+ nodeFields: [
101
+ "appliedTokens",
102
+ "cornerRadius",
103
+ "shadow",
104
+ "blur",
105
+ "backgroundBlur",
106
+ "blend-mode",
107
+ "fills",
108
+ "layout",
109
+ "layout-flex-dir",
110
+ "layout-gap-type",
111
+ "layout-gap",
112
+ "layout-align-items",
113
+ "layout-justify-content",
114
+ "layout-align-content",
115
+ "layout-wrap-type",
116
+ "layout-padding-type",
117
+ "layout-padding",
118
+ "layout-item-margin",
119
+ "layout-item-margin-type",
120
+ "layout-item-h-sizing",
121
+ "layout-item-v-sizing",
122
+ "layout-item-max-h",
123
+ "layout-item-min-h",
124
+ "layout-item-max-w",
125
+ "layout-item-min-w",
126
+ "layout-item-align-self",
127
+ "layout-item-absolute",
128
+ "layout-item-z-index",
129
+ "constraints-h",
130
+ "constraints-v",
131
+ "fixed-scroll",
132
+ "exports",
133
+ "content",
134
+ "pathData",
135
+ "points",
136
+ "flipX",
137
+ "flipY",
138
+ "growType",
139
+ "grids",
140
+ "height",
141
+ "hide-fill-on-export",
142
+ "hide-in-viewer",
143
+ "interactions",
144
+ "locked",
145
+ "masked-group",
146
+ "mediaRef",
147
+ "name",
148
+ "opacity",
149
+ "proportionLock",
150
+ "rotation",
151
+ "strokes",
152
+ "show-content",
153
+ "text",
154
+ "textBlocks",
155
+ "textStyle",
156
+ "tokenBindings",
157
+ "touched",
158
+ "visible",
159
+ "width",
160
+ "x",
161
+ "y",
162
+ ],
163
+ operationTypes: [
164
+ "add-component",
165
+ "add-presentation",
166
+ "add-presentation-node",
167
+ "clear-token-binding",
168
+ "delete-component-set",
169
+ "delete-context-file",
170
+ "delete-interaction",
171
+ "delete-requirement-file",
172
+ "delete-scenario",
173
+ "delete-screen",
174
+ "delete-variant",
175
+ "deprecate-token",
176
+ "delete-presentation",
177
+ "delete-presentation-node",
178
+ "delete-component",
179
+ "move-presentation",
180
+ "move-presentation-nodes",
181
+ "put-component-set",
182
+ "put-context-file",
183
+ "put-interaction",
184
+ "put-library",
185
+ "put-requirement-file",
186
+ "put-scenario",
187
+ "put-screen",
188
+ "put-token",
189
+ "put-variant",
190
+ "remove-token",
191
+ "remove-library",
192
+ "repair-reference",
193
+ "reorder-presentation-children",
194
+ "replace-asset-library",
195
+ "replace-token-library",
196
+ "restore-canonical-entry",
197
+ "select-instance-variant",
198
+ "set-default-screen",
199
+ "set-foundation-dependency",
200
+ "set-active-token-themes",
201
+ "set-token-binding",
202
+ "set-token-value",
203
+ "update-component-node",
204
+ "update-node",
205
+ "update-presentation",
206
+ "update-presentation-node",
207
+ "update-component",
208
+ ],
209
+ },
210
+ penpotWrite: {
211
+ attributes: [
212
+ "applied-tokens",
213
+ "background-blur",
214
+ "blend-mode",
215
+ "blur",
216
+ "blocked",
217
+ "fills",
218
+ "flip-x",
219
+ "flip-y",
220
+ "grow-type",
221
+ "grids",
222
+ "height",
223
+ "hide-fill-on-export",
224
+ "hide-in-viewer",
225
+ "interactions",
226
+ "layout",
227
+ "layout-flex-dir",
228
+ "layout-gap-type",
229
+ "layout-gap",
230
+ "layout-align-items",
231
+ "layout-justify-content",
232
+ "layout-align-content",
233
+ "layout-wrap-type",
234
+ "layout-padding-type",
235
+ "layout-padding",
236
+ "layout-item-margin",
237
+ "layout-item-margin-type",
238
+ "layout-item-h-sizing",
239
+ "layout-item-v-sizing",
240
+ "layout-item-max-h",
241
+ "layout-item-min-h",
242
+ "layout-item-max-w",
243
+ "layout-item-min-w",
244
+ "layout-item-align-self",
245
+ "layout-item-absolute",
246
+ "layout-item-z-index",
247
+ "constraints-h",
248
+ "constraints-v",
249
+ "fixed-scroll",
250
+ "exports",
251
+ "pathData",
252
+ "hidden",
253
+ "masked-group",
254
+ "metadata",
255
+ "name",
256
+ "opacity",
257
+ "proportion-lock",
258
+ "r1",
259
+ "r2",
260
+ "r3",
261
+ "r4",
262
+ "rotation",
263
+ "shadow",
264
+ "show-content",
265
+ "width",
266
+ "x",
267
+ "y",
268
+ "content",
269
+ "strokes",
270
+ "touched",
271
+ ],
272
+ changeTypes: [
273
+ "add-color",
274
+ "add-component",
275
+ "add-media",
276
+ "add-page",
277
+ "add-obj",
278
+ "del-page",
279
+ "del-obj",
280
+ "del-component",
281
+ "del-color",
282
+ "del-media",
283
+ "mod-page",
284
+ "mod-obj",
285
+ "mod-component",
286
+ "mod-color",
287
+ "mod-media",
288
+ "mov-page",
289
+ "mov-objects",
290
+ "reg-objects",
291
+ "reorder-children",
292
+ "rename-token-set-group",
293
+ "move-token-set",
294
+ "move-token-set-group",
295
+ "set-active-token-themes",
296
+ "set-flow",
297
+ "set-tokens-status",
298
+ "set-token",
299
+ "set-token-set",
300
+ "set-token-theme",
301
+ "add-typography",
302
+ "mod-typography",
303
+ "del-typography",
304
+ ],
305
+ derivedAttributes: [
306
+ "points",
307
+ "position-data",
308
+ "proportion",
309
+ "selrect",
310
+ "transform",
311
+ "transform-inverse",
312
+ ],
313
+ operationTypes: ["set", "set-touched"],
314
+ pageAttributes: [
315
+ "background",
316
+ "name",
317
+ "pixel-grid-color",
318
+ "pixel-grid-opacity",
319
+ ],
320
+ presentationMoveScope: "within-screen",
321
+ presentationTarget: "default-screen",
322
+ componentDeletePolicy: "unused-only",
323
+ assetDeletePolicy: "unused-only",
324
+ },
325
+ version: 1,
326
+ webProjection: {
327
+ appliedTokenAttributes: [
328
+ "column-gap",
329
+ "fill",
330
+ "font-family",
331
+ "font-size",
332
+ "font-weight",
333
+ "height",
334
+ "layout-item-max-h",
335
+ "layout-item-max-w",
336
+ "layout-item-min-h",
337
+ "layout-item-min-w",
338
+ "letter-spacing",
339
+ "line-height",
340
+ "m1",
341
+ "m2",
342
+ "m3",
343
+ "m4",
344
+ "opacity",
345
+ "p1",
346
+ "p2",
347
+ "p3",
348
+ "p4",
349
+ "r1",
350
+ "r2",
351
+ "r3",
352
+ "r4",
353
+ "rotation",
354
+ "row-gap",
355
+ "shadow",
356
+ "stroke-color",
357
+ "stroke-width",
358
+ "text-case",
359
+ "text-decoration",
360
+ "typography",
361
+ "width",
362
+ ],
363
+ cornerRadiusForms: ["uniform", "per-corner"],
364
+ componentModel: "located-main-instance",
365
+ entryKinds: ["assets", "components", "screens", "tokens"],
366
+ fillTypes: ["image", "linear-gradient", "radial-gradient", "solid"],
367
+ localAssetTypes: ["color", "font", "media", "typography"],
368
+ nodeFields: [
369
+ "appliedTokens",
370
+ "backgroundBlur",
371
+ "blend-mode",
372
+ "blur",
373
+ "children",
374
+ "componentId",
375
+ "componentVariantId",
376
+ "cornerRadius",
377
+ "fills",
378
+ "flipX",
379
+ "flipY",
380
+ "growType",
381
+ "grids",
382
+ "height",
383
+ "hide-fill-on-export",
384
+ "hide-in-viewer",
385
+ "id",
386
+ "interactions",
387
+ "layout",
388
+ "layout-flex-dir",
389
+ "layout-gap-type",
390
+ "layout-gap",
391
+ "layout-align-items",
392
+ "layout-justify-content",
393
+ "layout-align-content",
394
+ "layout-wrap-type",
395
+ "layout-padding-type",
396
+ "layout-padding",
397
+ "layout-item-margin",
398
+ "layout-item-margin-type",
399
+ "layout-item-h-sizing",
400
+ "layout-item-v-sizing",
401
+ "layout-item-max-h",
402
+ "layout-item-min-h",
403
+ "layout-item-max-w",
404
+ "layout-item-min-w",
405
+ "layout-item-align-self",
406
+ "layout-item-absolute",
407
+ "layout-item-z-index",
408
+ "constraints-h",
409
+ "constraints-v",
410
+ "fixed-scroll",
411
+ "exports",
412
+ "content",
413
+ "pathData",
414
+ "points",
415
+ "locked",
416
+ "masked-group",
417
+ "mediaRef",
418
+ "name",
419
+ "opacity",
420
+ "proportionLock",
421
+ "rotation",
422
+ "sourceNodeId",
423
+ "strokes",
424
+ "shadow",
425
+ "show-content",
426
+ "text",
427
+ "textBlocks",
428
+ "textStyle",
429
+ "touched",
430
+ "type",
431
+ "visible",
432
+ "width",
433
+ "x",
434
+ "y",
435
+ ],
436
+ nodeTypes: [
437
+ "COMPONENT",
438
+ "ELLIPSE",
439
+ "FRAME",
440
+ "GROUP",
441
+ "IMAGE",
442
+ "INSTANCE",
443
+ "PATH",
444
+ "RECTANGLE",
445
+ "TEXT",
446
+ ],
447
+ presentationRootForms: ["legacy-single", "forest"],
448
+ textModel: "blocks-runs",
449
+ strokeTypes: ["image", "linear-gradient", "radial-gradient", "solid"],
450
+ supportedMediaTypes: [
451
+ "image/gif",
452
+ "image/jpeg",
453
+ "image/png",
454
+ "image/svg+xml",
455
+ "image/webp",
456
+ ],
457
+ supportedFontTypes: ["font/otf", "font/ttf", "font/woff", "font/woff2"],
458
+ assetLibraryEntries: "zero-or-one",
459
+ tokenLibraryEntries: "zero-or-one",
460
+ touchedGroups: [
461
+ "blur-group",
462
+ "constraints-group",
463
+ "content-group",
464
+ "fill-group",
465
+ "geometry-group",
466
+ "layer-effects-group",
467
+ "mask-group",
468
+ "modifiable-group",
469
+ "name-group",
470
+ "radius-group",
471
+ "shadow-group",
472
+ "stroke-group",
473
+ "text-display-group",
474
+ "text-font-group",
475
+ "visibility-group",
476
+ ],
477
+ },
478
+ });
479
+
480
+ export const SMALLPEN_RUNTIME_CAPABILITIES = deepFreeze({
481
+ agentExecution: false,
482
+ aiChat: false,
483
+ comments: false,
484
+ externalChanges: true,
485
+ localHistory: true,
486
+ mcp: false,
487
+ multiplePackages: true,
488
+ networkInfrastructure: false,
489
+ plugins: false,
490
+ presence: false,
491
+ realtimeCollaboration: false,
492
+ remoteHistory: false,
493
+ repositoryMerge: false,
494
+ reviewWorkflow: false,
495
+ });