@stacksjs/defaults 0.75.318 → 0.75.321
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.
- package/ai/skills/stacks-browse/SKILL.md +8 -0
- package/ai/skills/stacks-browse/scripts/browse.ts +16 -6
- package/ai/skills/stacks-browse/scripts/chrome.ts +4 -0
- package/ai/skills/stacks-database/SKILL.md +1 -1
- package/ai/skills/stacks-desktop/SKILL.md +23 -0
- package/ai/skills/stacks-migrations/SKILL.md +2 -2
- package/ai/skills/stacks-native/CATALOG.md +8 -8
- package/app/Actions/Cms/AuthorUpdateAction.ts +4 -4
- package/app/Actions/Cms/CategorizableUpdateAction.ts +4 -4
- package/app/Actions/Cms/PostUpdateAction.ts +4 -5
- package/app/Actions/Cms/TaggableUpdateAction.ts +4 -2
- package/app/Actions/Commerce/CustomerStoreAction.ts +4 -6
- package/app/Actions/Commerce/CustomerUpdateAction.ts +4 -6
- package/app/Actions/Commerce/PaymentStoreAction.ts +5 -8
- package/app/Actions/Commerce/PaymentUpdateAction.ts +20 -17
- package/app/Actions/Dashboard/Commerce/commerce-product-records.test.ts +7 -0
- package/app/Actions/Dashboard/Commerce/commerce-product-records.ts +14 -3
- package/app/Actions/Dashboard/Commerce/review-records.test.ts +12 -0
- package/app/Actions/Dashboard/Commerce/review-records.ts +10 -5
- package/app/Actions/Dashboard/Content/AuthorStoreAction.ts +2 -0
- package/app/Actions/Dashboard/Content/CategoryStoreAction.ts +4 -1
- package/app/Actions/Dashboard/Content/PageStoreAction.ts +2 -0
- package/app/Actions/Dashboard/Content/PostStoreAction.ts +2 -0
- package/app/Actions/Dashboard/Content/TagStoreAction.ts +2 -0
- package/app/Actions/Dashboard/Content/content-input.ts +9 -4
- package/app/Actions/Dashboard/Content/content-record-input.test.ts +20 -1
- package/app/Actions/Dashboard/Marketing/CampaignIndexAction.ts +1 -1
- package/app/Actions/Dashboard/Marketing/ListIndexAction.ts +1 -1
- package/app/Actions/Dashboard/Models/ModelStoreAction.ts +5 -1
- package/app/Actions/Dashboard/Models/ModelUpdateAction.ts +5 -1
- package/app/Actions/Dashboard/Notifications/NotificationDeliveryOverviewAction.ts +1 -1
- package/app/Actions/Storefront/AddToCartAction.ts +5 -2
- package/app/Actions/Storefront/PlaceOrderAction.ts +6 -11
- package/app/Actions/Storefront/SubmitReviewAction.ts +6 -5
- package/app/Models/Activity.ts +1 -0
- package/app/Models/AnalyticsEvent.ts +1 -0
- package/app/Models/AutomationRun.ts +1 -1
- package/app/Models/BoardColumn.ts +0 -1
- package/app/Models/Campaign.ts +1 -1
- package/app/Models/CampaignSend.ts +3 -3
- package/app/Models/Card.ts +0 -1
- package/app/Models/CardComment.ts +0 -2
- package/app/Models/Content/Author.ts +2 -0
- package/app/Models/Content/Categorizable.ts +1 -0
- package/app/Models/Content/Menu.ts +2 -0
- package/app/Models/Content/MenuItem.ts +2 -0
- package/app/Models/Content/PageRevision.ts +2 -0
- package/app/Models/Content/Post.ts +2 -0
- package/app/Models/Content/Redirect.ts +2 -0
- package/app/Models/EmailListSubscriber.ts +2 -2
- package/app/Models/Error.ts +5 -0
- package/app/Models/Forms/Form.ts +2 -0
- package/app/Models/Forms/FormField.ts +2 -0
- package/app/Models/Forms/FormSubmission.ts +2 -0
- package/app/Models/Label.ts +0 -1
- package/app/Models/Log.ts +3 -1
- package/app/Models/MagicLinkToken.ts +0 -7
- package/app/Models/PaymentProduct.ts +1 -0
- package/app/Models/PaymentTransaction.ts +1 -0
- package/app/Models/Release.ts +3 -0
- package/app/Models/Request.ts +1 -0
- package/app/Models/SenderDomain.ts +2 -0
- package/app/Models/SmsOptOut.ts +0 -7
- package/app/Models/Subscription.ts +2 -0
- package/app/Models/commerce/Auction.ts +1 -0
- package/app/Models/commerce/AuctionItem.ts +1 -0
- package/app/Models/commerce/Cart.ts +83 -2
- package/app/Models/commerce/Category.ts +5 -1
- package/app/Models/commerce/Coupon.ts +4 -1
- package/app/Models/commerce/DigitalDelivery.ts +1 -0
- package/app/Models/commerce/GiftCard.ts +1 -0
- package/app/Models/commerce/LoyaltyPoint.ts +1 -0
- package/app/Models/commerce/LoyaltyReward.ts +3 -1
- package/app/Models/commerce/Order.ts +4 -1
- package/app/Models/commerce/OrderItem.ts +1 -0
- package/app/Models/commerce/Payment.ts +1 -0
- package/app/Models/commerce/Product.ts +15 -0
- package/app/Models/commerce/ProductVariant.ts +2 -0
- package/app/Models/commerce/Receipt.ts +1 -0
- package/app/Models/commerce/Review.ts +3 -1
- package/app/Models/commerce/Transaction.ts +1 -0
- package/app/Models/realtime/Websocket.ts +4 -1
- package/functions/dashboard-form.test.ts +10 -1
- package/functions/dashboard-form.ts +17 -0
- package/ide/vscode/package.json +1 -1
- package/package.json +4 -4
- package/resources/components/Dashboard/Analytics/AnalyticsPageHeader.stx +1 -1
- package/resources/components/Dashboard/App/RequestDetailsDialog.stx +1 -1
- package/resources/components/Dashboard/Auth/AccessTokenCreateDialog.stx +1 -1
- package/resources/components/Dashboard/Auth/ForgotPassword.stx +1 -1
- package/resources/components/Dashboard/Auth/Login.stx +1 -1
- package/resources/components/Dashboard/Auth/Register.stx +1 -1
- package/resources/components/Dashboard/Auth/ResetPassword.stx +1 -1
- package/resources/components/Dashboard/Auth/TwoFactorLogin.stx +1 -1
- package/resources/components/Dashboard/CodeEditor.stx +1 -1
- package/resources/components/Dashboard/Commerce/CommerceCategoriesDashboard.stx +1 -1
- package/resources/components/Dashboard/Commerce/CommerceCategoriesTable.stx +1 -1
- package/resources/components/Dashboard/Commerce/CommerceCategoryDeleteDialog.stx +1 -1
- package/resources/components/Dashboard/Commerce/CommerceCategoryDetailsDialog.stx +1 -1
- package/resources/components/Dashboard/Commerce/CommerceCategoryDialog.stx +4 -13
- package/resources/components/Dashboard/Commerce/CommerceCouponDeleteDialog.stx +1 -1
- package/resources/components/Dashboard/Commerce/CommerceCouponDetailsDialog.stx +1 -1
- package/resources/components/Dashboard/Commerce/CommerceCouponDialog.stx +1 -1
- package/resources/components/Dashboard/Commerce/CommerceCouponsTable.stx +1 -1
- package/resources/components/Dashboard/Commerce/CommerceCustomerDeleteDialog.stx +1 -1
- package/resources/components/Dashboard/Commerce/CommerceCustomerDetailsDialog.stx +1 -1
- package/resources/components/Dashboard/Commerce/CommerceCustomerDialog.stx +1 -1
- package/resources/components/Dashboard/Commerce/CommerceCustomersTable.stx +1 -1
- package/resources/components/Dashboard/Commerce/CommerceGiftCardDeleteDialog.stx +1 -1
- package/resources/components/Dashboard/Commerce/CommerceGiftCardDetailsDialog.stx +1 -1
- package/resources/components/Dashboard/Commerce/CommerceGiftCardDialog.stx +1 -1
- package/resources/components/Dashboard/Commerce/CommerceGiftCardsTable.stx +1 -1
- package/resources/components/Dashboard/Commerce/CommerceManufacturerDeleteDialog.stx +1 -1
- package/resources/components/Dashboard/Commerce/CommerceManufacturerDialog.stx +1 -1
- package/resources/components/Dashboard/Commerce/CommerceManufacturersTable.stx +1 -1
- package/resources/components/Dashboard/Commerce/CommerceOrderDeleteDialog.stx +1 -1
- package/resources/components/Dashboard/Commerce/CommerceOrderDetailsDialog.stx +1 -1
- package/resources/components/Dashboard/Commerce/CommerceOrderDialog.stx +1 -1
- package/resources/components/Dashboard/Commerce/CommerceOrdersTable.stx +1 -1
- package/resources/components/Dashboard/Commerce/CommercePaymentsTable.stx +1 -1
- package/resources/components/Dashboard/Commerce/CommercePosCart.stx +1 -1
- package/resources/components/Dashboard/Commerce/CommercePosCatalog.stx +1 -1
- package/resources/components/Dashboard/Commerce/CommercePosCheckoutDialog.stx +1 -1
- package/resources/components/Dashboard/Commerce/CommercePosReceiptDialog.stx +1 -1
- package/resources/components/Dashboard/Commerce/CommerceProductDeleteDialog.stx +1 -1
- package/resources/components/Dashboard/Commerce/CommerceProductDialog.stx +27 -2
- package/resources/components/Dashboard/Commerce/CommerceProductsTable.stx +1 -1
- package/resources/components/Dashboard/Commerce/CommerceReviewDeleteDialog.stx +1 -1
- package/resources/components/Dashboard/Commerce/CommerceReviewEditDialog.stx +7 -5
- package/resources/components/Dashboard/Commerce/CommerceReviewsDashboard.stx +12 -4
- package/resources/components/Dashboard/Commerce/CommerceReviewsTable.stx +3 -3
- package/resources/components/Dashboard/Commerce/CommerceTaxDeleteDialog.stx +1 -1
- package/resources/components/Dashboard/Commerce/CommerceTaxDialog.stx +1 -1
- package/resources/components/Dashboard/Commerce/CommerceTaxesTable.stx +1 -1
- package/resources/components/Dashboard/Commerce/CommerceUnitDeleteDialog.stx +1 -1
- package/resources/components/Dashboard/Commerce/CommerceUnitDialog.stx +1 -1
- package/resources/components/Dashboard/Commerce/CommerceUnitsTable.stx +1 -1
- package/resources/components/Dashboard/Commerce/CommerceVariantDeleteDialog.stx +1 -1
- package/resources/components/Dashboard/Commerce/CommerceVariantDialog.stx +1 -1
- package/resources/components/Dashboard/Commerce/CommerceVariantsTable.stx +1 -1
- package/resources/components/Dashboard/Commerce/Delivery/CourierDeleteDialog.stx +1 -1
- package/resources/components/Dashboard/Commerce/Delivery/CourierDialog.stx +1 -1
- package/resources/components/Dashboard/Commerce/Delivery/CouriersTable.stx +1 -1
- package/resources/components/Dashboard/Commerce/Delivery/DeliveryPagination.stx +1 -1
- package/resources/components/Dashboard/Commerce/Delivery/DeliveryRouteDeleteDialog.stx +1 -1
- package/resources/components/Dashboard/Commerce/Delivery/DeliveryRouteDialog.stx +1 -1
- package/resources/components/Dashboard/Commerce/Delivery/DeliveryRoutesTable.stx +1 -1
- package/resources/components/Dashboard/Commerce/Delivery/DigitalDeliveryDeleteDialog.stx +1 -1
- package/resources/components/Dashboard/Commerce/Delivery/DigitalDeliveryDialog.stx +1 -1
- package/resources/components/Dashboard/Commerce/Delivery/DigitalDeliveryTable.stx +1 -1
- package/resources/components/Dashboard/Commerce/Delivery/LicenseKeyDeleteDialog.stx +1 -1
- package/resources/components/Dashboard/Commerce/Delivery/LicenseKeyDialog.stx +1 -1
- package/resources/components/Dashboard/Commerce/Delivery/LicenseKeysTable.stx +1 -1
- package/resources/components/Dashboard/Commerce/Delivery/ShippingMethodDeleteDialog.stx +1 -1
- package/resources/components/Dashboard/Commerce/Delivery/ShippingMethodDialog.stx +1 -1
- package/resources/components/Dashboard/Commerce/Delivery/ShippingMethodsTable.stx +1 -1
- package/resources/components/Dashboard/Commerce/Delivery/ShippingRateDeleteDialog.stx +1 -1
- package/resources/components/Dashboard/Commerce/Delivery/ShippingRateDialog.stx +1 -1
- package/resources/components/Dashboard/Commerce/Delivery/ShippingRatesTable.stx +1 -1
- package/resources/components/Dashboard/Commerce/Delivery/ShippingZoneDeleteDialog.stx +1 -1
- package/resources/components/Dashboard/Commerce/Delivery/ShippingZoneDialog.stx +1 -1
- package/resources/components/Dashboard/Commerce/Delivery/ShippingZonesTable.stx +1 -1
- package/resources/components/Dashboard/Commerce/PaymentDetailsDialog.stx +1 -1
- package/resources/components/Dashboard/Commerce/PaymentRefundDialog.stx +1 -1
- package/resources/components/Dashboard/Commerce/PrintDeviceDeleteDialog.stx +1 -1
- package/resources/components/Dashboard/Commerce/PrintDeviceDetailsDialog.stx +1 -1
- package/resources/components/Dashboard/Commerce/PrintDeviceDialog.stx +1 -1
- package/resources/components/Dashboard/Commerce/PrintDevicesTable.stx +1 -1
- package/resources/components/Dashboard/Commerce/PrintLogDeleteDialog.stx +1 -1
- package/resources/components/Dashboard/Commerce/PrintLogDetailsDialog.stx +1 -1
- package/resources/components/Dashboard/Commerce/PrintLogsTable.stx +1 -1
- package/resources/components/Dashboard/Commerce/ProductWaitlistDeleteDialog.stx +1 -1
- package/resources/components/Dashboard/Commerce/ProductWaitlistEntryDialog.stx +1 -1
- package/resources/components/Dashboard/Commerce/ProductWaitlistTable.stx +1 -1
- package/resources/components/Dashboard/Commerce/RestaurantWaitlistDeleteDialog.stx +1 -1
- package/resources/components/Dashboard/Commerce/RestaurantWaitlistEntryDialog.stx +1 -1
- package/resources/components/Dashboard/Commerce/RestaurantWaitlistTable.stx +1 -1
- package/resources/components/Dashboard/Content/AuthorEditorDialog.stx +1 -1
- package/resources/components/Dashboard/Content/BlogPostEditorDialog.stx +1 -1
- package/resources/components/Dashboard/Content/CreateFolderDialog.stx +1 -1
- package/resources/components/Dashboard/Content/FileDetailsDrawer.stx +1 -1
- package/resources/components/Dashboard/Content/FileUploadDialog.stx +1 -1
- package/resources/components/Dashboard/Content/PageEditorDialog.stx +1 -1
- package/resources/components/Dashboard/Content/PostEditorDialog.stx +1 -1
- package/resources/components/Dashboard/Content/SeoEditorDialog.stx +1 -1
- package/resources/components/Dashboard/Content/TaxonomyEditorDialog.stx +1 -1
- package/resources/components/Dashboard/CreateRecordModal.stx +1 -1
- package/resources/components/Dashboard/Deployments/DeploymentPreviewDialog.stx +1 -1
- package/resources/components/Dashboard/Elements/DropdownNavigation.stx +1 -1
- package/resources/components/Dashboard/Email/CapturedMailList.stx +1 -1
- package/resources/components/Dashboard/Email/EmailSettingsList.stx +1 -1
- package/resources/components/Dashboard/Email/EmailSettingsNavigation.stx +1 -1
- package/resources/components/Dashboard/Email/EmailSidebar.stx +1 -1
- package/resources/components/Dashboard/Email/InboxComposer.stx +1 -1
- package/resources/components/Dashboard/Email/InboxMessageDetail.stx +1 -1
- package/resources/components/Dashboard/Email/InboxMessageList.stx +1 -1
- package/resources/components/Dashboard/Infrastructure/CloudDetailsDialog.stx +1 -1
- package/resources/components/Dashboard/Infrastructure/CloudResourceButton.stx +1 -1
- package/resources/components/Dashboard/Infrastructure/DnsRecordDialog.stx +1 -1
- package/resources/components/Dashboard/Infrastructure/LogDetailsDialog.stx +1 -1
- package/resources/components/Dashboard/Infrastructure/MailboxDetailsDialog.stx +1 -1
- package/resources/components/Dashboard/Infrastructure/ServerInspectorDialog.stx +1 -1
- package/resources/components/Dashboard/Jobs/JobTable.stx +1 -1
- package/resources/components/Dashboard/Library/SourceScaffoldDialog.stx +1 -1
- package/resources/components/Dashboard/Management/AssignmentDrawer.stx +1 -1
- package/resources/components/Dashboard/Marketing/CampaignDeleteDialog.stx +1 -1
- package/resources/components/Dashboard/Marketing/CampaignDeliveryDialog.stx +1 -1
- package/resources/components/Dashboard/Marketing/CampaignDialog.stx +1 -1
- package/resources/components/Dashboard/Marketing/CampaignsTable.stx +1 -1
- package/resources/components/Dashboard/Marketing/MarketingListDeleteDialog.stx +1 -1
- package/resources/components/Dashboard/Marketing/MarketingListDialog.stx +1 -1
- package/resources/components/Dashboard/Marketing/MarketingListsTable.stx +1 -1
- package/resources/components/Dashboard/Marketing/RecoveryCampaignDialog.stx +1 -1
- package/resources/components/Dashboard/Marketing/SocialPostDeleteDialog.stx +1 -1
- package/resources/components/Dashboard/Marketing/SocialPostDialog.stx +1 -1
- package/resources/components/Dashboard/Marketing/SocialPostsTable.stx +1 -1
- package/resources/components/Dashboard/MobileSidebar.stx +1 -1
- package/resources/components/Dashboard/Modals/BaseModal.stx +1 -1
- package/resources/components/Dashboard/Modals/Popups/Alert.stx +1 -1
- package/resources/components/Dashboard/Modals/Popups/Toast.stx +1 -1
- package/resources/components/Dashboard/Modals/ToastWrapper.stx +1 -1
- package/resources/components/Dashboard/Models/EditRecordModal.stx +1 -1
- package/resources/components/Dashboard/Models/ModelRecordActions.stx +1 -1
- package/resources/components/Dashboard/Monitoring/ErrorTable.stx +1 -1
- package/resources/components/Dashboard/Notifications/NotificationDeliveryDialog.stx +1 -1
- package/resources/components/Dashboard/Notifications/NotificationDeliveryTable.stx +1 -1
- package/resources/components/Dashboard/Operations/RecoveryDestinationDialog.stx +1 -1
- package/resources/components/Dashboard/Operations/RecoveryPointTable.stx +1 -1
- package/resources/components/Dashboard/Operations/RecoveryPolicyDialog.stx +1 -1
- package/resources/components/Dashboard/Operations/RecoveryRestoreDialog.stx +1 -1
- package/resources/components/Dashboard/Operations/SchedulerTaskTable.stx +1 -1
- package/resources/components/Dashboard/UI/Checkbox.stx +1 -1
- package/resources/components/Dashboard/UI/ConfirmDialog.stx +1 -1
- package/resources/components/Dashboard/UI/Drawer.stx +1 -1
- package/resources/components/Dashboard/UI/Dropdown.stx +1 -1
- package/resources/components/Dashboard/UI/Input.stx +1 -1
- package/resources/components/Dashboard/UI/Modal.stx +1 -1
- package/resources/components/Dashboard/UI/Pagination.stx +1 -1
- package/resources/components/Dashboard/UI/SearchFilter.stx +1 -1
- package/resources/components/Dashboard/UI/Select.stx +1 -1
- package/resources/components/Dashboard/UI/Table.stx +1 -1
- package/resources/components/Dashboard/UI/Tabs.stx +1 -1
- package/resources/components/Dashboard/UI/Textarea.stx +1 -1
- package/resources/components/Dashboard/UI/Toggle.stx +1 -1
- package/resources/components/Dashboard/UI/WindowControls.stx +1 -1
- package/resources/components/NativeActionSheet.stx +1 -1
- package/resources/components/NativeContextMenu.stx +1 -1
- package/resources/components/NativeHealthButton.stx +1 -1
- package/resources/components/NativePermissionButton.stx +1 -1
- package/resources/components/NativePullToRefresh.stx +1 -1
- package/resources/components/NativeSegmentedControl.stx +1 -1
- package/resources/components/NativeSheet.stx +1 -1
|
@@ -26,6 +26,13 @@ bun storage/framework/defaults/ai/skills/stacks-browse/scripts/browse.ts <comman
|
|
|
26
26
|
Every command prints a JSON result. Screenshots are written under `storage/framework/runtime/shots/` by
|
|
27
27
|
default; **Read the PNG** to view it.
|
|
28
28
|
|
|
29
|
+
Every command accepts `--scale N` for the native device-pixel ratio, defaulting
|
|
30
|
+
to `1`. It must be one positive finite number. The driver applies it before
|
|
31
|
+
navigation, including scenario runs and every responsive or crawl page. To
|
|
32
|
+
qualify Retina behavior, inspect the page's actual `devicePixelRatio`, canvas
|
|
33
|
+
backing dimensions or resolution media query; a requested value alone is not
|
|
34
|
+
evidence. Scenario reports include the requested `scale`.
|
|
35
|
+
|
|
29
36
|
## Browser discovery (no install step)
|
|
30
37
|
|
|
31
38
|
The driver finds a browser at runtime in this order, and falls through to the next if one
|
|
@@ -112,6 +119,7 @@ Extracts headings, links (`text -> href`), buttons, forms (action + field count)
|
|
|
112
119
|
### Scenario (stateful SPA interactions)
|
|
113
120
|
```bash
|
|
114
121
|
bun storage/framework/defaults/ai/skills/stacks-browse/scripts/browse.ts scenario <url> \
|
|
122
|
+
--scale 2 \
|
|
115
123
|
--step '{"action":"click","selector":"button[data-open]"}' \
|
|
116
124
|
--step '{"action":"focus","selector":"input[name=name]"}' \
|
|
117
125
|
--step '{"action":"evaluate","expression":"window.__stxDevtools?.stats()"}' \
|
|
@@ -600,6 +600,14 @@ function parseViewport(value: string | undefined): { w: number, h: number } {
|
|
|
600
600
|
return { w, h }
|
|
601
601
|
}
|
|
602
602
|
|
|
603
|
+
export function parseDeviceScale(value: string | boolean | Array<string | boolean> | undefined): number {
|
|
604
|
+
if (value === undefined) return 1
|
|
605
|
+
if (typeof value !== 'string' || !value.trim()) throw new TypeError('--scale requires one positive finite device-pixel ratio, for example --scale 2.')
|
|
606
|
+
const scale = Number(value)
|
|
607
|
+
if (!Number.isFinite(scale) || scale <= 0) throw new TypeError(`Invalid --scale "${value}". Expected a positive finite device-pixel ratio.`)
|
|
608
|
+
return scale
|
|
609
|
+
}
|
|
610
|
+
|
|
603
611
|
/** `--scroll-y` on `screenshot`: an explicit document Y to jump to before
|
|
604
612
|
* capturing just the viewport, for content a full-page capture cannot show
|
|
605
613
|
* (sticky/fixed elements, scroll-linked animation) at a specific fold. */
|
|
@@ -851,6 +859,7 @@ async function main() {
|
|
|
851
859
|
process.exit(url ? 0 : 1)
|
|
852
860
|
}
|
|
853
861
|
|
|
862
|
+
const scale = parseDeviceScale(flags.scale)
|
|
854
863
|
let session = await launch()
|
|
855
864
|
const cookies = flagList(flags.cookie)
|
|
856
865
|
const settleMs = flags.settle ? Number(flags.settle) : undefined
|
|
@@ -869,7 +878,7 @@ async function main() {
|
|
|
869
878
|
if (command === 'navigate' || command === 'go') {
|
|
870
879
|
const cdp = await openPage(session.port)
|
|
871
880
|
const t0 = performance.now()
|
|
872
|
-
const state = await gotoAndInstrument(cdp, url, { cookies, settleMs, scheme })
|
|
881
|
+
const state = await gotoAndInstrument(cdp, url, { scale, cookies, settleMs, scheme })
|
|
873
882
|
const loadMs = Math.round(performance.now() - t0)
|
|
874
883
|
console.log(JSON.stringify({
|
|
875
884
|
browser: session.browser,
|
|
@@ -887,7 +896,6 @@ async function main() {
|
|
|
887
896
|
else if (command === 'screenshot') {
|
|
888
897
|
const cdp = await openPage(session.port)
|
|
889
898
|
const viewport = parseViewport(typeof flags.viewport === 'string' ? flags.viewport : undefined)
|
|
890
|
-
const scale = flags.scale ? Number(flags.scale) : 1
|
|
891
899
|
const scrollY = parseScrollY(flags['scroll-y'])
|
|
892
900
|
const modes = [flags.full && 'full', flags.element && 'element', scrollY != null && 'scroll-y'].filter(Boolean)
|
|
893
901
|
if (modes.length > 1)
|
|
@@ -908,7 +916,7 @@ async function main() {
|
|
|
908
916
|
const results: any[] = []
|
|
909
917
|
for (const bp of BREAKPOINTS) {
|
|
910
918
|
const cdp = await openPage(session.port)
|
|
911
|
-
const state = await gotoAndInstrument(cdp, url, { viewport: { w: bp.w, h: bp.h }, cookies, settleMs, scheme, reducedMotion: true })
|
|
919
|
+
const state = await gotoAndInstrument(cdp, url, { viewport: { w: bp.w, h: bp.h }, scale, cookies, settleMs, scheme, reducedMotion: true })
|
|
912
920
|
const overflow = await cdp.send('Runtime.evaluate', {
|
|
913
921
|
// Mobile Chrome may expand innerWidth to fit overflowing content.
|
|
914
922
|
// Compare the page with the requested device width, not that expansion.
|
|
@@ -927,7 +935,7 @@ async function main() {
|
|
|
927
935
|
else if (command === 'monitor') {
|
|
928
936
|
const cdp = await openPage(session.port)
|
|
929
937
|
const ms = flags.ms ? Number(flags.ms) : 5000
|
|
930
|
-
const state = await gotoAndInstrument(cdp, url, { cookies, settleMs, scheme })
|
|
938
|
+
const state = await gotoAndInstrument(cdp, url, { scale, cookies, settleMs, scheme })
|
|
931
939
|
await Bun.sleep(ms)
|
|
932
940
|
const failed = state.responses.filter(r => r.status >= 400)
|
|
933
941
|
const slow = state.responses.filter(r => r.ms > 3000)
|
|
@@ -950,7 +958,7 @@ async function main() {
|
|
|
950
958
|
// auto-imported `state` signal factory, which has no `dispose`, so
|
|
951
959
|
// `browse snapshot` threw on its last line and left the CDP listeners
|
|
952
960
|
// attached.
|
|
953
|
-
const state = await gotoAndInstrument(cdp, url, { cookies, settleMs, scheme })
|
|
961
|
+
const state = await gotoAndInstrument(cdp, url, { scale, cookies, settleMs, scheme })
|
|
954
962
|
const expr = `(() => {
|
|
955
963
|
const sel = (q) => Array.from(document.querySelectorAll(q));
|
|
956
964
|
const txt = (e) => (e.innerText || e.textContent || '').trim().slice(0, 80);
|
|
@@ -976,7 +984,7 @@ async function main() {
|
|
|
976
984
|
|
|
977
985
|
const cdp = await openPage(session.port)
|
|
978
986
|
const viewport = parseViewport(typeof flags.viewport === 'string' ? flags.viewport : undefined)
|
|
979
|
-
const state = await gotoAndInstrument(cdp, url, { viewport, cookies, settleMs, scheme, reducedMotion: !!flags.full })
|
|
987
|
+
const state = await gotoAndInstrument(cdp, url, { viewport, scale, cookies, settleMs, scheme, reducedMotion: !!flags.full })
|
|
980
988
|
const results: Record<string, unknown>[] = []
|
|
981
989
|
await cdp.send('Page.bringToFront')
|
|
982
990
|
await cdp.send('Runtime.evaluate', {
|
|
@@ -1048,6 +1056,7 @@ async function main() {
|
|
|
1048
1056
|
console.log(JSON.stringify({
|
|
1049
1057
|
url,
|
|
1050
1058
|
viewport: `${viewport.w}x${viewport.h}`,
|
|
1059
|
+
scale,
|
|
1051
1060
|
steps: results,
|
|
1052
1061
|
final: finalState,
|
|
1053
1062
|
screenshot,
|
|
@@ -1115,6 +1124,7 @@ async function main() {
|
|
|
1115
1124
|
let state: PageState | undefined
|
|
1116
1125
|
try {
|
|
1117
1126
|
state = await gotoAndInstrument(cdp, current, {
|
|
1127
|
+
scale,
|
|
1118
1128
|
cookies,
|
|
1119
1129
|
settleMs: crawlSettleMs,
|
|
1120
1130
|
scheme,
|
|
@@ -115,6 +115,10 @@ export function prepareMacChrome(options: { source?: string, directory?: string
|
|
|
115
115
|
}
|
|
116
116
|
try {
|
|
117
117
|
run(['/bin/cp', '-cR', sourceApp, staged], 'Cloning Chrome')
|
|
118
|
+
// The clone keeps the installed app's extended attributes (Finder info,
|
|
119
|
+
// provenance, quarantine), and codesign refuses to sign over them:
|
|
120
|
+
// "resource fork, Finder information, or similar detritus not allowed".
|
|
121
|
+
run(['/usr/bin/xattr', '-cr', staged], 'Clearing extended attributes')
|
|
118
122
|
const stagedInfo = join(staged, 'Contents/Info.plist')
|
|
119
123
|
for (const key of UPDATER_KEYS) plist(stagedInfo, `Delete :${key}`)
|
|
120
124
|
run(['/usr/libexec/PlistBuddy', '-c', `Set :CFBundleIdentifier ${PRIVATE_BUNDLE_ID}`, stagedInfo], 'Renaming the Chrome bundle')
|
|
@@ -12,7 +12,7 @@ allowed-tools: Read Edit Write Bash Grep Glob
|
|
|
12
12
|
- Database package: `storage/framework/core/database/src/`
|
|
13
13
|
- Configuration: `config/database.ts`
|
|
14
14
|
- QB config: `config/query-builder.ts`
|
|
15
|
-
- Migrations: `database/migrations/` (
|
|
15
|
+
- Migrations: `database/migrations/` (247 migration files, `.sql` format)
|
|
16
16
|
- QB state: `.qb/`
|
|
17
17
|
- ORM: `storage/framework/orm/`
|
|
18
18
|
|
|
@@ -100,6 +100,29 @@ interface Desktop {
|
|
|
100
100
|
|
|
101
101
|
## Local-first apps: owning the launcher
|
|
102
102
|
|
|
103
|
+
### Model-backed offline native apps
|
|
104
|
+
|
|
105
|
+
An app created with `buddy new <name> --native` can use `craft.config.ts`'s
|
|
106
|
+
`backend: { entry: 'app/Desktop/api.ts' }` to bundle a Bun backend. The native
|
|
107
|
+
host owns an authenticated ephemeral loopback session and the backend's lifetime.
|
|
108
|
+
The binary does not need an installed Bun, external server or source files.
|
|
109
|
+
|
|
110
|
+
Define models under `app/Models` with `defineModel` from `@stacksjs/orm/define-model`.
|
|
111
|
+
In the backend, import those models explicitly and use `openNativeDatabase` and
|
|
112
|
+
`createNativeModelApi` from `@stacksjs/orm/native`. Pass an absolute SQLite path
|
|
113
|
+
inside Application Support and an explicit model registry. The same query-builder
|
|
114
|
+
migration planner derives the schema and atomically records its snapshot in the
|
|
115
|
+
database. Additive upgrades preserve rows; destructive changes are refused.
|
|
116
|
+
|
|
117
|
+
CRUD follows `traits.useApi.uri` and its explicit `routes` list. Native models
|
|
118
|
+
declare `middleware: []` because the transport owns session authorization.
|
|
119
|
+
`createNativeModelApi` requires an `authorize(request, model, ability)` callback
|
|
120
|
+
on every request. Only return true unconditionally when the handler runs solely
|
|
121
|
+
behind stx's authenticated native backend. Never expose that handler through an
|
|
122
|
+
unprotected HTTP server. Web middleware declarations are refused by this native
|
|
123
|
+
adapter instead of silently skipped. Writes use the model's validation, fillable
|
|
124
|
+
allowlist and hidden-field serialization; index requests have bounded pagination.
|
|
125
|
+
|
|
103
126
|
The launcher Stacks compiles opens a Craft window on the URL in `desktop.json`,
|
|
104
127
|
which is what a hosted Stacks application wants. An app whose subject is the
|
|
105
128
|
machine it runs on - a disk cleaner, a log viewer, a device tool - has no such
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: stacks-migrations
|
|
3
|
-
description: Use when working with database migrations in a Stacks application - creating migration files, running migrations, fresh migration (drop + recreate), seeding after migration, migration file naming conventions, or the
|
|
3
|
+
description: Use when working with database migrations in a Stacks application - creating migration files, running migrations, fresh migration (drop + recreate), seeding after migration, migration file naming conventions, or the 247 built-in migration files. For the database API itself (queries, connections, SQL helpers), see stacks-database.
|
|
4
4
|
license: MIT
|
|
5
5
|
compatibility: Bun >= 1.3.0, TypeScript, SQLite >= 3.47.2
|
|
6
6
|
allowed-tools: Read Edit Write Bash Grep Glob
|
|
@@ -236,7 +236,7 @@ lossless widenings; reports everything destructive), then
|
|
|
236
236
|
- Do not commit a second snapshot under `.qb/`; that indicates a missing `snapshotDir` configuration
|
|
237
237
|
- If a generated SQLite migration rebuilds tables, test it against a copy of the current database and run `PRAGMA integrity_check` plus `PRAGMA foreign_key_check`
|
|
238
238
|
- `--seed` flag after `migrate:fresh` seeds the database with factory data
|
|
239
|
-
-
|
|
239
|
+
- 247 migration files exist by default for all framework models
|
|
240
240
|
- SQLite >= 3.47.2 is required (system requirement)
|
|
241
241
|
- For the database API (queries, connections), see the `stacks-database` skill
|
|
242
242
|
|
|
@@ -35,7 +35,7 @@ Browser runtime bindings are documented separately in `stacks-auto-imports`.
|
|
|
35
35
|
| `@stacksjs/composables` | [`stacks-composables`](../stacks-composables/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/composables/src/index.ts) | 18 |
|
|
36
36
|
| `@stacksjs/config` | [`stacks-config`](../stacks-config/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/config/src/index.ts) | 16 |
|
|
37
37
|
| `@stacksjs/cron` | [`stacks-cron`](../stacks-cron/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/cron/src/index.ts) | 4 |
|
|
38
|
-
| `@stacksjs/database` | [`stacks-database`](../stacks-database/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/index.ts) |
|
|
38
|
+
| `@stacksjs/database` | [`stacks-database`](../stacks-database/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/index.ts) | 135 |
|
|
39
39
|
| `@stacksjs/datetime` | [`stacks-datetime`](../stacks-datetime/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/datetime/src/index.ts) | 13 |
|
|
40
40
|
| `@stacksjs/defaults` | [`stacks-build`](../stacks-build/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/defaults/package.json) | 2 |
|
|
41
41
|
| `@stacksjs/deploy` | [`stacks-deploy`](../stacks-deploy/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/deploy/package.json) | 1 |
|
|
@@ -65,7 +65,7 @@ Browser runtime bindings are documented separately in `stacks-auto-imports`.
|
|
|
65
65
|
| `@stacksjs/newsletter` | [`stacks-newsletter`](../stacks-newsletter/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/newsletter/src/index.ts) | 7 |
|
|
66
66
|
| `@stacksjs/notifications` | [`stacks-notifications`](../stacks-notifications/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/notifications/src/index.ts) | 16 |
|
|
67
67
|
| `@stacksjs/objects` | [`stacks-objects`](../stacks-objects/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/objects/src/index.ts) | 4 |
|
|
68
|
-
| `@stacksjs/orm` | [`stacks-orm`](../stacks-orm/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/index.ts) |
|
|
68
|
+
| `@stacksjs/orm` | [`stacks-orm`](../stacks-orm/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/index.ts) | 73 |
|
|
69
69
|
| `@stacksjs/pagination` | [`stacks-pagination`](../stacks-pagination/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/pagination/src/index.ts) | 0 |
|
|
70
70
|
| `@stacksjs/path` | [`stacks-path`](../stacks-path/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/path/src/index.ts) | 13 |
|
|
71
71
|
| `@stacksjs/payments` | [`stacks-payments`](../stacks-payments/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/payments/src/index.ts) | 29 |
|
|
@@ -75,7 +75,7 @@ Browser runtime bindings are documented separately in `stacks-auto-imports`.
|
|
|
75
75
|
| `@stacksjs/realtime` | [`stacks-realtime`](../stacks-realtime/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/realtime/src/index.ts) | 12 |
|
|
76
76
|
| `@stacksjs/registry` | [`stacks-registry`](../stacks-registry/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/registry/src/index.ts) | 1 |
|
|
77
77
|
| `@stacksjs/repl` | [`stacks-repl`](../stacks-repl/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/repl/src/index.ts) | 2 |
|
|
78
|
-
| `@stacksjs/router` | [`stacks-router`](../stacks-router/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/index.ts) |
|
|
78
|
+
| `@stacksjs/router` | [`stacks-router`](../stacks-router/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/index.ts) | 96 |
|
|
79
79
|
| `@stacksjs/scheduler` | [`stacks-scheduler`](../stacks-scheduler/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/scheduler/src/index.ts) | 14 |
|
|
80
80
|
| `@stacksjs/search-engine` | [`stacks-search-engine`](../stacks-search-engine/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/search-engine/src/index.ts) | 11 |
|
|
81
81
|
| `@stacksjs/security` | [`stacks-security`](../stacks-security/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/security/src/index.ts) | 11 |
|
|
@@ -83,7 +83,7 @@ Browser runtime bindings are documented separately in `stacks-auto-imports`.
|
|
|
83
83
|
| `@stacksjs/shell` | [`stacks-shell`](../stacks-shell/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/shell/src/index.ts) | 1 |
|
|
84
84
|
| `@stacksjs/sites` | [`stacks-sites`](../stacks-sites/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/sites/src/index.ts) | 3 |
|
|
85
85
|
| `@stacksjs/skills` | [`stacks-skills`](../stacks-skills/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/skills/src/index.ts) | 1 |
|
|
86
|
-
| `@stacksjs/slug` | [`stacks-slug`](../stacks-slug/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/slug/src/index.ts) |
|
|
86
|
+
| `@stacksjs/slug` | [`stacks-slug`](../stacks-slug/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/slug/src/index.ts) | 5 |
|
|
87
87
|
| `@stacksjs/sms` | [`stacks-sms`](../stacks-sms/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/sms/src/index.ts) | 5 |
|
|
88
88
|
| `@stacksjs/socials` | [`stacks-socials`](../stacks-socials/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/socials/src/index.ts) | 17 |
|
|
89
89
|
| `@stacksjs/storage` | [`stacks-storage`](../stacks-storage/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/src/index.ts) | 42 |
|
|
@@ -353,7 +353,7 @@ Declared runtime exports: `Database`, `EntityQueryBuilder`, `__flushAfterCommitN
|
|
|
353
353
|
|
|
354
354
|
Local source modules: [src/affected-rows.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/affected-rows.ts), [src/auth-tables.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/auth-tables.ts), [src/custom/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/custom/index.ts), [src/database.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/database.ts), [src/datetime-columns.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/datetime-columns.ts), [src/ddl-constraints.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/ddl-constraints.ts), [src/defaults.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/defaults.ts), [src/dialect.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/dialect.ts), [src/driver-config.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/driver-config.ts), [src/drivers/dynamodb.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/drivers/dynamodb.ts), [src/drivers/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/drivers/index.ts), [src/ensure-database.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/ensure-database.ts), [src/erd.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/erd.ts), [src/fk-audit.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/fk-audit.ts), [src/framework-renames.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/framework-renames.ts), [src/framework-route-admission.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/framework-route-admission.ts), [src/hand-written-migrations.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/hand-written-migrations.ts), [src/ignored-migrations.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/ignored-migrations.ts), [src/index-shape.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/index-shape.ts), [src/managed-columns.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/managed-columns.ts), [src/migration-dialect.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/migration-dialect.ts), [src/migration-ledger.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/migration-ledger.ts), [src/migration-names.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/migration-names.ts), [src/migration-path.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/migration-path.ts), [src/migrations.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/migrations.ts), [src/model-sources.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/model-sources.ts), [src/notification-tables.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/notification-tables.ts), [src/package-migrations.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/package-migrations.ts), [src/package-models.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/package-models.ts), [src/query-logger.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/query-logger.ts), [src/rbac-tables.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/rbac-tables.ts), [src/relation-columns.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/relation-columns.ts), [src/replicas.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/replicas.ts), [src/row-lock.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/row-lock.ts), [src/safe-migrations.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/safe-migrations.ts), [src/schema-align.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/schema-align.ts), [src/schema-drift.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/schema-drift.ts), [src/seeder.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/seeder.ts), [src/shadowed-models.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/shadowed-models.ts), [src/sql-helpers.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/sql-helpers.ts), [src/trait-tables.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/trait-tables.ts), [src/transaction-context.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/transaction-context.ts), [src/types.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/types.ts), [src/unique-audit.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/unique-audit.ts), [src/utc-defaults.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/utc-defaults.ts), [src/utils.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/utils.ts), [src/uuid-columns.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/uuid-columns.ts), [src/vschema.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/vschema.ts).
|
|
355
355
|
|
|
356
|
-
Evidence directory: [
|
|
356
|
+
Evidence directory: [135 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
|
|
357
357
|
|
|
358
358
|
### @stacksjs/datetime
|
|
359
359
|
|
|
@@ -635,7 +635,7 @@ Declared runtime exports: `Activity`, `AnalyticsEvent`, `Auction`, `AuctionItem`
|
|
|
635
635
|
|
|
636
636
|
Local source modules: [src/auto-crud.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/auto-crud.ts), [src/batch-loader.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/batch-loader.ts), [src/db.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/db.ts), [src/define-model.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/define-model.ts), [src/extend-model.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/extend-model.ts), [src/gdpr/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/gdpr/index.ts), [src/generate-database-schema.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/generate-database-schema.ts), [src/locked-row.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/locked-row.ts), [src/messaging.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/messaging.ts), [src/model-types.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/model-types.ts), [src/ownership.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/ownership.ts), [src/paginator-request.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/paginator-request.ts), [src/row-token.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/row-token.ts), [src/subquery.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/subquery.ts), [src/traits/audit.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/traits/audit.ts), [src/traits/billable.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/traits/billable.ts), [src/traits/categorizable.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/traits/categorizable.ts), [src/traits/commentable.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/traits/commentable.ts), [src/traits/likeable.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/traits/likeable.ts), [src/traits/taggable.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/traits/taggable.ts), [src/transaction.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/transaction.ts), [src/types.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/types.ts), [src/utils/encrypted.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/utils/encrypted.ts), [src/utils/prunable.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/utils/prunable.ts).
|
|
637
637
|
|
|
638
|
-
Evidence directory: [
|
|
638
|
+
Evidence directory: [73 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
|
|
639
639
|
|
|
640
640
|
### @stacksjs/pagination
|
|
641
641
|
|
|
@@ -725,7 +725,7 @@ Declared runtime exports: `DASHBOARD_ROUTE_GROUPS`, `DEFAULT_ROUTE_BUNDLE_FEATUR
|
|
|
725
725
|
|
|
726
726
|
Local source modules: [src/api-shape.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/api-shape.ts), [src/body.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/body.ts), [src/dashboard-access.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/dashboard-access.ts), [src/encrypted-session-store.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/encrypted-session-store.ts), [src/error-handler.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/error-handler.ts), [src/health.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/health.ts), [src/json.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/json.ts), [src/middleware.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/middleware.ts), [src/path-sanitize.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/path-sanitize.ts), [src/rate-limit.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/rate-limit.ts), [src/request-augmentation.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/request-augmentation.ts), [src/request-context.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/request-context.ts), [src/route-loader.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/route-loader.ts), [src/route-model-binding.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/route-model-binding.ts), [src/security-settings.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/security-settings.ts), [src/session-factory.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/session-factory.ts), [src/signed-url.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/signed-url.ts), [src/stacks-router.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/stacks-router.ts), [src/typed-router.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/typed-router.ts).
|
|
727
727
|
|
|
728
|
-
Evidence directory: [
|
|
728
|
+
Evidence directory: [96 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
|
|
729
729
|
|
|
730
730
|
### @stacksjs/scheduler
|
|
731
731
|
|
|
@@ -803,7 +803,7 @@ Read the entrypoint and package export map for re-exported or type-only surfaces
|
|
|
803
803
|
|
|
804
804
|
Local source modules: [src/unique.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/slug/src/unique.ts).
|
|
805
805
|
|
|
806
|
-
Evidence directory: [
|
|
806
|
+
Evidence directory: [5 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/slug/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
|
|
807
807
|
|
|
808
808
|
### @stacksjs/sms
|
|
809
809
|
|
|
@@ -14,10 +14,10 @@ export default new Action({
|
|
|
14
14
|
return response.json({ error: 'Author not found' }, 404)
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
// Only the fields the request sent: an absent one copied through
|
|
18
|
+
// request.get() reached the query as undefined, which binds NULL and
|
|
19
|
+
// erased the stored value (stacksjs/stacks#3010).
|
|
20
|
+
const result = await author.update(request.only(['name', 'email']))
|
|
21
21
|
|
|
22
22
|
return response.json(result)
|
|
23
23
|
},
|
|
@@ -31,10 +31,10 @@ export default new Action({
|
|
|
31
31
|
|
|
32
32
|
const id = Number(request.getParam('id'))
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
34
|
+
// Only the fields the request sent: an absent one copied through
|
|
35
|
+
// request.get() reached the query as undefined, which binds NULL and
|
|
36
|
+
// erased the stored value (stacksjs/stacks#3010).
|
|
37
|
+
const data = request.only(['name', 'description'])
|
|
38
38
|
|
|
39
39
|
const model = await categorizable.update({ id, ...data })
|
|
40
40
|
|
|
@@ -16,12 +16,11 @@ export default new Action({
|
|
|
16
16
|
|
|
17
17
|
const id = Number(request.getParam('id'))
|
|
18
18
|
|
|
19
|
+
// Only the fields the request sent: an absent one copied through
|
|
20
|
+
// request.get() reached the query as undefined, which binds NULL and
|
|
21
|
+
// erased the stored value (stacksjs/stacks#3010).
|
|
19
22
|
const data = {
|
|
20
|
-
|
|
21
|
-
excerpt: request.get('excerpt'),
|
|
22
|
-
content: request.get('content'),
|
|
23
|
-
status: request.get('status'),
|
|
24
|
-
poster: request.get('poster'),
|
|
23
|
+
...request.only(['title', 'excerpt', 'content', 'status', 'poster']),
|
|
25
24
|
updated_at: formatDate(new Date()),
|
|
26
25
|
}
|
|
27
26
|
|
|
@@ -30,10 +30,12 @@ export default new Action({
|
|
|
30
30
|
})
|
|
31
31
|
|
|
32
32
|
const id = Number(request.getParam('id'))
|
|
33
|
+
// Only the fields the request sent: an absent one copied through
|
|
34
|
+
// request.get() reached the query as undefined, which binds NULL and
|
|
35
|
+
// erased the stored value (stacksjs/stacks#3010).
|
|
33
36
|
const data = {
|
|
34
37
|
id,
|
|
35
|
-
|
|
36
|
-
description: request.get('description'),
|
|
38
|
+
...request.only(['name', 'description']),
|
|
37
39
|
}
|
|
38
40
|
|
|
39
41
|
const model = await tags.update(data)
|
|
@@ -14,13 +14,11 @@ export default new Action({
|
|
|
14
14
|
async handle(request) {
|
|
15
15
|
await request.validate()
|
|
16
16
|
|
|
17
|
+
// Only the fields the request sent: an absent one copied through
|
|
18
|
+
// request.get() reached the query as undefined, which binds NULL and
|
|
19
|
+
// erased the stored value or the column default (stacksjs/stacks#3010).
|
|
17
20
|
const data = toSnakeCaseKeys({
|
|
18
|
-
|
|
19
|
-
email: request.get('email'),
|
|
20
|
-
phone: request.get('phone'),
|
|
21
|
-
totalSpent: request.get('totalSpent'),
|
|
22
|
-
status: request.get('status'),
|
|
23
|
-
avatar: request.get('avatar'),
|
|
21
|
+
...request.only(['name', 'email', 'phone', 'totalSpent', 'status', 'avatar']),
|
|
24
22
|
uuid: randomUUIDv7(),
|
|
25
23
|
...(request.get('lastOrder') && { lastOrder: request.get('lastOrder') }),
|
|
26
24
|
})
|
|
@@ -18,13 +18,11 @@ export default new Action({
|
|
|
18
18
|
const { id } = identifier
|
|
19
19
|
|
|
20
20
|
await request.validate()
|
|
21
|
+
// Only the fields the request sent: an absent one copied through
|
|
22
|
+
// request.get() reached the query as undefined, which binds NULL and
|
|
23
|
+
// erased the stored value or the column default (stacksjs/stacks#3010).
|
|
21
24
|
const data = toSnakeCaseKeys({
|
|
22
|
-
|
|
23
|
-
email: request.get('email'),
|
|
24
|
-
phone: request.get('phone'),
|
|
25
|
-
totalSpent: request.get('totalSpent'),
|
|
26
|
-
status: request.get('status'),
|
|
27
|
-
avatar: request.get('avatar'),
|
|
25
|
+
...request.only(['name', 'email', 'phone', 'totalSpent', 'status', 'avatar']),
|
|
28
26
|
...(request.get('lastOrder') && { lastOrder: request.get('lastOrder') }),
|
|
29
27
|
})
|
|
30
28
|
|
|
@@ -9,15 +9,12 @@ export default new Action({
|
|
|
9
9
|
async handle(request: RequestInstance) {
|
|
10
10
|
await request.validate()
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
method: request.get('method'),
|
|
17
|
-
status: request.get('status'),
|
|
18
|
-
}
|
|
12
|
+
// Only the fields the request sent: an absent one copied through
|
|
13
|
+
// request.get() reached the query as undefined, which binds NULL and
|
|
14
|
+
// erased the stored value or the column default (stacksjs/stacks#3010).
|
|
15
|
+
const data = request.only(['order_id', 'customer_id', 'amount', 'method', 'status'])
|
|
19
16
|
|
|
20
|
-
const model = await payments.store(data)
|
|
17
|
+
const model = await payments.store(data as Parameters<typeof payments.store>[0])
|
|
21
18
|
|
|
22
19
|
return response.json(model)
|
|
23
20
|
},
|
|
@@ -14,24 +14,27 @@ export default new Action({
|
|
|
14
14
|
const { id } = identifier
|
|
15
15
|
|
|
16
16
|
await request.validate()
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
17
|
+
// Only the fields the request sent: an absent one copied through
|
|
18
|
+
// request.get() reached the query as undefined, which binds NULL and
|
|
19
|
+
// erased the stored value or the column default (stacksjs/stacks#3010).
|
|
20
|
+
const data = request.only([
|
|
21
|
+
'order_id',
|
|
22
|
+
'customer_id',
|
|
23
|
+
'amount',
|
|
24
|
+
'method',
|
|
25
|
+
'status',
|
|
26
|
+
'currency',
|
|
27
|
+
'reference_number',
|
|
28
|
+
'card_last_four',
|
|
29
|
+
'card_brand',
|
|
30
|
+
'billing_email',
|
|
31
|
+
'transaction_id',
|
|
32
|
+
'payment_provider',
|
|
33
|
+
'refund_amount',
|
|
34
|
+
'notes',
|
|
35
|
+
])
|
|
33
36
|
|
|
34
|
-
const model = await payments.update(id, data)
|
|
37
|
+
const model = await payments.update(id, data as Parameters<typeof payments.update>[1])
|
|
35
38
|
if (!model)
|
|
36
39
|
return commerceNotFound('Payment', id)
|
|
37
40
|
|
|
@@ -15,6 +15,7 @@ describe('dashboard commerce product records', () => {
|
|
|
15
15
|
const record = normalizeCommerceProductRecord({
|
|
16
16
|
id: 5,
|
|
17
17
|
name: 'Native Kit',
|
|
18
|
+
slug: 'native-kit',
|
|
18
19
|
price: 125,
|
|
19
20
|
is_available: 1,
|
|
20
21
|
inventory_count: 7,
|
|
@@ -29,6 +30,7 @@ describe('dashboard commerce product records', () => {
|
|
|
29
30
|
expect(record).toMatchObject({
|
|
30
31
|
id: '5',
|
|
31
32
|
name: 'Native Kit',
|
|
33
|
+
slug: 'native-kit',
|
|
32
34
|
price: 125,
|
|
33
35
|
isAvailable: true,
|
|
34
36
|
inventoryCount: 7,
|
|
@@ -72,6 +74,7 @@ describe('dashboard commerce product records', () => {
|
|
|
72
74
|
normalizeCommerceProductRecord({
|
|
73
75
|
id: 1,
|
|
74
76
|
name: 'Available',
|
|
77
|
+
slug: 'available',
|
|
75
78
|
price: 100,
|
|
76
79
|
isAvailable: true,
|
|
77
80
|
inventoryCount: 3,
|
|
@@ -81,6 +84,7 @@ describe('dashboard commerce product records', () => {
|
|
|
81
84
|
normalizeCommerceProductRecord({
|
|
82
85
|
id: 2,
|
|
83
86
|
name: 'Unavailable',
|
|
87
|
+
slug: 'unavailable',
|
|
84
88
|
price: 100,
|
|
85
89
|
isAvailable: false,
|
|
86
90
|
inventoryCount: 0,
|
|
@@ -101,6 +105,7 @@ describe('dashboard commerce product records', () => {
|
|
|
101
105
|
const base = {
|
|
102
106
|
id: 1,
|
|
103
107
|
name: 'Native Kit',
|
|
108
|
+
slug: 'native-kit',
|
|
104
109
|
price: 125,
|
|
105
110
|
is_available: 1,
|
|
106
111
|
inventory_count: 7,
|
|
@@ -132,6 +137,8 @@ describe('dashboard commerce product records', () => {
|
|
|
132
137
|
new Map(),
|
|
133
138
|
new Map(),
|
|
134
139
|
)).toThrow('references missing Category 99')
|
|
140
|
+
// An unrated review counts as a review, not as a 0-star one (#2999).
|
|
141
|
+
expect(summarizeProductReviews([{ rating: null, is_approved: 1 }, { rating: 4, is_approved: 0 }]).averageRating).toBe(4)
|
|
135
142
|
expect(() => summarizeProductReviews([{ rating: 'unknown', is_approved: 1 }]))
|
|
136
143
|
.toThrow('Review 1.rating must be a finite number')
|
|
137
144
|
expect(() => normalizeCommerceCurrency('US')).toThrow('three-letter currency code')
|
|
@@ -4,6 +4,8 @@ import { commerceTimestamp } from './commerce-record'
|
|
|
4
4
|
export interface CommerceProductRecord {
|
|
5
5
|
id: string
|
|
6
6
|
name: string
|
|
7
|
+
/** The storefront address, /products/{slug} (stacksjs/stacks#3005). */
|
|
8
|
+
slug: string
|
|
7
9
|
description: string
|
|
8
10
|
/** Integer minor units of the store currency (1999 is $19.99 in USD). */
|
|
9
11
|
price: number
|
|
@@ -68,6 +70,7 @@ export interface ProductReviewSummary {
|
|
|
68
70
|
*/
|
|
69
71
|
export interface ProductFormFields {
|
|
70
72
|
name: string
|
|
73
|
+
slug: string
|
|
71
74
|
description: string
|
|
72
75
|
price: string
|
|
73
76
|
imageUrl: string
|
|
@@ -83,6 +86,7 @@ export interface ProductFormFields {
|
|
|
83
86
|
/** What the dialog sends to `POST`/`PATCH /api/dashboard/commerce/products`. */
|
|
84
87
|
export interface ProductWritePayload {
|
|
85
88
|
name: string
|
|
89
|
+
slug: string
|
|
86
90
|
description: string
|
|
87
91
|
/** Integer minor units, never a decimal (stacksjs/stacks#2851). */
|
|
88
92
|
price: number
|
|
@@ -116,6 +120,7 @@ export function productWritePayload(form: ProductFormFields, currency: string):
|
|
|
116
120
|
const allergens = form.allergens.split(',').map(item => item.trim()).filter(Boolean)
|
|
117
121
|
return {
|
|
118
122
|
name: form.name.trim(),
|
|
123
|
+
slug: form.slug.trim(),
|
|
119
124
|
description: form.description.trim(),
|
|
120
125
|
price: parseMoneyInput(form.price, currency, { min: MIN_PRODUCT_PRICE }),
|
|
121
126
|
imageUrl: form.imageUrl.trim(),
|
|
@@ -285,6 +290,7 @@ export function normalizeCommerceProductRecord(
|
|
|
285
290
|
return {
|
|
286
291
|
id,
|
|
287
292
|
name: requiredText(value(product, 'name'), source, 'name'),
|
|
293
|
+
slug: requiredText(value(product, 'slug'), source, 'slug'),
|
|
288
294
|
description: optionalText(value(product, 'description'), source, 'description'),
|
|
289
295
|
price: number(value(product, 'price'), source, 'price', { min: 0 }),
|
|
290
296
|
imageUrl: optionalText(value(product, 'image_url', 'imageUrl'), source, 'image_url'),
|
|
@@ -352,9 +358,14 @@ export function summarizeCommerceProducts(records: CommerceProductRecord[]): Com
|
|
|
352
358
|
}
|
|
353
359
|
|
|
354
360
|
export function summarizeProductReviews(records: any[]): ProductReviewSummary {
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
)
|
|
361
|
+
// A review can be words without stars; it counts toward the total, not the
|
|
362
|
+
// average.
|
|
363
|
+
const ratings = records.flatMap((record, index) => {
|
|
364
|
+
const rating = value(record, 'rating')
|
|
365
|
+
return rating === null || rating === undefined
|
|
366
|
+
? []
|
|
367
|
+
: [number(rating, `Review ${index + 1}`, 'rating', { min: 1, max: 5 })]
|
|
368
|
+
})
|
|
358
369
|
const approved = records.filter((record, index) =>
|
|
359
370
|
boolean(value(record, 'is_approved', 'isApproved'), `Review ${index + 1}`, 'is_approved'),
|
|
360
371
|
).length
|
|
@@ -108,6 +108,18 @@ describe('dashboard review records', () => {
|
|
|
108
108
|
})
|
|
109
109
|
})
|
|
110
110
|
|
|
111
|
+
// A review can be words with no stars (9b8dd223e8), and one unrated review
|
|
112
|
+
// made the whole list answer 503 (stacksjs/stacks#2999).
|
|
113
|
+
test('keeps a review without a star rating, and averages only the rated ones', () => {
|
|
114
|
+
const unrated = normalizeReviewRecord(review({ rating: null }), new Map(), new Map())
|
|
115
|
+
expect(unrated.rating).toBeNull()
|
|
116
|
+
expect(() => normalizeReviewRecord(review({ rating: 6 }), new Map(), new Map())).toThrow('rating must be at most 5')
|
|
117
|
+
|
|
118
|
+
const rated = normalizeReviewRecord(review({ id: 10, rating: 4 }), new Map(), new Map())
|
|
119
|
+
expect(summarizeReviews([unrated, rated]).averageRating).toBe(4)
|
|
120
|
+
expect(summarizeReviews([unrated]).averageRating).toBe(0)
|
|
121
|
+
})
|
|
122
|
+
|
|
111
123
|
test('validates Product options and Customer context records', () => {
|
|
112
124
|
expect(normalizeReviewProductOption({ id: 4, name: 'Native Kit' }))
|
|
113
125
|
.toEqual({ id: '4', label: 'Native Kit' })
|