import { t as toArray, a as toTimestamp, f as fromNullable, b as fromArray, c as fromTimestamp, g as getIdentity, d as getDataBucket, e as toNullable, h as createCommonjsModule, i as getStorageBucket, s, j as createWorkerProxy, k as internetIdentityAuth, P as Pe, y as ye } from './auth.ic-2bedf400.js';
export { o as deleteAuth, g as getIdentity, l as initAuth, n as signIn, m as signOut } from './auth.ic-2bedf400.js';
import './index-5b83ee50.js';

const entries = async ({ startsWith, notContains }) => {
  const identity = getIdentity();
  if (!identity) {
    return [];
  }
  console.log('Data IC about to request entries');
  const t0 = performance.now();
  const { actor } = await getDataBucket({ identity });
  if (!actor) {
    return [];
  }
  const data = await actor.list(toNullable({
    startsWith: toNullable(startsWith),
    notContains: toNullable(notContains)
  }));
  const promises = data.map(([, data]) => fromData({ data, identity }));
  const results = await Promise.all(promises);
  const t1 = performance.now();
  console.log(`Data IC entries done. ${t1 - t0}`, results);
  return results;
};
const fromData = async ({ data, identity }) => {
  const dataData = await fromArray(data.data);
  return {
    id: data.id,
    data: Object.assign(Object.assign({}, dataData), { owner_id: identity.getPrincipal().toText(), created_at: fromTimestamp(data.created_at), updated_at: fromTimestamp(data.updated_at) })
  };
};
const deleteData = async ({ key, actor }) => {
  if (!key) {
    return;
  }
  console.log('Data IC about to delete data and its slides');
  const t0 = performance.now();
  const dataActor = actor || (await getDataActor());
  await dataActor.del(key);
  const t1 = performance.now();
  console.log('Data IC delete', t1 - t0);
};
const getData$1 = ({ key, actor }) => {
  return new Promise(async (resolve, reject) => {
    try {
      const dataActor = actor || (await getDataActor());
      const entry = fromNullable(await dataActor.get(key));
      if (!entry) {
        resolve(undefined);
        return;
      }
      const data = await fromArray(entry.data);
      resolve({
        id: entry.id,
        data: Object.assign(Object.assign({}, data), { created_at: fromTimestamp(entry.created_at), updated_at: fromTimestamp(entry.updated_at) })
      });
    }
    catch (err) {
      reject(err);
    }
  });
};
const setData$1 = ({ key, data, id, actor = undefined }) => {
  return new Promise(async (resolve, reject) => {
    try {
      console.log(`Data IC (${key}) about to SET`);
      const t0 = performance.now();
      const dataActor = actor || (await getDataActor());
      const now = new Date();
      await dataActor.set(key, {
        id,
        data: await toArray(data),
        created_at: toTimestamp(data.created_at || new Date()),
        updated_at: toTimestamp(now)
      });
      const t1 = performance.now();
      console.log(`Data IC SET (${key}) done:`, t1 - t0);
      const result = {
        id,
        data: Object.assign(Object.assign({}, data), { updated_at: now })
      };
      const t2 = performance.now();
      console.log(`Data IC GET (${key}):`, await dataActor.get(key), performance.now() - t2);
      resolve(result);
    }
    catch (err) {
      reject(err);
    }
  });
};
const getDataActor = async () => {
  const identity = getIdentity();
  if (!identity) {
    throw new Error('No internet identity.');
  }
  const { actor } = await getDataBucket({ identity });
  if (!actor) {
    throw new Error('No actor initialized.');
  }
  return actor;
};

const updateUser = async (user) => {
  console.log('User IC about to SET');
  const t0 = performance.now();
  const { data, id } = user;
  const updatedUser = await setData$1({ key: `/user`, id, data });
  const t1 = performance.now();
  console.log('User IC SET done', t1 - t0);
  return updatedUser;
};

const deckEntries = async (_userId) => entries({ startsWith: '/decks/', notContains: '/slides/' });
const deleteDeck = async (deckId) => deleteData({ key: `/decks/${deckId}` });
// Backwards compatibility with current publish mask in studio and Firebase support. In case of IC we actually do not need a snapshot, publish is synchronous on the client side.
const snapshotDeck = async ({ onNext }) => {
  document.addEventListener('deckPublished', ({ detail }) => onNext(detail), { passive: true });
  return () => document.removeEventListener('deckPublished', ({ detail }) => onNext(detail), false);
};

const docEntries = async (_userId) => entries({ startsWith: '/docs/', notContains: '/paragraphs/' });
const deleteDoc = async (docId) => deleteData({ key: `/docs/${docId}` });
// Backwards compatibility with current publish mask in studio and Firebase support. In case of IC we actually do not need a snapshot, publish is synchronous on the client side.
const snapshotDoc = async ({ onNext }) => {
  document.addEventListener('docPublished', ({ detail }) => onNext(detail), { passive: true });
  return () => document.removeEventListener('docPublished', ({ detail }) => onNext(detail), false);
};

const getSlide = (deckId, slideId) => getData$1({ key: `/decks/${deckId}/slides/${slideId}` });

const getParagraph = (docId, paragraphId) => getData$1({ key: `/docs/${docId}/paragraphs/${paragraphId}` });

