kritzel-stencil 0.2.1 → 0.2.2

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 (65) hide show
  1. package/dist/cjs/index.cjs.js +1 -1
  2. package/dist/cjs/kritzel-active-users_42.cjs.entry.js +80 -39
  3. package/dist/cjs/loader.cjs.js +1 -1
  4. package/dist/cjs/stencil.cjs.js +1 -1
  5. package/dist/cjs/{workspace.migrations-TAWnOE7r.js → workspace.migrations-BPwtowiJ.js} +159 -22
  6. package/dist/collection/classes/core/core.class.js +27 -19
  7. package/dist/collection/classes/handlers/selection.handler.js +36 -2
  8. package/dist/collection/classes/objects/group.class.js +69 -12
  9. package/dist/collection/classes/tools/text-tool.class.js +44 -8
  10. package/dist/collection/components/core/kritzel-engine/kritzel-engine.js +34 -17
  11. package/dist/collection/components/shared/kritzel-portal/kritzel-portal.js +23 -1
  12. package/dist/collection/constants/version.js +1 -1
  13. package/dist/collection/themes/dark-theme.js +5 -0
  14. package/dist/collection/themes/light-theme.js +5 -0
  15. package/dist/components/index.js +1 -1
  16. package/dist/components/kritzel-awareness-cursors.js +1 -1
  17. package/dist/components/kritzel-color-palette.js +1 -1
  18. package/dist/components/kritzel-color.js +1 -1
  19. package/dist/components/kritzel-controls.js +1 -1
  20. package/dist/components/kritzel-editor.js +1 -1
  21. package/dist/components/kritzel-engine.js +1 -1
  22. package/dist/components/kritzel-menu-item.js +1 -1
  23. package/dist/components/kritzel-menu.js +1 -1
  24. package/dist/components/kritzel-more-menu.js +1 -1
  25. package/dist/components/kritzel-portal.js +1 -1
  26. package/dist/components/kritzel-settings.js +1 -1
  27. package/dist/components/kritzel-split-button.js +1 -1
  28. package/dist/components/kritzel-stroke-size.js +1 -1
  29. package/dist/components/kritzel-tool-config.js +1 -1
  30. package/dist/components/kritzel-workspace-manager.js +1 -1
  31. package/dist/components/{p-CFzvz-B2.js → p-0YBCp8Wh.js} +1 -1
  32. package/dist/components/{p-DkT0CXfN.js → p-574MVXxi.js} +1 -1
  33. package/dist/components/p-BCzbwL4m.js +1 -0
  34. package/dist/components/p-BLjdzUzs.js +1 -0
  35. package/dist/components/{p-BFQVg_eQ.js → p-BSEdLfq2.js} +1 -1
  36. package/dist/components/{p-C3Dwuqka.js → p-BWrxz4mM.js} +1 -1
  37. package/dist/components/{p-ChqeIKg_.js → p-BYOIzv_f.js} +1 -1
  38. package/dist/components/{p-CekG3_ce.js → p-Bfa-Amjn.js} +1 -1
  39. package/dist/components/{p-mDz63oKF.js → p-BmcAX-1k.js} +1 -1
  40. package/dist/components/{p-CzIuqMQA.js → p-BtJB7FsW.js} +1 -1
  41. package/dist/components/{p-CVQBfO3r.js → p-C6Td7I4k.js} +1 -1
  42. package/dist/components/{p-ChQNi67Z.js → p-D9ifYAtg.js} +1 -1
  43. package/dist/components/{p-DoIOS3fS.js → p-DE2xDwUM.js} +1 -1
  44. package/dist/components/{p-B4wyWc66.js → p-DFeyobdy.js} +2 -2
  45. package/dist/components/{p--T9W9erA.js → p-DfB7uJ0N.js} +1 -1
  46. package/dist/components/{p-B2kHVHa_.js → p-u-827ZX7.js} +1 -1
  47. package/dist/esm/index.js +2 -2
  48. package/dist/esm/kritzel-active-users_42.entry.js +80 -39
  49. package/dist/esm/loader.js +1 -1
  50. package/dist/esm/stencil.js +1 -1
  51. package/dist/esm/{workspace.migrations-Dta1Yewh.js → workspace.migrations-C_uxbvuH.js} +159 -22
  52. package/dist/stencil/index.esm.js +1 -1
  53. package/dist/stencil/{p-22753671.entry.js → p-4d28c496.entry.js} +2 -2
  54. package/dist/stencil/p-C_uxbvuH.js +1 -0
  55. package/dist/stencil/stencil.esm.js +1 -1
  56. package/dist/types/classes/handlers/selection.handler.d.ts +15 -0
  57. package/dist/types/classes/objects/group.class.d.ts +15 -0
  58. package/dist/types/classes/tools/text-tool.class.d.ts +26 -8
  59. package/dist/types/components/shared/kritzel-portal/kritzel-portal.d.ts +1 -0
  60. package/dist/types/constants/version.d.ts +1 -1
  61. package/dist/types/interfaces/theme.interface.d.ts +12 -4
  62. package/package.json +1 -1
  63. package/dist/components/p-BYX50YSd.js +0 -1
  64. package/dist/components/p-CjazGGq3.js +0 -1
  65. package/dist/stencil/p-Dta1Yewh.js +0 -1
