@stacksjs/orm 0.75.112 → 0.75.113
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 +17 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -1
- package/dist/locked-row.d.ts +7 -0
- package/dist/locked-row.js +1 -0
- package/dist/row-token.d.ts +14 -0
- package/dist/row-token.js +1 -0
- package/package.json +23 -23
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"&¤t?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.
|
|
5
|
+
"version": "0.75.113",
|
|
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.
|
|
67
|
-
"@stacksjs/cli": "0.75.
|
|
68
|
-
"@stacksjs/config": "0.75.
|
|
69
|
-
"@stacksjs/database": "0.75.
|
|
70
|
-
"@stacksjs/env": "0.75.
|
|
71
|
-
"@stacksjs/error-handling": "0.75.
|
|
72
|
-
"@stacksjs/events": "0.75.
|
|
73
|
-
"@stacksjs/logging": "0.75.
|
|
74
|
-
"@stacksjs/model-meta": "0.75.
|
|
75
|
-
"@stacksjs/pagination": "0.75.
|
|
76
|
-
"@stacksjs/path": "0.75.
|
|
77
|
-
"@stacksjs/query-builder": "0.75.
|
|
78
|
-
"@stacksjs/realtime": "0.75.
|
|
79
|
-
"@stacksjs/router": "0.75.
|
|
80
|
-
"@stacksjs/storage": "0.75.
|
|
81
|
-
"@stacksjs/strings": "0.75.
|
|
66
|
+
"@stacksjs/cache": "0.75.113",
|
|
67
|
+
"@stacksjs/cli": "0.75.113",
|
|
68
|
+
"@stacksjs/config": "0.75.113",
|
|
69
|
+
"@stacksjs/database": "0.75.113",
|
|
70
|
+
"@stacksjs/env": "0.75.113",
|
|
71
|
+
"@stacksjs/error-handling": "0.75.113",
|
|
72
|
+
"@stacksjs/events": "0.75.113",
|
|
73
|
+
"@stacksjs/logging": "0.75.113",
|
|
74
|
+
"@stacksjs/model-meta": "0.75.113",
|
|
75
|
+
"@stacksjs/pagination": "0.75.113",
|
|
76
|
+
"@stacksjs/path": "0.75.113",
|
|
77
|
+
"@stacksjs/query-builder": "0.75.113",
|
|
78
|
+
"@stacksjs/realtime": "0.75.113",
|
|
79
|
+
"@stacksjs/router": "0.75.113",
|
|
80
|
+
"@stacksjs/storage": "0.75.113",
|
|
81
|
+
"@stacksjs/strings": "0.75.113",
|
|
82
82
|
"@stacksjs/ts-validation": "^0.5.6",
|
|
83
|
-
"@stacksjs/validation": "0.75.
|
|
83
|
+
"@stacksjs/validation": "0.75.113",
|
|
84
84
|
"bun-query-builder": "^0.3.5"
|
|
85
85
|
},
|
|
86
86
|
"peerDependencies": {
|
|
87
|
-
"@stacksjs/auth": "0.75.
|
|
88
|
-
"@stacksjs/payments": "0.75.
|
|
89
|
-
"@stacksjs/queue": "0.75.
|
|
90
|
-
"@stacksjs/search-engine": "0.75.
|
|
87
|
+
"@stacksjs/auth": "0.75.113",
|
|
88
|
+
"@stacksjs/payments": "0.75.113",
|
|
89
|
+
"@stacksjs/queue": "0.75.113",
|
|
90
|
+
"@stacksjs/search-engine": "0.75.113",
|
|
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.
|
|
111
|
+
"@stacksjs/types": "0.75.113",
|
|
112
112
|
"better-dx": "^0.2.24",
|
|
113
113
|
"stripe": "23.0.0"
|
|
114
114
|
}
|