var rngBrowser = createCommonjsModule(function (module) {
// Unique ID creation requires a high quality random # generator.  In the
// browser this is a little complicated due to unknown quality of Math.random()
// and inconsistent support for the `crypto` API.  We do the best we can via
// feature-detection

// getRandomValues needs to be invoked in a context where "this" is a Crypto
// implementation. Also, find the complete implementation of crypto on IE11.
var getRandomValues = (typeof(crypto) != 'undefined' && crypto.getRandomValues && crypto.getRandomValues.bind(crypto)) ||
                      (typeof(msCrypto) != 'undefined' && typeof window.msCrypto.getRandomValues == 'function' && msCrypto.getRandomValues.bind(msCrypto));

if (getRandomValues) {
  // WHATWG crypto RNG - http://wiki.whatwg.org/wiki/Crypto
  var rnds8 = new Uint8Array(16); // eslint-disable-line no-undef

  module.exports = function whatwgRNG() {
    getRandomValues(rnds8);
    return rnds8;
  };
} else {
  // Math.random()-based (RNG)
  //
  // If all else fails, use Math.random().  It's fast, but is of unspecified
  // quality.
  var rnds = new Array(16);

  module.exports = function mathRNG() {
    for (var i = 0, r; i < 16; i++) {
      if ((i & 0x03) === 0) r = Math.random() * 0x100000000;
      rnds[i] = r >>> ((i & 0x03) << 3) & 0xff;
    }

    return rnds;
  };
}
});

/**
 * Convert array of 16 byte values to UUID string format of the form:
 * XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
 */
var byteToHex = [];
for (var i = 0; i < 256; ++i) {
  byteToHex[i] = (i + 0x100).toString(16).substr(1);
}

function bytesToUuid(buf, offset) {
  var i = offset || 0;
  var bth = byteToHex;
  // join used to fix memory issue caused by concatenation: https://bugs.chromium.org/p/v8/issues/detail?id=3175#c4
  return ([
    bth[buf[i++]], bth[buf[i++]],
    bth[buf[i++]], bth[buf[i++]], '-',
    bth[buf[i++]], bth[buf[i++]], '-',
    bth[buf[i++]], bth[buf[i++]], '-',
    bth[buf[i++]], bth[buf[i++]], '-',
    bth[buf[i++]], bth[buf[i++]],
    bth[buf[i++]], bth[buf[i++]],
    bth[buf[i++]], bth[buf[i++]]
  ]).join('');
}

var bytesToUuid_1 = bytesToUuid;

// **`v1()` - Generate time-based UUID**
//
// Inspired by https://github.com/LiosK/UUID.js
// and http://docs.python.org/library/uuid.html

var _nodeId;
var _clockseq;

// Previous uuid creation time
var _lastMSecs = 0;
var _lastNSecs = 0;

// See https://github.com/uuidjs/uuid for API details
function v1(options, buf, offset) {
  var i = buf && offset || 0;
  var b = buf || [];

  options = options || {};
  var node = options.node || _nodeId;
  var clockseq = options.clockseq !== undefined ? options.clockseq : _clockseq;

  // node and clockseq need to be initialized to random values if they're not
  // specified.  We do this lazily to minimize issues related to insufficient
  // system entropy.  See #189
  if (node == null || clockseq == null) {
    var seedBytes = rngBrowser();
    if (node == null) {
      // Per 4.5, create and 48-bit node id, (47 random bits + multicast bit = 1)
      node = _nodeId = [
        seedBytes[0] | 0x01,
        seedBytes[1], seedBytes[2], seedBytes[3], seedBytes[4], seedBytes[5]
      ];
    }
    if (clockseq == null) {
      // Per 4.2.2, randomize (14 bit) clockseq
      clockseq = _clockseq = (seedBytes[6] << 8 | seedBytes[7]) & 0x3fff;
    }
  }

  // UUID timestamps are 100 nano-second units since the Gregorian epoch,
  // (1582-10-15 00:00).  JSNumbers aren't precise enough for this, so
  // time is handled internally as 'msecs' (integer milliseconds) and 'nsecs'
  // (100-nanoseconds offset from msecs) since unix epoch, 1970-01-01 00:00.
  var msecs = options.msecs !== undefined ? options.msecs : new Date().getTime();

  // Per 4.2.1.2, use count of uuid's generated during the current clock
  // cycle to simulate higher resolution clock
  var nsecs = options.nsecs !== undefined ? options.nsecs : _lastNSecs + 1;

  // Time since last uuid creation (in msecs)
  var dt = (msecs - _lastMSecs) + (nsecs - _lastNSecs)/10000;

  // Per 4.2.1.2, Bump clockseq on clock regression
  if (dt < 0 && options.clockseq === undefined) {
    clockseq = clockseq + 1 & 0x3fff;
  }

  // Reset nsecs if clock regresses (new clockseq) or we've moved onto a new
  // time interval
  if ((dt < 0 || msecs > _lastMSecs) && options.nsecs === undefined) {
    nsecs = 0;
  }

  // Per 4.2.1.2 Throw error if too many uuids are requested
  if (nsecs >= 10000) {
    throw new Error('uuid.v1(): Can\'t create more than 10M uuids/sec');
  }

  _lastMSecs = msecs;
  _lastNSecs = nsecs;
  _clockseq = clockseq;

  // Per 4.1.4 - Convert from unix epoch to Gregorian epoch
  msecs += 12219292800000;

  // `time_low`
  var tl = ((msecs & 0xfffffff) * 10000 + nsecs) % 0x100000000;
  b[i++] = tl >>> 24 & 0xff;
  b[i++] = tl >>> 16 & 0xff;
  b[i++] = tl >>> 8 & 0xff;
  b[i++] = tl & 0xff;

  // `time_mid`
  var tmh = (msecs / 0x100000000 * 10000) & 0xfffffff;
  b[i++] = tmh >>> 8 & 0xff;
  b[i++] = tmh & 0xff;

  // `time_high_and_version`
  b[i++] = tmh >>> 24 & 0xf | 0x10; // include version
  b[i++] = tmh >>> 16 & 0xff;

  // `clock_seq_hi_and_reserved` (Per 4.2.2 - include variant)
  b[i++] = clockseq >>> 8 | 0x80;

  // `clock_seq_low`
  b[i++] = clockseq & 0xff;

  // `node`
  for (var n = 0; n < 6; ++n) {
    b[i + n] = node[n];
  }

  return buf ? buf : bytesToUuid_1(b);
}

