@shipfox/client-shell 6.0.2 → 9.0.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.
@@ -1 +1 @@
1
- {"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../src/vite/manifest.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAC,MAAM,EAAiB,MAAM,MAAM,CAAC;AAqBjD,wBAAgB,qBAAqB,IAAI,MAAM,CAwF9C"}
1
+ {"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../src/vite/manifest.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAC,MAAM,EAAiB,MAAM,MAAM,CAAC;AAwBjD,wBAAgB,qBAAqB,IAAI,MAAM,CAwF9C"}
@@ -8,7 +8,10 @@ const assetNames = [
8
8
  'apple-touch-icon.png',
9
9
  'site.webmanifest',
10
10
  'web-app-manifest-192x192.png',
11
- 'web-app-manifest-512x512.png'
11
+ 'web-app-manifest-512x512.png',
12
+ // Transactional emails (@shipfox/node-email) link to this asset on the client
13
+ // origin, so every composed client must serve it.
14
+ 'email-logo.png'
12
15
  ];
13
16
  const assetDirectory = fileURLToPath(new URL('../../assets/', import.meta.url));
14
17
  const contentTypes = {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/vite/manifest.ts"],"sourcesContent":["import {access, readFile} from 'node:fs/promises';\nimport {extname, resolve} from 'node:path';\nimport {fileURLToPath} from 'node:url';\nimport type {Plugin, ResolvedConfig} from 'vite';\n\nconst assetNames = [\n 'favicon.ico',\n 'favicon.svg',\n 'favicon-96x96.png',\n 'apple-touch-icon.png',\n 'site.webmanifest',\n 'web-app-manifest-192x192.png',\n 'web-app-manifest-512x512.png',\n] as const;\n\nconst assetDirectory = fileURLToPath(new URL('../../assets/', import.meta.url));\n\nconst contentTypes: Record<string, string> = {\n '.ico': 'image/x-icon',\n '.png': 'image/png',\n '.svg': 'image/svg+xml',\n '.webmanifest': 'application/manifest+json',\n};\n\nexport function shipfoxClientManifest(): Plugin {\n let config: ResolvedConfig | undefined;\n\n function assetPath(name: (typeof assetNames)[number]): string {\n return resolve(assetDirectory, name);\n }\n\n async function assertNoPublicAssetConflicts(): Promise<void> {\n const publicDirectory = config?.publicDir;\n if (!publicDirectory) return;\n const conflicts = (\n await Promise.all(\n assetNames.map((name) => {\n const publicAsset = resolve(publicDirectory, name);\n if (publicAsset === assetPath(name)) return undefined;\n return access(publicAsset)\n .then(() => name)\n .catch(() => undefined);\n }),\n )\n ).filter((name): name is (typeof assetNames)[number] => name !== undefined);\n if (conflicts.length === 0) return;\n throw new Error(\n `shipfoxClientManifest() owns ${conflicts.map((name) => `/${name}`).join(', ')}. Remove the conflicting files from ${publicDirectory}.`,\n );\n }\n\n return {\n name: 'shipfox-client-manifest',\n async configResolved(resolvedConfig) {\n config = resolvedConfig;\n await assertNoPublicAssetConflicts();\n },\n async buildStart() {\n if (config?.command !== 'build') return;\n for (const name of assetNames) {\n this.emitFile({type: 'asset', fileName: name, source: await readFile(assetPath(name))});\n }\n },\n configureServer(server) {\n server.middlewares.use(async (request, response, next) => {\n const name = assetNames.find((assetName) => request.url?.split('?')[0] === `/${assetName}`);\n if (!name) return next();\n\n try {\n const content = await readFile(assetPath(name));\n response.setHeader(\n 'Content-Type',\n contentTypes[extname(name)] ?? 'application/octet-stream',\n );\n response.end(content);\n } catch (error) {\n next(error);\n }\n });\n },\n transformIndexHtml: {\n order: 'pre',\n handler() {\n return [\n {tag: 'title', children: 'Shipfox', injectTo: 'head'},\n {\n tag: 'link',\n attrs: {rel: 'icon', type: 'image/png', href: '/favicon-96x96.png', sizes: '96x96'},\n injectTo: 'head',\n },\n {\n tag: 'link',\n attrs: {rel: 'icon', type: 'image/svg+xml', href: '/favicon.svg'},\n injectTo: 'head',\n },\n {tag: 'link', attrs: {rel: 'shortcut icon', href: '/favicon.ico'}, injectTo: 'head'},\n {\n tag: 'link',\n attrs: {rel: 'apple-touch-icon', sizes: '180x180', href: '/apple-touch-icon.png'},\n injectTo: 'head',\n },\n {tag: 'link', attrs: {rel: 'manifest', href: '/site.webmanifest'}, injectTo: 'head'},\n {\n tag: 'meta',\n attrs: {name: 'apple-mobile-web-app-title', content: 'Shipfox'},\n injectTo: 'head',\n },\n {tag: 'meta', attrs: {name: 'theme-color', content: '#ff4b00'}, injectTo: 'head'},\n ];\n },\n },\n };\n}\n"],"names":["access","readFile","extname","resolve","fileURLToPath","assetNames","assetDirectory","URL","url","contentTypes","shipfoxClientManifest","config","assetPath","name","assertNoPublicAssetConflicts","publicDirectory","publicDir","conflicts","Promise","all","map","publicAsset","undefined","then","catch","filter","length","Error","join","configResolved","resolvedConfig","buildStart","command","emitFile","type","fileName","source","configureServer","server","middlewares","use","request","response","next","find","assetName","split","content","setHeader","end","error","transformIndexHtml","order","handler","tag","children","injectTo","attrs","rel","href","sizes"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/vite/manifest.ts"],"sourcesContent":["import {access, readFile} from 'node:fs/promises';\nimport {extname, resolve} from 'node:path';\nimport {fileURLToPath} from 'node:url';\nimport type {Plugin, ResolvedConfig} from 'vite';\n\nconst assetNames = [\n 'favicon.ico',\n 'favicon.svg',\n 'favicon-96x96.png',\n 'apple-touch-icon.png',\n 'site.webmanifest',\n 'web-app-manifest-192x192.png',\n 'web-app-manifest-512x512.png',\n // Transactional emails (@shipfox/node-email) link to this asset on the client\n // origin, so every composed client must serve it.\n 'email-logo.png',\n] as const;\n\nconst assetDirectory = fileURLToPath(new URL('../../assets/', import.meta.url));\n\nconst contentTypes: Record<string, string> = {\n '.ico': 'image/x-icon',\n '.png': 'image/png',\n '.svg': 'image/svg+xml',\n '.webmanifest': 'application/manifest+json',\n};\n\nexport function shipfoxClientManifest(): Plugin {\n let config: ResolvedConfig | undefined;\n\n function assetPath(name: (typeof assetNames)[number]): string {\n return resolve(assetDirectory, name);\n }\n\n async function assertNoPublicAssetConflicts(): Promise<void> {\n const publicDirectory = config?.publicDir;\n if (!publicDirectory) return;\n const conflicts = (\n await Promise.all(\n assetNames.map((name) => {\n const publicAsset = resolve(publicDirectory, name);\n if (publicAsset === assetPath(name)) return undefined;\n return access(publicAsset)\n .then(() => name)\n .catch(() => undefined);\n }),\n )\n ).filter((name): name is (typeof assetNames)[number] => name !== undefined);\n if (conflicts.length === 0) return;\n throw new Error(\n `shipfoxClientManifest() owns ${conflicts.map((name) => `/${name}`).join(', ')}. Remove the conflicting files from ${publicDirectory}.`,\n );\n }\n\n return {\n name: 'shipfox-client-manifest',\n async configResolved(resolvedConfig) {\n config = resolvedConfig;\n await assertNoPublicAssetConflicts();\n },\n async buildStart() {\n if (config?.command !== 'build') return;\n for (const name of assetNames) {\n this.emitFile({type: 'asset', fileName: name, source: await readFile(assetPath(name))});\n }\n },\n configureServer(server) {\n server.middlewares.use(async (request, response, next) => {\n const name = assetNames.find((assetName) => request.url?.split('?')[0] === `/${assetName}`);\n if (!name) return next();\n\n try {\n const content = await readFile(assetPath(name));\n response.setHeader(\n 'Content-Type',\n contentTypes[extname(name)] ?? 'application/octet-stream',\n );\n response.end(content);\n } catch (error) {\n next(error);\n }\n });\n },\n transformIndexHtml: {\n order: 'pre',\n handler() {\n return [\n {tag: 'title', children: 'Shipfox', injectTo: 'head'},\n {\n tag: 'link',\n attrs: {rel: 'icon', type: 'image/png', href: '/favicon-96x96.png', sizes: '96x96'},\n injectTo: 'head',\n },\n {\n tag: 'link',\n attrs: {rel: 'icon', type: 'image/svg+xml', href: '/favicon.svg'},\n injectTo: 'head',\n },\n {tag: 'link', attrs: {rel: 'shortcut icon', href: '/favicon.ico'}, injectTo: 'head'},\n {\n tag: 'link',\n attrs: {rel: 'apple-touch-icon', sizes: '180x180', href: '/apple-touch-icon.png'},\n injectTo: 'head',\n },\n {tag: 'link', attrs: {rel: 'manifest', href: '/site.webmanifest'}, injectTo: 'head'},\n {\n tag: 'meta',\n attrs: {name: 'apple-mobile-web-app-title', content: 'Shipfox'},\n injectTo: 'head',\n },\n {tag: 'meta', attrs: {name: 'theme-color', content: '#ff4b00'}, injectTo: 'head'},\n ];\n },\n },\n };\n}\n"],"names":["access","readFile","extname","resolve","fileURLToPath","assetNames","assetDirectory","URL","url","contentTypes","shipfoxClientManifest","config","assetPath","name","assertNoPublicAssetConflicts","publicDirectory","publicDir","conflicts","Promise","all","map","publicAsset","undefined","then","catch","filter","length","Error","join","configResolved","resolvedConfig","buildStart","command","emitFile","type","fileName","source","configureServer","server","middlewares","use","request","response","next","find","assetName","split","content","setHeader","end","error","transformIndexHtml","order","handler","tag","children","injectTo","attrs","rel","href","sizes"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../src/vite/plugin.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAC,MAAM,EAAiB,MAAM,MAAM,CAAC;AAKjD,MAAM,WAAW,+BAA+B;IAC9C,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAID,wBAAgB,wBAAwB,CAAC,EACvC,QAAQ,EACR,GAAgC,GACjC,EAAE,+BAA+B,GAAG,MAAM,CAqE1C"}
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../src/vite/plugin.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAC,MAAM,EAAiB,MAAM,MAAM,CAAC;AAOjD,MAAM,WAAW,+BAA+B;IAC9C,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAID,wBAAgB,wBAAwB,CAAC,EACvC,QAAQ,EACR,GAAgC,GACjC,EAAE,+BAA+B,GAAG,MAAM,CA0E1C"}
@@ -3,6 +3,7 @@ import { dirname, resolve } from 'node:path';
3
3
  import { composeClientFeatures } from '#compose/compose-client-features.js';
4
4
  import { evaluateFeatures } from './evaluate-features.js';
5
5
  import { generateAppModule } from './generate.js';
6
+ const manifestPluginName = 'shipfox-client-manifest';
6
7
  export function shipfoxClientComposition({ features, out = './src/shipfox-app.gen.ts' }) {
7
8
  let config;
8
9
  let watchedFiles = new Set();
@@ -39,6 +40,9 @@ export function shipfoxClientComposition({ features, out = './src/shipfox-app.ge
39
40
  name: 'shipfox-client-composition',
40
41
  configResolved (resolvedConfig) {
41
42
  config = resolvedConfig;
43
+ if (!resolvedConfig.plugins.some(({ name })=>name === manifestPluginName)) {
44
+ resolvedConfig.logger.warn(`shipfoxClientComposition() is registered without the "${manifestPluginName}" plugin (shipfoxClientManifest()). Add shipfoxClientManifest() to the Vite plugins to serve Shipfox branding assets.`);
45
+ }
42
46
  },
43
47
  async buildStart () {
44
48
  await generate({
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/vite/plugin.ts"],"sourcesContent":["import {mkdir, readFile, realpath, writeFile} from 'node:fs/promises';\nimport {dirname, resolve} from 'node:path';\nimport type {Plugin, ResolvedConfig} from 'vite';\nimport {composeClientFeatures} from '#compose/compose-client-features.js';\nimport {evaluateFeatures} from './evaluate-features.js';\nimport {generateAppModule} from './generate.js';\n\nexport interface ShipfoxClientCompositionOptions {\n features: string;\n out?: string;\n}\n\ntype RouteResolver = (source: string, importer?: string) => Promise<{id: string} | null>;\n\nexport function shipfoxClientComposition({\n features,\n out = './src/shipfox-app.gen.ts',\n}: ShipfoxClientCompositionOptions): Plugin {\n let config: ResolvedConfig | undefined;\n let watchedFiles = new Set<string>();\n\n const outputPath = () => resolve(config?.root ?? process.cwd(), out);\n const featuresPath = () => resolve(config?.root ?? process.cwd(), features);\n\n async function assertRoutesResolve(\n resolveRoute: RouteResolver,\n routes: ReturnType<typeof composeClientFeatures>['routes'],\n ): Promise<void> {\n for (const route of routes) {\n const resolvedRoute = await resolveRoute(route.impl, outputPath());\n if (!resolvedRoute) {\n throw new Error(\n `Could not resolve route implementation \"${route.impl}\" for \"${route.path}\".`,\n );\n }\n }\n }\n\n async function generate({\n addWatchFile,\n resolveRoute,\n }: {\n addWatchFile(file: string): void;\n resolveRoute: RouteResolver;\n }): Promise<void> {\n const evaluated = await evaluateFeatures(featuresPath());\n const composition = composeClientFeatures(evaluated.features);\n await assertRoutesResolve(resolveRoute, composition.routes);\n\n watchedFiles = new Set(evaluated.loadedFiles);\n for (const file of watchedFiles) addWatchFile(file);\n\n const output = generateAppModule({\n routes: composition.routes,\n navigation: composition.navigation,\n settingsSections: composition.settingsSections,\n });\n const path = outputPath();\n const existing = await readFile(path, 'utf8').catch(() => undefined);\n if (existing === output) return;\n await mkdir(dirname(path), {recursive: true});\n await writeFile(path, output);\n }\n\n return {\n name: 'shipfox-client-composition',\n configResolved(resolvedConfig) {\n config = resolvedConfig;\n },\n async buildStart() {\n await generate({\n addWatchFile: this.addWatchFile.bind(this),\n resolveRoute: this.resolve.bind(this),\n });\n },\n async hotUpdate({file, server}) {\n const resolvedFile = await realpath(file).catch(() => resolve(file));\n if (!watchedFiles.has(resolvedFile)) return;\n await generate({\n addWatchFile: server.watcher.add.bind(server.watcher),\n resolveRoute: this.environment.pluginContainer.resolveId.bind(\n this.environment.pluginContainer,\n ),\n });\n },\n };\n}\n"],"names":["mkdir","readFile","realpath","writeFile","dirname","resolve","composeClientFeatures","evaluateFeatures","generateAppModule","shipfoxClientComposition","features","out","config","watchedFiles","Set","outputPath","root","process","cwd","featuresPath","assertRoutesResolve","resolveRoute","routes","route","resolvedRoute","impl","Error","path","generate","addWatchFile","evaluated","composition","loadedFiles","file","output","navigation","settingsSections","existing","catch","undefined","recursive","name","configResolved","resolvedConfig","buildStart","bind","hotUpdate","server","resolvedFile","has","watcher","add","environment","pluginContainer","resolveId"],"mappings":"AAAA,SAAQA,KAAK,EAAEC,QAAQ,EAAEC,QAAQ,EAAEC,SAAS,QAAO,mBAAmB;AACtE,SAAQC,OAAO,EAAEC,OAAO,QAAO,YAAY;AAE3C,SAAQC,qBAAqB,QAAO,sCAAsC;AAC1E,SAAQC,gBAAgB,QAAO,yBAAyB;AACxD,SAAQC,iBAAiB,QAAO,gBAAgB;AAShD,OAAO,SAASC,yBAAyB,EACvCC,QAAQ,EACRC,MAAM,0BAA0B,EACA;IAChC,IAAIC;IACJ,IAAIC,eAAe,IAAIC;IAEvB,MAAMC,aAAa,IAAMV,QAAQO,QAAQI,QAAQC,QAAQC,GAAG,IAAIP;IAChE,MAAMQ,eAAe,IAAMd,QAAQO,QAAQI,QAAQC,QAAQC,GAAG,IAAIR;IAElE,eAAeU,oBACbC,YAA2B,EAC3BC,MAA0D;QAE1D,KAAK,MAAMC,SAASD,OAAQ;YAC1B,MAAME,gBAAgB,MAAMH,aAAaE,MAAME,IAAI,EAAEV;YACrD,IAAI,CAACS,eAAe;gBAClB,MAAM,IAAIE,MACR,CAAC,wCAAwC,EAAEH,MAAME,IAAI,CAAC,OAAO,EAAEF,MAAMI,IAAI,CAAC,EAAE,CAAC;YAEjF;QACF;IACF;IAEA,eAAeC,SAAS,EACtBC,YAAY,EACZR,YAAY,EAIb;QACC,MAAMS,YAAY,MAAMvB,iBAAiBY;QACzC,MAAMY,cAAczB,sBAAsBwB,UAAUpB,QAAQ;QAC5D,MAAMU,oBAAoBC,cAAcU,YAAYT,MAAM;QAE1DT,eAAe,IAAIC,IAAIgB,UAAUE,WAAW;QAC5C,KAAK,MAAMC,QAAQpB,aAAcgB,aAAaI;QAE9C,MAAMC,SAAS1B,kBAAkB;YAC/Bc,QAAQS,YAAYT,MAAM;YAC1Ba,YAAYJ,YAAYI,UAAU;YAClCC,kBAAkBL,YAAYK,gBAAgB;QAChD;QACA,MAAMT,OAAOZ;QACb,MAAMsB,WAAW,MAAMpC,SAAS0B,MAAM,QAAQW,KAAK,CAAC,IAAMC;QAC1D,IAAIF,aAAaH,QAAQ;QACzB,MAAMlC,MAAMI,QAAQuB,OAAO;YAACa,WAAW;QAAI;QAC3C,MAAMrC,UAAUwB,MAAMO;IACxB;IAEA,OAAO;QACLO,MAAM;QACNC,gBAAeC,cAAc;YAC3B/B,SAAS+B;QACX;QACA,MAAMC;YACJ,MAAMhB,SAAS;gBACbC,cAAc,IAAI,CAACA,YAAY,CAACgB,IAAI,CAAC,IAAI;gBACzCxB,cAAc,IAAI,CAAChB,OAAO,CAACwC,IAAI,CAAC,IAAI;YACtC;QACF;QACA,MAAMC,WAAU,EAACb,IAAI,EAAEc,MAAM,EAAC;YAC5B,MAAMC,eAAe,MAAM9C,SAAS+B,MAAMK,KAAK,CAAC,IAAMjC,QAAQ4B;YAC9D,IAAI,CAACpB,aAAaoC,GAAG,CAACD,eAAe;YACrC,MAAMpB,SAAS;gBACbC,cAAckB,OAAOG,OAAO,CAACC,GAAG,CAACN,IAAI,CAACE,OAAOG,OAAO;gBACpD7B,cAAc,IAAI,CAAC+B,WAAW,CAACC,eAAe,CAACC,SAAS,CAACT,IAAI,CAC3D,IAAI,CAACO,WAAW,CAACC,eAAe;YAEpC;QACF;IACF;AACF"}
1
+ {"version":3,"sources":["../../src/vite/plugin.ts"],"sourcesContent":["import {mkdir, readFile, realpath, writeFile} from 'node:fs/promises';\nimport {dirname, resolve} from 'node:path';\nimport type {Plugin, ResolvedConfig} from 'vite';\nimport {composeClientFeatures} from '#compose/compose-client-features.js';\nimport {evaluateFeatures} from './evaluate-features.js';\nimport {generateAppModule} from './generate.js';\n\nconst manifestPluginName = 'shipfox-client-manifest';\n\nexport interface ShipfoxClientCompositionOptions {\n features: string;\n out?: string;\n}\n\ntype RouteResolver = (source: string, importer?: string) => Promise<{id: string} | null>;\n\nexport function shipfoxClientComposition({\n features,\n out = './src/shipfox-app.gen.ts',\n}: ShipfoxClientCompositionOptions): Plugin {\n let config: ResolvedConfig | undefined;\n let watchedFiles = new Set<string>();\n\n const outputPath = () => resolve(config?.root ?? process.cwd(), out);\n const featuresPath = () => resolve(config?.root ?? process.cwd(), features);\n\n async function assertRoutesResolve(\n resolveRoute: RouteResolver,\n routes: ReturnType<typeof composeClientFeatures>['routes'],\n ): Promise<void> {\n for (const route of routes) {\n const resolvedRoute = await resolveRoute(route.impl, outputPath());\n if (!resolvedRoute) {\n throw new Error(\n `Could not resolve route implementation \"${route.impl}\" for \"${route.path}\".`,\n );\n }\n }\n }\n\n async function generate({\n addWatchFile,\n resolveRoute,\n }: {\n addWatchFile(file: string): void;\n resolveRoute: RouteResolver;\n }): Promise<void> {\n const evaluated = await evaluateFeatures(featuresPath());\n const composition = composeClientFeatures(evaluated.features);\n await assertRoutesResolve(resolveRoute, composition.routes);\n\n watchedFiles = new Set(evaluated.loadedFiles);\n for (const file of watchedFiles) addWatchFile(file);\n\n const output = generateAppModule({\n routes: composition.routes,\n navigation: composition.navigation,\n settingsSections: composition.settingsSections,\n });\n const path = outputPath();\n const existing = await readFile(path, 'utf8').catch(() => undefined);\n if (existing === output) return;\n await mkdir(dirname(path), {recursive: true});\n await writeFile(path, output);\n }\n\n return {\n name: 'shipfox-client-composition',\n configResolved(resolvedConfig) {\n config = resolvedConfig;\n if (!resolvedConfig.plugins.some(({name}) => name === manifestPluginName)) {\n resolvedConfig.logger.warn(\n `shipfoxClientComposition() is registered without the \"${manifestPluginName}\" plugin (shipfoxClientManifest()). Add shipfoxClientManifest() to the Vite plugins to serve Shipfox branding assets.`,\n );\n }\n },\n async buildStart() {\n await generate({\n addWatchFile: this.addWatchFile.bind(this),\n resolveRoute: this.resolve.bind(this),\n });\n },\n async hotUpdate({file, server}) {\n const resolvedFile = await realpath(file).catch(() => resolve(file));\n if (!watchedFiles.has(resolvedFile)) return;\n await generate({\n addWatchFile: server.watcher.add.bind(server.watcher),\n resolveRoute: this.environment.pluginContainer.resolveId.bind(\n this.environment.pluginContainer,\n ),\n });\n },\n };\n}\n"],"names":["mkdir","readFile","realpath","writeFile","dirname","resolve","composeClientFeatures","evaluateFeatures","generateAppModule","manifestPluginName","shipfoxClientComposition","features","out","config","watchedFiles","Set","outputPath","root","process","cwd","featuresPath","assertRoutesResolve","resolveRoute","routes","route","resolvedRoute","impl","Error","path","generate","addWatchFile","evaluated","composition","loadedFiles","file","output","navigation","settingsSections","existing","catch","undefined","recursive","name","configResolved","resolvedConfig","plugins","some","logger","warn","buildStart","bind","hotUpdate","server","resolvedFile","has","watcher","add","environment","pluginContainer","resolveId"],"mappings":"AAAA,SAAQA,KAAK,EAAEC,QAAQ,EAAEC,QAAQ,EAAEC,SAAS,QAAO,mBAAmB;AACtE,SAAQC,OAAO,EAAEC,OAAO,QAAO,YAAY;AAE3C,SAAQC,qBAAqB,QAAO,sCAAsC;AAC1E,SAAQC,gBAAgB,QAAO,yBAAyB;AACxD,SAAQC,iBAAiB,QAAO,gBAAgB;AAEhD,MAAMC,qBAAqB;AAS3B,OAAO,SAASC,yBAAyB,EACvCC,QAAQ,EACRC,MAAM,0BAA0B,EACA;IAChC,IAAIC;IACJ,IAAIC,eAAe,IAAIC;IAEvB,MAAMC,aAAa,IAAMX,QAAQQ,QAAQI,QAAQC,QAAQC,GAAG,IAAIP;IAChE,MAAMQ,eAAe,IAAMf,QAAQQ,QAAQI,QAAQC,QAAQC,GAAG,IAAIR;IAElE,eAAeU,oBACbC,YAA2B,EAC3BC,MAA0D;QAE1D,KAAK,MAAMC,SAASD,OAAQ;YAC1B,MAAME,gBAAgB,MAAMH,aAAaE,MAAME,IAAI,EAAEV;YACrD,IAAI,CAACS,eAAe;gBAClB,MAAM,IAAIE,MACR,CAAC,wCAAwC,EAAEH,MAAME,IAAI,CAAC,OAAO,EAAEF,MAAMI,IAAI,CAAC,EAAE,CAAC;YAEjF;QACF;IACF;IAEA,eAAeC,SAAS,EACtBC,YAAY,EACZR,YAAY,EAIb;QACC,MAAMS,YAAY,MAAMxB,iBAAiBa;QACzC,MAAMY,cAAc1B,sBAAsByB,UAAUpB,QAAQ;QAC5D,MAAMU,oBAAoBC,cAAcU,YAAYT,MAAM;QAE1DT,eAAe,IAAIC,IAAIgB,UAAUE,WAAW;QAC5C,KAAK,MAAMC,QAAQpB,aAAcgB,aAAaI;QAE9C,MAAMC,SAAS3B,kBAAkB;YAC/Be,QAAQS,YAAYT,MAAM;YAC1Ba,YAAYJ,YAAYI,UAAU;YAClCC,kBAAkBL,YAAYK,gBAAgB;QAChD;QACA,MAAMT,OAAOZ;QACb,MAAMsB,WAAW,MAAMrC,SAAS2B,MAAM,QAAQW,KAAK,CAAC,IAAMC;QAC1D,IAAIF,aAAaH,QAAQ;QACzB,MAAMnC,MAAMI,QAAQwB,OAAO;YAACa,WAAW;QAAI;QAC3C,MAAMtC,UAAUyB,MAAMO;IACxB;IAEA,OAAO;QACLO,MAAM;QACNC,gBAAeC,cAAc;YAC3B/B,SAAS+B;YACT,IAAI,CAACA,eAAeC,OAAO,CAACC,IAAI,CAAC,CAAC,EAACJ,IAAI,EAAC,GAAKA,SAASjC,qBAAqB;gBACzEmC,eAAeG,MAAM,CAACC,IAAI,CACxB,CAAC,sDAAsD,EAAEvC,mBAAmB,qHAAqH,CAAC;YAEtM;QACF;QACA,MAAMwC;YACJ,MAAMpB,SAAS;gBACbC,cAAc,IAAI,CAACA,YAAY,CAACoB,IAAI,CAAC,IAAI;gBACzC5B,cAAc,IAAI,CAACjB,OAAO,CAAC6C,IAAI,CAAC,IAAI;YACtC;QACF;QACA,MAAMC,WAAU,EAACjB,IAAI,EAAEkB,MAAM,EAAC;YAC5B,MAAMC,eAAe,MAAMnD,SAASgC,MAAMK,KAAK,CAAC,IAAMlC,QAAQ6B;YAC9D,IAAI,CAACpB,aAAawC,GAAG,CAACD,eAAe;YACrC,MAAMxB,SAAS;gBACbC,cAAcsB,OAAOG,OAAO,CAACC,GAAG,CAACN,IAAI,CAACE,OAAOG,OAAO;gBACpDjC,cAAc,IAAI,CAACmC,WAAW,CAACC,eAAe,CAACC,SAAS,CAACT,IAAI,CAC3D,IAAI,CAACO,WAAW,CAACC,eAAe;YAEpC;QACF;IACF;AACF"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@shipfox/client-shell",
3
3
  "license": "MIT",
4
- "version": "6.0.2",
4
+ "version": "9.0.0",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "git+https://github.com/ShipfoxHQ/shipfox.git",
@@ -30,7 +30,8 @@
30
30
  "./vite": {
31
31
  "types": "./dist/vite/index.d.ts",
32
32
  "default": "./dist/vite/index.js"
33
- }
33
+ },
34
+ "./assets/*": "./assets/*"
34
35
  },
35
36
  "dependencies": {
36
37
  "@swc/helpers": "^0.5.17",
@@ -38,10 +39,10 @@
38
39
  "tsx": "^4.22.4",
39
40
  "framer-motion": "^12.23.24",
40
41
  "@shipfox/api-auth-dto": "9.0.2",
41
- "@shipfox/client-config": "6.0.2",
42
- "@shipfox/client-ui": "6.0.2",
43
42
  "@shipfox/api-workspaces-dto": "9.0.2",
44
43
  "@shipfox/client-api": "6.0.1",
44
+ "@shipfox/client-config": "6.0.2",
45
+ "@shipfox/client-ui": "6.0.2",
45
46
  "@shipfox/react-ui": "0.3.7"
46
47
  },
47
48
  "peerDependencies": {