@1agh/maude 0.58.3 → 0.59.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 (67) hide show
  1. package/apps/studio/annotations-layer.tsx +49 -15
  2. package/apps/studio/bin/_import-asset.mjs +18 -0
  3. package/apps/studio/bin/_import-figma.mjs +868 -214
  4. package/apps/studio/bin/_perf-probe-safari.mjs +332 -0
  5. package/apps/studio/bin/_perf-probe.mjs +228 -0
  6. package/apps/studio/bin/_perf-shared.mjs +345 -0
  7. package/apps/studio/bin/_video-playwright.mjs +17 -4
  8. package/apps/studio/bin/import-figma.sh +10 -1
  9. package/apps/studio/bin/perf.sh +228 -0
  10. package/apps/studio/bin/smoke.sh +49 -5
  11. package/apps/studio/canvas-lib.tsx +148 -6
  12. package/apps/studio/client/app.jsx +152 -37
  13. package/apps/studio/client/panels/SyncPanel.jsx +229 -0
  14. package/apps/studio/client/panels/TimelinePanel.jsx +29 -1
  15. package/apps/studio/client/panels/timeline-comp-target.js +101 -0
  16. package/apps/studio/client/styles/3-shell-maude.css +30 -0
  17. package/apps/studio/client/styles/4-components.css +4 -4
  18. package/apps/studio/dist/client.bundle.js +772 -772
  19. package/apps/studio/dist/styles.css +1 -1
  20. package/apps/studio/exporters/video-encode-lib.ts +8 -5
  21. package/apps/studio/exporters/video.ts +10 -0
  22. package/apps/studio/figma/assets.test.ts +92 -0
  23. package/apps/studio/figma/assets.ts +63 -9
  24. package/apps/studio/figma/codegen-client.test.ts +276 -0
  25. package/apps/studio/figma/codegen-client.ts +509 -0
  26. package/apps/studio/figma/codegen-fonts.test.ts +103 -0
  27. package/apps/studio/figma/codegen-fonts.ts +195 -0
  28. package/apps/studio/figma/codegen-values.test.ts +179 -0
  29. package/apps/studio/figma/codegen-values.ts +270 -0
  30. package/apps/studio/figma/endpoints.ts +73 -0
  31. package/apps/studio/figma/fig-decode.test.ts +702 -0
  32. package/apps/studio/figma/fig-decode.ts +617 -0
  33. package/apps/studio/figma/fig-kiwi.ts +410 -0
  34. package/apps/studio/figma/fig-zip.ts +270 -0
  35. package/apps/studio/figma/from-codegen.test.ts +408 -0
  36. package/apps/studio/figma/from-codegen.ts +1103 -0
  37. package/apps/studio/figma/sanitize.test.ts +69 -0
  38. package/apps/studio/figma/sanitize.ts +139 -47
  39. package/apps/studio/figma/tailwind-map.test.ts +142 -0
  40. package/apps/studio/figma/tailwind-map.ts +545 -0
  41. package/apps/studio/figma/to-render.ts +25 -3
  42. package/apps/studio/figma/types.ts +6 -1
  43. package/apps/studio/http.ts +47 -0
  44. package/apps/studio/sync/asset-push.ts +346 -38
  45. package/apps/studio/sync/connection-state.ts +71 -3
  46. package/apps/studio/sync/index.ts +10 -1
  47. package/apps/studio/sync/status.ts +18 -0
  48. package/apps/studio/test/canvas-origin-gate.test.ts +4 -0
  49. package/apps/studio/test/figma-explode.test.ts +438 -0
  50. package/apps/studio/test/fixtures/perf-canvas.mjs +201 -0
  51. package/apps/studio/test/import-figma.test.ts +192 -4
  52. package/apps/studio/test/sync-asset-push.test.ts +490 -47
  53. package/apps/studio/test/sync-connection-state.test.ts +66 -0
  54. package/apps/studio/test/sync-panel-surface.test.ts +90 -0
  55. package/apps/studio/test/sync-status.test.ts +28 -0
  56. package/apps/studio/test/timeline-comp-target.test.ts +139 -0
  57. package/apps/studio/test/video-comp.test.ts +81 -1
  58. package/apps/studio/test/video-encode-lib.test.ts +63 -0
  59. package/apps/studio/use-artboard-drag.tsx +37 -3
  60. package/apps/studio/video-comp.tsx +51 -0
  61. package/apps/studio/whats-new.json +71 -0
  62. package/cli/commands/design.mjs +7 -0
  63. package/cli/commands/kg.mjs +8 -1
  64. package/cli/commands/kg.test.mjs +24 -0
  65. package/cli/lib/figma-codegen-reachability.test.mjs +104 -0
  66. package/cli/lib/figma-import-controls.test.mjs +70 -0
  67. package/package.json +8 -8
@@ -76,6 +76,43 @@ export interface FigmaImportRequest {
76
76
  dryRun?: boolean;
77
77
  }
78
78
 