var v1_1 = v1;

function v4(options, buf, offset) {
  var i = buf && offset || 0;

  if (typeof(options) == 'string') {
    buf = options === 'binary' ? new Array(16) : null;
    options = null;
  }
  options = options || {};

  var rnds = options.random || (options.rng || rngBrowser)();

  // Per 4.4, set bits for version and `clock_seq_hi_and_reserved`
  rnds[6] = (rnds[6] & 0x0f) | 0x40;
  rnds[8] = (rnds[8] & 0x3f) | 0x80;

  // Copy bytes to buffer, if provided
  if (buf) {
    for (var ii = 0; ii < 16; ++ii) {
      buf[i + ii] = rnds[ii];
    }
  }

  return buf || bytesToUuid_1(rnds);
}

var v4_1 = v4;

var uuid = v4_1;
uuid.v1 = v1_1;
uuid.v4 = v4_1;

var uuid_1 = uuid;

const getUserTemplates = (_userId) => entries({ startsWith: '/templates/' });
const createTemplate = (data) => {
  const id = uuid_1.v4();
  return setData$1({ key: `/templates/${id}`, id, data });
};
const updateTemplate$1 = (template) => {
  const { data, id } = template;
  return setData$1({ key: `/templates/${id}`, id, data });
};

const upload = async ({ data, filename, folder, storageActor, headers, token, fullPath: storagePath }) => {
  console.log('About to upload to the IC');
  const t0 = performance.now();
  const fullPath = storagePath || `/${folder}/${filename}`;
  const { batchId } = await storageActor.initUpload({
    name: filename,
    fullPath,
    token: toNullable(token),
    folder
  });
  const t1 = performance.now();
  console.log('Upload create_batch', t1 - t0);
  const promises = [];
  const chunkSize = 700000;
  for (let start = 0; start < data.size; start += chunkSize) {
    const chunk = data.slice(start, start + chunkSize);
    promises.push(uploadChunk({
      batchId,
      chunk,
      storageActor
    }));
  }
  const chunkIds = await Promise.all(promises);
  const t2 = performance.now();
  console.log('Upload upload chunks', t2 - t1);
  await storageActor.commitUpload({
    batchId,
    chunkIds: chunkIds.map(({ chunkId }) => chunkId),
    headers: [['Content-Type', data.type], ['accept-ranges', 'bytes'], ...headers]
  });
  const t3 = performance.now();
  console.log('Upload commit_batch', t3 - t2);
  console.log('Data uploaded', t3 - t0);
  return {
    fullPath,
    filename,
    token
  };
};
const uploadChunk = async ({ batchId, chunk, storageActor }) => storageActor.uploadChunk({
  batchId,
  content: [...new Uint8Array(await chunk.arrayBuffer())]
});
const encodeFilename = (filename) => encodeURI(filename.toLowerCase().replace(/\s/g, '-'));
const getStorageActor = async () => {
  const identity = getIdentity();
  if (!identity) {
    throw new Error('No internet identity.');
  }
  const result = await getStorageBucket({ identity });
  const { actor, bucketId } = result;
  if (!actor) {
    throw new Error('No actor initialized.');
  }
  // That would be strange
  if (!bucketId) {
    throw new Error('No bucket principal defined');
  }
  return result;
};

const uploadFile = async ({ data, folder, maxSize }) => {
  const identity = getIdentity();
  return uploadFileIC({ data, folder, maxSize, identity });
};
const uploadFileIC = async ({ data, maxSize, host, folder, identity, storageBucket }) => {
  if (!data || !data.name) {
    throw new Error('File not valid.');
  }
  if (data.size > maxSize) {
    throw new Error(`File is too big (max. ${maxSize / 1048576} Mb)`);
  }
  const { actor, bucketId } = storageBucket || (await getStorageBucket({ host, identity }));
  if (!actor || !bucketId) {
    throw new Error('Storage bucket is not initialized.');
  }
  const { fullPath, filename, token } = await upload({
    data,
    filename: encodeFilename(data.name),
    folder,
    storageActor: actor,
    token: uuid_1.v4(),
    headers: [['cache-control', 'private, max-age=0']]
  });
  return {
    downloadUrl: `https://${bucketId.toText()}.raw.ic0.app${fullPath}?token=${token}`,
    fullPath,
    name: filename
  };
};
const getFiles = async ({ folder }) => {
  const { actor, bucketId } = await getStorageActor();
  const assets = await actor.list(toNullable(folder));
  const host = `https://${bucketId.toText()}.raw.ic0.app`;
  return {
    items: assets.map(({ name, fullPath, token }) => ({
      downloadUrl: `${host}${fullPath}?token=${token}`,
      fullPath,
      name
    })),
    nextPageToken: null
  };
};
const deleteFile = async ({ downloadUrl, fullPath }) => {
  const { actor } = await getStorageActor();
  let token = null;
  if (downloadUrl) {
    const { searchParams } = new URL(downloadUrl);
    token = searchParams.get('token');
  }
  return actor.del({ fullPath, token: toNullable(token ? token : undefined) });
};

