@happyvertical/smrt-planner 0.0.1 → 0.0.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 (414) hide show
  1. package/app/404.html +12 -12
  2. package/app/_app/immutable/chunks/2jFBkS1C.js +1 -0
  3. package/app/_app/immutable/chunks/6P9zxrzU.js +1 -0
  4. package/app/_app/immutable/chunks/{DyGfbRG-.js → BnRri03M.js} +1 -1
  5. package/app/_app/immutable/chunks/Ci0DUht6.js +34 -0
  6. package/app/_app/immutable/chunks/{CV-2zt0K.js → CsprTb3f.js} +2 -2
  7. package/app/_app/immutable/chunks/{D333l2GL.js → DkR8_Ws6.js} +1 -1
  8. package/app/_app/immutable/chunks/{DJtH-lRi.js → Xp1g1t4n.js} +1 -1
  9. package/app/_app/immutable/entry/{app.D5JJain6.js → app.IZIJXhgq.js} +2 -2
  10. package/app/_app/immutable/entry/start.BuaYHD1N.js +1 -0
  11. package/app/_app/immutable/nodes/{0.CL1MxOva.js → 0.m_U8WC7E.js} +3 -3
  12. package/app/_app/immutable/nodes/{1.BO731RRg.js → 1.Crw8ULhB.js} +1 -1
  13. package/app/_app/immutable/nodes/{12.BmZyLHbM.js → 12.BIocA1aI.js} +1 -1
  14. package/app/_app/immutable/nodes/{2.BEw046av.js → 2.CR5BwGnt.js} +2 -2
  15. package/app/_app/immutable/nodes/{3.DvwpTAQA.js → 3.1B56hgAG.js} +1 -1
  16. package/app/_app/immutable/nodes/{4.qrT4bnmS.js → 4.SSIC7sUh.js} +1 -1
  17. package/app/_app/immutable/nodes/{5.DDLa2uhV.js → 5.DgdwleDQ.js} +1 -1
  18. package/app/_app/immutable/nodes/{6.DN0QTY6z.js → 6.DmD9rqLU.js} +1 -1
  19. package/app/_app/immutable/nodes/{7.C_8N82Wq.js → 7.DdngsBmo.js} +1 -1
  20. package/app/_app/version.json +1 -1
  21. package/app/ai/index.html +14 -14
  22. package/app/blueprint/index.html +13 -13
  23. package/app/cookbook/index.html +13 -13
  24. package/app/index.html +13 -13
  25. package/app/m/ads/AdDeliveryTier/index.html +14 -14
  26. package/app/m/ads/AdEvent/index.html +14 -14
  27. package/app/m/ads/AdFormat/index.html +14 -14
  28. package/app/m/ads/AdGroup/index.html +14 -14
  29. package/app/m/ads/AdVariation/index.html +14 -14
  30. package/app/m/analytics/AnalyticsDataStream/index.html +14 -14
  31. package/app/m/analytics/AnalyticsEvent/index.html +14 -14
  32. package/app/m/analytics/AnalyticsProperty/index.html +14 -14
  33. package/app/m/analytics/AnalyticsReport/index.html +14 -14
  34. package/app/m/approvals/ApprovalEvent/index.html +14 -14
  35. package/app/m/approvals/ApprovalPolicy/index.html +14 -14
  36. package/app/m/approvals/ApprovalRequest/index.html +14 -14
  37. package/app/m/assets/Asset/index.html +14 -14
  38. package/app/m/assets/AssetAssociation/index.html +14 -14
  39. package/app/m/assets/AssetMetafield/index.html +14 -14
  40. package/app/m/assets/AssetStatus/index.html +14 -14
  41. package/app/m/assets/AssetType/index.html +14 -14
  42. package/app/m/assets/Folder/index.html +14 -14
  43. package/app/m/chat/AgentSession/index.html +14 -14
  44. package/app/m/chat/ChatMessage/index.html +14 -14
  45. package/app/m/chat/ChatParticipant/index.html +14 -14
  46. package/app/m/chat/ChatReaction/index.html +14 -14
  47. package/app/m/chat/ChatRoom/index.html +14 -14
  48. package/app/m/chat/ChatThread/index.html +14 -14
  49. package/app/m/chat/VoiceGatewayTurn/index.html +14 -14
  50. package/app/m/chat/VoiceSession/index.html +14 -14
  51. package/app/m/commerce/Agreement/index.html +14 -14
  52. package/app/m/commerce/Cart/index.html +14 -14
  53. package/app/m/commerce/Contract/index.html +14 -14
  54. package/app/m/commerce/ContractLineItem/index.html +14 -14
  55. package/app/m/commerce/Customer/index.html +14 -14
  56. package/app/m/commerce/Estimate/index.html +14 -14
  57. package/app/m/commerce/Fulfillment/index.html +14 -14
  58. package/app/m/commerce/FulfillmentLineItem/index.html +14 -14
  59. package/app/m/commerce/Invoice/index.html +14 -14
  60. package/app/m/commerce/InvoiceLineItem/index.html +14 -14
  61. package/app/m/commerce/Lease/index.html +14 -14
  62. package/app/m/commerce/LicenseSale/index.html +14 -14
  63. package/app/m/commerce/Order/index.html +14 -14
  64. package/app/m/commerce/Payment/index.html +14 -14
  65. package/app/m/commerce/PaymentAllocation/index.html +14 -14
  66. package/app/m/commerce/PaymentInstrument/index.html +14 -14
  67. package/app/m/commerce/PaymentIntent/index.html +14 -14
  68. package/app/m/commerce/Payout/index.html +14 -14
  69. package/app/m/commerce/ProductionOrder/index.html +14 -14
  70. package/app/m/commerce/PurchaseOrder/index.html +14 -14
  71. package/app/m/commerce/Vendor/index.html +14 -14
  72. package/app/m/commerce/WholesaleOrder/index.html +14 -14
  73. package/app/m/content/Content/index.html +14 -14
  74. package/app/m/content/ContentContribution/index.html +14 -14
  75. package/app/m/content/ContentContributionAttachment/index.html +14 -14
  76. package/app/m/content/ContentContributionRevision/index.html +14 -14
  77. package/app/m/content/ContentContributionType/index.html +14 -14
  78. package/app/m/content/ContentContributor/index.html +14 -14
  79. package/app/m/content/ContentCorrection/index.html +14 -14
  80. package/app/m/content/ContentFeedSource/index.html +14 -14
  81. package/app/m/content/ContentGovernanceAssignment/index.html +14 -14
  82. package/app/m/content/ContentGovernancePolicy/index.html +14 -14
  83. package/app/m/content/ContentGovernanceProfile/index.html +14 -14
  84. package/app/m/content/ContentReference/index.html +14 -14
  85. package/app/m/content/ContentReview/index.html +14 -14
  86. package/app/m/content/ContentVersion/index.html +14 -14
  87. package/app/m/content/Contents/index.html +14 -14
  88. package/app/m/events/Event/index.html +14 -14
  89. package/app/m/events/EventParticipant/index.html +14 -14
  90. package/app/m/events/EventSeries/index.html +14 -14
  91. package/app/m/events/EventType/index.html +14 -14
  92. package/app/m/facts/Fact/index.html +14 -14
  93. package/app/m/facts/FactContent/index.html +14 -14
  94. package/app/m/facts/FactEvidence/index.html +14 -14
  95. package/app/m/facts/FactSource/index.html +14 -14
  96. package/app/m/facts/FactSubject/index.html +14 -14
  97. package/app/m/facts/FactTag/index.html +14 -14
  98. package/app/m/fields/FieldPolicy/index.html +14 -14
  99. package/app/m/fields/FieldPolicySuggestion/index.html +14 -14
  100. package/app/m/fields/FieldUsageCounter/index.html +14 -14
  101. package/app/m/images/Image/index.html +14 -14
  102. package/app/m/inventory/InventoryLocation/index.html +14 -14
  103. package/app/m/inventory/StockLevel/index.html +14 -14
  104. package/app/m/inventory/StockMovement/index.html +14 -14
  105. package/app/m/ledgers/Account/index.html +14 -14
  106. package/app/m/ledgers/Journal/index.html +14 -14
  107. package/app/m/ledgers/JournalEntry/index.html +14 -14
  108. package/app/m/manufacturing/Assembly/index.html +14 -14
  109. package/app/m/manufacturing/BillOfMaterials/index.html +14 -14
  110. package/app/m/manufacturing/BomLine/index.html +14 -14
  111. package/app/m/manufacturing/Operation/index.html +14 -14
  112. package/app/m/manufacturing/ProductionRun/index.html +14 -14
  113. package/app/m/manufacturing/ProductionRunCompletion/index.html +14 -14
  114. package/app/m/manufacturing/RoutingStep/index.html +14 -14
  115. package/app/m/marketing/Campaign/index.html +14 -14
  116. package/app/m/marketing/CampaignChannel/index.html +14 -14
  117. package/app/m/marketing/CampaignMetricSnapshot/index.html +14 -14
  118. package/app/m/messages/Account/index.html +14 -14
  119. package/app/m/messages/Attachment/index.html +14 -14
  120. package/app/m/messages/Blacklist/index.html +14 -14
  121. package/app/m/messages/Email/failed-sends/index.html +14 -14
  122. package/app/m/messages/Email/index.html +14 -14
  123. package/app/m/messages/Email/mailbox/index.html +14 -14
  124. package/app/m/messages/EmailAccount/index.html +14 -14
  125. package/app/m/messages/EmailFolder/index.html +14 -14
  126. package/app/m/messages/Message/index.html +14 -14
  127. package/app/m/messages/MessagingEndpoint/index.html +14 -14
  128. package/app/m/messages/PersonaMessageRoute/index.html +14 -14
  129. package/app/m/messages/SlackAccount/index.html +14 -14
  130. package/app/m/messages/SlackMessage/index.html +14 -14
  131. package/app/m/messages/TelegramAccount/index.html +14 -14
  132. package/app/m/messages/Tweet/index.html +14 -14
  133. package/app/m/messages/TwitterAccount/index.html +14 -14
  134. package/app/m/messages/Whitelist/index.html +14 -14
  135. package/app/m/messages/ZulipAccount/index.html +14 -14
  136. package/app/m/places/Place/index.html +14 -14
  137. package/app/m/places/PlaceType/index.html +14 -14
  138. package/app/m/preferences/UiPreferenceRecord/index.html +14 -14
  139. package/app/m/products/Category/index.html +14 -14
  140. package/app/m/products/Material/index.html +14 -14
  141. package/app/m/products/Product/index.html +14 -14
  142. package/app/m/products/Product/ingredients/index.html +14 -14
  143. package/app/m/products/ProductVariant/index.html +14 -14
  144. package/app/m/products/Sku/index.html +14 -14
  145. package/app/m/profiles/ApiKey/index.html +14 -14
  146. package/app/m/profiles/Bot/index.html +14 -14
  147. package/app/m/profiles/MagicLinkToken/index.html +14 -14
  148. package/app/m/profiles/NostrIdentity/index.html +14 -14
  149. package/app/m/profiles/OidcIdentity/index.html +14 -14
  150. package/app/m/profiles/Organization/index.html +14 -14
  151. package/app/m/profiles/Person/index.html +14 -14
  152. package/app/m/profiles/Profile/index.html +14 -14
  153. package/app/m/profiles/ProfileMetadata/index.html +14 -14
  154. package/app/m/profiles/ProfileMetafield/index.html +14 -14
  155. package/app/m/profiles/ProfileRelationship/index.html +14 -14
  156. package/app/m/profiles/ProfileRelationshipTerm/index.html +14 -14
  157. package/app/m/profiles/ProfileRelationshipType/index.html +14 -14
  158. package/app/m/profiles/ProfileType/index.html +14 -14
  159. package/app/m/projects/Comment/index.html +14 -14
  160. package/app/m/projects/Issue/index.html +14 -14
  161. package/app/m/projects/Label/index.html +14 -14
  162. package/app/m/projects/Project/index.html +14 -14
  163. package/app/m/projects/ProjectIntegration/index.html +14 -14
  164. package/app/m/projects/PullRequest/index.html +14 -14
  165. package/app/m/projects/Repository/index.html +14 -14
  166. package/app/m/properties/Property/index.html +14 -14
  167. package/app/m/properties/Zone/index.html +14 -14
  168. package/app/m/reports/RuntimeReport/index.html +14 -14
  169. package/app/m/reports/SmrtPrincipalReportRefreshTask/index.html +14 -14
  170. package/app/m/reports/SmrtReportLock/index.html +14 -14
  171. package/app/m/reports/SmrtReportRefreshTask/index.html +14 -14
  172. package/app/m/reports/SmrtReportRun/index.html +14 -14
  173. package/app/m/reports/SmrtReportSchedule/index.html +14 -14
  174. package/app/m/reports/SmrtReportWatermark/index.html +14 -14
  175. package/app/m/sales/AttributionException/index.html +14 -14
  176. package/app/m/sales/AttributionPolicy/index.html +14 -14
  177. package/app/m/sales/Commission/index.html +14 -14
  178. package/app/m/sales/CommissionAdjustment/index.html +14 -14
  179. package/app/m/sales/CommissionPayout/index.html +14 -14
  180. package/app/m/sales/CommissionPlan/index.html +14 -14
  181. package/app/m/sales/Earner/index.html +14 -14
  182. package/app/m/sales/EarnerSourceAttribution/index.html +14 -14
  183. package/app/m/sales/EarningEvent/index.html +14 -14
  184. package/app/m/sales/ExecutedAgreement/index.html +14 -14
  185. package/app/m/sales/Lead/index.html +14 -14
  186. package/app/m/sales/Opportunity/index.html +14 -14
  187. package/app/m/sales/OpportunityConversion/index.html +14 -14
  188. package/app/m/sales/PipelineDefinition/index.html +14 -14
  189. package/app/m/sales/PipelineStage/index.html +14 -14
  190. package/app/m/sales/Referral/index.html +14 -14
  191. package/app/m/sales/ReferralAgreement/index.html +14 -14
  192. package/app/m/sales/ReferralLink/index.html +14 -14
  193. package/app/m/sales/ReferralProgram/index.html +14 -14
  194. package/app/m/sales/ReferralTermSnapshot/index.html +14 -14
  195. package/app/m/sales/ReferralTouch/index.html +14 -14
  196. package/app/m/sales/Referrer/index.html +14 -14
  197. package/app/m/sales/SalesActivity/index.html +14 -14
  198. package/app/m/sales/SalesRepresentative/index.html +14 -14
  199. package/app/m/sites/Site/index.html +14 -14
  200. package/app/m/sites/SiteAgentBinding/index.html +14 -14
  201. package/app/m/social/OAuthState/index.html +14 -14
  202. package/app/m/social/SocialAccount/index.html +14 -14
  203. package/app/m/social/SocialPost/index.html +14 -14
  204. package/app/m/social/SocialPostAnalyticsSnapshot/index.html +14 -14
  205. package/app/m/subscriptions/BillingAdjustment/index.html +14 -14
  206. package/app/m/subscriptions/ClientCharge/index.html +14 -14
  207. package/app/m/subscriptions/CreditGrant/index.html +14 -14
  208. package/app/m/subscriptions/PricingRule/index.html +14 -14
  209. package/app/m/subscriptions/RetailCharge/index.html +14 -14
  210. package/app/m/subscriptions/SpendingPolicy/index.html +14 -14
  211. package/app/m/subscriptions/SubscriptionPlan/index.html +14 -14
  212. package/app/m/subscriptions/TenantSubscription/index.html +14 -14
  213. package/app/m/subscriptions/TenantUsageMetric/index.html +14 -14
  214. package/app/m/support/ServiceTimeEntry/index.html +14 -14
  215. package/app/m/support/SupportAiRun/index.html +14 -14
  216. package/app/m/support/SupportAvailability/index.html +14 -14
  217. package/app/m/support/SupportCase/index.html +14 -14
  218. package/app/m/support/SupportCaseEvent/index.html +14 -14
  219. package/app/m/support/SupportChannelBinding/index.html +14 -14
  220. package/app/m/support/SupportCharge/index.html +14 -14
  221. package/app/m/support/SupportCompensation/index.html +14 -14
  222. package/app/m/support/SupportCompensationPlan/index.html +14 -14
  223. package/app/m/support/SupportEscalation/index.html +14 -14
  224. package/app/m/support/SupportInteraction/index.html +14 -14
  225. package/app/m/support/SupportPlan/index.html +14 -14
  226. package/app/m/support/SupportPolicy/index.html +14 -14
  227. package/app/m/support/SupportQualification/index.html +14 -14
  228. package/app/m/support/SupportServiceTarget/index.html +14 -14
  229. package/app/m/support/SupportSpecialist/index.html +14 -14
  230. package/app/m/support/SupportWorkLink/index.html +14 -14
  231. package/app/m/tags/Tag/index.html +14 -14
  232. package/app/m/tags/TagAlias/index.html +14 -14
  233. package/app/m/timesheets/AttendanceBreak/index.html +14 -14
  234. package/app/m/timesheets/AttendancePunch/index.html +14 -14
  235. package/app/m/timesheets/ServiceChargeSnapshot/index.html +14 -14
  236. package/app/m/timesheets/ServiceCompensationSnapshot/index.html +14 -14
  237. package/app/m/timesheets/ServiceTimeEntry/index.html +14 -14
  238. package/app/m/users/AccessRequest/index.html +14 -14
  239. package/app/m/users/Group/index.html +14 -14
  240. package/app/m/users/GroupMember/index.html +14 -14
  241. package/app/m/users/GroupRole/index.html +14 -14
  242. package/app/m/users/Membership/index.html +14 -14
  243. package/app/m/users/MembershipOverride/index.html +14 -14
  244. package/app/m/users/Permission/index.html +14 -14
  245. package/app/m/users/ResourceGrant/index.html +14 -14
  246. package/app/m/users/Role/index.html +14 -14
  247. package/app/m/users/RolePermission/index.html +14 -14
  248. package/app/m/users/Session/index.html +14 -14
  249. package/app/m/users/Tenant/index.html +14 -14
  250. package/app/m/users/TenantIntegration/index.html +14 -14
  251. package/app/m/users/TenantPermissionOverride/index.html +14 -14
  252. package/app/m/users/User/index.html +14 -14
  253. package/app/m/users/UsersCliAuthRequest/index.html +14 -14
  254. package/app/m/users/UsersMagicLinkToken/index.html +14 -14
  255. package/app/m/video/Character/index.html +14 -14
  256. package/app/m/video/CharacterAsset/index.html +14 -14
  257. package/app/m/video/CompositeJob/index.html +14 -14
  258. package/app/m/video/Performer/index.html +14 -14
  259. package/app/m/video/PerformerAsset/index.html +14 -14
  260. package/app/m/video/Scene/index.html +14 -14
  261. package/app/m/video/SceneAsset/index.html +14 -14
  262. package/app/m/video/VideoComposition/index.html +14 -14
  263. package/app/m/video/VideoCompositionAsset/index.html +14 -14
  264. package/app/m/video/VideoSequence/index.html +14 -14
  265. package/app/m/video/VideoSequenceAsset/index.html +14 -14
  266. package/app/m/video/VideoShot/index.html +14 -14
  267. package/app/m/video/VideoShotAsset/index.html +14 -14
  268. package/app/m/video/VideoShotCharacter/index.html +14 -14
  269. package/app/m/video/VideoWorkflow/index.html +14 -14
  270. package/app/m/voice/VoiceOutput/index.html +14 -14
  271. package/app/m/voice/VoiceProfile/index.html +14 -14
  272. package/app/m/voice/VoiceSample/index.html +14 -14
  273. package/app/packages/ads/index.html +12 -12
  274. package/app/packages/analytics/index.html +12 -12
  275. package/app/packages/approvals/index.html +12 -12
  276. package/app/packages/assets/index.html +12 -12
  277. package/app/packages/chat/index.html +12 -12
  278. package/app/packages/comments/index.html +12 -12
  279. package/app/packages/commerce/index.html +12 -12
  280. package/app/packages/content/index.html +12 -12
  281. package/app/packages/events/index.html +12 -12
  282. package/app/packages/expenses/index.html +12 -12
  283. package/app/packages/facts/index.html +12 -12
  284. package/app/packages/fields/index.html +12 -12
  285. package/app/packages/human-resources/index.html +12 -12
  286. package/app/packages/images/index.html +12 -12
  287. package/app/packages/index.html +12 -12
  288. package/app/packages/inventory/index.html +12 -12
  289. package/app/packages/ledgers/index.html +12 -12
  290. package/app/packages/manufacturing/index.html +12 -12
  291. package/app/packages/marketing/index.html +12 -12
  292. package/app/packages/messages/index.html +12 -12
  293. package/app/packages/places/index.html +12 -12
  294. package/app/packages/preferences/index.html +12 -12
  295. package/app/packages/products/index.html +12 -12
  296. package/app/packages/profiles/index.html +12 -12
  297. package/app/packages/projects/index.html +12 -12
  298. package/app/packages/properties/index.html +12 -12
  299. package/app/packages/reports/index.html +12 -12
  300. package/app/packages/sales/index.html +12 -12
  301. package/app/packages/sites/index.html +12 -12
  302. package/app/packages/social/index.html +12 -12
  303. package/app/packages/subscriptions/index.html +12 -12
  304. package/app/packages/support/index.html +12 -12
  305. package/app/packages/tags/index.html +12 -12
  306. package/app/packages/timesheets/index.html +12 -12
  307. package/app/packages/users/index.html +12 -12
  308. package/app/packages/video/index.html +12 -12
  309. package/app/packages/voice/index.html +12 -12
  310. package/app/recipes/account-access/help/index.html +12 -12
  311. package/app/recipes/account-access/index.html +12 -12
  312. package/app/recipes/activity/help/index.html +12 -12
  313. package/app/recipes/activity/index.html +12 -12
  314. package/app/recipes/agreements/help/index.html +12 -12
  315. package/app/recipes/agreements/index.html +12 -12
  316. package/app/recipes/analytics.reports/help/index.html +12 -12
  317. package/app/recipes/analytics.reports/index.html +12 -12
  318. package/app/recipes/assets/help/index.html +12 -12
  319. package/app/recipes/assets/index.html +12 -12
  320. package/app/recipes/billing/help/index.html +12 -12
  321. package/app/recipes/billing/index.html +12 -12
  322. package/app/recipes/chat.assistant/help/index.html +12 -12
  323. package/app/recipes/chat.assistant/index.html +12 -12
  324. package/app/recipes/comments/help/index.html +12 -12
  325. package/app/recipes/comments/index.html +12 -12
  326. package/app/recipes/commerce.customers/help/index.html +12 -12
  327. package/app/recipes/commerce.customers/index.html +12 -12
  328. package/app/recipes/commerce.estimates/help/index.html +12 -12
  329. package/app/recipes/commerce.estimates/index.html +12 -12
  330. package/app/recipes/commerce.purchases/help/index.html +12 -12
  331. package/app/recipes/commerce.purchases/index.html +12 -12
  332. package/app/recipes/commerce.sales/help/index.html +12 -12
  333. package/app/recipes/commerce.sales/index.html +12 -12
  334. package/app/recipes/commerce.vendors/help/index.html +12 -12
  335. package/app/recipes/commerce.vendors/index.html +12 -12
  336. package/app/recipes/commerce.wholesale/help/index.html +12 -12
  337. package/app/recipes/commerce.wholesale/index.html +12 -12
  338. package/app/recipes/events.calendar/help/index.html +12 -12
  339. package/app/recipes/events.calendar/index.html +12 -12
  340. package/app/recipes/fields.form-customization/help/index.html +12 -12
  341. package/app/recipes/fields.form-customization/index.html +12 -12
  342. package/app/recipes/inventory.stock/help/index.html +12 -12
  343. package/app/recipes/inventory.stock/index.html +12 -12
  344. package/app/recipes/ledgers.bookkeeping/help/index.html +12 -12
  345. package/app/recipes/ledgers.bookkeeping/index.html +12 -12
  346. package/app/recipes/messages/help/index.html +12 -12
  347. package/app/recipes/messages/index.html +12 -12
  348. package/app/recipes/products/help/index.html +12 -12
  349. package/app/recipes/products/index.html +12 -12
  350. package/app/recipes/projects.tracker/help/index.html +12 -12
  351. package/app/recipes/projects.tracker/index.html +12 -12
  352. package/app/recipes/reports.materialized/help/index.html +12 -12
  353. package/app/recipes/reports.materialized/index.html +12 -12
  354. package/app/recipes/sales.pipeline/help/index.html +12 -12
  355. package/app/recipes/sales.pipeline/index.html +12 -12
  356. package/app/recipes/tags.taxonomy/help/index.html +12 -12
  357. package/app/recipes/tags.taxonomy/index.html +12 -12
  358. package/app/recipes/team-collaboration/help/index.html +12 -12
  359. package/app/recipes/team-collaboration/index.html +12 -12
  360. package/app/s/custom-billing/index.html +13 -13
  361. package/app/s/custom-buying/index.html +13 -13
  362. package/app/s/custom-classes/index.html +13 -13
  363. package/app/s/custom-jobs/index.html +13 -13
  364. package/app/s/custom-kitchen/index.html +13 -13
  365. package/app/s/custom-material/index.html +13 -13
  366. package/app/s/custom-members/index.html +13 -13
  367. package/app/s/custom-parts/index.html +13 -13
  368. package/app/s/custom-schedule/index.html +13 -13
  369. package/app/s/custom-shop/index.html +13 -13
  370. package/app/s/custom-wholesale/index.html +13 -13
  371. package/app/s/section-access-control/index.html +13 -13
  372. package/app/s/section-account-security/index.html +13 -13
  373. package/app/s/section-accounting/index.html +13 -13
  374. package/app/s/section-activity/index.html +13 -13
  375. package/app/s/section-agreements/index.html +13 -13
  376. package/app/s/section-analytics/index.html +13 -13
  377. package/app/s/section-assets/index.html +13 -13
  378. package/app/s/section-billing/index.html +13 -13
  379. package/app/s/section-calendar/index.html +13 -13
  380. package/app/s/section-catalog/index.html +13 -13
  381. package/app/s/section-chat.assistant/index.html +13 -13
  382. package/app/s/section-comments/index.html +13 -13
  383. package/app/s/section-fields.form-customization/index.html +13 -13
  384. package/app/s/section-messages/index.html +13 -13
  385. package/app/s/section-more/index.html +13 -13
  386. package/app/s/section-operations/index.html +13 -13
  387. package/app/s/section-projects/index.html +13 -13
  388. package/app/s/section-purchasing/index.html +13 -13
  389. package/app/s/section-reports.materialized/index.html +13 -13
  390. package/app/s/section-sales/index.html +13 -13
  391. package/app/s/section-taxonomy/index.html +13 -13
  392. package/app/s/section-team/index.html +13 -13
  393. package/dist/ai/state.svelte.d.ts +9 -4
  394. package/dist/ai/state.svelte.js +46 -16
  395. package/dist/ai/status.js +8 -0
  396. package/dist/assistant/session.svelte.d.ts +1 -0
  397. package/dist/assistant/session.svelte.js +22 -4
  398. package/dist/components/AiSetup.svelte +31 -2
  399. package/dist/components/BrowserAssistant.svelte +12 -8
  400. package/dist/core/app.d.ts +33 -8
  401. package/dist/core/app.js +112 -8
  402. package/dist/index.d.ts +1 -1
  403. package/dist/inference/byo.svelte.d.ts +8 -4
  404. package/dist/inference/byo.svelte.js +36 -8
  405. package/dist/inference/config.d.ts +12 -5
  406. package/dist/inference/config.js +96 -40
  407. package/dist/inference/openai.js +5 -0
  408. package/dist/kitchen/client.js +10 -4
  409. package/dist/planner/assistant.js +1 -1
  410. package/package.json +2 -1
  411. package/app/_app/immutable/chunks/BYde9M_U.js +0 -1
  412. package/app/_app/immutable/chunks/OJ_lLTHH.js +0 -1
  413. package/app/_app/immutable/chunks/ufuM4XBq.js +0 -33
  414. package/app/_app/immutable/entry/start.CH9DJLgI.js +0 -1