79
+ export interface FigmaExplodeRequest {
80
+ /** Canvas path RELATIVE to the design root. Never absolute, never `..`. */
81
+ canvas: string;
82
+ /** The `DCArtboard` id. Code-computed at import time, so a strict charset. */
83
+ artboard: string;
84
+ dryRun?: boolean;
85
+ confirmDocument?: boolean;
86
+ }
87
+
88
+ /**
89
+ * Validate an explode request.
90
+ *
91
+ * Narrower than `parseImportRequest`, because this one MUTATES an existing
92
+ * reviewed, versioned, peer-synced artifact. The caller supplies a target and
93
+ * nothing else: no output path, no node id, no URL, no size. Everything else is
94
+ * read from what the deterministic import already recorded (DDR-219 D8, which
95
+ * inherits DDR-216 D3's "the producer never picks its own target").
96
+ */
97
+ export function parseExplodeRequest(body: unknown): FigmaExplodeRequest | null {
98
+ if (!body || typeof body !== 'object') return null;
99
+ const b = body as Record<string, unknown>;
100
+ if (typeof b.canvas !== 'string' || b.canvas.length === 0 || b.canvas.length > 512) return null;
101
+ // Traversal is refused HERE as well as by the verb's realpath containment.
102
+ // Two independent checks, because this one is cheap and the failure is total.
103
+ if (b.canvas.includes('..') || b.canvas.startsWith('/') || /^[A-Za-z]:/.test(b.canvas)) {
104
+ return null;
105
+ }
106
+ if (!b.canvas.endsWith('.tsx')) return null;
107
+ if (typeof b.artboard !== 'string' || !/^[a-z0-9-]{1,64}$/.test(b.artboard)) return null;
108
+ return {
109
+ canvas: b.canvas,
110
+ artboard: b.artboard,
111
+ dryRun: b.dryRun === true,
112
+ confirmDocument: b.confirmDocument === true,
113
+ };
114
+ }
115
+
79
116
  export interface FigmaEndpoints {
80
117
  /** POST — store a PAT. Returns presence only, never the value. */
81
118
  connect(body: unknown): FigmaEndpointResult;
@@ -87,6 +124,8 @@ export interface FigmaEndpoints {
87
124
  probe(): Promise<FigmaEndpointResult>;
88
125
  /** POST — run an import. Same work the CLI verb does, same guarantees. */
89
126
  runImport(body: unknown): Promise<FigmaEndpointResult>;
127
+ /** POST — make ONE already-imported artboard editable via Dev Mode codegen. */
128
+ explode(body: unknown): Promise<FigmaEndpointResult>;
90
129
  }
91
130
 
92
131
  /**
@@ -116,6 +155,10 @@ export interface FigmaEndpointDeps {
116
155
  runImport?(req: FigmaImportRequest): Promise<{
117
156
  summary: Record<string, unknown>;
118
157
  }>;
158
+ /** Same injection, same reason. The real implementation is the verb's
159
+ * `explodeArtboard`, so the panel and the CLI cannot drift apart in what
160
+ * they validate, cap or report. */
161
+ explode?(req: FigmaExplodeRequest): Promise<{ summary: Record<string, unknown> }>;
119
162
  }
120
163
 
121
164
  export function createFigmaEndpoints(deps: FigmaEndpointDeps = {}): FigmaEndpoints {
@@ -196,5 +239,35 @@ export function createFigmaEndpoints(deps: FigmaEndpointDeps = {}): FigmaEndpoin
196
239
  return { status: 500, json: { ok: false, reason: 'failed', error: 'Import failed.' } };
197
240
  }
198
241
  },
242
+
243
+ async explode(body: unknown): Promise<FigmaEndpointResult> {
244
+ const req = parseExplodeRequest(body);
245
+ if (!req) return { status: 400, json: { error: 'canvas and artboard are required' } };
246
+ if (!deps.explode) {
247
+ return { status: 501, json: { error: 'codegen is not available in this shell' } };
248
+ }
249
+ try {
250
+ const { summary } = await deps.explode(req);
251
+ return { status: 200, json: { ok: true, ...summary } };
252
+ } catch (err) {
253
+ // Codegen being unavailable is the COMMON case (no Dev/Full seat, Figma
254
+ // desktop not running, Dev Mode off, wrong tab). It is a 409, not a 500:
255
+ // nothing is wrong with the request or with us. The reason code is the
256
+ // client's OWN enum — `CodegenError.kind` / `CodegenConvertError.reason`
257
+ // are code-owned strings from fixed tables, never upstream text.
258
+ const kind = (err as { kind?: string; reason?: string } | null)?.kind;
259
+ const reason = (err as { reason?: string } | null)?.reason;
260
+ if (typeof kind === 'string') {
261
+ return {
262
+ status: 409,
263
+ json: { ok: false, reason: kind, error: (err as Error).message },
264
+ };
265
+ }
266
+ if (typeof reason === 'string') {
267
+ return { status: 422, json: { ok: false, reason, error: (err as Error).message } };
268
+ }
269
+ return { status: 500, json: { ok: false, reason: 'failed', error: 'Explode failed.' } };
270
+ }
271
+ },
199
272
  };
200
273
  }