/**
 * Work around Safari 14 IndexedDB open bug.
 *
 * Safari has a horrible bug where IDB requests can hang while the browser is starting up. https://bugs.webkit.org/show_bug.cgi?id=226547
 * The only solution is to keep nudging it until it's awake.
 */
function idbReady() {
    var isSafari = !navigator.userAgentData &&
        /Safari\//.test(navigator.userAgent) &&
        !/Chrom(e|ium)\//.test(navigator.userAgent);
    // No point putting other browsers or older versions of Safari through this mess.
    if (!isSafari || !indexedDB.databases)
        return Promise.resolve();
    var intervalId;
    return new Promise(function (resolve) {
        var tryIdb = function () { return indexedDB.databases().finally(resolve); };
        intervalId = setInterval(tryIdb, 100);
        tryIdb();
    }).finally(function () { return clearInterval(intervalId); });
}

function promisifyRequest(request) {
  return new Promise(function (resolve, reject) {
    // @ts-ignore - file size hacks
    request.oncomplete = request.onsuccess = function () {
      return resolve(request.result);
    }; // @ts-ignore - file size hacks


    request.onabort = request.onerror = function () {
      return reject(request.error);
    };
  });
}

function createStore(dbName, storeName) {
  var dbp = idbReady().then(function () {
    var request = indexedDB.open(dbName);

    request.onupgradeneeded = function () {
      return request.result.createObjectStore(storeName);
    };

    return promisifyRequest(request);
  });
  return function (txMode, callback) {
    return dbp.then(function (db) {
      return callback(db.transaction(storeName, txMode).objectStore(storeName));
    });
  };
}

var defaultGetStoreFunc;

function defaultGetStore() {
  if (!defaultGetStoreFunc) {
    defaultGetStoreFunc = createStore('keyval-store', 'keyval');
  }

  return defaultGetStoreFunc;
}
/**
 * Get a value by its key.
 *
 * @param key
 * @param customStore Method to get a custom store. Use with caution (see the docs).
 */


function get(key) {
  var customStore = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : defaultGetStore();
  return customStore('readonly', function (store) {
    return promisifyRequest(store.get(key));
  });
}
/**
 * Set a value with a key.
 *
 * @param key
 * @param value
 * @param customStore Method to get a custom store. Use with caution (see the docs).
 */


function set(key, value) {
  var customStore = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : defaultGetStore();
  return customStore('readwrite', function (store) {
    store.put(value, key);
    return promisifyRequest(store.transaction);
  });
}

const updateDeckBackground = ({ deck, storageFile, imgSrc }) => {
  if (!storageFile || !imgSrc) {
    return Object.assign({}, deck);
  }
  return {
    id: deck.id,
    data: Object.assign(Object.assign({}, deck.data), { updated_at: new Date(), background: updateContentImgSrcAlt({ data: deck.data.background, imgSrc, storageFile }) })
  };
};
const updateSlideImages = ({ slide, images }) => {
  if (!images) {
    return Object.assign({}, slide);
  }
  const validImages = images.filter(({ src, storageFile }) => src !== undefined && storageFile !== undefined);
  let { content } = slide.data;
  validImages.forEach(({ src, storageFile }) => {
    content = updateContentImgSrcAlt({ data: content, storageFile, imgSrc: src });
  });
  return {
    id: slide.id,
    data: Object.assign(Object.assign({}, slide.data), { updated_at: new Date(), content })
  };
};
const updateParagraphImages = ({ paragraph, images }) => {
  if (!images) {
    return Object.assign({}, paragraph);
  }
  const validImages = images.filter(({ src, storageFile }) => src !== undefined && storageFile !== undefined);
  let { children, nodeName, attributes } = paragraph.data;
  // The paragraph itself might be an image
  if (nodeName === 'deckgo-lazy-img' && attributes) {
    validImages.forEach(({ src, storageFile }) => {
      attributes = updateAttributeImgSrc({ attributes, storageFile, imgSrc: src });
    });
  }
  children = children === null || children === void 0 ? void 0 : children.map((content) => {
    validImages.forEach(({ src, storageFile }) => {
      content = updateContentImgSrcAlt({ data: content, storageFile, imgSrc: src });
    });
    return content;
  });
  return {
    id: paragraph.id,
    data: Object.assign(Object.assign({}, paragraph.data), { updated_at: new Date(), children,
      attributes })
  };
};
const updateSlideChart = ({ slide, chart }) => {
  if (!chart) {
    return Object.assign({}, slide);
  }
  const { src, storageFile } = chart;
  if (!src || !storageFile) {
    return Object.assign({}, slide);
  }
  const { attributes } = slide.data;
  if (!attributes) {
    return Object.assign({}, slide);
  }
  const { downloadUrl } = storageFile;
  return {
    id: slide.id,
    data: Object.assign(Object.assign({}, slide.data), { updated_at: new Date(), attributes: Object.assign(Object.assign({}, attributes), { src: downloadUrl }) })
  };
};
const updateContentImgSrcAlt = ({ data, storageFile, imgSrc }) => {
  const { downloadUrl, name } = storageFile;
  let updateData = data.replaceAll(`img-src="${imgSrc}"`, `img-src="${downloadUrl}"`);
  updateData = updateData.replaceAll(`img-alt="${imgSrc}"`, `img-alt="${name}"`);
  return updateData;
};
const updateAttributeImgSrc = ({ attributes, storageFile, imgSrc }) => {
  const { downloadUrl } = storageFile;
  return Object.keys(attributes).reduce((acc, key) => {
    acc[key] = attributes[key] === imgSrc ? downloadUrl : attributes[key];
    return acc;
  }, {});
};