@@ -1,7 +1,7 @@
1
1
  import { AssistantSession, type SessionOptions } from '../assistant/session.svelte.ts';
2
2
  import { type VoiceOptions, VoiceSession } from '../assistant/voice.svelte.ts';
3
3
  import { ByoModel } from '../inference/byo.svelte.ts';
4
- import { type ConfigResult, type InferenceConfig } from '../inference/config.ts';
4
+ import { type ConfigResult, type InferenceConfig, type InferenceMode } from '../inference/config.ts';
5
5
  import { type CapabilitySummary } from './status.ts';
6
6
  /** UI choices that are not part of the cookbook. */
7
7
  export interface AiPrefs {
@@ -59,7 +59,9 @@ export declare class AiState {
59
59
  speaking: boolean;
60
60
  /** Where the model runs, from `planner.config.json` or the `inference` prop. */
61
61
  inference: InferenceConfig;
62
- /** Set when the config was unusable and `browser` is used instead. */
62
+ /** Modes this policy exposes. Manual is always available for a multi-mode policy. */
63
+ availableModes: InferenceMode[];
64
+ /** Set when the config was unusable and inference fails closed to manual. */
63
65
  notice: string;
64
66
  /** The visitor's own endpoint (byo mode only). */
65
67
  byo: ByoModel | null;
@@ -84,10 +86,13 @@ export declare class AiState {
84
86
  /**
85
87
  * Apply the inference config. `host` is ready at once (nothing to download);
86
88
  * `byo` is ready once the visitor has connected an endpoint on the AI page;
87
- * `browser` is today's WebLLM. An unusable config arrives as `browser` with
88
- * a `notice`.
89
+ * `browser` is today's WebLLM. An unusable config arrives as `manual` with a
90
+ * `notice`.
89
91
  */
90
92
  configure(result: ConfigResult): void;
93
+ /** Change providers only after a visitor selects one from the configured policy. */
94
+ selectInference(mode: InferenceMode): void;
95
+ private applyMode;
91
96
  private syncByo;
92
97
  private decideFirstRun;
93
98
  /** Before hydration every capability reads as not set up, as on the server. */
@@ -63,7 +63,9 @@ export class AiState {
63
63
  speaking = $state(false);
64
64
  /** Where the model runs, from `planner.config.json` or the `inference` prop. */
65
65
  inference = $state(DEFAULT_INFERENCE);
66
- /** Set when the config was unusable and `browser` is used instead. */
66
+ /** Modes this policy exposes. Manual is always available for a multi-mode policy. */
67
+ availableModes = $state(['browser']);
68
+ /** Set when the config was unusable and inference fails closed to manual. */
67
69
  notice = $state('');
68
70
  /** The visitor's own endpoint (byo mode only). */
69
71
  byo = $state(null);
@@ -119,36 +121,60 @@ export class AiState {
119
121
  /**
120
122
  * Apply the inference config. `host` is ready at once (nothing to download);
121
123
  * `byo` is ready once the visitor has connected an endpoint on the AI page;
122
- * `browser` is today's WebLLM. An unusable config arrives as `browser` with
123
- * a `notice`.
124
+ * `browser` is today's WebLLM. An unusable config arrives as `manual` with a
125
+ * `notice`.
124
126
  */
125
127
  configure(result) {
126
128
  const { config, notice } = result;
127
129
  this.pendingConfig = false;
128
130
  this.inference = config;
129
131
  this.notice = notice ?? '';
130
- this.session.setMode(config.mode);
131
- this.byo = null;
132
- if (config.mode === 'host' && config.host) {
132
+ const configured = [config.mode, ...(config.alternatives ?? [])];
133
+ this.availableModes = [
134
+ ...configured,
135
+ ...(config.alternatives?.length && !configured.includes('manual')
136
+ ? ['manual']
137
+ : []),
138
+ ];
139
+ this.byo = configured.includes('byo')
140
+ ? new ByoModel({
141
+ storage: this.options.storage,
142
+ credentialPersistence: config.credentialPersistence,
143
+ presets: config.byo?.presets,
144
+ fetch: this.options.fetch,
145
+ onChange: () => this.syncByo(),
146
+ })
147
+ : null;
148
+ this.applyMode(config.mode);
149
+ if (this.hydrated)
150
+ this.decideFirstRun();
151
+ }
152
+ /** Change providers only after a visitor selects one from the configured policy. */
153
+ selectInference(mode) {
154
+ if (!this.availableModes.includes(mode) || mode === this.inference.mode) {
155
+ return;
156
+ }
157
+ this.inference = { ...this.inference, mode };
158
+ this.notice = '';
159
+ this.applyMode(mode);
160
+ }
161
+ applyMode(mode) {
162
+ this.session.setMode(mode);
163
+ if (mode === 'host' && this.inference.host) {
133
164
  const { controller, store, settings, theme } = this.options.session;
134
165
  const plan = controller ?? createSliceController({ store, settings, theme });
135
166
  this.session.useRemote(createHostChat({
136
- endpoint: config.host.endpoint,
167
+ endpoint: this.inference.host.endpoint,
137
168
  snapshot: () => plan.snapshot(),
138
169
  fetch: this.options.fetch,
139
170
  }), 'Server');
140
171
  }
141
- else if (config.mode === 'byo') {
142
- this.byo = new ByoModel({
143
- storage: this.options.storage,
144
- presets: config.byo?.presets,
145
- fetch: this.options.fetch,
146
- onChange: () => this.syncByo(),
147
- });
172
+ else if (mode === 'byo') {
148
173
  this.syncByo();
149
174
  }
150
- if (this.hydrated)
151
- this.decideFirstRun();
175
+ else if (mode === 'manual') {
176
+ this.session.useRemote(null, '');
177
+ }
152
178
  }
153
179
  syncByo() {
154
180
  const byo = this.byo;
@@ -160,6 +186,7 @@ export class AiState {
160
186
  // A host's server needs nothing set up, so the form has nothing to ask for.
161
187
  this.firstRun =
162
188
  this.inference.mode !== 'host' &&
189
+ this.inference.mode !== 'manual' &&
163
190
  needsFirstRunSetup({
164
191
  thinkDownloaded: this.session.prefs.consented.length > 0 ||
165
192
  this.session.status === 'ready',
@@ -194,6 +221,9 @@ export class AiState {
194
221
  }
195
222
  /** One sentence on where what the visitor types goes, for the AI page. */
196
223
  get privacyNote() {
224
+ if (this.inference.mode === 'manual') {
225
+ return 'Inference is off. Planning, validation and export still work without a model.';
226
+ }
197
227
  if (this.inference.mode === 'host') {
198
228
  return "Your messages and a short summary of your plan go to this site's server. Voice typing and reading aloud stay on this device.";
199
229
  }
package/dist/ai/status.js CHANGED
@@ -7,6 +7,14 @@ export function deriveCapabilities(input) {
7
7
  }
8
8
  function thinkSummary(t) {
9
9
  const base = { id: 'think', name: 'Think' };
10
+ if (t.mode === 'manual') {
11
+ return {
12
+ ...base,
13
+ state: 'off',
14
+ label: 'Think: inference off',
15
+ where: 'Off',
16
+ };
17
+ }
10
18
  if (t.mode === 'host') {
11
19
  return {
12
20
  ...base,
@@ -52,6 +52,7 @@ export declare class AssistantSession {
52
52
  private loaded;
53
53
  private chat;
54
54
  private abort;
55
+ private loadGeneration;
55
56
  private readonly options;
56
57
  constructor(options: SessionOptions);
57
58
  /**
@@ -40,6 +40,7 @@ export class AssistantSession {
40
40
  loaded = null;
41
41
  chat = null;
42
42
  abort = null;
43
+ loadGeneration = 0;
43
44
  options;
44
45
  constructor(options) {
45
46
  this.options = options;
@@ -65,7 +66,9 @@ export class AssistantSession {
65
66
  ? 'Connect your model on the AI page first, then I can help. The cards on the Planner page work without one.'
66
67
  : this.mode === 'host'
67
68
  ? 'The assistant is not available right now. The cards on the Planner page work without it.'
68
- : 'Download a model first, then I can help. The cards on the Planner page work without one.',
69
+ : this.mode === 'manual'
70
+ ? 'Inference is off. The cards on the Planner page work without it.'
71
+ : 'Download a model first, then I can help. The cards on the Planner page work without one.',
69
72
  onReply: (text) => options.onReply?.(text),
70
73
  });
71
74
  }
@@ -74,14 +77,18 @@ export class AssistantSession {
74
77
  * download; the chat is set with `useRemote`.
75
78
  */
76
79
  setMode(mode) {
80
+ if (mode !== this.mode)
81
+ this.unload();
77
82
  this.mode = mode;
78
83
  if (mode !== 'browser') {
79
- this.unload();
80
84
  this.status = 'idle';
81
85
  }
82
86
  else if (!(this.options.webgpu ?? isWebGPUAvailable)()) {
83
87
  this.status = 'unsupported';
84
88
  }
89
+ else {
90
+ this.status = 'idle';
91
+ }
85
92
  }
86
93
  /** The remote chat model, or null when none is connected (byo, before setup). */
87
94
  useRemote(chat, label) {
@@ -112,11 +119,16 @@ export class AssistantSession {
112
119
  this.error = '';
113
120
  this.progress = { progress: 0, text: 'Starting' };
114
121
  const abort = new AbortController();
122
+ const generation = ++this.loadGeneration;
115
123
  this.abort = abort;
116
124
  try {
117
125
  const loaded = await loadModel(modelId, (report) => {
118
126
  this.progress = report;
119
127
  }, abort.signal, this.options.host ?? browserHost);
128
+ if (generation !== this.loadGeneration || this.mode !== 'browser') {
129
+ loaded.dispose();
130
+ return;
131
+ }
120
132
  this.loaded = loaded;
121
133
  // Consent is recorded only once the download completed: a cancelled or
122
134
  // failed attempt must show the size and memory warning again.
@@ -133,6 +145,8 @@ export class AssistantSession {
133
145
  this.status = 'ready';
134
146
  }
135
147
  catch (error) {
148
+ if (generation !== this.loadGeneration)
149
+ return;
136
150
  if (abort.signal.aborted) {
137
151
  this.status = 'idle';
138
152
  }
@@ -142,7 +156,8 @@ export class AssistantSession {
142
156
  }
143
157
  }
144
158
  finally {
145
- this.abort = null;
159
+ if (generation === this.loadGeneration)
160
+ this.abort = null;
146
161
  }
147
162
  }
148
163
  /** Stop a download in progress. */
@@ -152,7 +167,10 @@ export class AssistantSession {
152
167
  /** Free the model, for example to choose another. */
153
168
  unload() {
154
169
  // A load in progress is aborted too, which terminates its worker.
155
- this.abort?.abort();
170
+ this.loadGeneration += 1;
171
+ const abort = this.abort;
172
+ this.abort = null;
173
+ abort?.abort();
156
174
  this.transport.abort();
157
175
  this.loaded?.dispose();
158
176
  this.loaded = null;
@@ -42,6 +42,12 @@ const byo = $derived(aiState.byo);
42
42
  const thinkWhere = $derived(
43
43
  summaries.find((s) => s.id === 'think')?.where ?? '',
44
44
  );
45
+ const modeLabel = {
46
+ manual: 'Manual planning',
47
+ byo: 'Your model',
48
+ browser: 'In-browser model (WebLLM)',
49
+ host: "This site's server",
50
+ } as const;
45
51
 
46
52
  const model = $derived(getModel(session.prefs.modelId));
47
53
  // A roomy graphics card can run the smarter model; it is only suggested, the
@@ -84,7 +90,28 @@ const handsFreeAvailable = $derived(voice.status === 'ready');
84
90
  </p>
85
91
  </div>
86
92
  </header>
87
- {#if mode === 'host'}
93
+ {#if aiState.availableModes.length > 1}
94
+ <label>
95
+ Assistant mode
96
+ <Select
97
+ value={mode}
98
+ onchange={(event) =>
99
+ aiState.selectInference(event.currentTarget.value as keyof typeof modeLabel)}
100
+ >
101
+ {#each aiState.availableModes as option (option)}
102
+ <option value={option}>{modeLabel[option]}</option>
103
+ {/each}
104
+ </Select>
105
+ </label>
106
+ <p class="meta">Changing modes happens only when you choose it here.</p>
107
+ {/if}
108
+ {#if mode === 'manual'}
109
+ <p class="status">Inference off</p>
110
+ <p class="meta">
111
+ Build, edit, validate and export your cookbook without a model. No
112
+ provider is contacted and no browser model is downloaded.
113
+ </p>
114
+ {:else if mode === 'host'}
88
115
  <p class="status">Server</p>
89
116
  <p class="meta">
90
117
  This site's server answers the assistant. What you type, and a short
@@ -146,7 +173,9 @@ const handsFreeAvailable = $derived(voice.status === 'ready');
146
173
  </p>
147
174
  {/if}
148
175
  <p class="meta">
149
- Stored only in this browser, and sent only to {byo.baseUrl || 'the address above'} (https, or this computer).
176
+ {aiState.inference.credentialPersistence === 'memory'
177
+ ? 'Kept only in this tab until reload'
178
+ : 'Stored only in this browser'}, and sent only to {byo.baseUrl || 'the address above'} (https, or this computer).
150
179
  <button class="link" type="button" onclick={() => byo.forgetKey()}>
151
180
  Forget the key
152
181
  </button>
@@ -33,13 +33,15 @@ const voice = $derived(aiState.voice);
33
33
  const model = $derived(getModel(session.prefs.modelId));
34
34
  const dataSource = useDataSource();
35
35
  const thinkName = $derived(
36
- session.mode === 'browser'
37
- ? model
38
- ? shortLabel(model)
39
- : ''
40
- : session.mode === 'host'
41
- ? 'Server'
42
- : session.remoteLabel,
36
+ session.mode === 'manual'
37
+ ? 'Off'
38
+ : session.mode === 'browser'
39
+ ? model
40
+ ? shortLabel(model)
41
+ : ''
42
+ : session.mode === 'host'
43
+ ? 'Server'
44
+ : session.remoteLabel,
43
45
  );
44
46
 
45
47
  // Applying a cookbook runs the Cookbooks tab's path, with the cookbook's own
@@ -192,7 +194,9 @@ $effect(() => {
192
194
  <h2>Assistant</h2>
193
195
  <p>
194
196
  Describe your business and an assistant adds the matching recipes.
195
- {aiState.inference.mode === 'browser'
197
+ {aiState.inference.mode === 'manual'
198
+ ? 'Inference is off. The Planner page still works without a model.'
199
+ : aiState.inference.mode === 'browser'
196
200
  ? 'It runs on your own device, so nothing you type leaves this page.'
197
201
  : aiState.privacyNote}
198
202
  </p>
@@ -1,12 +1,37 @@
1
+ import type { InferenceConfig } from '../inference/config.ts';
2
+ import type { KitchenEndpoint } from '../kitchen/client.ts';
1
3
  /**
2
- * Absolute path of the prerendered static planner app inside this package
3
- * (`app/`, built with the planner's relative base, so it works at `/` and at
4
- * any sub-path). Node only; kept out of `./core` so that entry stays free of
5
- * Node built-ins.
6
- *
7
- * Serve the files from here, and write your own `planner.config.json` next to
8
- * its `index.html` (copy the directory, or answer that one path yourself).
4
+ * Absolute path of the root-built prerendered planner app inside this package.
5
+ * Node only; kept out of `./core` so that entry stays free of Node built-ins.
6
+ * Serve it at `/`, or use `materializeApp` for a supported subpath artifact.
9
7
  */
10
8
  export declare const appDir: string;
11
- /** Absolute path of one file in the app, e.g. `appFile('planner.config.json')`. */
9
+ /** Absolute path of one packaged app file, e.g. `appFile('index.html')`. */
12
10
  export declare function appFile(relativePath: string): string;
11
+ export interface PlannerAppConfig {
12
+ inference?: InferenceConfig;
13
+ kitchen?: KitchenEndpoint;
14
+ }
15
+ export interface MaterializeAppOptions {
16
+ /** New or empty directory that receives the app root. */
17
+ outDir: string;
18
+ /** Canonical mount prefix: leading slash, no trailing slash, e.g. `/plan`. */
19
+ basePath: string;
20
+ /** Written as `planner.config.json` after validation and normalization. */
21
+ config: PlannerAppConfig;
22
+ }
23
+ export interface MaterializedApp {
24
+ outDir: string;
25
+ configFile: string;
26
+ fallbackFile: string;
27
+ }
28
+ /** Validate and canonicalize a non-root app mount prefix. */
29
+ export declare function normalizeAppBasePath(basePath: string): string;
30
+ /** Validate config strictly enough for an immutable public artifact. */
31
+ export declare function normalizePlannerAppConfig(config: PlannerAppConfig): PlannerAppConfig;
32
+ /**
33
+ * Copy the published static app into a deterministic, prefix-safe deployment
34
+ * artifact. The copy is assembled beside `outDir` and renamed only after its
35
+ * fallback and config validate, so callers never receive a partial tree.
36
+ */
37
+ export declare function materializeApp(options: MaterializeAppOptions): MaterializedApp;
package/dist/core/app.js CHANGED
@@ -1,15 +1,119 @@
1
+ import { cpSync, existsSync, mkdirSync, mkdtempSync, readdirSync, readFileSync, renameSync, rmdirSync, rmSync, statSync, writeFileSync, } from 'node:fs';
2
+ import { dirname, relative, resolve, sep } from 'node:path';
1
3
  import { fileURLToPath } from 'node:url';
4
+ import { validateInferenceConfig } from "../inference/config.js";
5
+ import { parseKitchenConfig } from "../kitchen/client.js";
2
6
  /**
3
- * Absolute path of the prerendered static planner app inside this package
4
- * (`app/`, built with the planner's relative base, so it works at `/` and at
5
- * any sub-path). Node only; kept out of `./core` so that entry stays free of
6
- * Node built-ins.
7
- *
8
- * Serve the files from here, and write your own `planner.config.json` next to
9
- * its `index.html` (copy the directory, or answer that one path yourself).
7
+ * Absolute path of the root-built prerendered planner app inside this package.
8
+ * Node only; kept out of `./core` so that entry stays free of Node built-ins.
9
+ * Serve it at `/`, or use `materializeApp` for a supported subpath artifact.
10
10
  */
11
11
  export const appDir = fileURLToPath(new URL('../../app/', import.meta.url));
12
- /** Absolute path of one file in the app, e.g. `appFile('planner.config.json')`. */
12
+ /** Absolute path of one packaged app file, e.g. `appFile('index.html')`. */
13
13
  export function appFile(relativePath) {
14
14
  return fileURLToPath(new URL(relativePath, new URL('../../app/', import.meta.url)));
15
15
  }
16
+ const sensitiveName = /^(?:api[-_]?key|key|token|authorization|secret|password)$/i;
17
+ /** Validate and canonicalize a non-root app mount prefix. */
18
+ export function normalizeAppBasePath(basePath) {
19
+ if (typeof basePath !== 'string' ||
20
+ !/^\/[A-Za-z0-9._~-]+(?:\/[A-Za-z0-9._~-]+)*$/.test(basePath) ||
21
+ basePath.split('/').some((segment) => segment === '.' || segment === '..')) {
22
+ throw new Error('basePath must start with /, contain URL-safe path segments, and have no trailing slash');
23
+ }
24
+ return basePath;
25
+ }
26
+ function assertCredentialFree(value, path = 'config') {
27
+ if (!value || typeof value !== 'object')
28
+ return;
29
+ if (Array.isArray(value)) {
30
+ value.forEach((entry, index) => {
31
+ assertCredentialFree(entry, `${path}[${index}]`);
32
+ });
33
+ return;
34
+ }
35
+ for (const [name, entry] of Object.entries(value)) {
36
+ if (sensitiveName.test(name)) {
37
+ throw new Error(`${path}.${name} is a credential field and cannot be built into the app`);
38
+ }
39
+ assertCredentialFree(entry, `${path}.${name}`);
40
+ }
41
+ }
42
+ /** Validate config strictly enough for an immutable public artifact. */
43
+ export function normalizePlannerAppConfig(config) {
44
+ if (!config || typeof config !== 'object' || Array.isArray(config)) {
45
+ throw new Error('config must be an object');
46
+ }
47
+ const unknown = Object.keys(config).filter((name) => name !== 'inference' && name !== 'kitchen');
48
+ if (unknown.length)
49
+ throw new Error(`unknown app config field: ${unknown[0]}`);
50
+ assertCredentialFree(config);
51
+ const inference = validateInferenceConfig({
52
+ inference: config.inference,
53
+ });
54
+ if (inference.notice)
55
+ throw new Error(inference.notice);
56
+ let kitchen;
57
+ if (config.kitchen !== undefined) {
58
+ kitchen = parseKitchenConfig(config.kitchen);
59
+ if (!kitchen) {
60
+ throw new Error('kitchen.endpoint must be a usable http(s) URL');
61
+ }
62
+ }
63
+ return {
64
+ inference: inference.config,
65
+ ...(kitchen ? { kitchen } : {}),
66
+ };
67
+ }
68
+ function patchFallback(file, basePath) {
69
+ const source = readFileSync(file, 'utf8');
70
+ if (!source.includes('/_app/') || !/base:\s*""/.test(source)) {
71
+ throw new Error('packaged 404.html does not match the supported root fallback');
72
+ }
73
+ const patched = source
74
+ .replaceAll('/_app/', `${basePath}/_app/`)
75
+ .replace(/base:\s*""/, `base: ${JSON.stringify(basePath)}`);
76
+ if (patched.includes('"/_app/') || /base:\s*""/.test(patched)) {
77
+ throw new Error('could not make the fallback prefix-safe');
78
+ }
79
+ writeFileSync(file, patched);
80
+ }
81
+ /**
82
+ * Copy the published static app into a deterministic, prefix-safe deployment
83
+ * artifact. The copy is assembled beside `outDir` and renamed only after its
84
+ * fallback and config validate, so callers never receive a partial tree.
85
+ */
86
+ export function materializeApp(options) {
87
+ const basePath = normalizeAppBasePath(options.basePath);
88
+ const config = normalizePlannerAppConfig(options.config);
89
+ const outDir = resolve(options.outDir);
90
+ const source = resolve(appDir);
91
+ const relation = relative(source, outDir);
92
+ if (!relation || (!relation.startsWith(`..${sep}`) && relation !== '..')) {
93
+ throw new Error('outDir must be outside the packaged app directory');
94
+ }
95
+ if (existsSync(outDir)) {
96
+ if (!statSync(outDir).isDirectory() || readdirSync(outDir).length > 0) {
97
+ throw new Error('outDir must be new or empty');
98
+ }
99
+ }
100
+ mkdirSync(dirname(outDir), { recursive: true });
101
+ const temporary = mkdtempSync(resolve(dirname(outDir), '.smrt-planner-'));
102
+ try {
103
+ cpSync(source, temporary, { recursive: true });
104
+ patchFallback(resolve(temporary, '404.html'), basePath);
105
+ writeFileSync(resolve(temporary, 'planner.config.json'), `${JSON.stringify(config, null, 2)}\n`);
106
+ if (existsSync(outDir))
107
+ rmdirSync(outDir);
108
+ renameSync(temporary, outDir);
109
+ }
110
+ catch (error) {
111
+ rmSync(temporary, { recursive: true, force: true });
112
+ throw error;
113
+ }
114
+ return {
115
+ outDir,
116
+ configFile: resolve(outDir, 'planner.config.json'),
117
+ fallbackFile: resolve(outDir, '404.html'),
118
+ };
119
+ }
package/dist/index.d.ts CHANGED
@@ -5,7 +5,7 @@
5
5
  *
6
6
  * @module
7
7
  */
8
- export { type ByoPresetDefinition, type ConfigResult, type InferenceConfig, type InferenceMode, loadInferenceConfig, parseInferenceConfig, } from './inference/config.ts';
8
+ export { type ByoPresetDefinition, type ConfigResult, type CredentialPersistence, type InferenceConfig, type InferenceMode, loadInferenceConfig, parseInferenceConfig, } from './inference/config.ts';
9
9
  export { createHostChat, type HostChatOptions, type HostRequest, } from './inference/host.ts';
10
10
  export { createOpenAIChat, testConnection } from './inference/openai.ts';
11
11
  export { type KitchenConfig, type KitchenEndpoint, type KitchenOutcome, type KitchenResult, parseKitchenConfig, sendToKitchen, } from './kitchen/client.ts';
@@ -1,5 +1,5 @@
1
1
  import type { ChatModel } from '../assistant/transport.ts';
2
- import type { ByoPresetDefinition } from './config.ts';
2
+ import type { ByoPresetDefinition, CredentialPersistence } from './config.ts';
3
3
  import { type ConnectionResult } from './openai.ts';
4
4
  /** Choices (not the key): which endpoint, its address and model, and whether it is in use. */
5
5
  export declare const BYO_PREFS_KEY = "smrt-planner:inference:v1";
@@ -24,6 +24,8 @@ export declare function loadByoKeys(storage: Storage | null): Record<string, Byo
24
24
  export type ByoTestStatus = 'idle' | 'testing' | 'ok' | 'failed';
25
25
  export interface ByoOptions {
26
26
  storage: Storage | null;
27
+ /** Credentials default to local storage for compatibility; hosted apps use memory. */
28
+ credentialPersistence?: CredentialPersistence;
27
29
  /** The config's `byo.presets`; default all built-ins. */
28
30
  presets?: readonly (string | ByoPresetDefinition)[];
29
31
  fetch?: typeof fetch;
@@ -33,8 +35,9 @@ export interface ByoOptions {
33
35
  /**
34
36
  * The visitor's own OpenAI-compatible endpoint: the preset they picked, its
35
37
  * address, model and key, a connection test, and whether the assistant uses
36
- * it. The key lives only in this browser's localStorage and is only ever sent
37
- * as the Authorization header to the chosen address.
38
+ * it. The key lives in the configured credential store (tab memory for hosted
39
+ * policies, localStorage for the compatible standalone default) and is only
40
+ * ever sent as the Authorization header to the chosen address.
38
41
  */
39
42
  export declare class ByoModel {
40
43
  readonly presets: ByoPresetDefinition[];
@@ -45,6 +48,7 @@ export declare class ByoModel {
45
48
  testStatus: ByoTestStatus;
46
49
  testMessage: string;
47
50
  private readonly options;
51
+ private readonly credentialStorage;
48
52
  constructor(options: ByoOptions);
49
53
  get preset(): ByoPresetDefinition | undefined;
50
54
  get baseUrl(): string;
@@ -82,5 +86,5 @@ export declare class ByoModel {
82
86
  * (a mounted `Planner` in byo mode has no AI page of its own). Null when none
83
87
  * is connected or what was saved is incomplete.
84
88
  */
85
- export declare function savedByoChat(storage: Storage | null, presets?: readonly (string | ByoPresetDefinition)[], fetcher?: typeof fetch): ChatModel | null;
89
+ export declare function savedByoChat(storage: Storage | null, presets?: readonly (string | ByoPresetDefinition)[], fetcher?: typeof fetch, credentialPersistence?: CredentialPersistence): ChatModel | null;
86
90
  export {};