@stacksjs/features 0.74.4
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/LICENSE.md +21 -0
- package/README.md +24 -0
- package/dist/index.d.ts +100 -0
- package/dist/index.js +2 -0
- package/package.json +50 -0
package/LICENSE.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2023 Open Web Foundation
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# @stacksjs/features
|
|
2
|
+
|
|
3
|
+
Which files and tables belong to which optional Stacks feature.
|
|
4
|
+
|
|
5
|
+
Two very different callers need this manifest and neither should own it. The
|
|
6
|
+
CLI installs and uninstalls a feature, so it needs the file list.
|
|
7
|
+
The migration runner hides a disabled feature's migrations before a run, so it
|
|
8
|
+
needs the table list.
|
|
9
|
+
|
|
10
|
+
The manifest used to live in `@stacksjs/buddy`, and the migration runner
|
|
11
|
+
reached into the CLI through a best-effort dynamic import to read it — so
|
|
12
|
+
`@stacksjs/database` depended on `@stacksjs/buddy`, and the two sat inside a
|
|
13
|
+
dependency cycle that no publish order could satisfy.
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
import { FEATURE_NAMES, migrationFeature, migrationTable } from '@stacksjs/features'
|
|
17
|
+
|
|
18
|
+
migrationTable('0000000133-create-campaigns-table.sql') // 'campaigns'
|
|
19
|
+
migrationFeature('0000000133-create-campaigns-table.sql') // 'marketing'
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Nothing here reads config or touches a database — it is the manifest and three
|
|
23
|
+
lookups over it. Deciding whether a feature is *enabled* is `@stacksjs/config`'s
|
|
24
|
+
job, and acting on that is the caller's.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse a migration filename like `0000000045-create-posts-table.sql` or
|
|
3
|
+
* `0000000085-alter-posts-author_id.sql` to extract the table name it
|
|
4
|
+
* acts on. Returns `null` for filenames that don't match the
|
|
5
|
+
* recognised `create-<table>-table` / `alter-<table>-` shapes — those
|
|
6
|
+
* pass through the gate unchanged.
|
|
7
|
+
*
|
|
8
|
+
* Index migrations (`create-<table>_<col>_unique-index-in-<table>.sql`)
|
|
9
|
+
* use the trailing `-in-<table>.sql` segment as the source of truth
|
|
10
|
+
* since the leading segment includes the index name. The other
|
|
11
|
+
* forms read the table from the segment immediately after the verb.
|
|
12
|
+
*/
|
|
13
|
+
export declare function migrationTable(filename: string): string | null;
|
|
14
|
+
/**
|
|
15
|
+
* Returns the feature that owns the given migration filename, or `null`
|
|
16
|
+
* if the migration isn't claimed by any feature (in which case it
|
|
17
|
+
* always runs). Used by the migration runner's gating pass.
|
|
18
|
+
*/
|
|
19
|
+
export declare function migrationFeature(filename: string): FeatureName | null;
|
|
20
|
+
/**
|
|
21
|
+
* True when an application-owned, top-level model explicitly declares a table.
|
|
22
|
+
* This lets apps intentionally use generic names such as `payments` without
|
|
23
|
+
* their migrations being mistaken for disabled framework-feature scaffolding.
|
|
24
|
+
* Root models listed in FEATURE_FILES remain feature-owned and do not override
|
|
25
|
+
* the gate.
|
|
26
|
+
*/
|
|
27
|
+
export declare function appModelClaimsTable(table: string, root?: string): boolean;
|
|
28
|
+
export declare const FEATURE_NAMES: readonly ['dashboard', 'commerce', 'cms', 'forms', 'marketing', 'monitoring', 'realtime', 'queue'];
|
|
29
|
+
/**
|
|
30
|
+
* Per-feature stamped file/directory manifest. Paths are relative to the
|
|
31
|
+
* project root and mirror the layout that `./buddy new` lays down. Entries
|
|
32
|
+
* ending in `/` are directory trees (recursive remove on uninstall); bare
|
|
33
|
+
* paths are single files.
|
|
34
|
+
*
|
|
35
|
+
* A feature must also claim the shared files its own actions IMPORT.
|
|
36
|
+
* `app/Actions/Dashboard/dashboard-response.ts` is the case that bit: five
|
|
37
|
+
* features publish a subdirectory of `app/Actions/Dashboard/`, and the actions
|
|
38
|
+
* in each import `../dashboard-response`. Without it, `<feature>:install`
|
|
39
|
+
* copied 22 actions whose very first import did not resolve.
|
|
40
|
+
*
|
|
41
|
+
* Manifests intentionally overlap where features share scaffolding —
|
|
42
|
+
* `dashboard` claims the umbrella `app/Actions/Dashboard/` even though
|
|
43
|
+
* `app/Actions/Dashboard/Content/` is also claimed by `cms`. Both the
|
|
44
|
+
* uninstall delete and the doctor orphan check are idempotent
|
|
45
|
+
* (already-gone paths are skipped silently), so the overlap is safe.
|
|
46
|
+
*
|
|
47
|
+
* Adding a new file to one of these directories does **not** require a
|
|
48
|
+
* manifest update — directory entries are recursive. Only add an entry
|
|
49
|
+
* when a feature introduces a new top-level path the framework didn't
|
|
50
|
+
* already claim.
|
|
51
|
+
* @defaultValue
|
|
52
|
+
* ```ts
|
|
53
|
+
* {
|
|
54
|
+
* forms: [ 'app/Models/Forms/', ],
|
|
55
|
+
* cms: [ 'app/Actions/Cms/', 'app/Actions/Dashboard/Content/', 'app/Actions/Dashboard/dashboard-response.ts', 'app/Models/Content/', 'app/Models/Tag.ts', 'app/Models/Comment.ts', 'resources/views/dashboard/content/', ],
|
|
56
|
+
* commerce: [ 'app/Actions/Commerce/', 'app/Actions/Dashboard/Commerce/', 'app/Actions/Dashboard/dashboard-response.ts', 'app/Models/commerce/', 'resources/components/Dashboard/Commerce/', 'resources/views/dashboard/commerce/', ],
|
|
57
|
+
* dashboard: [ 'app/Actions/Dashboard/', 'resources/components/Dashboard/', 'resources/views/dashboard/', 'routes/dashboard.ts', 'routes/dashboard-api.ts', ],
|
|
58
|
+
* marketing: [ 'app/Actions/Dashboard/Marketing/', 'app/Actions/Dashboard/dashboard-response.ts', 'app/Models/Campaign.ts', 'app/Models/CampaignSend.ts', 'app/Models/EmailList.ts', 'app/Models/EmailListSubscriber.ts', 'app/Models/SocialPost.ts', 'resources/components/Marketing/', 'resources/views/dashboard/marketing/', ],
|
|
59
|
+
* monitoring: [ 'app/Actions/Monitoring/', 'app/Actions/TestErrorAction.ts', 'app/Models/Error.ts', 'functions/monitoring/', 'resources/views/dashboard/monitoring/', 'resources/views/dashboard/errors/', ],
|
|
60
|
+
* realtime: [ 'app/Actions/Realtime/', 'app/Actions/Dashboard/Realtime/', 'app/Actions/Dashboard/dashboard-response.ts', 'app/Models/realtime/', 'app/Broadcasts/', 'functions/realtime/', 'resources/views/dashboard/realtime/', ],
|
|
61
|
+
* queue: [ 'app/Actions/Queue/', 'app/Actions/Dashboard/Jobs/', 'app/Actions/Dashboard/dashboard-response.ts', 'app/Jobs/', 'app/Models/Job.ts', 'app/Models/FailedJob.ts', 'functions/jobs.ts', 'resources/views/dashboard/queue/', 'resources/views/dashboard/jobs/', ]
|
|
62
|
+
* }
|
|
63
|
+
* ```
|
|
64
|
+
*/
|
|
65
|
+
export declare const FEATURE_FILES: Record<FeatureName, readonly string[]>;
|
|
66
|
+
/**
|
|
67
|
+
* Per-feature database table ownership (stacksjs/stacks#1854).
|
|
68
|
+
*
|
|
69
|
+
* Stacks generates SQL migrations from model files, so each feature's
|
|
70
|
+
* tables map 1:1 with the models in its `FEATURE_FILES.app/Models/...`
|
|
71
|
+
* entries. Listed here explicitly rather than derived at runtime so
|
|
72
|
+
* additions are visible in a single grep-able place and the migration
|
|
73
|
+
* gate doesn't depend on filesystem scanning at boot.
|
|
74
|
+
*
|
|
75
|
+
* The migration runner consults this when `config.<feature>.enabled =
|
|
76
|
+
* false`: matching `*-create-<table>-table.sql` (and `*-alter-<table>-*.sql`)
|
|
77
|
+
* files get hidden for the duration of the run, so a project that
|
|
78
|
+
* never installed CMS doesn't materialize `posts`, `pages`,
|
|
79
|
+
* `comments`, etc. on `./buddy migrate`.
|
|
80
|
+
*
|
|
81
|
+
* Tables on this list are scoped to a single feature. Tables shared
|
|
82
|
+
* across features (none today, but `categories` could end up here)
|
|
83
|
+
* should stay out of the manifest until that's resolved — the runner
|
|
84
|
+
* defaults to "run unless owned by a disabled feature".
|
|
85
|
+
* @defaultValue
|
|
86
|
+
* ```ts
|
|
87
|
+
* {
|
|
88
|
+
* forms: ['forms', 'form_fields', 'form_submissions'],
|
|
89
|
+
* cms: [ 'posts', 'pages', 'comments', 'tags', 'authors', 'categories', 'taggable_models', 'categorizable_models', 'commentables', 'page_revisions', 'redirects', 'menus', 'menu_items', ],
|
|
90
|
+
* commerce: [ 'products', 'product_variants', 'product_units', 'manufacturers', 'orders', 'order_items', 'order_idempotency', 'carts', 'cart_items', 'payments', 'payment_methods', 'payment_products', 'payment_transactions', 'customers', 'subscribers', 'subscriber_emails', 'subscriptions', 'gift_cards', 'coupons', 'transactions', 'reviews', 'couriers', 'courier_pings', 'delivery_routes', 'delivery_stops', 'digital_deliveries', 'shipping_methods', 'shipping_rates', 'shipping_zones', 'license_keys', 'loyalty_points', 'loyalty_rewards', 'print_devices', 'receipts', 'tax_rates', 'waitlist_products', 'waitlist_restaurants', 'auctions', 'auction_items', 'bids', 'pledges', ],
|
|
91
|
+
* dashboard: [ 'boards', 'board_columns', 'cards', 'card_labels', 'card_assignees', 'card_comments', 'labels', 'ci_run_states', 'ci_runner_samples', 'ci_runner_alert_states', 'requests', 'logs', ],
|
|
92
|
+
* marketing: [ 'campaigns', 'campaign_sends', 'email_lists', 'email_list_subscribers', 'social_posts', 'mail_preferences', ],
|
|
93
|
+
* monitoring: ['errors'],
|
|
94
|
+
* realtime: ['websockets'],
|
|
95
|
+
* queue: ['jobs', 'failed_jobs']
|
|
96
|
+
* }
|
|
97
|
+
* ```
|
|
98
|
+
*/
|
|
99
|
+
export declare const FEATURE_TABLES: Record<FeatureName, readonly string[]>;
|
|
100
|
+
export type FeatureName = (typeof FEATURE_NAMES)[number];
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import{existsSync as p,readdirSync as d,readFileSync as m}from"fs";import{join as t}from"path";import{projectPath as l}from"@stacksjs/path";var i=["dashboard","commerce","cms","forms","marketing","monitoring","realtime","queue"],u={forms:["app/Models/Forms/"],cms:["app/Actions/Cms/","app/Actions/Dashboard/Content/","app/Actions/Dashboard/dashboard-response.ts","app/Models/Content/","app/Models/Tag.ts","app/Models/Comment.ts","resources/views/dashboard/content/"],commerce:["app/Actions/Commerce/","app/Actions/Dashboard/Commerce/","app/Actions/Dashboard/dashboard-response.ts","app/Models/commerce/","resources/components/Dashboard/Commerce/","resources/views/dashboard/commerce/"],dashboard:["app/Actions/Dashboard/","resources/components/Dashboard/","resources/views/dashboard/","routes/dashboard.ts","routes/dashboard-api.ts"],marketing:["app/Actions/Dashboard/Marketing/","app/Actions/Dashboard/dashboard-response.ts","app/Models/Campaign.ts","app/Models/CampaignSend.ts","app/Models/EmailList.ts","app/Models/EmailListSubscriber.ts","app/Models/SocialPost.ts","resources/components/Marketing/","resources/views/dashboard/marketing/"],monitoring:["app/Actions/Monitoring/","app/Actions/TestErrorAction.ts","app/Models/Error.ts","functions/monitoring/","resources/views/dashboard/monitoring/","resources/views/dashboard/errors/"],realtime:["app/Actions/Realtime/","app/Actions/Dashboard/Realtime/","app/Actions/Dashboard/dashboard-response.ts","app/Models/realtime/","app/Broadcasts/","functions/realtime/","resources/views/dashboard/realtime/"],queue:["app/Actions/Queue/","app/Actions/Dashboard/Jobs/","app/Actions/Dashboard/dashboard-response.ts","app/Jobs/","app/Models/Job.ts","app/Models/FailedJob.ts","functions/jobs.ts","resources/views/dashboard/queue/","resources/views/dashboard/jobs/"]},b={forms:["forms","form_fields","form_submissions"],cms:["posts","pages","comments","tags","authors","categories","taggable_models","categorizable_models","commentables","page_revisions","redirects","menus","menu_items"],commerce:["products","product_variants","product_units","manufacturers","orders","order_items","order_idempotency","carts","cart_items","payments","payment_methods","payment_products","payment_transactions","customers","subscribers","subscriber_emails","subscriptions","gift_cards","coupons","transactions","reviews","couriers","courier_pings","delivery_routes","delivery_stops","digital_deliveries","shipping_methods","shipping_rates","shipping_zones","license_keys","loyalty_points","loyalty_rewards","print_devices","receipts","tax_rates","waitlist_products","waitlist_restaurants","auctions","auction_items","bids","pledges"],dashboard:["boards","board_columns","cards","card_labels","card_assignees","card_comments","labels","ci_run_states","ci_runner_samples","ci_runner_alert_states","requests","logs"],marketing:["campaigns","campaign_sends","email_lists","email_list_subscribers","social_posts","mail_preferences"],monitoring:["errors"],realtime:["websockets"],queue:["jobs","failed_jobs"]};function _(r){let o=r.match(/-in-([a-z0-9_]+)\.sql$/i);if(o)return o[1]??null;let s=r.match(/-create-([a-z0-9_]+)-table\.sql$/i);if(s)return s[1]??null;let a=r.match(/-alter-([a-z0-9_]+)-/i);if(a)return a[1]??null;return null}function M(r){let o=_(r);if(!o)return null;for(let s of i)if(b[s].includes(o))return s;return null}function A(r,o=l()){let s=t(o,"app/Models");if(!p(s))return!1;let a=new Set(i.flatMap((e)=>u[e]).filter((e)=>e.startsWith("app/Models/")&&!e.endsWith("/"))),n=r.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),c=new RegExp(`\\btable\\s*:\\s*['"]${n}['"]`);for(let e of d(s,{withFileTypes:!0})){if(!e.isFile()||!/\.[cm]?[jt]s$/.test(e.name))continue;if(a.has(`app/Models/${e.name}`))continue;if(c.test(m(t(s,e.name),"utf8")))return!0}return!1}export{u as FEATURE_FILES,i as FEATURE_NAMES,b as FEATURE_TABLES,A as appModelClaimsTable,M as migrationFeature,_ as migrationTable};
|
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@stacksjs/features",
|
|
3
|
+
"type": "module",
|
|
4
|
+
"version": "0.74.4",
|
|
5
|
+
"description": "Which files and tables belong to which optional Stacks feature.",
|
|
6
|
+
"author": "Chris Breuer",
|
|
7
|
+
"contributors": [
|
|
8
|
+
"Chris Breuer <chris@stacksjs.com>"
|
|
9
|
+
],
|
|
10
|
+
"license": "MIT",
|
|
11
|
+
"funding": "https://github.com/sponsors/chrisbbreuer",
|
|
12
|
+
"homepage": "https://github.com/stacksjs/stacks/tree/main/storage/framework/core/features#readme",
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "git+https://github.com/stacksjs/stacks.git",
|
|
16
|
+
"directory": "./storage/framework/core/features"
|
|
17
|
+
},
|
|
18
|
+
"bugs": {
|
|
19
|
+
"url": "https://github.com/stacksjs/stacks/issues"
|
|
20
|
+
},
|
|
21
|
+
"keywords": [
|
|
22
|
+
"features",
|
|
23
|
+
"migrations",
|
|
24
|
+
"manifest",
|
|
25
|
+
"stacks"
|
|
26
|
+
],
|
|
27
|
+
"exports": {
|
|
28
|
+
".": {
|
|
29
|
+
"types": "./dist/index.d.ts",
|
|
30
|
+
"bun": "./dist/index.js",
|
|
31
|
+
"import": "./dist/index.js"
|
|
32
|
+
},
|
|
33
|
+
"./*": {
|
|
34
|
+
"import": "./dist/*"
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
"module": "./dist/index.js",
|
|
38
|
+
"types": "./dist/index.d.ts",
|
|
39
|
+
"files": [
|
|
40
|
+
"README.md",
|
|
41
|
+
"dist"
|
|
42
|
+
],
|
|
43
|
+
"scripts": {
|
|
44
|
+
"build": "bun build.ts",
|
|
45
|
+
"typecheck": "bun --bun tsc --noEmit"
|
|
46
|
+
},
|
|
47
|
+
"dependencies": {
|
|
48
|
+
"@stacksjs/path": "0.74.4"
|
|
49
|
+
}
|
|
50
|
+
}
|