const syncDeckBackground = async (data) => {
  // 1. We update the deck in the DOM
  updateDeckDOM(data);
  // 2. We replicate the same changes to the slides in the DOM
  await updateSlidesDOM(data);
  // 3. We update the indexedDB stored deck with the new downloadUrl.
  await updateDeckIDB(data);
};
const syncSlideImage = async (data) => {
  const { selector } = data;
  if (!selector) {
    return;
  }
  // 1. We update the slide in the DOM
  await updateElementImagesDOM(data);
  // 2. We update the indexedDB stored slide with the new downloadUrl.
  await updateSlideImagesIDB(data);
};
const syncParagraphImage = async (data) => {
  const { selector } = data;
  if (!selector) {
    return;
  }
  // 1. We update the paragraph in the DOM
  await updateElementImagesDOM(data);
  // 2. We update the indexedDB stored paragraph with the new downloadUrl.
  await updateParagraphImagesIDB(data);
};
const syncSlideChart = async (data) => {
  const { selector } = data;
  if (!selector) {
    return;
  }
  // 1. We update the slide in the DOM
  updateSlideChartDOM(data);
  // 2. We update the indexedDB stored slide with the new downloadUrl.
  await updateSlideChartIDB(data);
};
const updateDeckDOM = ({ storageFile }) => {
  const backgroundElement = document.querySelector(`${s} > *[slot="background"]`);
  const img = backgroundElement === null || backgroundElement === void 0 ? void 0 : backgroundElement.querySelector('deckgo-lazy-img');
  if (!img) {
    return;
  }
  const { downloadUrl, name } = storageFile;
  img.imgSrc = downloadUrl;
  img.imgAlt = name;
};
const updateElementImagesDOM = async ({ selector, storageFile, src }) => {
  const element = document.querySelector(selector);
  // The paragraph might be an image itself
  if ((element === null || element === void 0 ? void 0 : element.nodeName.toLowerCase()) === 'deckgo-lazy-img') {
    await updateImagesDOM({ images: [element], storageFile, src });
    return;
  }
  const images = element === null || element === void 0 ? void 0 : element.querySelectorAll('deckgo-lazy-img');
  await updateImagesDOM({ images: Array.from(images), storageFile, src });
};
const updateSlideChartDOM = ({ selector, storageFile }) => {
  const slideElement = document.querySelector(selector);
  if (!slideElement || !slideElement.nodeName || slideElement.nodeName.toLowerCase() !== 'deckgo-slide-chart') {
    return;
  }
  const { downloadUrl } = storageFile;
  slideElement.src = downloadUrl;
};
const updateSlidesDOM = async ({ storageFile, src }) => {
  const images = document.querySelectorAll(`${s} .deckgo-slide-container:not([custom-background]) *[slot="background"] deckgo-lazy-img`);
  await updateImagesDOM({ images: Array.from(images), storageFile, src });
};
const updateImagesDOM = async ({ storageFile, images, src }) => {
  const matchingImages = images.filter((img) => img.imgSrc === src);
  if (!matchingImages || matchingImages.length <= 0) {
    return;
  }
  const updateImage = async (img) => {
    const { downloadUrl, name } = storageFile;
    img.imgSrc = downloadUrl;
    img.imgAlt = name;
  };
  const promises = Array.from(matchingImages).map((img) => updateImage(img));
  await Promise.all(promises);
};
const updateDeckIDB = async ({ storageFile, src, key }) => {
  const deck = await getData({ key });
  const updateDeck = updateDeckBackground({ deck, imgSrc: src, storageFile });
  await setData({ key, data: updateDeck });
};
const updateSlideImagesIDB = async ({ storageFile, src, key }) => {
  const slide = await getData({ key });
  const updateSlide = updateSlideImages({
    slide,
    images: [
      {
        src,
        storageFile
      }
    ]
  });
  await setData({ key, data: updateSlide });
};
const updateParagraphImagesIDB = async ({ storageFile, src, key }) => {
  const paragraph = await getData({ key });
  const updateParagraph = updateParagraphImages({
    paragraph,
    images: [
      {
        src,
        storageFile
      }
    ]
  });
  await setData({ key, data: updateParagraph });
};
const updateSlideChartIDB = async ({ storageFile, src, key }) => {
  const slide = await getData({ key });
  const updateSlide = updateSlideChart({
    slide,
    chart: {
      src,
      storageFile
    }
  });
  await setData({ key, data: updateSlide });
};
const getData = async ({ key }) => {
  const data = await get(key);
  if (!data) {
    throw new Error('Data not found and that is really weird here.');
  }
  return data;
};
const setData = async ({ key, data }) => set(key, data);

