@stacksjs/orm 0.75.112 → 0.75.114

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/README.md CHANGED
@@ -46,3 +46,20 @@ Many thanks to the following core technologies & people who have contributed to
46
46
  The MIT License (MIT). Please see [LICENSE](https://github.com/stacksjs/stacks/tree/main/LICENSE.md) for more information.
47
47
 
48
48
  Made with 💙
49
+
50
+ ## Scoped locked operations and stored link credentials
51
+
52
+ `withLockedRow(table, scope, async (row, tx) => ..., { tx? })` locks and reads
53
+ a scoped row on one reserved connection. It returns null for a missing row.
54
+ Use the callback handle for every related read/write; `tx` reuses an enclosing
55
+ transaction. A scope must identify one row; empty or non-unique scopes are refused. This is the query-builder seam: model
56
+ casts, fillable filtering and lifecycle hooks remain the caller's responsibility.
57
+
58
+ `rowToken({ table, scope, column, action, tx?, timestampColumn? })` manages a
59
+ stored share/feed credential. Read returns the live token; enable preserves
60
+ it; rotate replaces it; disable clears it. Mutations serialize under the row
61
+ lock and join an enclosing transaction when supplied. Missing owners throw
62
+ `RowTokenNotFoundError` (404). The default timestamp column is updated_at;
63
+ pass false for a table without timestamps. Identifiers and scope must be
64
+ application-selected, and the caller must authorize that owner. This is for
65
+ stored public-link secrets, not hashed authentication tokens with expiry.
package/dist/index.d.ts CHANGED
@@ -303,6 +303,8 @@ export * from './batch-loader';
303
303
  export * from './db';
304
304
  export * from './subquery';
305
305
  export * from './transaction';
306
+ export * from './locked-row';
307
+ export * from './row-token';
306
308
  // Data-subject access, erasure and retention, plus the processing register,
307
309
  // read off each model's `personal` attributes and `gdpr` trait
308
310
  // (stacksjs/stacks#365).
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- import"@stacksjs/validation/runtime";import{isCompiledBinary}from"./utils/compiled-binary";export*from"./utils/prunable";export{collectEncryptedAttributes,decryptValue,encryptValue,isEncrypted}from"./utils/encrypted";export{setAuditUser,createAuditMethods}from"./traits/audit";export{createCommentableMethods}from"./traits/commentable";export{createTaggableMethods}from"./traits/taggable";export{createCategorizableMethods}from"./traits/categorizable";export{createLikeableMethods}from"./traits/likeable";export{BILLABLE_INSTANCE_METHODS,isBillable,SubscriptionNotOwnedError}from"./traits/billable";export{filterFillable,getWritableFields,isUniqueViolation,mapWriteError,toSnakeCaseKeys}from"./auto-crud";export{customerOwnership,parentOwnership,selfOwnership,siteOwnership,teamMembershipOwnership}from"./ownership";export*from"./batch-loader";export*from"./db";export*from"./subquery";export*from"./transaction";export*from"./gdpr";export*from"./model-types";export*from"./types";export*from"@stacksjs/model-meta";export*from"./define-model";export*from"./extend-model";export{buildDatabaseSchema,renderDatabaseTypeFile}from"./generate-database-schema";export{isCursorPaginator,isPaginator,isSimplePaginator,toCursorPaginator,toPaginator,toSimplePaginator}from"@stacksjs/pagination";export{enrichPaginatorUrls,parseCursor,resolveCursorArgs,resolvePageArgs}from"./paginator-request";import{configureOrm}from"@stacksjs/query-builder";function autoConfigureOrm(){try{const dbPath=process.env.DB_DATABASE_PATH||"database/stacks.sqlite";if((process.env.DB_CONNECTION||"sqlite")==="sqlite")configureOrm({database:dbPath})}catch{}}autoConfigureOrm();async function importDefault(modulePath){for(let attempt=0;;attempt++){const mod=await import(modulePath);try{return mod.default}catch(err){if(attempt<5&&err instanceof ReferenceError&&/before initialization/.test(err.message)){await new Promise((resolve)=>setTimeout(resolve,0));continue}throw err}}}let announcedCompiledSkip=!1;async function loadUserlandModel(modelName,subdirs=[""]){if(isCompiledBinary()){if(!announcedCompiledSkip){announcedCompiledSkip=!0;console.debug("[orm] running from a compiled binary, so framework default models are not probed on disk; models this app uses are bundled.")}return null}const{path}=await import("@stacksjs/path"),userPath=path.userModelsPath(`${modelName}.ts`);try{if(await Bun.file(userPath).exists())return await importDefault(userPath)}catch(err){console.error(`[orm] Failed to import userland model ${modelName} from ${userPath} - falling back to framework default. Reason:`,err)}for(const sub of subdirs){const prefix=sub?`${sub}/`:"",defaultPath=path.frameworkPath(`defaults/app/Models/${prefix}${modelName}.ts`);try{if(await Bun.file(defaultPath).exists())return await importDefault(defaultPath)}catch(err){console.error(`[orm] Failed to import framework default model ${modelName} from ${defaultPath} - trying next subdir. Reason:`,err)}}return null}const _loaded={};let _readyResolve=()=>{};export const ormReady=new Promise((resolve)=>{_readyResolve=resolve});function lazyModel(name){return new Proxy(function _modelStub(){},{get(_target,prop){if(prop==="then")return;const m=_loaded[name];if(m==null)return;const value=m[prop];return typeof value==="function"?value.bind(m):value},set(_target,prop,value){const m=_loaded[name];if(m==null)return!1;m[prop]=value;return!0},has(_target,prop){const m=_loaded[name];return m==null?!1:(prop in m)},apply(_target,thisArg,args){const m=_loaded[name];if(m==null||typeof m!=="function")return;return m.apply(thisArg,args)}})}export const User=lazyModel("User"),Job=lazyModel("Job"),FailedJob=lazyModel("FailedJob");const FRAMEWORK_MODEL_MANIFEST=[["Referral",[""],"auth"],["ReferralCode",[""],"auth"],["Team",[""],"auth"],["TeamInvitation",[""],"auth"],["TeamMember",[""],"auth"],["SocialAccount",[""],"auth"],["Subscriber",[""],"auth"],["SubscriberEmail",[""],"auth"],["Subscription",[""],"auth"],["Categorizable",["Content"],"cms"],["Post",["Content"],"cms"],["Page",["Content"],"cms"],["PageRevision",["Content"],"cms"],["Redirect",["Content"],"cms"],["Menu",["Content"],"cms"],["MenuItem",["Content"],"cms"],["Author",["Content"],"cms"],["Comment",[""],"cms"],["Tag",[""],"cms"],["Site",[""],"auth"],["SiteDomain",[""],"auth"],["MagicLinkToken",[""],"auth"],["SmsOptOut",[""],"auth"],["GdprRequest",[""],"auth"],["Form",["Forms"],"forms"],["FormField",["Forms"],"forms"],["FormSubmission",["Forms"],"forms"],["Activity",[""],"dashboard"],["Board",[""],"dashboard"],["BoardColumn",[""],"dashboard"],["Card",[""],"dashboard"],["CardAttachment",[""],"dashboard"],["CardComment",[""],"dashboard"],["Deployment",[""],"dashboard"],["FeedbackToken",[""],"dashboard"],["Label",[""],"dashboard"],["Release",[""],"dashboard"],["Notification",[""],"dashboard"],["NotificationDelivery",[""],"dashboard"],["PersonalAccessToken",[""],"dashboard"],["MailPreference",[""],"dashboard"],["Log",[""],"dashboard"],["Request",[""],"dashboard"],["AnalyticsEvent",[""],"dashboard"],["QueryLog",[""],"dashboard"],["StorageItem",[""],"dashboard"],["StorageItemTask",[""],"dashboard"],["Error",[""],"monitoring"],["Websocket",["realtime"],"realtime"],["Campaign",[""],"marketing"],["CampaignSend",[""],"marketing"],["EmailList",[""],"marketing"],["EmailListSubscriber",[""],"marketing"],["EmailIdempotency",[""],"marketing"],["EmailSuppression",[""],"marketing"],["EmailWebhookEvent",[""],"marketing"],["SocialPost",[""],"marketing"],["Automation",[""],"marketing"],["AutomationRun",[""],"marketing"],["CampaignVariant",[""],"marketing"],["CommunicationSuppression",[""],"marketing"],["ConsentEvent",[""],"marketing"],["SenderDomain",[""],"marketing"],["UsageEvent",[""],"marketing"],["PaymentMethod",[""],"commerce"],["PaymentProduct",[""],"commerce"],["PaymentTransaction",[""],"commerce"],["Order",["commerce"],"commerce"],["OrderIdempotency",["commerce"],"commerce"],["OrderItem",["commerce"],"commerce"],["Cart",["commerce"],"commerce"],["CartItem",["commerce"],"commerce"],["Customer",["commerce"],"commerce"],["Product",["commerce"],"commerce"],["ProductVariant",["commerce"],"commerce"],["ProductUnit",["commerce"],"commerce"],["Manufacturer",["commerce"],"commerce"],["Category",["commerce"],"commerce"],["Coupon",["commerce"],"commerce"],["GiftCard",["commerce"],"commerce"],["LicenseKey",["commerce"],"commerce"],["Review",["commerce"],"commerce"],["Receipt",["commerce"],"commerce"],["PrintDevice",["commerce"],"commerce"],["ShippingMethod",["commerce"],"commerce"],["ShippingRate",["commerce"],"commerce"],["ShippingZone",["commerce"],"commerce"],["DeliveryRoute",["commerce"],"commerce"],["DeliveryStop",["commerce"],"commerce"],["DigitalDelivery",["commerce"],"commerce"],["Courier",["commerce"],"commerce"],["CourierPing",["commerce"],"commerce"],["TaxRate",["commerce"],"commerce"],["WaitlistProduct",["commerce"],"commerce"],["WaitlistRestaurant",["commerce"],"commerce"],["Auction",["commerce"],"commerce"],["AuctionItem",["commerce"],"commerce"],["Bid",["commerce"],"commerce"],["Pledge",["commerce"],"commerce"],["LoyaltyPoint",["commerce"],"commerce"],["LoyaltyReward",["commerce"],"commerce"],["Payment",["commerce"],"commerce"],["PaymentWebhookEvent",["commerce"],"commerce"],["Transaction",["commerce"],"commerce"]];queueMicrotask(async()=>{try{const{feature}=await import("@stacksjs/config"),userModel=await loadUserlandModel("User");if(userModel)_loaded.User=userModel;if(feature("queue")){const job=await loadUserlandModel("Job");if(job)_loaded.Job=job;const failedJob=await loadUserlandModel("FailedJob");if(failedJob)_loaded.FailedJob=failedJob}for(const[name,subdirs,featureFlag]of FRAMEWORK_MODEL_MANIFEST){if(!feature(featureFlag))continue;const M=await loadUserlandModel(name,subdirs);if(M)_loaded[name]=M}}catch(err){console.error("[orm] deferred model load failed:",err)}finally{_readyResolve()}});export const Activity=lazyModel("Activity"),AnalyticsEvent=lazyModel("AnalyticsEvent"),Automation=lazyModel("Automation"),AutomationRun=lazyModel("AutomationRun"),Auction=lazyModel("Auction"),CampaignVariant=lazyModel("CampaignVariant"),CommunicationSuppression=lazyModel("CommunicationSuppression"),ConsentEvent=lazyModel("ConsentEvent"),SenderDomain=lazyModel("SenderDomain"),UsageEvent=lazyModel("UsageEvent"),AuctionItem=lazyModel("AuctionItem"),Author=lazyModel("Author"),Bid=lazyModel("Bid"),Board=lazyModel("Board"),BoardColumn=lazyModel("BoardColumn"),Campaign=lazyModel("Campaign"),Card=lazyModel("Card"),CardAttachment=lazyModel("CardAttachment"),CardComment=lazyModel("CardComment"),Cart=lazyModel("Cart"),CartItem=lazyModel("CartItem"),Category=lazyModel("Category"),Comment=lazyModel("Comment"),Coupon=lazyModel("Coupon"),Customer=lazyModel("Customer"),DeliveryRoute=lazyModel("DeliveryRoute"),DeliveryStop=lazyModel("DeliveryStop"),Deployment=lazyModel("Deployment"),FeedbackToken=lazyModel("FeedbackToken"),DigitalDelivery=lazyModel("DigitalDelivery"),Courier=lazyModel("Courier"),CourierPing=lazyModel("CourierPing"),CampaignSend=lazyModel("CampaignSend"),EmailList=lazyModel("EmailList"),EmailListSubscriber=lazyModel("EmailListSubscriber"),Form=lazyModel("Form"),FormField=lazyModel("FormField"),FormSubmission=lazyModel("FormSubmission"),MagicLinkToken=lazyModel("MagicLinkToken"),Menu=lazyModel("Menu"),MenuItem=lazyModel("MenuItem"),PageRevision=lazyModel("PageRevision"),Pledge=lazyModel("Pledge"),Redirect=lazyModel("Redirect"),Site=lazyModel("Site"),SiteDomain=lazyModel("SiteDomain"),SmsOptOut=lazyModel("SmsOptOut"),GdprRequest=lazyModel("GdprRequest"),StorageItem=lazyModel("StorageItem"),StorageItemTask=lazyModel("StorageItemTask"),EmailIdempotency=lazyModel("EmailIdempotency"),EmailSuppression=lazyModel("EmailSuppression"),EmailWebhookEvent=lazyModel("EmailWebhookEvent"),ErrorModel=lazyModel("Error"),GiftCard=lazyModel("GiftCard"),Label=lazyModel("Label"),LicenseKey=lazyModel("LicenseKey"),Log=lazyModel("Log"),LoyaltyPoint=lazyModel("LoyaltyPoint"),LoyaltyReward=lazyModel("LoyaltyReward"),MailPreference=lazyModel("MailPreference"),Manufacturer=lazyModel("Manufacturer"),Notification=lazyModel("Notification"),NotificationDelivery=lazyModel("NotificationDelivery"),Order=lazyModel("Order"),OrderIdempotency=lazyModel("OrderIdempotency"),PersonalAccessToken=lazyModel("PersonalAccessToken"),OrderItem=lazyModel("OrderItem"),Page=lazyModel("Page"),Payment=lazyModel("Payment"),PaymentWebhookEvent=lazyModel("PaymentWebhookEvent"),PaymentMethod=lazyModel("PaymentMethod"),PaymentProduct=lazyModel("PaymentProduct"),PaymentTransaction=lazyModel("PaymentTransaction"),Post=lazyModel("Post"),Categorizable=lazyModel("Categorizable"),PrintDevice=lazyModel("PrintDevice"),Product=lazyModel("Product"),ProductUnit=lazyModel("ProductUnit"),ProductVariant=lazyModel("ProductVariant"),QueryLog=lazyModel("QueryLog"),Receipt=lazyModel("Receipt"),Referral=lazyModel("Referral"),ReferralCode=lazyModel("ReferralCode"),Release=lazyModel("Release"),Request=lazyModel("Request"),Review=lazyModel("Review"),ShippingMethod=lazyModel("ShippingMethod"),ShippingRate=lazyModel("ShippingRate"),ShippingZone=lazyModel("ShippingZone"),SocialPost=lazyModel("SocialPost"),SocialAccount=lazyModel("SocialAccount"),Subscriber=lazyModel("Subscriber"),SubscriberEmail=lazyModel("SubscriberEmail"),Subscription=lazyModel("Subscription"),Tag=lazyModel("Tag"),TaxRate=lazyModel("TaxRate"),Team=lazyModel("Team"),TeamInvitation=lazyModel("TeamInvitation"),TeamMember=lazyModel("TeamMember"),Transaction=lazyModel("Transaction"),WaitlistProduct=lazyModel("WaitlistProduct"),WaitlistRestaurant=lazyModel("WaitlistRestaurant"),Websocket=lazyModel("Websocket");const _allExports={User,Job,FailedJob,Activity,AnalyticsEvent,Automation,AutomationRun,Auction,AuctionItem,Author,Bid,Board,BoardColumn,Campaign,CampaignSend,CampaignVariant,Card,CardComment,Cart,CartItem,Categorizable,Category,Comment,Coupon,Customer,CommunicationSuppression,ConsentEvent,DeliveryRoute,DeliveryStop,Deployment,DigitalDelivery,Courier,CourierPing,EmailList,EmailListSubscriber,EmailIdempotency,EmailSuppression,EmailWebhookEvent,ErrorModel,Form,FormField,FormSubmission,GdprRequest,GiftCard,Label,LicenseKey,Log,LoyaltyPoint,LoyaltyReward,MailPreference,Manufacturer,Notification,MagicLinkToken,Menu,MenuItem,NotificationDelivery,Order,OrderIdempotency,OrderItem,Page,PageRevision,Payment,PaymentMethod,PaymentProduct,PaymentTransaction,PaymentWebhookEvent,Pledge,Post,PrintDevice,Product,ProductUnit,ProductVariant,QueryLog,Receipt,Release,Request,Review,ShippingMethod,Redirect,SenderDomain,ShippingRate,ShippingZone,Site,SiteDomain,SmsOptOut,SocialAccount,SocialPost,Subscriber,SubscriberEmail,Subscription,Tag,TaxRate,Team,TeamInvitation,TeamMember,Transaction,UsageEvent,WaitlistProduct,WaitlistRestaurant,Websocket},g=globalThis;for(const[name,M]of Object.entries(_allExports))if(M&&g[name]===void 0)g[name]=M;export const modelGlobalNames=Object.keys(_allExports);async function _safeAll(M){if(!M)return[];try{if(typeof M.all==="function"){const rows=await M.all();return Array.isArray(rows)?rows:[]}if(typeof M.get==="function"){const rows=await M.get();return Array.isArray(rows)?rows:[]}}catch{}return[]}function _safeGet(row,key,fallback=""){if(!row)return fallback;try{if(typeof row.get==="function"){const v=row.get(key);if(v!==void 0&&v!==null)return v}}catch{}const direct=row?.[key];return direct!==void 0&&direct!==null?direct:fallback}if(g.safeAll===void 0)g.safeAll=_safeAll;if(g.safeGet===void 0)g.safeGet=_safeGet;
1
+ import"@stacksjs/validation/runtime";import{isCompiledBinary}from"./utils/compiled-binary";export*from"./utils/prunable";export{collectEncryptedAttributes,decryptValue,encryptValue,isEncrypted}from"./utils/encrypted";export{setAuditUser,createAuditMethods}from"./traits/audit";export{createCommentableMethods}from"./traits/commentable";export{createTaggableMethods}from"./traits/taggable";export{createCategorizableMethods}from"./traits/categorizable";export{createLikeableMethods}from"./traits/likeable";export{BILLABLE_INSTANCE_METHODS,isBillable,SubscriptionNotOwnedError}from"./traits/billable";export{filterFillable,getWritableFields,isUniqueViolation,mapWriteError,toSnakeCaseKeys}from"./auto-crud";export{customerOwnership,parentOwnership,selfOwnership,siteOwnership,teamMembershipOwnership}from"./ownership";export*from"./batch-loader";export*from"./db";export*from"./subquery";export*from"./transaction";export*from"./locked-row";export*from"./row-token";export*from"./gdpr";export*from"./model-types";export*from"./types";export*from"@stacksjs/model-meta";export*from"./define-model";export*from"./extend-model";export{buildDatabaseSchema,renderDatabaseTypeFile}from"./generate-database-schema";export{isCursorPaginator,isPaginator,isSimplePaginator,toCursorPaginator,toPaginator,toSimplePaginator}from"@stacksjs/pagination";export{enrichPaginatorUrls,parseCursor,resolveCursorArgs,resolvePageArgs}from"./paginator-request";import{configureOrm}from"@stacksjs/query-builder";function autoConfigureOrm(){try{const dbPath=process.env.DB_DATABASE_PATH||"database/stacks.sqlite";if((process.env.DB_CONNECTION||"sqlite")==="sqlite")configureOrm({database:dbPath})}catch{}}autoConfigureOrm();async function importDefault(modulePath){for(let attempt=0;;attempt++){const mod=await import(modulePath);try{return mod.default}catch(err){if(attempt<5&&err instanceof ReferenceError&&/before initialization/.test(err.message)){await new Promise((resolve)=>setTimeout(resolve,0));continue}throw err}}}let announcedCompiledSkip=!1;async function loadUserlandModel(modelName,subdirs=[""]){if(isCompiledBinary()){if(!announcedCompiledSkip){announcedCompiledSkip=!0;console.debug("[orm] running from a compiled binary, so framework default models are not probed on disk; models this app uses are bundled.")}return null}const{path}=await import("@stacksjs/path"),userPath=path.userModelsPath(`${modelName}.ts`);try{if(await Bun.file(userPath).exists())return await importDefault(userPath)}catch(err){console.error(`[orm] Failed to import userland model ${modelName} from ${userPath} - falling back to framework default. Reason:`,err)}for(const sub of subdirs){const prefix=sub?`${sub}/`:"",defaultPath=path.frameworkPath(`defaults/app/Models/${prefix}${modelName}.ts`);try{if(await Bun.file(defaultPath).exists())return await importDefault(defaultPath)}catch(err){console.error(`[orm] Failed to import framework default model ${modelName} from ${defaultPath} - trying next subdir. Reason:`,err)}}return null}const _loaded={};let _readyResolve=()=>{};export const ormReady=new Promise((resolve)=>{_readyResolve=resolve});function lazyModel(name){return new Proxy(function _modelStub(){},{get(_target,prop){if(prop==="then")return;const m=_loaded[name];if(m==null)return;const value=m[prop];return typeof value==="function"?value.bind(m):value},set(_target,prop,value){const m=_loaded[name];if(m==null)return!1;m[prop]=value;return!0},has(_target,prop){const m=_loaded[name];return m==null?!1:(prop in m)},apply(_target,thisArg,args){const m=_loaded[name];if(m==null||typeof m!=="function")return;return m.apply(thisArg,args)}})}export const User=lazyModel("User"),Job=lazyModel("Job"),FailedJob=lazyModel("FailedJob");const FRAMEWORK_MODEL_MANIFEST=[["Referral",[""],"auth"],["ReferralCode",[""],"auth"],["Team",[""],"auth"],["TeamInvitation",[""],"auth"],["TeamMember",[""],"auth"],["SocialAccount",[""],"auth"],["Subscriber",[""],"auth"],["SubscriberEmail",[""],"auth"],["Subscription",[""],"auth"],["Categorizable",["Content"],"cms"],["Post",["Content"],"cms"],["Page",["Content"],"cms"],["PageRevision",["Content"],"cms"],["Redirect",["Content"],"cms"],["Menu",["Content"],"cms"],["MenuItem",["Content"],"cms"],["Author",["Content"],"cms"],["Comment",[""],"cms"],["Tag",[""],"cms"],["Site",[""],"auth"],["SiteDomain",[""],"auth"],["MagicLinkToken",[""],"auth"],["SmsOptOut",[""],"auth"],["GdprRequest",[""],"auth"],["Form",["Forms"],"forms"],["FormField",["Forms"],"forms"],["FormSubmission",["Forms"],"forms"],["Activity",[""],"dashboard"],["Board",[""],"dashboard"],["BoardColumn",[""],"dashboard"],["Card",[""],"dashboard"],["CardAttachment",[""],"dashboard"],["CardComment",[""],"dashboard"],["Deployment",[""],"dashboard"],["FeedbackToken",[""],"dashboard"],["Label",[""],"dashboard"],["Release",[""],"dashboard"],["Notification",[""],"dashboard"],["NotificationDelivery",[""],"dashboard"],["PersonalAccessToken",[""],"dashboard"],["MailPreference",[""],"dashboard"],["Log",[""],"dashboard"],["Request",[""],"dashboard"],["AnalyticsEvent",[""],"dashboard"],["QueryLog",[""],"dashboard"],["StorageItem",[""],"dashboard"],["StorageItemTask",[""],"dashboard"],["Error",[""],"monitoring"],["Websocket",["realtime"],"realtime"],["Campaign",[""],"marketing"],["CampaignSend",[""],"marketing"],["EmailList",[""],"marketing"],["EmailListSubscriber",[""],"marketing"],["EmailIdempotency",[""],"marketing"],["EmailSuppression",[""],"marketing"],["EmailWebhookEvent",[""],"marketing"],["SocialPost",[""],"marketing"],["Automation",[""],"marketing"],["AutomationRun",[""],"marketing"],["CampaignVariant",[""],"marketing"],["CommunicationSuppression",[""],"marketing"],["ConsentEvent",[""],"marketing"],["SenderDomain",[""],"marketing"],["UsageEvent",[""],"marketing"],["PaymentMethod",[""],"commerce"],["PaymentProduct",[""],"commerce"],["PaymentTransaction",[""],"commerce"],["Order",["commerce"],"commerce"],["OrderIdempotency",["commerce"],"commerce"],["OrderItem",["commerce"],"commerce"],["Cart",["commerce"],"commerce"],["CartItem",["commerce"],"commerce"],["Customer",["commerce"],"commerce"],["Product",["commerce"],"commerce"],["ProductVariant",["commerce"],"commerce"],["ProductUnit",["commerce"],"commerce"],["Manufacturer",["commerce"],"commerce"],["Category",["commerce"],"commerce"],["Coupon",["commerce"],"commerce"],["GiftCard",["commerce"],"commerce"],["LicenseKey",["commerce"],"commerce"],["Review",["commerce"],"commerce"],["Receipt",["commerce"],"commerce"],["PrintDevice",["commerce"],"commerce"],["ShippingMethod",["commerce"],"commerce"],["ShippingRate",["commerce"],"commerce"],["ShippingZone",["commerce"],"commerce"],["DeliveryRoute",["commerce"],"commerce"],["DeliveryStop",["commerce"],"commerce"],["DigitalDelivery",["commerce"],"commerce"],["Courier",["commerce"],"commerce"],["CourierPing",["commerce"],"commerce"],["TaxRate",["commerce"],"commerce"],["WaitlistProduct",["commerce"],"commerce"],["WaitlistRestaurant",["commerce"],"commerce"],["Auction",["commerce"],"commerce"],["AuctionItem",["commerce"],"commerce"],["Bid",["commerce"],"commerce"],["Pledge",["commerce"],"commerce"],["LoyaltyPoint",["commerce"],"commerce"],["LoyaltyReward",["commerce"],"commerce"],["Payment",["commerce"],"commerce"],["PaymentWebhookEvent",["commerce"],"commerce"],["Transaction",["commerce"],"commerce"]];queueMicrotask(async()=>{try{const{feature}=await import("@stacksjs/config"),userModel=await loadUserlandModel("User");if(userModel)_loaded.User=userModel;if(feature("queue")){const job=await loadUserlandModel("Job");if(job)_loaded.Job=job;const failedJob=await loadUserlandModel("FailedJob");if(failedJob)_loaded.FailedJob=failedJob}for(const[name,subdirs,featureFlag]of FRAMEWORK_MODEL_MANIFEST){if(!feature(featureFlag))continue;const M=await loadUserlandModel(name,subdirs);if(M)_loaded[name]=M}}catch(err){console.error("[orm] deferred model load failed:",err)}finally{_readyResolve()}});export const Activity=lazyModel("Activity"),AnalyticsEvent=lazyModel("AnalyticsEvent"),Automation=lazyModel("Automation"),AutomationRun=lazyModel("AutomationRun"),Auction=lazyModel("Auction"),CampaignVariant=lazyModel("CampaignVariant"),CommunicationSuppression=lazyModel("CommunicationSuppression"),ConsentEvent=lazyModel("ConsentEvent"),SenderDomain=lazyModel("SenderDomain"),UsageEvent=lazyModel("UsageEvent"),AuctionItem=lazyModel("AuctionItem"),Author=lazyModel("Author"),Bid=lazyModel("Bid"),Board=lazyModel("Board"),BoardColumn=lazyModel("BoardColumn"),Campaign=lazyModel("Campaign"),Card=lazyModel("Card"),CardAttachment=lazyModel("CardAttachment"),CardComment=lazyModel("CardComment"),Cart=lazyModel("Cart"),CartItem=lazyModel("CartItem"),Category=lazyModel("Category"),Comment=lazyModel("Comment"),Coupon=lazyModel("Coupon"),Customer=lazyModel("Customer"),DeliveryRoute=lazyModel("DeliveryRoute"),DeliveryStop=lazyModel("DeliveryStop"),Deployment=lazyModel("Deployment"),FeedbackToken=lazyModel("FeedbackToken"),DigitalDelivery=lazyModel("DigitalDelivery"),Courier=lazyModel("Courier"),CourierPing=lazyModel("CourierPing"),CampaignSend=lazyModel("CampaignSend"),EmailList=lazyModel("EmailList"),EmailListSubscriber=lazyModel("EmailListSubscriber"),Form=lazyModel("Form"),FormField=lazyModel("FormField"),FormSubmission=lazyModel("FormSubmission"),MagicLinkToken=lazyModel("MagicLinkToken"),Menu=lazyModel("Menu"),MenuItem=lazyModel("MenuItem"),PageRevision=lazyModel("PageRevision"),Pledge=lazyModel("Pledge"),Redirect=lazyModel("Redirect"),Site=lazyModel("Site"),SiteDomain=lazyModel("SiteDomain"),SmsOptOut=lazyModel("SmsOptOut"),GdprRequest=lazyModel("GdprRequest"),StorageItem=lazyModel("StorageItem"),StorageItemTask=lazyModel("StorageItemTask"),EmailIdempotency=lazyModel("EmailIdempotency"),EmailSuppression=lazyModel("EmailSuppression"),EmailWebhookEvent=lazyModel("EmailWebhookEvent"),ErrorModel=lazyModel("Error"),GiftCard=lazyModel("GiftCard"),Label=lazyModel("Label"),LicenseKey=lazyModel("LicenseKey"),Log=lazyModel("Log"),LoyaltyPoint=lazyModel("LoyaltyPoint"),LoyaltyReward=lazyModel("LoyaltyReward"),MailPreference=lazyModel("MailPreference"),Manufacturer=lazyModel("Manufacturer"),Notification=lazyModel("Notification"),NotificationDelivery=lazyModel("NotificationDelivery"),Order=lazyModel("Order"),OrderIdempotency=lazyModel("OrderIdempotency"),PersonalAccessToken=lazyModel("PersonalAccessToken"),OrderItem=lazyModel("OrderItem"),Page=lazyModel("Page"),Payment=lazyModel("Payment"),PaymentWebhookEvent=lazyModel("PaymentWebhookEvent"),PaymentMethod=lazyModel("PaymentMethod"),PaymentProduct=lazyModel("PaymentProduct"),PaymentTransaction=lazyModel("PaymentTransaction"),Post=lazyModel("Post"),Categorizable=lazyModel("Categorizable"),PrintDevice=lazyModel("PrintDevice"),Product=lazyModel("Product"),ProductUnit=lazyModel("ProductUnit"),ProductVariant=lazyModel("ProductVariant"),QueryLog=lazyModel("QueryLog"),Receipt=lazyModel("Receipt"),Referral=lazyModel("Referral"),ReferralCode=lazyModel("ReferralCode"),Release=lazyModel("Release"),Request=lazyModel("Request"),Review=lazyModel("Review"),ShippingMethod=lazyModel("ShippingMethod"),ShippingRate=lazyModel("ShippingRate"),ShippingZone=lazyModel("ShippingZone"),SocialPost=lazyModel("SocialPost"),SocialAccount=lazyModel("SocialAccount"),Subscriber=lazyModel("Subscriber"),SubscriberEmail=lazyModel("SubscriberEmail"),Subscription=lazyModel("Subscription"),Tag=lazyModel("Tag"),TaxRate=lazyModel("TaxRate"),Team=lazyModel("Team"),TeamInvitation=lazyModel("TeamInvitation"),TeamMember=lazyModel("TeamMember"),Transaction=lazyModel("Transaction"),WaitlistProduct=lazyModel("WaitlistProduct"),WaitlistRestaurant=lazyModel("WaitlistRestaurant"),Websocket=lazyModel("Websocket");const _allExports={User,Job,FailedJob,Activity,AnalyticsEvent,Automation,AutomationRun,Auction,AuctionItem,Author,Bid,Board,BoardColumn,Campaign,CampaignSend,CampaignVariant,Card,CardComment,Cart,CartItem,Categorizable,Category,Comment,Coupon,Customer,CommunicationSuppression,ConsentEvent,DeliveryRoute,DeliveryStop,Deployment,DigitalDelivery,Courier,CourierPing,EmailList,EmailListSubscriber,EmailIdempotency,EmailSuppression,EmailWebhookEvent,ErrorModel,Form,FormField,FormSubmission,GdprRequest,GiftCard,Label,LicenseKey,Log,LoyaltyPoint,LoyaltyReward,MailPreference,Manufacturer,Notification,MagicLinkToken,Menu,MenuItem,NotificationDelivery,Order,OrderIdempotency,OrderItem,Page,PageRevision,Payment,PaymentMethod,PaymentProduct,PaymentTransaction,PaymentWebhookEvent,Pledge,Post,PrintDevice,Product,ProductUnit,ProductVariant,QueryLog,Receipt,Release,Request,Review,ShippingMethod,Redirect,SenderDomain,ShippingRate,ShippingZone,Site,SiteDomain,SmsOptOut,SocialAccount,SocialPost,Subscriber,SubscriberEmail,Subscription,Tag,TaxRate,Team,TeamInvitation,TeamMember,Transaction,UsageEvent,WaitlistProduct,WaitlistRestaurant,Websocket},g=globalThis;for(const[name,M]of Object.entries(_allExports))if(M&&g[name]===void 0)g[name]=M;export const modelGlobalNames=Object.keys(_allExports);async function _safeAll(M){if(!M)return[];try{if(typeof M.all==="function"){const rows=await M.all();return Array.isArray(rows)?rows:[]}if(typeof M.get==="function"){const rows=await M.get();return Array.isArray(rows)?rows:[]}}catch{}return[]}function _safeGet(row,key,fallback=""){if(!row)return fallback;try{if(typeof row.get==="function"){const v=row.get(key);if(v!==void 0&&v!==null)return v}}catch{}const direct=row?.[key];return direct!==void 0&&direct!==null?direct:fallback}if(g.safeAll===void 0)g.safeAll=_safeAll;if(g.safeGet===void 0)g.safeGet=_safeGet;
@@ -0,0 +1,7 @@
1
+ import { type TransactionHandle } from './transaction';
2
+ /** Lock, read and operate on a scoped row on one connection. Missing rows return null. */
3
+ export declare function withLockedRow<T>(table: string, scope: RowScope, callback: (row: Record<string, unknown>, tx: TransactionHandle) => Promise<T>, options?: LockedRowOptions): Promise<T | null>;
4
+ export declare interface LockedRowOptions {
5
+ tx?: TransactionHandle
6
+ }
7
+ export type RowScope = Record<string, string | number | null>;
@@ -0,0 +1 @@
1
+ import{lockRow}from"@stacksjs/database/runtime";import{transaction}from"./transaction";export async function withLockedRow(table,scope,callback,options={}){const run=async(tx)=>{const row=await lockRow(tx,table,scope);return row?callback(row,tx):null};return options.tx?run(options.tx):transaction(run)}
@@ -0,0 +1,14 @@
1
+ import { type LockedRowOptions, type RowScope } from './locked-row';
2
+ /** Manage a stored share/feed credential. Repeated enable preserves the live token. */
3
+ export declare function rowToken(options: RowTokenOptions): Promise<string | null>;
4
+ export declare interface RowTokenOptions extends LockedRowOptions {
5
+ table: string
6
+ scope: RowScope
7
+ column: string
8
+ action: RowTokenAction
9
+ timestampColumn?: string | false
10
+ }
11
+ export type RowTokenAction = 'read' | 'enable' | 'rotate' | 'disable';
12
+ export declare class RowTokenNotFoundError extends Error {
13
+ readonly status: number;
14
+ }
@@ -0,0 +1 @@
1
+ import{randomBytes}from"node:crypto";import{assertSqlIdentifier,db}from"@stacksjs/database/runtime";import{withLockedRow}from"./locked-row";export class RowTokenNotFoundError extends Error{status=404}export async function rowToken(options){const{table,scope,column,action}=options,timestamp=options.timestampColumn===void 0?"updated_at":options.timestampColumn;assertSqlIdentifier(table);assertSqlIdentifier(column);if(timestamp)assertSqlIdentifier(timestamp);for(const key of Object.keys(scope))assertSqlIdentifier(key);if(!["read","enable","rotate","disable"].includes(action))throw Error("Invalid token operation");if(!Object.keys(scope).length)throw Error("A token operation requires a scope");const currentToken=(row)=>typeof row[column]==="string"&&row[column]?row[column]:null;if(action==="read"){let query=(options.tx??db).selectFrom(table).select([column]);for(const[key,value]of Object.entries(scope))query=value===null?query.whereNull(key):query.where(key,"=",value);const rows=await query.limit(2).execute();if(rows.length>1)throw Error("Token operations require a unique owner scope");const row=rows[0];if(!row)throw new RowTokenNotFoundError("Token owner not found");return currentToken(row)}const result=await withLockedRow(table,scope,async(row,tx)=>{const current=currentToken(row),token=action==="disable"?null:action==="enable"&&current?current:randomBytes(32).toString("hex");if(token!==current){const values={[column]:token};if(timestamp)values[timestamp]=new Date().toISOString();let update=tx.updateTable(table).set(values);for(const[key,value]of Object.entries(scope))update=value===null?update.whereNull(key):update.where(key,"=",value);await update.execute()}return{token}},options);if(!result)throw new RowTokenNotFoundError("Token owner not found");return result.token}
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@stacksjs/orm",
3
3
  "type": "module",
4
4
  "sideEffects": false,
5
- "version": "0.75.112",
5
+ "version": "0.75.114",
6
6
  "description": "The Stacks ORM integration",
7
7
  "author": "Chris Breuer",
8
8
  "contributors": [
@@ -63,31 +63,31 @@
63
63
  "prepublishOnly": "bun run build"
64
64
  },
65
65
  "dependencies": {
66
- "@stacksjs/cache": "0.75.112",
67
- "@stacksjs/cli": "0.75.112",
68
- "@stacksjs/config": "0.75.112",
69
- "@stacksjs/database": "0.75.112",
70
- "@stacksjs/env": "0.75.112",
71
- "@stacksjs/error-handling": "0.75.112",
72
- "@stacksjs/events": "0.75.112",
73
- "@stacksjs/logging": "0.75.112",
74
- "@stacksjs/model-meta": "0.75.112",
75
- "@stacksjs/pagination": "0.75.112",
76
- "@stacksjs/path": "0.75.112",
77
- "@stacksjs/query-builder": "0.75.112",
78
- "@stacksjs/realtime": "0.75.112",
79
- "@stacksjs/router": "0.75.112",
80
- "@stacksjs/storage": "0.75.112",
81
- "@stacksjs/strings": "0.75.112",
66
+ "@stacksjs/cache": "0.75.114",
67
+ "@stacksjs/cli": "0.75.114",
68
+ "@stacksjs/config": "0.75.114",
69
+ "@stacksjs/database": "0.75.114",
70
+ "@stacksjs/env": "0.75.114",
71
+ "@stacksjs/error-handling": "0.75.114",
72
+ "@stacksjs/events": "0.75.114",
73
+ "@stacksjs/logging": "0.75.114",
74
+ "@stacksjs/model-meta": "0.75.114",
75
+ "@stacksjs/pagination": "0.75.114",
76
+ "@stacksjs/path": "0.75.114",
77
+ "@stacksjs/query-builder": "0.75.114",
78
+ "@stacksjs/realtime": "0.75.114",
79
+ "@stacksjs/router": "0.75.114",
80
+ "@stacksjs/storage": "0.75.114",
81
+ "@stacksjs/strings": "0.75.114",
82
82
  "@stacksjs/ts-validation": "^0.5.6",
83
- "@stacksjs/validation": "0.75.112",
83
+ "@stacksjs/validation": "0.75.114",
84
84
  "bun-query-builder": "^0.3.5"
85
85
  },
86
86
  "peerDependencies": {
87
- "@stacksjs/auth": "0.75.112",
88
- "@stacksjs/payments": "0.75.112",
89
- "@stacksjs/queue": "0.75.112",
90
- "@stacksjs/search-engine": "0.75.112",
87
+ "@stacksjs/auth": "0.75.114",
88
+ "@stacksjs/payments": "0.75.114",
89
+ "@stacksjs/queue": "0.75.114",
90
+ "@stacksjs/search-engine": "0.75.114",
91
91
  "stripe": "23.0.0"
92
92
  },
93
93
  "peerDependenciesMeta": {
@@ -108,7 +108,7 @@
108
108
  }
109
109
  },
110
110
  "devDependencies": {
111
- "@stacksjs/types": "0.75.112",
111
+ "@stacksjs/types": "0.75.114",
112
112
  "better-dx": "^0.2.24",
113
113
  "stripe": "23.0.0"
114
114
  }