@@ -14490,6 +14490,11 @@ const lightTheme = {
14490
14490
  engine: {
14491
14491
  backgroundColor: '#ffffff',
14492
14492
  },
14493
+ snap: {
14494
+ indicatorFill: 'rgba(59, 130, 246, 0.3)',
14495
+ indicatorStroke: '#007bff',
14496
+ lineStroke: 'rgba(0, 0, 0, 0.2)',
14497
+ },
14493
14498
  fontSize: {
14494
14499
  hoverBackgroundColor: '#ebebeb',
14495
14500
  selectedBackgroundColor: '#ebebeb',
@@ -14754,6 +14759,11 @@ const darkTheme = {
14754
14759
  engine: {
14755
14760
  backgroundColor: '#1a1a1a',
14756
14761
  },
14762
+ snap: {
14763
+ indicatorFill: 'rgba(10, 132, 255, 0.35)',
14764
+ indicatorStroke: '#0A84FF',
14765
+ lineStroke: 'rgba(255, 255, 255, 0.35)',
14766
+ },
14757
14767
  fontSize: {
14758
14768
  hoverBackgroundColor: '#3a3a3a',
14759
14769
  selectedBackgroundColor: '#3a3a3a',
@@ -18246,6 +18256,23 @@ class KritzelGroup extends KritzelBaseObject {
18246
18256
  }
18247
18257
  return null;
18248
18258
  }
18259
+ /**
18260
+ * Recursively collects the IDs of all descendants of the given group (children,
18261
+ * grandchildren, etc.). Useful for detecting when a selection contains both an
18262
+ * ancestor group and one of its descendants — a configuration that would otherwise
18263
+ * cause the descendant to be transformed twice (once via the ancestor, once directly).
18264
+ * @param group - The group whose descendants should be collected.
18265
+ * @param out - A set that will be populated with all descendant object IDs.
18266
+ */
18267
+ static collectDescendantIds(group, out = new Set()) {
18268
+ for (const child of group.children) {
18269
+ out.add(child.id);
18270
+ if (child instanceof KritzelGroup) {
18271
+ KritzelGroup.collectDescendantIds(child, out);
18272
+ }
18273
+ }
18274
+ return out;
18275
+ }
18249
18276
  /**
18250
18277
  * Adds a child object to this group.
18251
18278
  * If the object is already a child, no action is taken.
@@ -18289,8 +18316,19 @@ class KritzelGroup extends KritzelBaseObject {
18289
18316
  * Finalizes the group after children have been positioned (e.g., after paste).
18290
18317
  * Refreshes the bounding box to encompass all children and captures
18291
18318
  * child snapshots for subsequent transformation operations.
18319
+ *
18320
+ * Recursively finalizes nested child groups first, so that when a transform
18321
+ * (rotate/resize) cascades through nested groups, every group's snapshots are
18322
+ * aligned with the current visual state. Without this, a nested group's
18323
+ * `snapshotRotation` could be stale, causing the inner group to be offset
18324
+ * relative to its parent during rotation.
18292
18325
  */
18293
18326
  finalize() {
18327
+ for (const child of this.children) {
18328
+ if (child instanceof KritzelGroup) {
18329
+ child.finalize();
18330
+ }
18331
+ }
18294
18332
  this.refreshBoundingBox();
18295
18333
  this.captureChildSnapshots();
18296
18334
  }
@@ -18447,11 +18485,23 @@ class KritzelGroup extends KritzelBaseObject {
18447
18485
  * @param height - The new height of the group's content area.
18448
18486
  */
18449
18487
  resize(x, y, width, height) {
18450
- const widthScaleFactor = width / this.width;
18451
- const heightScaleFactor = height / this.height;
18452
- // Calculate old center
18453
- const oldCenterX = this.translateX + this.totalWidth / 2 / this.scale;
18454
- const oldCenterY = this.translateY + this.totalHeight / 2 / this.scale;
18488
+ // Use snapshot dimensions (stable across the gesture) instead of `this.*`,
18489
+ // which mutates each frame and gets distorted by descendants like KritzelText
18490
+ // that clamp to a uniform scale, causing the cascade factor to drift.
18491
+ const baseWidth = this.snapshotTotalWidth > 0
18492
+ ? this.snapshotTotalWidth - this.padding * 2
18493
+ : this.width;
18494
+ const baseHeight = this.snapshotTotalHeight > 0
18495
+ ? this.snapshotTotalHeight - this.padding * 2
18496
+ : this.height;
18497
+ const baseScale = this.snapshotScale || this.scale || 1;
18498
+ const widthScaleFactor = baseWidth !== 0 ? width / baseWidth : 1;
18499
+ const heightScaleFactor = baseHeight !== 0 ? height / baseHeight : 1;
18500
+ // Calculate old center from snapshot (stable across the gesture)
18501
+ const snapshotTotalWidth = this.snapshotTotalWidth || (this.width + this.padding * 2);
18502
+ const snapshotTotalHeight = this.snapshotTotalHeight || (this.height + this.padding * 2);
18503
+ const oldCenterX = this.snapshotTranslateX + snapshotTotalWidth / 2 / baseScale;
18504
+ const oldCenterY = this.snapshotTranslateY + snapshotTotalHeight / 2 / baseScale;
18455
18505
  // Calculate new center
18456
18506
  const newTotalWidth = width + this.padding * 2;
18457
18507
  const newTotalHeight = height + this.padding * 2;
@@ -18464,9 +18514,20 @@ class KritzelGroup extends KritzelBaseObject {
18464
18514
  const sinR = Math.sin(rotation);
18465
18515
  this._core.store.objects.transaction(() => {
18466
18516
  this.children.forEach(child => {
18467
- // Calculate child center
18468
- const childCenterX = child.translateX + child.totalWidth / 2 / child.scale;
18469
- const childCenterY = child.translateY + child.totalHeight / 2 / child.scale;
18517
+ // Use snapshot values for the child to avoid compounding distortions caused
18518
+ // by descendants like text that cannot honour requested aspect ratios.
18519
+ const snapshot = this.unchangedChildSnapshots.get(child.id);
18520
+ const childTranslateX = snapshot ? snapshot.translateX : child.translateX;
18521
+ const childTranslateY = snapshot ? snapshot.translateY : child.translateY;
18522
+ const childTotalWidth = snapshot ? snapshot.totalWidth : child.totalWidth;
18523
+ const childTotalHeight = snapshot ? snapshot.totalHeight : child.totalHeight;
18524
+ const childWidth = snapshot ? snapshot.width : child.width;
18525
+ const childHeight = snapshot ? snapshot.height : child.height;
18526
+ const childRotation = snapshot ? snapshot.rotation : child.rotation;
18527
+ const childScale = (snapshot ? snapshot.scale : child.scale) || 1;
18528
+ // Calculate child center from snapshot
18529
+ const childCenterX = childTranslateX + childTotalWidth / 2 / childScale;
18530
+ const childCenterY = childTranslateY + childTotalHeight / 2 / childScale;
18470
18531
  // Vector from old group center to child center
18471
18532
  const dx = childCenterX - oldCenterX;
18472
18533
  const dy = childCenterY - oldCenterY;
@@ -18483,13 +18544,13 @@ class KritzelGroup extends KritzelBaseObject {
18483
18544
  const newChildCenterX = newCenterX + rotatedX;
18484
18545
  const newChildCenterY = newCenterY + rotatedY;
18485
18546
  // Calculate relative rotation for scaling
18486
- const relativeRotation = child.rotation - rotation;
18547
+ const relativeRotation = childRotation - rotation;
18487
18548
  const cosRel = Math.cos(relativeRotation);
18488
18549
  const sinRel = Math.sin(relativeRotation);
18489
18550
  const newChildWidthScale = Math.sqrt(Math.pow(widthScaleFactor * cosRel, 2) + Math.pow(heightScaleFactor * sinRel, 2));
18490
18551
  const newChildHeightScale = Math.sqrt(Math.pow(widthScaleFactor * sinRel, 2) + Math.pow(heightScaleFactor * cosRel, 2));
18491
- const updatedWidth = child.width * newChildWidthScale;
18492
- const updatedHeight = child.height * newChildHeightScale;
18552
+ const updatedWidth = childWidth * newChildWidthScale;
18553
+ const updatedHeight = childHeight * newChildHeightScale;
18493
18554
  const updatedTotalWidth = updatedWidth + child.padding * 2;
18494
18555
  const updatedTotalHeight = updatedHeight + child.padding * 2;
18495
18556
  const updatedX = newChildCenterX - updatedTotalWidth / 2 / child.scale;
@@ -18499,7 +18560,13 @@ class KritzelGroup extends KritzelBaseObject {
18499
18560
  this._core.anchorManager.updateAnchorsForObject(child.id);
18500
18561
  });
18501
18562
  this.refreshBoundingBox();
18502
- this.captureChildSnapshots();
18563
+ // Don't recapture snapshots while an interactive resize is in progress —
18564
+ // recapturing each frame would defeat the purpose of using stable snapshots
18565
+ // and re-introduce the compounding distortion described above. Snapshots are
18566
+ // refreshed at the start of the next gesture via beginTransform/finalize.
18567
+ if (!this._core.store.state.isResizing) {
18568
+ this.captureChildSnapshots();
18569
+ }
18503
18570
  this._core.store.objects.update(this);
18504
18571
  });
18505
18572
  }
@@ -20795,14 +20862,38 @@ class KritzelImageTool extends KritzelBaseTool {
20795
20862
  * Supports configurable font family, size, color, and opacity.
20796
20863
  */
20797
20864
  class KritzelTextTool extends KritzelBaseTool {
20798
- /** The font family for new text objects */
20799
- fontFamily = 'Arial';
20800
- /** The font size for new text objects in pixels */
20801
- fontSize = 16;
20802
- /** The font color for new text objects (supports theme-aware light/dark colors) */
20803
- fontColor = DEFAULT_COLOR_PALETTE[0];
20804
- /** The opacity of new text objects (0-1) */
20805
- opacity = 1;
20865
+ /** Backing field for {@link fontFamily}. */
20866
+ _fontFamily = 'Arial';
20867
+ /** Backing field for {@link fontSize}. */
20868
+ _fontSize = 16;
20869
+ /** Backing field for {@link fontColor}. */
20870
+ _fontColor = DEFAULT_COLOR_PALETTE[0];
20871
+ /** Backing field for {@link opacity}. */
20872
+ _opacity = 1;
20873
+ /** The font family for new text objects. */
20874
+ get fontFamily() { return this._fontFamily; }
20875
+ set fontFamily(value) {
20876
+ this._fontFamily = value;
20877
+ this.applyToActiveText({ fontFamily: value });
20878
+ }
20879
+ /** The font size for new text objects in pixels. */
20880
+ get fontSize() { return this._fontSize; }
20881
+ set fontSize(value) {
20882
+ this._fontSize = value;
20883
+ this.applyToActiveText({ fontSize: value });
20884
+ }
20885
+ /** The font color for new text objects (supports theme-aware light/dark colors). */
20886
+ get fontColor() { return this._fontColor; }
20887
+ set fontColor(value) {
20888
+ this._fontColor = value;
20889
+ this.applyToActiveText({ fontColor: value });
20890
+ }
20891
+ /** The opacity of new text objects (0-1). */
20892
+ get opacity() { return this._opacity; }
20893
+ set opacity(value) {
20894
+ this._opacity = value;
20895
+ this.applyToActiveText({ opacity: value });
20896
+ }
20806
20897
  /** Available color palette for the text tool */
20807
20898
  palette = [...DEFAULT_COLOR_PALETTE];
20808
20899
  /**
@@ -20812,6 +20903,18 @@ class KritzelTextTool extends KritzelBaseTool {
20812
20903
  constructor(core) {
20813
20904
  super(core);
20814
20905
  }
20906
+ /**
20907
+ * Propagates a property change to the text object that is currently being edited, if any.
20908
+ * Mirrors the selection tool pattern of pushing tool-config changes down to live objects,
20909
+ * but scoped to the single text in edit mode rather than the current selection.
20910
+ */
20911
+ applyToActiveText(updatedProperties) {
20912
+ const activeText = this._core?.store?.activeText;
20913
+ if (!activeText)
20914
+ return;
20915
+ this._core.updateObject(activeText, updatedProperties);
20916
+ this._core.rerender();
20917
+ }
20815
20918
  /**
20816
20919
  * Handles pointer down events for text creation and editing.
20817
20920
  * If clicking on an existing text object, enters edit mode for that object.
@@ -22539,6 +22642,7 @@ class KritzelSelectionHandler extends KritzelBaseHandler {
22539
22642
  const existingGroup = this._core.store.selectionGroup;
22540
22643
  if (shiftKey && existingGroup) {
22541
22644
  existingGroup.addOrRemove(objectToSelect);
22645
+ this.removeDescendantsOfSelectedGroups(existingGroup);
22542
22646
  if (existingGroup.objects.length === 0) {
22543
22647
  this._core.removeSelectionGroup();
22544
22648
  }
@@ -22584,15 +22688,17 @@ class KritzelSelectionHandler extends KritzelBaseHandler {
22584
22688
  obj.isSelected = false;
22585
22689
  }
22586
22690
  const unrolledObjects = Array.from(resolvedObjects.values());
22691
+ const filteredObjects = this.filterDescendantsOfSelectedGroups(unrolledObjects);
22587
22692
  const existingGroup = this._core.store.selectionGroup;
22588
22693
  if (shiftKey && existingGroup) {
22589
- existingGroup.addObjects(unrolledObjects);
22694
+ existingGroup.addObjects(filteredObjects);
22695
+ this.removeDescendantsOfSelectedGroups(existingGroup);
22590
22696
  this._core.rerender();
22591
22697
  }
22592
22698
  else {
22593
22699
  // Create selection group and set all IDs at once (no per-item refresh)
22594
22700
  const selectionGroup = KritzelSelectionGroup.create(this._core);
22595
- selectionGroup.objectIds = Array.from(resolvedObjects.keys());
22701
+ selectionGroup.objectIds = filteredObjects.map(o => o.id);
22596
22702
  // Only refresh dimensions and capture snapshots ONCE at the end - O(n) instead of O(n²)
22597
22703
  if (selectionGroup.length === 1) {
22598
22704
  selectionGroup.rotation = selectionGroup.objects[0].rotation;
@@ -22604,6 +22710,37 @@ class KritzelSelectionHandler extends KritzelBaseHandler {
22604
22710
  this._core.rerender();
22605
22711
  }
22606
22712
  }
22713
+ /**
22714
+ * Removes objects that are descendants of any KritzelGroup also present in the list.
22715
+ * Prevents an ancestor group and one of its descendants from coexisting in a selection,
22716
+ * which would otherwise cause the descendant to be transformed twice (once via the
22717
+ * ancestor group, and once directly).
22718
+ * @param objects - The candidate objects for the selection.
22719
+ * @returns A new array with descendants of selected groups removed.
22720
+ */
22721
+ filterDescendantsOfSelectedGroups(objects) {
22722
+ const descendantIds = new Set();
22723
+ for (const obj of objects) {
22724
+ if (obj instanceof KritzelGroup) {
22725
+ KritzelGroup.collectDescendantIds(obj, descendantIds);
22726
+ }
22727
+ }
22728
+ if (descendantIds.size === 0) {
22729
+ return objects;
22730
+ }
22731
+ return objects.filter(o => !descendantIds.has(o.id));
22732
+ }
22733
+ /**
22734
+ * Mutates an existing selection group to remove any descendants of groups
22735
+ * already present in it. See {@link filterDescendantsOfSelectedGroups}.
22736
+ * @param selectionGroup - The selection group to clean up in place.
22737
+ */
22738
+ removeDescendantsOfSelectedGroups(selectionGroup) {
22739
+ const filtered = this.filterDescendantsOfSelectedGroups(selectionGroup.objects);
22740
+ if (filtered.length !== selectionGroup.objects.length) {
22741
+ selectionGroup.objectIds = filtered.map(o => o.id);
22742
+ }
22743
+ }
22607
22744
  }
22608
22745
 
22609
22746
  /**
@@ -1 +1 @@
1
- import{H as a,a as T}from"./p-Dta1Yewh.js";export{E as APP_STATE_MIGRATIONS,A as AssetNotFoundError,C as CURRENT_APP_STATE_SCHEMA_VERSION,z as CURRENT_WORKSPACE_SCHEMA_VERSION,v as DEFAULT_ASSET_STORAGE_CONFIG,D as DEFAULT_BRUSH_CONFIG,u as DEFAULT_LINE_TOOL_CONFIG,t as DEFAULT_TEXT_CONFIG,p as IndexedDBAssetProvider,I as IndexedDBSyncProvider,y as KritzelAlignment,r as KritzelAnchorManager,o as KritzelAssetResolver,g as KritzelBrushTool,m as KritzelCursorHelper,i as KritzelEraserTool,e as KritzelGroup,c as KritzelImage,j as KritzelImageTool,d as KritzelLine,h as KritzelLineTool,b as KritzelPath,n as KritzelSelectionTool,f as KritzelShape,l as KritzelShapeTool,K as KritzelText,k as KritzelTextTool,s as KritzelThemeManager,q as KritzelWorkspace,S as ShapeType,W as WORKSPACE_EXPORT_VERSION,F as WORKSPACE_MIGRATIONS,x as darkTheme,w as lightTheme,B as runMigrations}from"./p-Dta1Yewh.js";import*as P from"yjs";import{WebsocketProvider as $}from"y-websocket";import"y-indexeddb";const _=Math.floor,U=127,H=Number.MAX_SAFE_INTEGER;class R{constructor(){this.cpos=0,this.cbuf=new Uint8Array(100),this.bufs=[]}}const O=()=>new R,N=t=>{const e=new Uint8Array((t=>{let e=t.cpos;for(let s=0;s<t.bufs.length;s++)e+=t.bufs[s].length;return e})(t));let s=0;for(let i=0;i<t.bufs.length;i++){const n=t.bufs[i];e.set(n,s),s+=n.length}return e.set(new Uint8Array(t.cbuf.buffer,0,t.cpos),s),e},M=(t,e)=>{const s=t.cbuf.length;t.cpos===s&&(t.bufs.push(t.cbuf),t.cbuf=new Uint8Array(2*s),t.cpos=0),t.cbuf[t.cpos++]=e},L=(t,e)=>{for(;e>U;)M(t,128|U&e),e=_(e/128);M(t,U&e)},G=(t,e)=>{L(t,e.byteLength),((t,e)=>{const s=t.cbuf.length,i=t.cpos,n=((t,e)=>t<e?t:e)(s-i,e.length),o=e.length-n;t.cbuf.set(e.subarray(0,n),i),t.cpos+=n,o>0&&(t.bufs.push(t.cbuf),t.cbuf=new Uint8Array(((t,e)=>t>e?t:e)(2*s,o)),t.cbuf.set(e.subarray(n)),t.cpos=o)})(t,e)},V=t=>new Error(t),X=V("Unexpected end of array"),Y=V("Integer out of Range");class J{constructor(t){this.arr=t,this.pos=0}}const Q=t=>((t,e)=>{const s=new Uint8Array(t.arr.buffer,t.pos+t.arr.byteOffset,e);return t.pos+=e,s})(t,Z(t)),Z=t=>{let e=0,s=1;const i=t.arr.length;for(;t.pos<i;){const i=t.arr[t.pos++];if(e+=(i&U)*s,s*=128,i<128)return e;if(e>H)throw Y}throw X};class tt{type="local";doc;channel;_synced=!1;constructor(t,e,s){this.doc=e,this.channel=new BroadcastChannel(t),this.channel.onmessage=t=>{this.handleMessage(t.data)},this.doc.on("update",this.handleDocUpdate),this.broadcastSync(),setTimeout((()=>{this._synced=!0}),100),s?.quiet||console.info(`BroadcastChannel Provider initialized: ${t}`)}handleDocUpdate=(t,e)=>{if(e!==this){const e=O();L(e,0),G(e,t),this.channel.postMessage(N(e))}};handleMessage(t){const e=(s=new Uint8Array(t),new J(s));var s;switch(Z(e)){case 0:const t=Q(e);P.applyUpdate(this.doc,t,this);break;case 1:this.broadcastSync();break;case 2:const s=Q(e),i=P.encodeStateAsUpdate(this.doc,s);if(i.length>0){const t=O();L(t,0),G(t,i),this.channel.postMessage(N(t))}}}broadcastSync(){const t=O();L(t,2),G(t,P.encodeStateVector(this.doc)),this.channel.postMessage(N(t))}async connect(){if(!this._synced)return new Promise((t=>{const e=()=>{this._synced?t():setTimeout(e,50)};e()}))}disconnect(){}async reconnect(){return this.disconnect(),this.connect()}destroy(){this.doc.off("update",this.handleDocUpdate),this.channel.close()}}class et{type="network";provider;isConnected=!1;_quiet=!1;get awareness(){return this.provider.awareness}constructor(t,e,s){const i=s?.url||"ws://localhost:1234",n=s?.roomName||t;this.provider=new $(i,n,e,{params:s?.params,protocols:s?.protocols,WebSocketPolyfill:s?.WebSocketPolyfill,awareness:s?.awareness,maxBackoffTime:s?.maxBackoffTime,disableBc:!0}),this._quiet=s?.quiet??!1,this.setupEventListeners(),this._quiet||console.info(`WebSocket Provider initialized: ${i}/${n}`)}static with(t){return{create:(e,s,i)=>{const n=i?{...t,...i}:t;return new et(e,s,n)}}}setupEventListeners(){this.provider.on("status",(({status:t})=>{"connected"===t?(this.isConnected=!0,this._quiet||console.info("WebSocket connected")):"disconnected"===t&&(this.isConnected=!1,this._quiet||console.info("WebSocket disconnected"))})),this.provider.on("sync",(t=>{t&&!this._quiet&&console.info("WebSocket synced")}))}async connect(){if(!this.isConnected)return new Promise(((t,e)=>{const s=setTimeout((()=>{e(new Error("WebSocket connection timeout"))}),1e4),i=({status:e})=>{"connected"===e&&(clearTimeout(s),this.provider.off("status",i),this.isConnected=!0,t())};this.provider.on("status",i),this.provider.wsconnected&&(clearTimeout(s),this.provider.off("status",i),this.isConnected=!0,t())}))}disconnect(){this.provider&&this.provider.disconnect(),this.isConnected=!1}async reconnect(){return this.disconnect(),this.connect()}destroy(){this.provider&&this.provider.destroy(),this.isConnected=!1}}class st{type="network";provider;isConnected=!1;isSynced=!1;usesSharedSocket=!1;isDestroyed=!1;connectTimeout=null;pendingConnectReject=null;connectionTimeoutMs;_connectionStatus="disconnected";visibilityHandler=null;onlineHandler=null;get awareness(){return this.provider.awareness}get connectionStatus(){return this._connectionStatus}static sharedWebSocketProvider=null;constructor(t,e,s){const i=s?.name||t,n=s?.url||"ws://localhost:1234";this.connectionTimeoutMs=s?.connectionTimeout??1e4;const o=s?.websocketProvider||st.sharedWebSocketProvider,r={};void 0!==s?.delay&&(r.delay=s.delay),void 0!==s?.factor&&(r.factor=s.factor),void 0!==s?.maxAttempts&&(r.maxAttempts=s.maxAttempts),void 0!==s?.minDelay&&(r.minDelay=s.minDelay),void 0!==s?.maxDelay&&(r.maxDelay=s.maxDelay);const c=()=>{this.isDestroyed||(this.isConnected=!0,this._connectionStatus="connected",s?.quiet||console.info(`Hocuspocus connected: ${i}`),s?.onConnect&&s.onConnect())},h=()=>{this.isDestroyed||(this.isConnected=!1,this.isSynced=!1,this._connectionStatus="disconnected",s?.quiet||console.info(`Hocuspocus disconnected: ${i}`),s?.onDisconnect&&s.onDisconnect())},d=()=>{this.isDestroyed||(this.isSynced=!0,this._connectionStatus="synced",s?.quiet||console.info(`Hocuspocus synced: ${i}`),s?.onSynced&&s.onSynced())},l=t=>{this.isDestroyed||("connecting"===t.status&&(this._connectionStatus="connecting"),s?.onStatus&&s.onStatus(t))};if(o){this.usesSharedSocket=!0;const t={websocketProvider:o,name:i,document:e,token:s?.token||null,onStatus:l,onConnect:c,onDisconnect:h,onSynced:d,...r};void 0!==s?.forceSyncInterval&&(t.forceSyncInterval=s.forceSyncInterval),s?.onAuthenticationFailed&&(t.onAuthenticationFailed=s.onAuthenticationFailed),this.provider=new a(t),this.provider.attach(),s?.quiet||console.info(`Hocuspocus Provider initialized (multiplexed): ${i}`)}else{this.usesSharedSocket=!1;const t={url:n,name:i,document:e,token:s?.token||null,autoConnect:!1,onStatus:l,onConnect:c,onDisconnect:h,onSynced:d,...r};void 0!==s?.forceSyncInterval&&(t.forceSyncInterval=s.forceSyncInterval),s?.onAuthenticationFailed&&(t.onAuthenticationFailed=s.onAuthenticationFailed),s?.WebSocketPolyfill&&(t.WebSocketPolyfill=s.WebSocketPolyfill),this.provider=new a(t),s?.quiet||console.info(`Hocuspocus Provider initialized: ${n}/${i}`)}this.setupBrowserEventListeners()}setupBrowserEventListeners(){"undefined"!=typeof document&&(this.visibilityHandler=()=>{"visible"!==document.visibilityState||this.isConnected||this.isDestroyed||this.provider.connect()},document.addEventListener("visibilitychange",this.visibilityHandler)),"undefined"!=typeof window&&(this.onlineHandler=()=>{this.isConnected||this.isDestroyed||this.provider.connect()},window.addEventListener("online",this.onlineHandler))}removeBrowserEventListeners(){this.visibilityHandler&&"undefined"!=typeof document&&(document.removeEventListener("visibilitychange",this.visibilityHandler),this.visibilityHandler=null),this.onlineHandler&&"undefined"!=typeof window&&(window.removeEventListener("online",this.onlineHandler),this.onlineHandler=null)}static createSharedWebSocket(t){if(st.sharedWebSocketProvider)return console.warn("Shared WebSocket already exists. Returning existing instance."),st.sharedWebSocketProvider;const e={url:t.url};return t.WebSocketPolyfill&&(e.WebSocketPolyfill=t.WebSocketPolyfill),t.onConnect&&(e.onConnect=t.onConnect),t.onDisconnect&&(e.onDisconnect=t.onDisconnect),t.onStatus&&(e.onStatus=t.onStatus),st.sharedWebSocketProvider=new T(e),console.info(`Shared Hocuspocus WebSocket created: ${t.url}`),st.sharedWebSocketProvider}static destroySharedWebSocket(){st.sharedWebSocketProvider&&(st.sharedWebSocketProvider.destroy(),st.sharedWebSocketProvider=null,console.info("Shared Hocuspocus WebSocket destroyed"))}static getSharedWebSocket(){return st.sharedWebSocketProvider}static with(t){return{create:(e,s,i)=>{const n=i?{...t,...i}:t;return new st(e,s,n)}}}async connect(){if(!this.isSynced&&!this.isDestroyed)return this._connectionStatus="connecting",new Promise(((t,e)=>{this.pendingConnectReject=e,this.connectTimeout=setTimeout((()=>{this.pendingConnectReject=null,this.connectTimeout=null,e(new Error("Hocuspocus connection timeout"))}),this.connectionTimeoutMs);const s=()=>{this.connectTimeout&&(clearTimeout(this.connectTimeout),this.connectTimeout=null),this.pendingConnectReject=null,this.provider.off("synced",s),this.isDestroyed||t()};if(this.provider.on("synced",s),this.provider.isSynced)return this.connectTimeout&&(clearTimeout(this.connectTimeout),this.connectTimeout=null),this.pendingConnectReject=null,this.provider.off("synced",s),void t();this.isConnected||this.usesSharedSocket||this.provider.connect()}))}async reconnect(){return this.disconnect(),this.connect()}disconnect(){this.connectTimeout&&(clearTimeout(this.connectTimeout),this.connectTimeout=null),this.pendingConnectReject&&(this.pendingConnectReject=null),this.provider&&(this.usesSharedSocket?this.provider.detach():this.provider.disconnect()),this.isConnected=!1,this.isSynced=!1,this._connectionStatus="disconnected"}destroy(){this.isDestroyed=!0,this.connectTimeout&&(clearTimeout(this.connectTimeout),this.connectTimeout=null),this.pendingConnectReject&&(this.pendingConnectReject=null),this.removeBrowserEventListeners(),this.provider&&this.provider.destroy(),this.isConnected=!1,this.isSynced=!1,this._connectionStatus="disconnected"}}class it{type="remote";name="HttpAssetProvider";_options;constructor(t){this._options=t}static with(t){return{create:()=>new it(t)}}async init(){this._options.quiet||console.info("HttpAssetProvider initialized")}destroy(){}canResolve(t){return!0}async put(t,e){const s=e.id??this.generateUuid(),i={...e,id:s},n=await(this._options.headers?.())??{},o=await this._options.uploadUrl(i),r=this._options.upload??this.defaultUpload;return{id:(await r(o,t,i,n)).id??s,kind:e.kind??"file",mimeType:e.mimeType,size:t.size,createdAt:Date.now(),width:e.width,height:e.height,durationMs:e.durationMs,originalFilename:e.originalFilename}}async resolve(t){return this._options.resolveUrl(t)}async fetch(t){const e=await this._options.resolveUrl(t),s=await(this._options.headers?.())??{},i=await fetch(e,{headers:s});if(!i.ok)throw new Error(`[HttpAssetProvider] Failed to fetch asset ${t}: ${i.status} ${i.statusText}`);return i.blob()}async delete(t){if(!this._options.deleteUrl)return;const e=await this._options.deleteUrl(t),s=await(this._options.headers?.())??{},i=await fetch(e,{method:"DELETE",headers:s});if(!i.ok)throw new Error(`[HttpAssetProvider] Failed to delete asset ${t}: ${i.status} ${i.statusText}`);this._options.quiet||console.info(`HttpAssetProvider: deleted asset ${t}`)}defaultUpload=async(t,e,s,i)=>{const n=new FormData;n.append("metadata",JSON.stringify(s)),n.append("file",e,s.originalFilename||`${s.id}.${this.extensionFromMime(s.mimeType)}`);const o=await fetch(t,{method:"POST",headers:i,body:n});if(!o.ok)throw new Error(`[HttpAssetProvider] Upload failed: ${o.status} ${o.statusText}`);return(o.headers.get("content-type")||"").includes("application/json")?await o.json():{}};extensionFromMime(t){const e=t.indexOf("/");return e>=0?t.slice(e+1):"bin"}generateUuid(){if("undefined"!=typeof crypto&&"function"==typeof crypto.randomUUID)return crypto.randomUUID();const t=crypto.getRandomValues(new Uint8Array(16));t[6]=15&t[6]|64,t[8]=63&t[8]|128;const e=Array.from(t,(t=>t.toString(16).padStart(2,"0"))).join("");return`${e.slice(0,8)}-${e.slice(8,12)}-${e.slice(12,16)}-${e.slice(16,20)}-${e.slice(20)}`}}class nt{type="remote";name="PresignedAssetProvider";_options;constructor(t){this._options=t}static with(t){return{create:()=>new nt(t)}}async init(){this._options.quiet||console.info("PresignedAssetProvider initialized")}destroy(){}canResolve(t){return!0}async put(t,e){const s=await this._options.getUploadDescriptor(e),i=s.method??"PUT",n={...s.headers??{}};let o;if(n["Content-Type"]||n["content-type"]||(n["Content-Type"]=e.mimeType),"POST"===i&&s.fields){const e=new FormData;for(const[t,i]of Object.entries(s.fields))e.append(t,i);e.append("file",t),o=e,delete n["Content-Type"],delete n["content-type"]}else o=t;const r=await fetch(s.url,{method:i,headers:n,body:o});if(!r.ok)throw new Error(`[PresignedAssetProvider] Upload failed: ${r.status} ${r.statusText}`);return{id:s.id,kind:e.kind??"file",mimeType:e.mimeType,size:t.size,createdAt:Date.now(),width:e.width,height:e.height,durationMs:e.durationMs,originalFilename:e.originalFilename}}async resolve(t){return this._options.getDownloadUrl(t)}async fetch(t){const e=await this._options.getDownloadUrl(t),s=await fetch(e);if(!s.ok)throw new Error(`[PresignedAssetProvider] Failed to fetch asset ${t}: ${s.status} ${s.statusText}`);return s.blob()}async delete(t){this._options.deleteAsset&&(await this._options.deleteAsset(t),this._options.quiet||console.info(`PresignedAssetProvider: deleted asset ${t}`))}}export{tt as BroadcastSyncProvider,st as HocuspocusSyncProvider,it as HttpAssetProvider,nt as PresignedAssetProvider,et as WebSocketSyncProvider}
1
+ import{H as a,a as T}from"./p-C_uxbvuH.js";export{E as APP_STATE_MIGRATIONS,A as AssetNotFoundError,C as CURRENT_APP_STATE_SCHEMA_VERSION,z as CURRENT_WORKSPACE_SCHEMA_VERSION,v as DEFAULT_ASSET_STORAGE_CONFIG,D as DEFAULT_BRUSH_CONFIG,u as DEFAULT_LINE_TOOL_CONFIG,t as DEFAULT_TEXT_CONFIG,p as IndexedDBAssetProvider,I as IndexedDBSyncProvider,y as KritzelAlignment,r as KritzelAnchorManager,o as KritzelAssetResolver,g as KritzelBrushTool,m as KritzelCursorHelper,i as KritzelEraserTool,e as KritzelGroup,c as KritzelImage,j as KritzelImageTool,d as KritzelLine,h as KritzelLineTool,b as KritzelPath,n as KritzelSelectionTool,f as KritzelShape,l as KritzelShapeTool,K as KritzelText,k as KritzelTextTool,s as KritzelThemeManager,q as KritzelWorkspace,S as ShapeType,W as WORKSPACE_EXPORT_VERSION,F as WORKSPACE_MIGRATIONS,x as darkTheme,w as lightTheme,B as runMigrations}from"./p-C_uxbvuH.js";import*as P from"yjs";import{WebsocketProvider as $}from"y-websocket";import"y-indexeddb";const _=Math.floor,H=127,U=Number.MAX_SAFE_INTEGER;class R{constructor(){this.cpos=0,this.cbuf=new Uint8Array(100),this.bufs=[]}}const O=()=>new R,N=t=>{const e=new Uint8Array((t=>{let e=t.cpos;for(let s=0;s<t.bufs.length;s++)e+=t.bufs[s].length;return e})(t));let s=0;for(let i=0;i<t.bufs.length;i++){const n=t.bufs[i];e.set(n,s),s+=n.length}return e.set(new Uint8Array(t.cbuf.buffer,0,t.cpos),s),e},M=(t,e)=>{const s=t.cbuf.length;t.cpos===s&&(t.bufs.push(t.cbuf),t.cbuf=new Uint8Array(2*s),t.cpos=0),t.cbuf[t.cpos++]=e},L=(t,e)=>{for(;e>H;)M(t,128|H&e),e=_(e/128);M(t,H&e)},G=(t,e)=>{L(t,e.byteLength),((t,e)=>{const s=t.cbuf.length,i=t.cpos,n=((t,e)=>t<e?t:e)(s-i,e.length),o=e.length-n;t.cbuf.set(e.subarray(0,n),i),t.cpos+=n,o>0&&(t.bufs.push(t.cbuf),t.cbuf=new Uint8Array(((t,e)=>t>e?t:e)(2*s,o)),t.cbuf.set(e.subarray(n)),t.cpos=o)})(t,e)},V=t=>new Error(t),X=V("Unexpected end of array"),J=V("Integer out of Range");class Q{constructor(t){this.arr=t,this.pos=0}}const Y=t=>((t,e)=>{const s=new Uint8Array(t.arr.buffer,t.pos+t.arr.byteOffset,e);return t.pos+=e,s})(t,Z(t)),Z=t=>{let e=0,s=1;const i=t.arr.length;for(;t.pos<i;){const i=t.arr[t.pos++];if(e+=(i&H)*s,s*=128,i<128)return e;if(e>U)throw J}throw X};class tt{type="local";doc;channel;_synced=!1;constructor(t,e,s){this.doc=e,this.channel=new BroadcastChannel(t),this.channel.onmessage=t=>{this.handleMessage(t.data)},this.doc.on("update",this.handleDocUpdate),this.broadcastSync(),setTimeout((()=>{this._synced=!0}),100),s?.quiet||console.info(`BroadcastChannel Provider initialized: ${t}`)}handleDocUpdate=(t,e)=>{if(e!==this){const e=O();L(e,0),G(e,t),this.channel.postMessage(N(e))}};handleMessage(t){const e=(s=new Uint8Array(t),new Q(s));var s;switch(Z(e)){case 0:const t=Y(e);P.applyUpdate(this.doc,t,this);break;case 1:this.broadcastSync();break;case 2:const s=Y(e),i=P.encodeStateAsUpdate(this.doc,s);if(i.length>0){const t=O();L(t,0),G(t,i),this.channel.postMessage(N(t))}}}broadcastSync(){const t=O();L(t,2),G(t,P.encodeStateVector(this.doc)),this.channel.postMessage(N(t))}async connect(){if(!this._synced)return new Promise((t=>{const e=()=>{this._synced?t():setTimeout(e,50)};e()}))}disconnect(){}async reconnect(){return this.disconnect(),this.connect()}destroy(){this.doc.off("update",this.handleDocUpdate),this.channel.close()}}class et{type="network";provider;isConnected=!1;_quiet=!1;get awareness(){return this.provider.awareness}constructor(t,e,s){const i=s?.url||"ws://localhost:1234",n=s?.roomName||t;this.provider=new $(i,n,e,{params:s?.params,protocols:s?.protocols,WebSocketPolyfill:s?.WebSocketPolyfill,awareness:s?.awareness,maxBackoffTime:s?.maxBackoffTime,disableBc:!0}),this._quiet=s?.quiet??!1,this.setupEventListeners(),this._quiet||console.info(`WebSocket Provider initialized: ${i}/${n}`)}static with(t){return{create:(e,s,i)=>{const n=i?{...t,...i}:t;return new et(e,s,n)}}}setupEventListeners(){this.provider.on("status",(({status:t})=>{"connected"===t?(this.isConnected=!0,this._quiet||console.info("WebSocket connected")):"disconnected"===t&&(this.isConnected=!1,this._quiet||console.info("WebSocket disconnected"))})),this.provider.on("sync",(t=>{t&&!this._quiet&&console.info("WebSocket synced")}))}async connect(){if(!this.isConnected)return new Promise(((t,e)=>{const s=setTimeout((()=>{e(new Error("WebSocket connection timeout"))}),1e4),i=({status:e})=>{"connected"===e&&(clearTimeout(s),this.provider.off("status",i),this.isConnected=!0,t())};this.provider.on("status",i),this.provider.wsconnected&&(clearTimeout(s),this.provider.off("status",i),this.isConnected=!0,t())}))}disconnect(){this.provider&&this.provider.disconnect(),this.isConnected=!1}async reconnect(){return this.disconnect(),this.connect()}destroy(){this.provider&&this.provider.destroy(),this.isConnected=!1}}class st{type="network";provider;isConnected=!1;isSynced=!1;usesSharedSocket=!1;isDestroyed=!1;connectTimeout=null;pendingConnectReject=null;connectionTimeoutMs;_connectionStatus="disconnected";visibilityHandler=null;onlineHandler=null;get awareness(){return this.provider.awareness}get connectionStatus(){return this._connectionStatus}static sharedWebSocketProvider=null;constructor(t,e,s){const i=s?.name||t,n=s?.url||"ws://localhost:1234";this.connectionTimeoutMs=s?.connectionTimeout??1e4;const o=s?.websocketProvider||st.sharedWebSocketProvider,r={};void 0!==s?.delay&&(r.delay=s.delay),void 0!==s?.factor&&(r.factor=s.factor),void 0!==s?.maxAttempts&&(r.maxAttempts=s.maxAttempts),void 0!==s?.minDelay&&(r.minDelay=s.minDelay),void 0!==s?.maxDelay&&(r.maxDelay=s.maxDelay);const c=()=>{this.isDestroyed||(this.isConnected=!0,this._connectionStatus="connected",s?.quiet||console.info(`Hocuspocus connected: ${i}`),s?.onConnect&&s.onConnect())},h=()=>{this.isDestroyed||(this.isConnected=!1,this.isSynced=!1,this._connectionStatus="disconnected",s?.quiet||console.info(`Hocuspocus disconnected: ${i}`),s?.onDisconnect&&s.onDisconnect())},d=()=>{this.isDestroyed||(this.isSynced=!0,this._connectionStatus="synced",s?.quiet||console.info(`Hocuspocus synced: ${i}`),s?.onSynced&&s.onSynced())},l=t=>{this.isDestroyed||("connecting"===t.status&&(this._connectionStatus="connecting"),s?.onStatus&&s.onStatus(t))};if(o){this.usesSharedSocket=!0;const t={websocketProvider:o,name:i,document:e,token:s?.token||null,onStatus:l,onConnect:c,onDisconnect:h,onSynced:d,...r};void 0!==s?.forceSyncInterval&&(t.forceSyncInterval=s.forceSyncInterval),s?.onAuthenticationFailed&&(t.onAuthenticationFailed=s.onAuthenticationFailed),this.provider=new a(t),this.provider.attach(),s?.quiet||console.info(`Hocuspocus Provider initialized (multiplexed): ${i}`)}else{this.usesSharedSocket=!1;const t={url:n,name:i,document:e,token:s?.token||null,autoConnect:!1,onStatus:l,onConnect:c,onDisconnect:h,onSynced:d,...r};void 0!==s?.forceSyncInterval&&(t.forceSyncInterval=s.forceSyncInterval),s?.onAuthenticationFailed&&(t.onAuthenticationFailed=s.onAuthenticationFailed),s?.WebSocketPolyfill&&(t.WebSocketPolyfill=s.WebSocketPolyfill),this.provider=new a(t),s?.quiet||console.info(`Hocuspocus Provider initialized: ${n}/${i}`)}this.setupBrowserEventListeners()}setupBrowserEventListeners(){"undefined"!=typeof document&&(this.visibilityHandler=()=>{"visible"!==document.visibilityState||this.isConnected||this.isDestroyed||this.provider.connect()},document.addEventListener("visibilitychange",this.visibilityHandler)),"undefined"!=typeof window&&(this.onlineHandler=()=>{this.isConnected||this.isDestroyed||this.provider.connect()},window.addEventListener("online",this.onlineHandler))}removeBrowserEventListeners(){this.visibilityHandler&&"undefined"!=typeof document&&(document.removeEventListener("visibilitychange",this.visibilityHandler),this.visibilityHandler=null),this.onlineHandler&&"undefined"!=typeof window&&(window.removeEventListener("online",this.onlineHandler),this.onlineHandler=null)}static createSharedWebSocket(t){if(st.sharedWebSocketProvider)return console.warn("Shared WebSocket already exists. Returning existing instance."),st.sharedWebSocketProvider;const e={url:t.url};return t.WebSocketPolyfill&&(e.WebSocketPolyfill=t.WebSocketPolyfill),t.onConnect&&(e.onConnect=t.onConnect),t.onDisconnect&&(e.onDisconnect=t.onDisconnect),t.onStatus&&(e.onStatus=t.onStatus),st.sharedWebSocketProvider=new T(e),console.info(`Shared Hocuspocus WebSocket created: ${t.url}`),st.sharedWebSocketProvider}static destroySharedWebSocket(){st.sharedWebSocketProvider&&(st.sharedWebSocketProvider.destroy(),st.sharedWebSocketProvider=null,console.info("Shared Hocuspocus WebSocket destroyed"))}static getSharedWebSocket(){return st.sharedWebSocketProvider}static with(t){return{create:(e,s,i)=>{const n=i?{...t,...i}:t;return new st(e,s,n)}}}async connect(){if(!this.isSynced&&!this.isDestroyed)return this._connectionStatus="connecting",new Promise(((t,e)=>{this.pendingConnectReject=e,this.connectTimeout=setTimeout((()=>{this.pendingConnectReject=null,this.connectTimeout=null,e(new Error("Hocuspocus connection timeout"))}),this.connectionTimeoutMs);const s=()=>{this.connectTimeout&&(clearTimeout(this.connectTimeout),this.connectTimeout=null),this.pendingConnectReject=null,this.provider.off("synced",s),this.isDestroyed||t()};if(this.provider.on("synced",s),this.provider.isSynced)return this.connectTimeout&&(clearTimeout(this.connectTimeout),this.connectTimeout=null),this.pendingConnectReject=null,this.provider.off("synced",s),void t();this.isConnected||this.usesSharedSocket||this.provider.connect()}))}async reconnect(){return this.disconnect(),this.connect()}disconnect(){this.connectTimeout&&(clearTimeout(this.connectTimeout),this.connectTimeout=null),this.pendingConnectReject&&(this.pendingConnectReject=null),this.provider&&(this.usesSharedSocket?this.provider.detach():this.provider.disconnect()),this.isConnected=!1,this.isSynced=!1,this._connectionStatus="disconnected"}destroy(){this.isDestroyed=!0,this.connectTimeout&&(clearTimeout(this.connectTimeout),this.connectTimeout=null),this.pendingConnectReject&&(this.pendingConnectReject=null),this.removeBrowserEventListeners(),this.provider&&this.provider.destroy(),this.isConnected=!1,this.isSynced=!1,this._connectionStatus="disconnected"}}class it{type="remote";name="HttpAssetProvider";_options;constructor(t){this._options=t}static with(t){return{create:()=>new it(t)}}async init(){this._options.quiet||console.info("HttpAssetProvider initialized")}destroy(){}canResolve(t){return!0}async put(t,e){const s=e.id??this.generateUuid(),i={...e,id:s},n=await(this._options.headers?.())??{},o=await this._options.uploadUrl(i),r=this._options.upload??this.defaultUpload;return{id:(await r(o,t,i,n)).id??s,kind:e.kind??"file",mimeType:e.mimeType,size:t.size,createdAt:Date.now(),width:e.width,height:e.height,durationMs:e.durationMs,originalFilename:e.originalFilename}}async resolve(t){return this._options.resolveUrl(t)}async fetch(t){const e=await this._options.resolveUrl(t),s=await(this._options.headers?.())??{},i=await fetch(e,{headers:s});if(!i.ok)throw new Error(`[HttpAssetProvider] Failed to fetch asset ${t}: ${i.status} ${i.statusText}`);return i.blob()}async delete(t){if(!this._options.deleteUrl)return;const e=await this._options.deleteUrl(t),s=await(this._options.headers?.())??{},i=await fetch(e,{method:"DELETE",headers:s});if(!i.ok)throw new Error(`[HttpAssetProvider] Failed to delete asset ${t}: ${i.status} ${i.statusText}`);this._options.quiet||console.info(`HttpAssetProvider: deleted asset ${t}`)}defaultUpload=async(t,e,s,i)=>{const n=new FormData;n.append("metadata",JSON.stringify(s)),n.append("file",e,s.originalFilename||`${s.id}.${this.extensionFromMime(s.mimeType)}`);const o=await fetch(t,{method:"POST",headers:i,body:n});if(!o.ok)throw new Error(`[HttpAssetProvider] Upload failed: ${o.status} ${o.statusText}`);return(o.headers.get("content-type")||"").includes("application/json")?await o.json():{}};extensionFromMime(t){const e=t.indexOf("/");return e>=0?t.slice(e+1):"bin"}generateUuid(){if("undefined"!=typeof crypto&&"function"==typeof crypto.randomUUID)return crypto.randomUUID();const t=crypto.getRandomValues(new Uint8Array(16));t[6]=15&t[6]|64,t[8]=63&t[8]|128;const e=Array.from(t,(t=>t.toString(16).padStart(2,"0"))).join("");return`${e.slice(0,8)}-${e.slice(8,12)}-${e.slice(12,16)}-${e.slice(16,20)}-${e.slice(20)}`}}class nt{type="remote";name="PresignedAssetProvider";_options;constructor(t){this._options=t}static with(t){return{create:()=>new nt(t)}}async init(){this._options.quiet||console.info("PresignedAssetProvider initialized")}destroy(){}canResolve(t){return!0}async put(t,e){const s=await this._options.getUploadDescriptor(e),i=s.method??"PUT",n={...s.headers??{}};let o;if(n["Content-Type"]||n["content-type"]||(n["Content-Type"]=e.mimeType),"POST"===i&&s.fields){const e=new FormData;for(const[t,i]of Object.entries(s.fields))e.append(t,i);e.append("file",t),o=e,delete n["Content-Type"],delete n["content-type"]}else o=t;const r=await fetch(s.url,{method:i,headers:n,body:o});if(!r.ok)throw new Error(`[PresignedAssetProvider] Upload failed: ${r.status} ${r.statusText}`);return{id:s.id,kind:e.kind??"file",mimeType:e.mimeType,size:t.size,createdAt:Date.now(),width:e.width,height:e.height,durationMs:e.durationMs,originalFilename:e.originalFilename}}async resolve(t){return this._options.getDownloadUrl(t)}async fetch(t){const e=await this._options.getDownloadUrl(t),s=await fetch(e);if(!s.ok)throw new Error(`[PresignedAssetProvider] Failed to fetch asset ${t}: ${s.status} ${s.statusText}`);return s.blob()}async delete(t){this._options.deleteAsset&&(await this._options.deleteAsset(t),this._options.quiet||console.info(`PresignedAssetProvider: deleted asset ${t}`))}}export{tt as BroadcastSyncProvider,st as HocuspocusSyncProvider,it as HttpAssetProvider,nt as PresignedAssetProvider,et as WebSocketSyncProvider}