const workerPromise = import('./sync.ic.worker-6f7fba93.js').then(m => m.worker);
const uploadWorker = /*@__PURE__*/createWorkerProxy(workerPromise, 'stencil.sync.ic.worker', 'uploadWorker');

// - we cannot use postmessage because of CORS
// - we have to path the function separately in the function's call for serialisation reason (not within the object)
const syncWindow = async ({ msg, data }) => {
  if (msg === 'deckdeckgo_sync_deck_background') {
    await syncDeckBackground(data);
  }
  if (msg === 'deckdeckgo_sync_slide_image') {
    await syncSlideImage(data);
  }
  if (msg === 'deckdeckgo_sync_slide_chart') {
    await syncSlideChart(data);
  }
  if (msg === 'deckdeckgo_sync_paragraph_image') {
    await syncParagraphImage(data);
  }
};
const sync = async ({ syncData, clean }) => {
  const identity = getIdentity();
  if (!identity) {
    throw new Error('No internet identity to sync data');
  }
  const internetIdentity = await internetIdentityAuth();
  await uploadWorker({
    internetIdentity,
    syncData,
    host: `https://ic0.app`
  }, syncWindow);
  await clean(syncData);
};

const socialImageFolder = 'meta';
const socialImageExtension = 'png';
const updateTemplateSocialImage = ({ html, data, bucketUrl }) => {
  const { social_image_name } = data;
  const pathname = `/${socialImageFolder}/${social_image_name}.${socialImageExtension}`;
  return html.replaceAll('{{DECKDECKGO_SOCIAL_IMAGE}}', `${bucketUrl}${pathname}`);
};
const uploadSocialImage = async ({ storageUpload, publishData }) => {
  const { social_image_name, social_image_value } = publishData;
  if (!social_image_value) {
    return;
  }
  const { actor } = storageUpload;
  await upload({
    data: social_image_value,
    filename: `${social_image_name}.${socialImageExtension}`,
    folder: socialImageFolder,
    storageActor: actor,
    headers: [['Cache-Control', 'max-age=3600']]
  });
};

const updateTemplate = ({ template, data }) => Object.entries(data).reduce((acc, [key, value]) => acc
  .replaceAll(`{{DECKDECKGO_${key.toUpperCase()}}}`, value || '')
  .replaceAll(`<!-- DECKDECKGO_${key.toUpperCase()} -->`, value || ''), template);
const initUpload = async ({ indexHTML, folder, meta }) => {
  const { html, publishData } = indexHTML;
  // 1. Get actor
  const { bucketId, actor } = await getStorageActor();
  // 2. Folder and filename
  const { filename, pathname } = uploadPaths({ publishData, meta, folder });
  const bucketUrl = `https://${bucketId.toText()}.raw.ic0.app`;
  const fullUrl = `${bucketUrl}${pathname}`;
  // 3. Update URL
  let updatedHTML = html.replace('{{DECKDECKGO_URL}}', fullUrl);
  // 4. Update the social image URL
  updatedHTML = updateTemplateSocialImage({ html: updatedHTML, data: publishData, bucketUrl });
  return {
    storageUpload: {
      html: updatedHTML,
      actor,
      filename,
      pathname,
      fullUrl,
      bucketUrl,
      folder
    },
    publishData
  };
};
/**
 * !!IMPORTANT!!: The pathname never changes if it has been published once otherwise we cannot delete the content when a doc or deck is deleted
 */
const uploadPaths = ({ publishData, meta, folder }) => {
  if (meta === null || meta === void 0 ? void 0 : meta.pathname) {
    const { pathname } = meta;
    return {
      filename: pathname.replace(`/${folder}/`, ''),
      pathname
    };
  }
  const filename = encodeFilename(publishData.title);
  const pathname = `/${folder}/${filename}`;
  return {
    filename,
    pathname
  };
};
const initIndexHTML = async ({ publishData, updateTemplateContent, sourceFolder }) => {
  const template = await htmlTemplate$1(sourceFolder);
  const updatedTemplate = updateTemplate({ template, data: publishData });
  const { attributes } = publishData;
  const attr = attributes
    ? Object.entries(attributes)
      .reduce((acc, [key, value]) => `${key}="${value}"; ${acc}`, '')
      .trim()
    : undefined;
  return {
    html: updateTemplateContent({ attr, template: updatedTemplate })
  };
};
const htmlTemplate$1 = async (sourceFolder) => {
  const htmlTemplate = await fetch(`https://raw.githubusercontent.com/deckgo/ic-kit/main/dist/${sourceFolder}/index.html`);
  return htmlTemplate.text();
};
const updateMetaData = ({ data, storageUpload, meta, name }) => {
  const { pathname } = storageUpload;
  const now = new Date();
  return Object.assign(Object.assign({}, data), { meta: Object.assign(Object.assign({}, (meta || { title: name })), { pathname, published: true, published_at: now, updated_at: now }) });
};
const uploadPublishFileIC = async ({ filename, html, actor, folder }) => {
  await upload({
    data: new Blob([html], { type: 'text/html' }),
    filename,
    folder,
    storageActor: actor,
    headers: [['Cache-Control', 'max-age=3600']]
  });
};

const publishDeck = async ({ deck: deckSource }) => {
  const { id, data } = deckSource;
  const { meta } = data;
  // 1. Init and fill HTML
  const indexHTML = await initDeckIndexHTML({ deck: deckSource });
  const { storageUpload, publishData } = await initUpload({ indexHTML, folder: 'p', meta });
  // 2. Update deck published meta
  const deckData = updateMetaData({ data, meta: data.meta, name: data.name, storageUpload });
  // 3. Update deck meta information
  const deck = await setData$1({ key: `/decks/${id}`, id, data: deckData });
  // 4. Upload
  await uploadPublishFileIC(storageUpload);
  // 5. Upload
  await uploadSocialImage({ storageUpload, publishData });
  // 6. Tells the snapshot the process is over
  emitDeckPublished(deck);
  return {
    storageUpload,
    publishData,
    deck
  };
};
const initDeckIndexHTML = async ({ deck }) => {
  const publishData = await Pe({ deck });
  const { slides } = publishData;
  const updateTemplateContent = ({ attr, template }) => template.replace('<!-- DECKDECKGO_DECK -->', `<deckgo-deck id="slider" embedded="true" ${attr || ''}>${slides.join('')}</deckgo-deck>`);
  const { html } = await initIndexHTML({ publishData, updateTemplateContent, sourceFolder: 'p' });
  return {
    html,
    publishData
  };
};
const emitDeckPublished = (deck) => {
  const { id, data } = deck;
  const deployedDeck = {
    id,
    data: Object.assign(Object.assign({}, data), { deploy: {
        api: {
          status: 'successful',
          updated_at: new Date()
        }
      } })
  };
  const $event = new CustomEvent('deckPublished', { detail: deployedDeck });
  document.dispatchEvent($event);
};

const kitPath = 'https://raw.githubusercontent.com/deckgo/ic-kit/main/dist';
const kit = [
  {
    src: `${kitPath}/workbox-c837f436.js`,
    mimeType: 'text/javascript'
  },
  {
    src: `${kitPath}/service-worker.js`,
    mimeType: 'text/javascript'
  },
  {
    src: `${kitPath}/robots.txt`,
    mimeType: 'text/plain'
  },
  {
    src: `${kitPath}/manifest.webmanifest`,
    mimeType: 'application/manifest+json',
    updateContent: ({ content, meta }) => { var _a; return content.replace('{{DECKDECKGO_AUTHOR}}', ((_a = meta === null || meta === void 0 ? void 0 : meta.author) === null || _a === void 0 ? void 0 : _a.name) || 'DeckDeckGo'); }
  },
  {
    src: `${kitPath}/build/index-M763JKRZ.css`,
    mimeType: 'text/css'
  },
  {
    src: `${kitPath}/build/index-55VE2P7H.js`,
    mimeType: 'text/javascript'
  },
  {
    src: `${kitPath}/build/deck/index-ELSPH57U.js`,
    mimeType: 'text/javascript'
  },
  {
    src: `${kitPath}/build/deck/index-HPLMJ2FO.css`,
    mimeType: 'text/css'
  },
  {
    src: `${kitPath}/build/doc/index-6WZFUT5N.css`,
    mimeType: 'text/css'
  }
].map((resource) => {
  const { pathname } = new URL(resource.src);
  return Object.assign(Object.assign({}, resource), { filename: pathname.split('/').pop(), headers: [['Cache-Control', 'max-age=31536000']] });
});
const uploadResources = async ({ meta }) => {
  // 1. Get actor
  const { actor } = await getStorageActor();
  const assetKeys = await actor.list(toNullable('resources'));
  const keys = assetKeys.map(({ name }) => name);
  // We only upload resources that have not been yet uploaded. In other words: we upload the resources the first time or if hashes are modified.
  const kitFiles = kit.filter(({ filename }) => !keys.includes(filename));
  if (!kitFiles || kitFiles.length <= 0) {
    return;
  }
  const promises = kitFiles.map((kit) => addKitIC({ kit, actor, meta }));
  await Promise.all(promises);
  // If there was an update, we ensure we also update the sw list
  await addSwKitIC({ kitFiles, actor, meta });
};
const addKitIC = async ({ kit, actor, meta }) => {
  const { src, filename, mimeType, updateContent, headers } = kit;
  const content = await downloadKit(src);
  const updatedContent = updateContent ? updateContent({ content, meta }) : content;
  await uploadKit({ filename, content: updatedContent, actor, mimeType, headers, fullPath: src.replace(kitPath, '') });
};
const addSwKitIC = async ({ kitFiles, actor, meta }) => {
  const sw = kitFiles.find(({ filename }) => filename === 'service-worker.js');
  if (sw !== undefined) {
    return;
  }
  const swKit = kit.find(({ filename }) => filename === 'service-worker.js');
  if (!swKit !== undefined) {
    return;
  }
  await addKitIC({ kit: swKit, actor, meta });
};
const uploadKit = async ({ filename, fullPath, content, actor, mimeType, headers }) => {
  await upload({
    data: new Blob([content], { type: mimeType }),
    filename,
    folder: 'resources',
    storageActor: actor,
    fullPath,
    headers
  });
};
const downloadKit = async (src) => {
  const htmlTemplate = await fetch(src);
  return htmlTemplate.text();
};

var __rest = (undefined && undefined.__rest) || function (s, e) {
  var t = {};
  for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
    t[p] = s[p];
  if (s != null && typeof Object.getOwnPropertySymbols === "function")
    for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
      if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
        t[p[i]] = s[p[i]];
    }
  return t;
};
const publishOverview = async ({ dataId, storageUpload, publishData }) => {
  const template = await htmlTemplate();
  const { photo_url } = publishData, data = __rest(publishData, ["photo_url"]);
  let html = updateTemplate({ template, data });
  html = updatePhotoUrl({ html, photo_url });
  html = await updateList({ dataId, template: html, publishData, storageUpload });
  const { actor } = storageUpload;
  await uploadOverviewIC({ html, actor });
};
const htmlTemplate = async () => {
  const htmlTemplate = await fetch('https://raw.githubusercontent.com/deckgo/ic-kit/main/dist/index.html');
  return htmlTemplate.text();
};
const updatePhotoUrl = ({ photo_url, html }) => {
  if (!photo_url) {
    return html;
  }
  return html.replace('<!-- DECKDECKGO_PHOTO_URL -->', `<img role="presentation" alt="" loading="lazy" src="${photo_url}" />`);
};
const updateList = async ({ dataId, template, storageUpload, publishData }) => {
  const { title } = publishData;
  const { fullUrl } = storageUpload;
  const li = `<li data-id="${dataId}"><a href="${fullUrl}">${title}</a></li>`;
  const source = await htmlSource(storageUpload);
  if (!source) {
    return template.replace(/<!-- DECKDECKGO_DATA -->/, `${li}`);
  }
  const matches = [...source.matchAll(/<li\x20.*?data-id=".*?".*?li>/gm)];
  if (!matches || matches.length <= 0) {
    return template.replace(/<!-- DECKDECKGO_DATA -->/, `${li}`);
  }
  const list = matches.map((match) => match[0]);
  const index = list.indexOf(li);
  if (index > -1) {
    return template.replace(/<!-- DECKDECKGO_DATA -->/, list.map((entry, i) => (i === index ? li : entry)).join(''));
  }
  return template.replace(/<!-- DECKDECKGO_DATA -->/, [li, ...list].join(''));
};
const htmlSource = async ({ bucketUrl }) => {
  const response = await fetch(bucketUrl);
  if (response.ok) {
    return response.text();
  }
  return undefined;
};
const uploadOverviewIC = async ({ html, actor }) => {
  await upload({
    data: new Blob([html], { type: 'text/html' }),
    filename: 'index.html',
    folder: 'resources',
    storageActor: actor,
    headers: [['Cache-Control', 'max-age=0']],
    fullPath: '/'
  });
};

const publishDoc = async ({ doc: docSource }) => {
  const { id, data } = docSource;
  const { meta } = data;
  // 1. Init and fill HTML
  const indexHTML = await initDocIndexHTML({ doc: docSource });
  const { storageUpload, publishData } = await initUpload({ indexHTML, folder: 'd', meta });
  // 2. Update doc published meta
  const docData = updateMetaData({ data, meta: data.meta, name: data.name, storageUpload });
  // 3. Update doc meta information
  const doc = await setData$1({ key: `/docs/${id}`, id, data: docData });
  // 4. Upload
  await uploadPublishFileIC(storageUpload);
  // 5. Upload
  await uploadSocialImage({ storageUpload, publishData });
  // 6. Tells the snapshot the process is over
  emitDocPublished(doc);
  return {
    storageUpload,
    publishData,
    doc
  };
};
const initDocIndexHTML = async ({ doc }) => {
  const publishData = await ye({ doc });
  const { paragraphs } = publishData;
  const updateTemplateContent = ({ attr, template }) => template.replace('<!-- DECKDECKGO_DOC -->', `<deckgo-doc ${attr || ''}>${paragraphs.join('')}</deckgo-doc>`);
  const { html } = await initIndexHTML({ publishData, updateTemplateContent, sourceFolder: 'd' });
  return {
    html,
    publishData
  };
};
const emitDocPublished = (doc) => {
  const { id, data } = doc;
  const deployedDoc = {
    id,
    data: Object.assign(Object.assign({}, data), { deploy: {
        api: {
          status: 'successful',
          updated_at: new Date()
        }
      } })
  };
  const $event = new CustomEvent('docPublished', { detail: deployedDoc });
  document.dispatchEvent($event);
};

const deckPublish = async ({ deck }) => {
  await uploadResources({ meta: deck.data.meta });
  const { storageUpload, publishData, deck: updatedDeck } = await publishDeck({ deck });
  await publishOverview({ storageUpload, publishData, dataId: updatedDeck.id });
  return updatedDeck;
};
const docPublish = async ({ doc }) => {
  await uploadResources({ meta: doc.data.meta });
  const { storageUpload, publishData, doc: updatedDoc } = await publishDoc({ doc });
  await publishOverview({ storageUpload, publishData, dataId: updatedDoc.id });
  return updatedDoc;
};
const publishUrl = async () => {
  const { bucketId } = await getStorageActor();
  return `https://${bucketId.toText()}.raw.ic0.app`;
};

export { createTemplate, deckEntries, deckPublish, deleteDeck, deleteDoc, deleteFile, docEntries, docPublish, getFiles, getParagraph, getSlide, getUserTemplates, publishUrl, snapshotDeck, snapshotDoc, sync, updateTemplate$1 as updateTemplate, updateUser, uploadFile, uploadFileIC };
