@fonderie/cli 0.3.0 → 0.4.0
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/bin/fonderie.mjs +33 -0
- package/bin/fonderie.test.mjs +19 -2
- package/data/knowledge.json +755 -7
- package/package.json +5 -5
package/bin/fonderie.mjs
CHANGED
|
@@ -317,6 +317,36 @@ async function adminFetch(method, path, body) {
|
|
|
317
317
|
console.log(typeof result === 'string' ? result : JSON.stringify(result, null, 2));
|
|
318
318
|
}
|
|
319
319
|
|
|
320
|
+
// ── fonderie admin <page> — read a deployment's operator surface (@fonderie/admin) ─
|
|
321
|
+
// One page per operator question. Read-only; the prefix defaults to /_admin
|
|
322
|
+
// and follows FONDERIE_ADMIN_PREFIX when the app moved it.
|
|
323
|
+
const ADMIN_PAGES = {
|
|
324
|
+
attention: { path: '', about: 'what needs the operator today' },
|
|
325
|
+
manifest: { path: '/manifest', about: 'modules, versions, readiness, the route table' },
|
|
326
|
+
doctor: { path: '/doctor', about: 'every reconciliation check, on demand' },
|
|
327
|
+
config: { path: '/config', about: 'readiness per module + env presence' },
|
|
328
|
+
routes: { path: '/routes', about: 'every exposed route with its guard' },
|
|
329
|
+
tokens: { path: '/access/tokens', about: 'the admin token verdict + legacy per-brick tokens' },
|
|
330
|
+
log: { path: '/activity/admin-log', about: 'who did what through the surface (--limit, --before)' },
|
|
331
|
+
};
|
|
332
|
+
async function adminCmd() {
|
|
333
|
+
const pageName = argv[1];
|
|
334
|
+
const page = ADMIN_PAGES[pageName];
|
|
335
|
+
if (!page) {
|
|
336
|
+
console.error(`fonderie admin <${Object.keys(ADMIN_PAGES).join('|')}>`);
|
|
337
|
+
for (const [k, v] of Object.entries(ADMIN_PAGES)) console.error(` ${k.padEnd(10)} ${v.about}`);
|
|
338
|
+
process.exit(2);
|
|
339
|
+
}
|
|
340
|
+
const prefix = (process.env.FONDERIE_ADMIN_PREFIX || '/_admin').replace(/\/$/, '');
|
|
341
|
+
const q = new URLSearchParams();
|
|
342
|
+
const limit = arg('--limit', undefined);
|
|
343
|
+
const before = arg('--before', undefined);
|
|
344
|
+
if (pageName === 'log' && limit) q.set('limit', limit);
|
|
345
|
+
if (pageName === 'log' && before) q.set('before', before);
|
|
346
|
+
const qs = q.toString();
|
|
347
|
+
return adminFetch('GET', prefix + page.path + (qs ? `?${qs}` : ''));
|
|
348
|
+
}
|
|
349
|
+
|
|
320
350
|
// The supported management verbs (kubectl-inspired) — the single source of truth
|
|
321
351
|
// for the CLI's config/secret surface. Each maps to a method + optional path
|
|
322
352
|
// suffix + what it requires (a key, a body value, a --to-version).
|
|
@@ -398,6 +428,7 @@ else if (cmd === 'init') doInit();
|
|
|
398
428
|
else if (cmd === 'config') resourceCmd('config', '/admin/config').catch((e) => { console.error(e.message); process.exit(1); });
|
|
399
429
|
else if (cmd === 'secret') resourceCmd('secret', '/admin/secrets').catch((e) => { console.error(e.message); process.exit(1); });
|
|
400
430
|
else if (cmd === 'template') resourceCmd('template', '/admin/templates').catch((e) => { console.error(e.message); process.exit(1); });
|
|
431
|
+
else if (cmd === 'admin') adminCmd().catch((e) => { console.error(e.message); process.exit(1); });
|
|
401
432
|
else {
|
|
402
433
|
console.log(`fonderie — the Fonderie CLI (lazy skills for coding agents)
|
|
403
434
|
|
|
@@ -411,6 +442,8 @@ else {
|
|
|
411
442
|
fonderie secret <get|set|delete|history|rollback|reveal> [key] [value] [--env <e>] ...
|
|
412
443
|
fonderie template <get|set|delete|history|rollback> [type] [text] [--locale <l>] [--subject <s>] [--html <h>] ...
|
|
413
444
|
manage a live deployment over its admin API — set FONDERIE_ADMIN_URL + FONDERIE_ADMIN_TOKEN
|
|
445
|
+
fonderie admin <attention|manifest|doctor|config|routes|tokens|log> [--limit <n>] [--before <cursor>]
|
|
446
|
+
read a deployment's operator surface (@fonderie/admin) — same env; FONDERIE_ADMIN_PREFIX if moved
|
|
414
447
|
|
|
415
448
|
Zero deps. No MCP server. A binary + markdown that runs in any agent harness.`);
|
|
416
449
|
if (cmd && cmd !== 'help' && cmd !== '--help') process.exit(2);
|
package/bin/fonderie.test.mjs
CHANGED
|
@@ -55,8 +55,12 @@ if (!existsSync(join(out, 'fonderie', 'auth.md'))) fail('missing lazy body fonde
|
|
|
55
55
|
if (existsSync(join(out, 'fonderie', 'workspaces.md'))) fail('should NOT emit a body for an uninstalled package');
|
|
56
56
|
if (!/class BillingModule/.test(readFileSync(join(out, 'fonderie', 'billing.md'), 'utf8'))) fail('billing body missing its signatures');
|
|
57
57
|
|
|
58
|
-
//
|
|
59
|
-
|
|
58
|
+
// Router stays lazy: it lists one row per concept + invariants, so it grows with
|
|
59
|
+
// the catalog (61 concepts ≈ 5.9k tok as of 2026-08). The budget guards the lazy
|
|
60
|
+
// win — the router must stay well under the 6–28k eager brain it replaces, not
|
|
61
|
+
// that it be tiny. Bump this if the catalog legitimately grows; shrink the router
|
|
62
|
+
// (e.g. collapse uninstalled concepts) if it approaches the eager range.
|
|
63
|
+
if (Math.ceil(router.length / 4) > 8000) fail(`router too big (~${Math.ceil(router.length / 4)} tok) — lazy defeated`);
|
|
60
64
|
|
|
61
65
|
// --- init → generates the skill AND wires a fresh-keeping postinstall ---
|
|
62
66
|
const proj2 = mkdtempSync(join(tmpdir(), 'fonderie-init-'));
|
|
@@ -128,6 +132,19 @@ await (async () => {
|
|
|
128
132
|
if (find('POST', '/admin/config/feature.x/rollback')?.body?.toVersion !== 2) fail('rollback: toVersion body wrong');
|
|
129
133
|
if (!find('POST', '/admin/secrets/stripe.key/reveal?environment=prod')) fail('secret reveal: wrong path');
|
|
130
134
|
|
|
135
|
+
// fonderie admin <page> — the operator surface, read-only, prefix-aware
|
|
136
|
+
await cli(['admin', 'manifest']);
|
|
137
|
+
await cli(['admin', 'attention']);
|
|
138
|
+
await cli(['admin', 'log', '--limit', '5', '--before', 'abc']);
|
|
139
|
+
await execFileP('node', [bin, 'admin', 'doctor'], { env: { ...env, FONDERIE_ADMIN_PREFIX: '/ops/' } });
|
|
140
|
+
if (!find('GET', '/_admin/manifest')?.auth?.includes('sekret')) fail('admin manifest: wrong request/auth');
|
|
141
|
+
if (!find('GET', '/_admin')) fail('admin attention: should hit the prefix root');
|
|
142
|
+
if (!find('GET', '/_admin/activity/admin-log?limit=5&before=abc')) fail('admin log: flags not forwarded');
|
|
143
|
+
if (!find('GET', '/ops/doctor')) fail('admin doctor: FONDERIE_ADMIN_PREFIX not honoured');
|
|
144
|
+
let unknown = 0;
|
|
145
|
+
try { await cli(['admin', 'nope']); } catch (e) { unknown = e.code; }
|
|
146
|
+
if (unknown !== 2) fail(`admin <unknown page> should exit 2, got ${unknown}`);
|
|
147
|
+
|
|
131
148
|
// 409 conflict → exit 2 (reload + retry)
|
|
132
149
|
let code = 0;
|
|
133
150
|
try { await cli(['config', 'set', 'conflict', 'x']); } catch (e) { code = e.code; }
|
package/data/knowledge.json
CHANGED
|
@@ -36,17 +36,17 @@
|
|
|
36
36
|
"recipe": "teams-invites"
|
|
37
37
|
},
|
|
38
38
|
"permissions.rbac": {
|
|
39
|
-
"description": "roles and permissions — admin/member/viewer, access control",
|
|
39
|
+
"description": "roles and permissions — admin/member/viewer, access control. Backend-only: @fonderie/permissions has no HTTP routes (server-side requirePermission/requireRole middleware + PermissionsEngine.can/.assert). For a frontend role-management UI, see react-workspaces.hooks / vue-workspaces.composables (useRoles, useMemberRoles) — role CRUD is exposed under @fonderie/workspaces' routes.",
|
|
40
40
|
"package": "permissions",
|
|
41
41
|
"recipe": "rbac"
|
|
42
42
|
},
|
|
43
43
|
"courier.messaging": {
|
|
44
|
-
"description": "SEND any transactional message — email, SMS, push; use this for password-reset, email-verification, welcome, and invite emails (auth.* is who can log in, courier is what delivers the message)",
|
|
44
|
+
"description": "SEND any transactional message — email, SMS, push; use this for password-reset, email-verification, welcome, and invite emails (auth.* is who can log in, courier is what delivers the message). No end-user-facing HTTP API — messages are sent server-side via the event bus, not called from a frontend. For an admin template-editor UI, see react-courier-admin.templates / vue-courier-admin.templates.",
|
|
45
45
|
"package": "courier",
|
|
46
46
|
"recipe": "transactional-email"
|
|
47
47
|
},
|
|
48
48
|
"webhooks.in-out": {
|
|
49
|
-
"description": "receive webhooks (Stripe) and emit your own to other apps",
|
|
49
|
+
"description": "receive webhooks (Stripe) and emit your own to other apps — full CRUD on outbound endpoints plus delivery history and test-send. Session-authenticated like billing/workspaces/audit (not the admin-token model courier-admin/config-admin use). For a frontend endpoint manager, see react-webhooks.hooks / vue-webhooks.composables.",
|
|
50
50
|
"package": "webhooks",
|
|
51
51
|
"recipe": "webhooks-in-out"
|
|
52
52
|
},
|
|
@@ -55,11 +55,11 @@
|
|
|
55
55
|
"package": "events"
|
|
56
56
|
},
|
|
57
57
|
"config.flags": {
|
|
58
|
-
"description": "feature flags, remote config, kill switches",
|
|
58
|
+
"description": "feature flags, remote config, kill switches. No end-user-facing HTTP API — apps read config server-side or via defineConfig(); the only HTTP surface is the admin-token-guarded /admin/config and /admin/secrets management API. For an admin dashboard UI, see react-config-admin.admin / vue-config-admin.admin.",
|
|
59
59
|
"package": "config"
|
|
60
60
|
},
|
|
61
61
|
"audit.trail": {
|
|
62
|
-
"description": "workspace-scoped audit log — who did what, compliance",
|
|
62
|
+
"description": "workspace-scoped audit log — who did what, compliance. One read-only route (GET /audit); no create/update/delete API since events are written internally by other modules. For a frontend log viewer, see react-audit.hooks / vue-audit.composables — session-authenticated like billing/workspaces, not the admin-token model courier-admin/config-admin use.",
|
|
63
63
|
"package": "audit"
|
|
64
64
|
},
|
|
65
65
|
"rate-limit.throttle": {
|
|
@@ -67,7 +67,7 @@
|
|
|
67
67
|
"package": "rate-limit"
|
|
68
68
|
},
|
|
69
69
|
"customers.crm": {
|
|
70
|
-
"description": "customer records / CRM tied to billing",
|
|
70
|
+
"description": "customer records / CRM tied to billing — session-authenticated like billing/workspaces/audit/webhooks (not the admin-token model courier-admin/config-admin use). Widest surface in the SDK: core customer CRUD + blacklist, plus emails/phones/addresses/notes/tags/relationships/labels sub-resources (35 routes). Only the label is editable on an existing email/phone/address, not the value — remove and re-add to change it. For a frontend customer manager, see react-customers.hooks / vue-customers.composables.",
|
|
71
71
|
"package": "customers"
|
|
72
72
|
},
|
|
73
73
|
"core.app": {
|
|
@@ -77,6 +77,226 @@
|
|
|
77
77
|
"store.database": {
|
|
78
78
|
"description": "Postgres access and append-only migrations",
|
|
79
79
|
"package": "store"
|
|
80
|
+
},
|
|
81
|
+
"react-auth.hooks": {
|
|
82
|
+
"description": "React hooks for auth — useLogin, useRegister, useSession, useLogout, useForgotPassword, useResetPassword, useVerifyEmail, wrapping @fonderie/client",
|
|
83
|
+
"package": "react-auth",
|
|
84
|
+
"recipe": "react-auth-wiring"
|
|
85
|
+
},
|
|
86
|
+
"react-auth.screens": {
|
|
87
|
+
"description": "pre-built React auth screens (LoginScreen, RegisterScreen, ForgotPasswordScreen) built on react-auth hooks — bring your own styling",
|
|
88
|
+
"package": "react-auth-screens",
|
|
89
|
+
"recipe": "react-auth-screens-wiring"
|
|
90
|
+
},
|
|
91
|
+
"react-native-auth.hooks": {
|
|
92
|
+
"description": "React Native hooks for auth — same shape as react-auth, token persisted to AsyncStorage instead of localStorage",
|
|
93
|
+
"package": "react-native-auth",
|
|
94
|
+
"recipe": "react-native-auth-wiring"
|
|
95
|
+
},
|
|
96
|
+
"react-native-auth.screens": {
|
|
97
|
+
"description": "pre-built React Native auth screens (LoginScreen, RegisterScreen, ForgotPasswordScreen) built on react-native-auth hooks",
|
|
98
|
+
"package": "react-native-auth-screens",
|
|
99
|
+
"recipe": "react-native-auth-screens-wiring"
|
|
100
|
+
},
|
|
101
|
+
"vue-auth.composables": {
|
|
102
|
+
"description": "Vue composables for auth — useLogin, useRegister, useSession, useLogout, useForgotPassword, useResetPassword, useVerifyEmail, wrapping @fonderie/client",
|
|
103
|
+
"package": "vue-auth",
|
|
104
|
+
"recipe": "vue-auth-wiring"
|
|
105
|
+
},
|
|
106
|
+
"vue-auth.screens": {
|
|
107
|
+
"description": "pre-built Vue auth screens (LoginScreen, RegisterScreen, ForgotPasswordScreen) built on vue-auth composables via Vue's h() render API",
|
|
108
|
+
"package": "vue-auth-screens",
|
|
109
|
+
"recipe": "vue-auth-screens-wiring"
|
|
110
|
+
},
|
|
111
|
+
"react-billing.hooks": {
|
|
112
|
+
"description": "React hooks for billing — usePlans, usePlan, useSubscription, useCheckout, useBillingPortal, useUsage, useRecordUsage, plus usePlanAdmin (create/update/delete plans) wrapping @fonderie/client's BillingClient. usePlanAdmin's routes are the one write surface in this SDK with no requireAuth/admin-token gate server-side — the app must authorize access to it itself before shipping any UI built on it.",
|
|
113
|
+
"package": "react-billing",
|
|
114
|
+
"recipe": "react-billing-wiring"
|
|
115
|
+
},
|
|
116
|
+
"react-billing.screens": {
|
|
117
|
+
"description": "pre-built React billing screens (PricingScreen, SubscriptionScreen) built on react-billing hooks — bring your own styling",
|
|
118
|
+
"package": "react-billing-screens",
|
|
119
|
+
"recipe": "react-billing-screens-wiring"
|
|
120
|
+
},
|
|
121
|
+
"react-native-billing.hooks": {
|
|
122
|
+
"description": "React Native billing hooks — re-exports react-billing wholesale (no platform-specific storage, unlike auth)",
|
|
123
|
+
"package": "react-native-billing",
|
|
124
|
+
"recipe": "react-native-billing-wiring"
|
|
125
|
+
},
|
|
126
|
+
"react-native-billing.screens": {
|
|
127
|
+
"description": "pre-built React Native billing screens (PricingScreen, SubscriptionScreen) built on react-native-billing hooks",
|
|
128
|
+
"package": "react-native-billing-screens",
|
|
129
|
+
"recipe": "react-native-billing-screens-wiring"
|
|
130
|
+
},
|
|
131
|
+
"vue-billing.composables": {
|
|
132
|
+
"description": "Vue composables for billing — usePlans, usePlan, useSubscription, useCheckout, useBillingPortal, useUsage, useRecordUsage, plus usePlanAdmin (create/update/delete plans) wrapping @fonderie/client's BillingClient. usePlanAdmin's routes are the one write surface in this SDK with no requireAuth/admin-token gate server-side — the app must authorize access to it itself before shipping any UI built on it.",
|
|
133
|
+
"package": "vue-billing",
|
|
134
|
+
"recipe": "vue-billing-wiring"
|
|
135
|
+
},
|
|
136
|
+
"vue-billing.screens": {
|
|
137
|
+
"description": "pre-built Vue billing screens (PricingScreen, SubscriptionScreen) built on vue-billing composables via Vue's h() render API",
|
|
138
|
+
"package": "vue-billing-screens",
|
|
139
|
+
"recipe": "vue-billing-screens-wiring"
|
|
140
|
+
},
|
|
141
|
+
"react-workspaces.hooks": {
|
|
142
|
+
"description": "React hooks for workspaces — useWorkspaces, useCreateWorkspace, useWorkspaceProfile (update/archive/restore the current workspace — action-only, no read hook since there's no 'get current workspace' route), useMembers, useRemoveMember, useInvitations, useAcceptInvitation, useWorkspaceSettings, plus role management (useRoles, useUpdateRole, useSetRolePermissions, useMemberRoles) — @fonderie/permissions has no HTTP API of its own, role CRUD lives here under @fonderie/workspaces' routes. Wraps @fonderie/client's WorkspacesClient.",
|
|
143
|
+
"package": "react-workspaces",
|
|
144
|
+
"recipe": "react-workspaces-wiring"
|
|
145
|
+
},
|
|
146
|
+
"react-workspaces.screens": {
|
|
147
|
+
"description": "pre-built React workspaces screens (TeamMembersScreen, InviteMembersScreen) built on react-workspaces hooks — bring your own styling",
|
|
148
|
+
"package": "react-workspaces-screens",
|
|
149
|
+
"recipe": "react-workspaces-screens-wiring"
|
|
150
|
+
},
|
|
151
|
+
"react-native-workspaces.hooks": {
|
|
152
|
+
"description": "React Native workspaces hooks — re-exports react-workspaces wholesale (no platform-specific storage, unlike auth)",
|
|
153
|
+
"package": "react-native-workspaces",
|
|
154
|
+
"recipe": "react-native-workspaces-wiring"
|
|
155
|
+
},
|
|
156
|
+
"react-native-workspaces.screens": {
|
|
157
|
+
"description": "pre-built React Native workspaces screens (TeamMembersScreen, InviteMembersScreen) built on react-native-workspaces hooks",
|
|
158
|
+
"package": "react-native-workspaces-screens",
|
|
159
|
+
"recipe": "react-native-workspaces-screens-wiring"
|
|
160
|
+
},
|
|
161
|
+
"vue-workspaces.composables": {
|
|
162
|
+
"description": "Vue composables for workspaces — useWorkspaces, useCreateWorkspace, useWorkspaceProfile (update/archive/restore the current workspace — action-only, no read composable since there's no 'get current workspace' route), useMembers, useRemoveMember, useInvitations, useAcceptInvitation, useWorkspaceSettings, plus role management (useRoles, useUpdateRole, useSetRolePermissions, useMemberRoles) — @fonderie/permissions has no HTTP API of its own, role CRUD lives here under @fonderie/workspaces' routes. Wraps @fonderie/client's WorkspacesClient.",
|
|
163
|
+
"package": "vue-workspaces",
|
|
164
|
+
"recipe": "vue-workspaces-wiring"
|
|
165
|
+
},
|
|
166
|
+
"vue-workspaces.screens": {
|
|
167
|
+
"description": "pre-built Vue workspaces screens (TeamMembersScreen, InviteMembersScreen) built on vue-workspaces composables via Vue's h() render API",
|
|
168
|
+
"package": "vue-workspaces-screens",
|
|
169
|
+
"recipe": "vue-workspaces-screens-wiring"
|
|
170
|
+
},
|
|
171
|
+
"react-courier-admin.templates": {
|
|
172
|
+
"description": "React hooks for courier's email/SMS/push template admin API — useTemplates, useTemplate, useSaveTemplate, useDeleteTemplate, useTemplateRevisions (list + rollback). Admin-token authenticated via a standalone CourierAdminClient — does NOT share FonderieClient's session token with auth/billing/workspaces.",
|
|
173
|
+
"package": "react-courier-admin",
|
|
174
|
+
"recipe": "react-courier-admin-wiring"
|
|
175
|
+
},
|
|
176
|
+
"react-courier-admin.screens": {
|
|
177
|
+
"description": "pre-built React screens (TemplateListScreen, TemplateEditorScreen with revision history + rollback) built on react-courier-admin hooks — an admin-dashboard surface, bring your own styling",
|
|
178
|
+
"package": "react-courier-admin-screens",
|
|
179
|
+
"recipe": "react-courier-admin-screens-wiring"
|
|
180
|
+
},
|
|
181
|
+
"vue-courier-admin.composables": {
|
|
182
|
+
"description": "Vue composables for courier's email/SMS/push template admin API — useTemplates, useTemplate, useSaveTemplate, useDeleteTemplate, useTemplateRevisions (list + rollback). Admin-token authenticated via a standalone CourierAdminClient — does NOT share FonderieClient's session token with auth/billing/workspaces.",
|
|
183
|
+
"package": "vue-courier-admin",
|
|
184
|
+
"recipe": "vue-courier-admin-wiring"
|
|
185
|
+
},
|
|
186
|
+
"vue-courier-admin.screens": {
|
|
187
|
+
"description": "pre-built Vue screens (TemplateListScreen, TemplateEditorScreen with revision history + rollback) built on vue-courier-admin composables via Vue's h() render API — an admin-dashboard surface",
|
|
188
|
+
"package": "vue-courier-admin-screens",
|
|
189
|
+
"recipe": "vue-courier-admin-screens-wiring"
|
|
190
|
+
},
|
|
191
|
+
"react-config-admin.admin": {
|
|
192
|
+
"description": "React hooks for config's feature-flag/remote-config + secrets admin API — useConfigEntries, useConfigEntry, useSaveConfigEntry, useDeleteConfigEntry, useConfigRevisions and the secret equivalents (useSecrets, useSecret, useSaveSecret, useDeleteSecret, useSecretRevisions) plus useRevealSecret. Admin-token authenticated via a standalone ConfigAdminClient — does NOT share FonderieClient's session token with auth/billing/workspaces.",
|
|
193
|
+
"package": "react-config-admin",
|
|
194
|
+
"recipe": "react-config-admin-wiring"
|
|
195
|
+
},
|
|
196
|
+
"react-config-admin.screens": {
|
|
197
|
+
"description": "pre-built React screens (ConfigListScreen: config + masked secrets dashboard; ConfigEditorScreen: JSON/secret editor with revision history + rollback) built on react-config-admin hooks — an admin-dashboard surface, bring your own styling",
|
|
198
|
+
"package": "react-config-admin-screens",
|
|
199
|
+
"recipe": "react-config-admin-screens-wiring"
|
|
200
|
+
},
|
|
201
|
+
"vue-config-admin.admin": {
|
|
202
|
+
"description": "Vue composables for config's feature-flag/remote-config + secrets admin API — same set as react-config-admin.admin. Admin-token authenticated via a standalone ConfigAdminClient — does NOT share FonderieClient's session token with auth/billing/workspaces.",
|
|
203
|
+
"package": "vue-config-admin",
|
|
204
|
+
"recipe": "vue-config-admin-wiring"
|
|
205
|
+
},
|
|
206
|
+
"vue-config-admin.screens": {
|
|
207
|
+
"description": "pre-built Vue screens (ConfigListScreen, ConfigEditorScreen) built on vue-config-admin composables via Vue's h() render API — an admin-dashboard surface",
|
|
208
|
+
"package": "vue-config-admin-screens",
|
|
209
|
+
"recipe": "vue-config-admin-screens-wiring"
|
|
210
|
+
},
|
|
211
|
+
"react-audit.hooks": {
|
|
212
|
+
"description": "React hook for the audit log — useAuditEvents, cursor-paginated with type/actorId/date-range filters and loadMore. Read-only (@fonderie/audit has one route); session-authenticated like billing/workspaces, wraps @fonderie/client's AuditClient.",
|
|
213
|
+
"package": "react-audit",
|
|
214
|
+
"recipe": "react-audit-wiring"
|
|
215
|
+
},
|
|
216
|
+
"react-audit.screens": {
|
|
217
|
+
"description": "pre-built React screen (AuditLogScreen: type/actor filters, expandable JSON payload, load-more) built on react-audit's useAuditEvents — bring your own styling",
|
|
218
|
+
"package": "react-audit-screens",
|
|
219
|
+
"recipe": "react-audit-screens-wiring"
|
|
220
|
+
},
|
|
221
|
+
"react-native-audit.hooks": {
|
|
222
|
+
"description": "React Native audit log hook — re-exports react-audit wholesale (no platform-specific storage, unlike auth)",
|
|
223
|
+
"package": "react-native-audit",
|
|
224
|
+
"recipe": "react-native-audit-wiring"
|
|
225
|
+
},
|
|
226
|
+
"react-native-audit.screens": {
|
|
227
|
+
"description": "pre-built React Native screen (AuditLogScreen) built on react-native-audit's useAuditEvents",
|
|
228
|
+
"package": "react-native-audit-screens",
|
|
229
|
+
"recipe": "react-native-audit-screens-wiring"
|
|
230
|
+
},
|
|
231
|
+
"vue-audit.composables": {
|
|
232
|
+
"description": "Vue composable for the audit log — useAuditEvents, cursor-paginated with type/actorId/date-range filters and loadMore. Read-only (@fonderie/audit has one route); session-authenticated like billing/workspaces, wraps @fonderie/client's AuditClient.",
|
|
233
|
+
"package": "vue-audit",
|
|
234
|
+
"recipe": "vue-audit-wiring"
|
|
235
|
+
},
|
|
236
|
+
"vue-audit.screens": {
|
|
237
|
+
"description": "pre-built Vue screen (AuditLogScreen) built on vue-audit's useAuditEvents via Vue's h() render API",
|
|
238
|
+
"package": "vue-audit-screens",
|
|
239
|
+
"recipe": "vue-audit-screens-wiring"
|
|
240
|
+
},
|
|
241
|
+
"react-webhooks.hooks": {
|
|
242
|
+
"description": "React hooks for webhook endpoints — useWebhookEndpoints (list/create/delete), useWebhookEndpoint (get/update), useWebhookDeliveries (delivery history), useTestWebhookEndpoint (send a test event). Session-authenticated like billing/workspaces/audit, wraps @fonderie/client's WebhooksClient. createEndpoint's signing secret is only returned once, at creation.",
|
|
243
|
+
"package": "react-webhooks",
|
|
244
|
+
"recipe": "react-webhooks-wiring"
|
|
245
|
+
},
|
|
246
|
+
"react-webhooks-screens.screens": {
|
|
247
|
+
"description": "pre-built React screens (WebhooksListScreen: create form + list + test/delete + one-time secret banner; WebhookDetailScreen: edit form + delivery history) built on react-webhooks' hooks — bring your own styling",
|
|
248
|
+
"package": "react-webhooks-screens",
|
|
249
|
+
"recipe": "react-webhooks-screens-wiring"
|
|
250
|
+
},
|
|
251
|
+
"react-native-webhooks.hooks": {
|
|
252
|
+
"description": "React Native webhook hooks — re-exports react-webhooks wholesale (no platform-specific storage, unlike auth)",
|
|
253
|
+
"package": "react-native-webhooks",
|
|
254
|
+
"recipe": "react-native-webhooks-wiring"
|
|
255
|
+
},
|
|
256
|
+
"react-native-webhooks-screens.screens": {
|
|
257
|
+
"description": "pre-built React Native screens (WebhooksListScreen, WebhookDetailScreen) built on react-native-webhooks' hooks, using FlatList/TextInput/TouchableOpacity",
|
|
258
|
+
"package": "react-native-webhooks-screens",
|
|
259
|
+
"recipe": "react-native-webhooks-screens-wiring"
|
|
260
|
+
},
|
|
261
|
+
"vue-webhooks.composables": {
|
|
262
|
+
"description": "Vue composables for webhook endpoints — useWebhookEndpoints, useWebhookEndpoint, useWebhookDeliveries, useTestWebhookEndpoint. Session-authenticated like billing/workspaces/audit, wraps @fonderie/client's WebhooksClient. Endpoint IDs are read once at setup; call refresh() after changing them.",
|
|
263
|
+
"package": "vue-webhooks",
|
|
264
|
+
"recipe": "vue-webhooks-wiring"
|
|
265
|
+
},
|
|
266
|
+
"vue-webhooks-screens.screens": {
|
|
267
|
+
"description": "pre-built Vue screens (WebhooksListScreen, WebhookDetailScreen) built on vue-webhooks' composables via Vue's h() render API, emitting select-endpoint / navigate-list",
|
|
268
|
+
"package": "vue-webhooks-screens",
|
|
269
|
+
"recipe": "vue-webhooks-screens-wiring"
|
|
270
|
+
},
|
|
271
|
+
"react-customers.hooks": {
|
|
272
|
+
"description": "React hooks for customers — useCustomers (list/create/delete/blacklist), useCustomer (get/update), plus one combined hook per sub-resource: useCustomerEmails, useCustomerPhones, useCustomerAddresses, useCustomerNotes, useCustomerTags, useCustomerRelationships, useCustomerLabels. Session-authenticated like billing/workspaces/audit/webhooks, wraps @fonderie/client's CustomersClient. Only the label is editable on an existing email/phone/address, not the value.",
|
|
273
|
+
"package": "react-customers",
|
|
274
|
+
"recipe": "react-customers-wiring"
|
|
275
|
+
},
|
|
276
|
+
"react-customers-screens.screens": {
|
|
277
|
+
"description": "pre-built React screens (CustomersListScreen: search + create + blacklist badge; CustomerDetailScreen: profile edit + inline emails/phones/tags/notes) built on react-customers' hooks — relationships and label vocabulary aren't covered, use the hooks directly for those",
|
|
278
|
+
"package": "react-customers-screens",
|
|
279
|
+
"recipe": "react-customers-screens-wiring"
|
|
280
|
+
},
|
|
281
|
+
"react-native-customers.hooks": {
|
|
282
|
+
"description": "React Native customer hooks — re-exports react-customers wholesale (no platform-specific storage, unlike auth)",
|
|
283
|
+
"package": "react-native-customers",
|
|
284
|
+
"recipe": "react-native-customers-wiring"
|
|
285
|
+
},
|
|
286
|
+
"react-native-customers-screens.screens": {
|
|
287
|
+
"description": "pre-built React Native screens (CustomersListScreen, CustomerDetailScreen) built on react-native-customers' hooks, using FlatList/TextInput/TouchableOpacity",
|
|
288
|
+
"package": "react-native-customers-screens",
|
|
289
|
+
"recipe": "react-native-customers-screens-wiring"
|
|
290
|
+
},
|
|
291
|
+
"vue-customers.composables": {
|
|
292
|
+
"description": "Vue composables for customers — useCustomers, useCustomer, plus one combined composable per sub-resource: useCustomerEmails, useCustomerPhones, useCustomerAddresses, useCustomerNotes, useCustomerTags, useCustomerRelationships, useCustomerLabels. Session-authenticated like billing/workspaces/audit/webhooks, wraps @fonderie/client's CustomersClient.",
|
|
293
|
+
"package": "vue-customers",
|
|
294
|
+
"recipe": "vue-customers-wiring"
|
|
295
|
+
},
|
|
296
|
+
"vue-customers-screens.screens": {
|
|
297
|
+
"description": "pre-built Vue screens (CustomersListScreen, CustomerDetailScreen) built on vue-customers' composables via Vue's h() render API, emitting select-customer / navigate-list",
|
|
298
|
+
"package": "vue-customers-screens",
|
|
299
|
+
"recipe": "vue-customers-screens-wiring"
|
|
80
300
|
}
|
|
81
301
|
},
|
|
82
302
|
"recipes": {
|
|
@@ -198,6 +418,528 @@
|
|
|
198
418
|
"webhook-route-before-auth-mw",
|
|
199
419
|
"rate-limit-default-on"
|
|
200
420
|
]
|
|
421
|
+
},
|
|
422
|
+
"react-auth-wiring": {
|
|
423
|
+
"when": "adding auth to a React web app",
|
|
424
|
+
"packages": [
|
|
425
|
+
"client",
|
|
426
|
+
"react-auth"
|
|
427
|
+
],
|
|
428
|
+
"invariants": [
|
|
429
|
+
"frontend-client-injection",
|
|
430
|
+
"frontend-token-storage"
|
|
431
|
+
]
|
|
432
|
+
},
|
|
433
|
+
"react-auth-screens-wiring": {
|
|
434
|
+
"when": "adding auth to a React web app with pre-built UI, not just hooks",
|
|
435
|
+
"packages": [
|
|
436
|
+
"client",
|
|
437
|
+
"react-auth",
|
|
438
|
+
"react-auth-screens"
|
|
439
|
+
],
|
|
440
|
+
"invariants": [
|
|
441
|
+
"frontend-client-injection",
|
|
442
|
+
"frontend-token-storage"
|
|
443
|
+
]
|
|
444
|
+
},
|
|
445
|
+
"react-native-auth-wiring": {
|
|
446
|
+
"when": "adding auth to a React Native app",
|
|
447
|
+
"packages": [
|
|
448
|
+
"client",
|
|
449
|
+
"react-native-auth"
|
|
450
|
+
],
|
|
451
|
+
"invariants": [
|
|
452
|
+
"frontend-client-injection",
|
|
453
|
+
"frontend-token-storage"
|
|
454
|
+
]
|
|
455
|
+
},
|
|
456
|
+
"react-native-auth-screens-wiring": {
|
|
457
|
+
"when": "adding auth to a React Native app with pre-built UI, not just hooks",
|
|
458
|
+
"packages": [
|
|
459
|
+
"client",
|
|
460
|
+
"react-native-auth",
|
|
461
|
+
"react-native-auth-screens"
|
|
462
|
+
],
|
|
463
|
+
"invariants": [
|
|
464
|
+
"frontend-client-injection",
|
|
465
|
+
"frontend-token-storage"
|
|
466
|
+
]
|
|
467
|
+
},
|
|
468
|
+
"vue-auth-wiring": {
|
|
469
|
+
"when": "adding auth to a Vue 3 app",
|
|
470
|
+
"packages": [
|
|
471
|
+
"client",
|
|
472
|
+
"vue-auth"
|
|
473
|
+
],
|
|
474
|
+
"invariants": [
|
|
475
|
+
"frontend-client-injection",
|
|
476
|
+
"frontend-token-storage"
|
|
477
|
+
]
|
|
478
|
+
},
|
|
479
|
+
"vue-auth-screens-wiring": {
|
|
480
|
+
"when": "adding auth to a Vue 3 app with pre-built UI, not just composables",
|
|
481
|
+
"packages": [
|
|
482
|
+
"client",
|
|
483
|
+
"vue-auth",
|
|
484
|
+
"vue-auth-screens"
|
|
485
|
+
],
|
|
486
|
+
"invariants": [
|
|
487
|
+
"frontend-client-injection",
|
|
488
|
+
"frontend-token-storage"
|
|
489
|
+
]
|
|
490
|
+
},
|
|
491
|
+
"react-billing-wiring": {
|
|
492
|
+
"when": "adding billing/pricing/checkout to a React web app",
|
|
493
|
+
"packages": [
|
|
494
|
+
"client",
|
|
495
|
+
"react-billing"
|
|
496
|
+
],
|
|
497
|
+
"invariants": [
|
|
498
|
+
"frontend-client-injection",
|
|
499
|
+
"frontend-shared-token"
|
|
500
|
+
]
|
|
501
|
+
},
|
|
502
|
+
"react-billing-screens-wiring": {
|
|
503
|
+
"when": "adding billing to a React web app with pre-built UI, not just hooks",
|
|
504
|
+
"packages": [
|
|
505
|
+
"client",
|
|
506
|
+
"react-billing",
|
|
507
|
+
"react-billing-screens"
|
|
508
|
+
],
|
|
509
|
+
"invariants": [
|
|
510
|
+
"frontend-client-injection",
|
|
511
|
+
"frontend-shared-token"
|
|
512
|
+
]
|
|
513
|
+
},
|
|
514
|
+
"react-native-billing-wiring": {
|
|
515
|
+
"when": "adding billing/pricing/checkout to a React Native app",
|
|
516
|
+
"packages": [
|
|
517
|
+
"client",
|
|
518
|
+
"react-native-billing"
|
|
519
|
+
],
|
|
520
|
+
"invariants": [
|
|
521
|
+
"frontend-client-injection",
|
|
522
|
+
"frontend-shared-token"
|
|
523
|
+
]
|
|
524
|
+
},
|
|
525
|
+
"react-native-billing-screens-wiring": {
|
|
526
|
+
"when": "adding billing to a React Native app with pre-built UI, not just hooks",
|
|
527
|
+
"packages": [
|
|
528
|
+
"client",
|
|
529
|
+
"react-native-billing",
|
|
530
|
+
"react-native-billing-screens"
|
|
531
|
+
],
|
|
532
|
+
"invariants": [
|
|
533
|
+
"frontend-client-injection",
|
|
534
|
+
"frontend-shared-token"
|
|
535
|
+
]
|
|
536
|
+
},
|
|
537
|
+
"vue-billing-wiring": {
|
|
538
|
+
"when": "adding billing/pricing/checkout to a Vue 3 app",
|
|
539
|
+
"packages": [
|
|
540
|
+
"client",
|
|
541
|
+
"vue-billing"
|
|
542
|
+
],
|
|
543
|
+
"invariants": [
|
|
544
|
+
"frontend-client-injection",
|
|
545
|
+
"frontend-shared-token"
|
|
546
|
+
]
|
|
547
|
+
},
|
|
548
|
+
"vue-billing-screens-wiring": {
|
|
549
|
+
"when": "adding billing to a Vue 3 app with pre-built UI, not just composables",
|
|
550
|
+
"packages": [
|
|
551
|
+
"client",
|
|
552
|
+
"vue-billing",
|
|
553
|
+
"vue-billing-screens"
|
|
554
|
+
],
|
|
555
|
+
"invariants": [
|
|
556
|
+
"frontend-client-injection",
|
|
557
|
+
"frontend-shared-token"
|
|
558
|
+
]
|
|
559
|
+
},
|
|
560
|
+
"react-workspaces-wiring": {
|
|
561
|
+
"when": "adding teams/workspaces UI to a React web app",
|
|
562
|
+
"packages": [
|
|
563
|
+
"client",
|
|
564
|
+
"react-workspaces"
|
|
565
|
+
],
|
|
566
|
+
"invariants": [
|
|
567
|
+
"frontend-client-injection",
|
|
568
|
+
"frontend-shared-token",
|
|
569
|
+
"frontend-workspace-scoping"
|
|
570
|
+
]
|
|
571
|
+
},
|
|
572
|
+
"react-workspaces-screens-wiring": {
|
|
573
|
+
"when": "adding teams/workspaces to a React web app with pre-built UI, not just hooks",
|
|
574
|
+
"packages": [
|
|
575
|
+
"client",
|
|
576
|
+
"react-workspaces",
|
|
577
|
+
"react-workspaces-screens"
|
|
578
|
+
],
|
|
579
|
+
"invariants": [
|
|
580
|
+
"frontend-client-injection",
|
|
581
|
+
"frontend-shared-token",
|
|
582
|
+
"frontend-workspace-scoping"
|
|
583
|
+
]
|
|
584
|
+
},
|
|
585
|
+
"react-native-workspaces-wiring": {
|
|
586
|
+
"when": "adding teams/workspaces UI to a React Native app",
|
|
587
|
+
"packages": [
|
|
588
|
+
"client",
|
|
589
|
+
"react-native-workspaces"
|
|
590
|
+
],
|
|
591
|
+
"invariants": [
|
|
592
|
+
"frontend-client-injection",
|
|
593
|
+
"frontend-shared-token",
|
|
594
|
+
"frontend-workspace-scoping"
|
|
595
|
+
]
|
|
596
|
+
},
|
|
597
|
+
"react-native-workspaces-screens-wiring": {
|
|
598
|
+
"when": "adding teams/workspaces to a React Native app with pre-built UI, not just hooks",
|
|
599
|
+
"packages": [
|
|
600
|
+
"client",
|
|
601
|
+
"react-native-workspaces",
|
|
602
|
+
"react-native-workspaces-screens"
|
|
603
|
+
],
|
|
604
|
+
"invariants": [
|
|
605
|
+
"frontend-client-injection",
|
|
606
|
+
"frontend-shared-token",
|
|
607
|
+
"frontend-workspace-scoping"
|
|
608
|
+
]
|
|
609
|
+
},
|
|
610
|
+
"vue-workspaces-wiring": {
|
|
611
|
+
"when": "adding teams/workspaces UI to a Vue 3 app",
|
|
612
|
+
"packages": [
|
|
613
|
+
"client",
|
|
614
|
+
"vue-workspaces"
|
|
615
|
+
],
|
|
616
|
+
"invariants": [
|
|
617
|
+
"frontend-client-injection",
|
|
618
|
+
"frontend-shared-token",
|
|
619
|
+
"frontend-workspace-scoping"
|
|
620
|
+
]
|
|
621
|
+
},
|
|
622
|
+
"vue-workspaces-screens-wiring": {
|
|
623
|
+
"when": "adding teams/workspaces to a Vue 3 app with pre-built UI, not just composables",
|
|
624
|
+
"packages": [
|
|
625
|
+
"client",
|
|
626
|
+
"vue-workspaces",
|
|
627
|
+
"vue-workspaces-screens"
|
|
628
|
+
],
|
|
629
|
+
"invariants": [
|
|
630
|
+
"frontend-client-injection",
|
|
631
|
+
"frontend-shared-token",
|
|
632
|
+
"frontend-workspace-scoping"
|
|
633
|
+
]
|
|
634
|
+
},
|
|
635
|
+
"react-courier-admin-wiring": {
|
|
636
|
+
"when": "building an admin dashboard to edit courier's email/SMS/push templates in React",
|
|
637
|
+
"packages": [
|
|
638
|
+
"client",
|
|
639
|
+
"react-courier-admin"
|
|
640
|
+
],
|
|
641
|
+
"invariants": [
|
|
642
|
+
"frontend-admin-token"
|
|
643
|
+
]
|
|
644
|
+
},
|
|
645
|
+
"react-courier-admin-screens-wiring": {
|
|
646
|
+
"when": "building an admin dashboard for courier templates in React with pre-built UI, not just hooks",
|
|
647
|
+
"packages": [
|
|
648
|
+
"client",
|
|
649
|
+
"react-courier-admin",
|
|
650
|
+
"react-courier-admin-screens"
|
|
651
|
+
],
|
|
652
|
+
"invariants": [
|
|
653
|
+
"frontend-admin-token"
|
|
654
|
+
]
|
|
655
|
+
},
|
|
656
|
+
"vue-courier-admin-wiring": {
|
|
657
|
+
"when": "building an admin dashboard to edit courier's email/SMS/push templates in Vue 3",
|
|
658
|
+
"packages": [
|
|
659
|
+
"client",
|
|
660
|
+
"vue-courier-admin"
|
|
661
|
+
],
|
|
662
|
+
"invariants": [
|
|
663
|
+
"frontend-admin-token"
|
|
664
|
+
]
|
|
665
|
+
},
|
|
666
|
+
"vue-courier-admin-screens-wiring": {
|
|
667
|
+
"when": "building an admin dashboard for courier templates in Vue 3 with pre-built UI, not just composables",
|
|
668
|
+
"packages": [
|
|
669
|
+
"client",
|
|
670
|
+
"vue-courier-admin",
|
|
671
|
+
"vue-courier-admin-screens"
|
|
672
|
+
],
|
|
673
|
+
"invariants": [
|
|
674
|
+
"frontend-admin-token"
|
|
675
|
+
]
|
|
676
|
+
},
|
|
677
|
+
"react-config-admin-wiring": {
|
|
678
|
+
"when": "building an admin dashboard to manage feature flags/remote config and secrets in React",
|
|
679
|
+
"packages": [
|
|
680
|
+
"client",
|
|
681
|
+
"react-config-admin"
|
|
682
|
+
],
|
|
683
|
+
"invariants": [
|
|
684
|
+
"frontend-admin-token"
|
|
685
|
+
]
|
|
686
|
+
},
|
|
687
|
+
"react-config-admin-screens-wiring": {
|
|
688
|
+
"when": "building a config/secrets admin dashboard in React with pre-built UI, not just hooks",
|
|
689
|
+
"packages": [
|
|
690
|
+
"client",
|
|
691
|
+
"react-config-admin",
|
|
692
|
+
"react-config-admin-screens"
|
|
693
|
+
],
|
|
694
|
+
"invariants": [
|
|
695
|
+
"frontend-admin-token"
|
|
696
|
+
]
|
|
697
|
+
},
|
|
698
|
+
"vue-config-admin-wiring": {
|
|
699
|
+
"when": "building an admin dashboard to manage feature flags/remote config and secrets in Vue 3",
|
|
700
|
+
"packages": [
|
|
701
|
+
"client",
|
|
702
|
+
"vue-config-admin"
|
|
703
|
+
],
|
|
704
|
+
"invariants": [
|
|
705
|
+
"frontend-admin-token"
|
|
706
|
+
]
|
|
707
|
+
},
|
|
708
|
+
"vue-config-admin-screens-wiring": {
|
|
709
|
+
"when": "building a config/secrets admin dashboard in Vue 3 with pre-built UI, not just composables",
|
|
710
|
+
"packages": [
|
|
711
|
+
"client",
|
|
712
|
+
"vue-config-admin",
|
|
713
|
+
"vue-config-admin-screens"
|
|
714
|
+
],
|
|
715
|
+
"invariants": [
|
|
716
|
+
"frontend-admin-token"
|
|
717
|
+
]
|
|
718
|
+
},
|
|
719
|
+
"react-audit-wiring": {
|
|
720
|
+
"when": "showing an audit/activity log in a React web app",
|
|
721
|
+
"packages": [
|
|
722
|
+
"client",
|
|
723
|
+
"react-audit"
|
|
724
|
+
],
|
|
725
|
+
"invariants": [
|
|
726
|
+
"frontend-client-injection",
|
|
727
|
+
"frontend-shared-token",
|
|
728
|
+
"frontend-workspace-scoping"
|
|
729
|
+
]
|
|
730
|
+
},
|
|
731
|
+
"react-audit-screens-wiring": {
|
|
732
|
+
"when": "showing an audit/activity log in a React web app with pre-built UI, not just the hook",
|
|
733
|
+
"packages": [
|
|
734
|
+
"client",
|
|
735
|
+
"react-audit",
|
|
736
|
+
"react-audit-screens"
|
|
737
|
+
],
|
|
738
|
+
"invariants": [
|
|
739
|
+
"frontend-client-injection",
|
|
740
|
+
"frontend-shared-token",
|
|
741
|
+
"frontend-workspace-scoping"
|
|
742
|
+
]
|
|
743
|
+
},
|
|
744
|
+
"react-native-audit-wiring": {
|
|
745
|
+
"when": "showing an audit/activity log in a React Native app",
|
|
746
|
+
"packages": [
|
|
747
|
+
"client",
|
|
748
|
+
"react-native-audit"
|
|
749
|
+
],
|
|
750
|
+
"invariants": [
|
|
751
|
+
"frontend-client-injection",
|
|
752
|
+
"frontend-shared-token",
|
|
753
|
+
"frontend-workspace-scoping"
|
|
754
|
+
]
|
|
755
|
+
},
|
|
756
|
+
"react-native-audit-screens-wiring": {
|
|
757
|
+
"when": "showing an audit/activity log in a React Native app with pre-built UI, not just the hook",
|
|
758
|
+
"packages": [
|
|
759
|
+
"client",
|
|
760
|
+
"react-native-audit",
|
|
761
|
+
"react-native-audit-screens"
|
|
762
|
+
],
|
|
763
|
+
"invariants": [
|
|
764
|
+
"frontend-client-injection",
|
|
765
|
+
"frontend-shared-token",
|
|
766
|
+
"frontend-workspace-scoping"
|
|
767
|
+
]
|
|
768
|
+
},
|
|
769
|
+
"vue-audit-wiring": {
|
|
770
|
+
"when": "showing an audit/activity log in a Vue 3 app",
|
|
771
|
+
"packages": [
|
|
772
|
+
"client",
|
|
773
|
+
"vue-audit"
|
|
774
|
+
],
|
|
775
|
+
"invariants": [
|
|
776
|
+
"frontend-client-injection",
|
|
777
|
+
"frontend-shared-token",
|
|
778
|
+
"frontend-workspace-scoping"
|
|
779
|
+
]
|
|
780
|
+
},
|
|
781
|
+
"vue-audit-screens-wiring": {
|
|
782
|
+
"when": "showing an audit/activity log in a Vue 3 app with pre-built UI, not just the composable",
|
|
783
|
+
"packages": [
|
|
784
|
+
"client",
|
|
785
|
+
"vue-audit",
|
|
786
|
+
"vue-audit-screens"
|
|
787
|
+
],
|
|
788
|
+
"invariants": [
|
|
789
|
+
"frontend-client-injection",
|
|
790
|
+
"frontend-shared-token",
|
|
791
|
+
"frontend-workspace-scoping"
|
|
792
|
+
]
|
|
793
|
+
},
|
|
794
|
+
"react-webhooks-wiring": {
|
|
795
|
+
"when": "managing webhook endpoints in a React web app",
|
|
796
|
+
"packages": [
|
|
797
|
+
"client",
|
|
798
|
+
"react-webhooks"
|
|
799
|
+
],
|
|
800
|
+
"invariants": [
|
|
801
|
+
"frontend-client-injection",
|
|
802
|
+
"frontend-shared-token",
|
|
803
|
+
"frontend-workspace-scoping"
|
|
804
|
+
]
|
|
805
|
+
},
|
|
806
|
+
"react-webhooks-screens-wiring": {
|
|
807
|
+
"when": "managing webhook endpoints in a React web app with pre-built UI, not just the hooks",
|
|
808
|
+
"packages": [
|
|
809
|
+
"client",
|
|
810
|
+
"react-webhooks",
|
|
811
|
+
"react-webhooks-screens"
|
|
812
|
+
],
|
|
813
|
+
"invariants": [
|
|
814
|
+
"frontend-client-injection",
|
|
815
|
+
"frontend-shared-token",
|
|
816
|
+
"frontend-workspace-scoping"
|
|
817
|
+
]
|
|
818
|
+
},
|
|
819
|
+
"react-native-webhooks-wiring": {
|
|
820
|
+
"when": "managing webhook endpoints in a React Native app",
|
|
821
|
+
"packages": [
|
|
822
|
+
"client",
|
|
823
|
+
"react-native-webhooks"
|
|
824
|
+
],
|
|
825
|
+
"invariants": [
|
|
826
|
+
"frontend-client-injection",
|
|
827
|
+
"frontend-shared-token",
|
|
828
|
+
"frontend-workspace-scoping"
|
|
829
|
+
]
|
|
830
|
+
},
|
|
831
|
+
"react-native-webhooks-screens-wiring": {
|
|
832
|
+
"when": "managing webhook endpoints in a React Native app with pre-built UI, not just the hooks",
|
|
833
|
+
"packages": [
|
|
834
|
+
"client",
|
|
835
|
+
"react-native-webhooks",
|
|
836
|
+
"react-native-webhooks-screens"
|
|
837
|
+
],
|
|
838
|
+
"invariants": [
|
|
839
|
+
"frontend-client-injection",
|
|
840
|
+
"frontend-shared-token",
|
|
841
|
+
"frontend-workspace-scoping"
|
|
842
|
+
]
|
|
843
|
+
},
|
|
844
|
+
"vue-webhooks-wiring": {
|
|
845
|
+
"when": "managing webhook endpoints in a Vue 3 app",
|
|
846
|
+
"packages": [
|
|
847
|
+
"client",
|
|
848
|
+
"vue-webhooks"
|
|
849
|
+
],
|
|
850
|
+
"invariants": [
|
|
851
|
+
"frontend-client-injection",
|
|
852
|
+
"frontend-shared-token",
|
|
853
|
+
"frontend-workspace-scoping"
|
|
854
|
+
]
|
|
855
|
+
},
|
|
856
|
+
"vue-webhooks-screens-wiring": {
|
|
857
|
+
"when": "managing webhook endpoints in a Vue 3 app with pre-built UI, not just the composables",
|
|
858
|
+
"packages": [
|
|
859
|
+
"client",
|
|
860
|
+
"vue-webhooks",
|
|
861
|
+
"vue-webhooks-screens"
|
|
862
|
+
],
|
|
863
|
+
"invariants": [
|
|
864
|
+
"frontend-client-injection",
|
|
865
|
+
"frontend-shared-token",
|
|
866
|
+
"frontend-workspace-scoping"
|
|
867
|
+
]
|
|
868
|
+
},
|
|
869
|
+
"react-customers-wiring": {
|
|
870
|
+
"when": "managing customers/CRM records in a React web app",
|
|
871
|
+
"packages": [
|
|
872
|
+
"client",
|
|
873
|
+
"react-customers"
|
|
874
|
+
],
|
|
875
|
+
"invariants": [
|
|
876
|
+
"frontend-client-injection",
|
|
877
|
+
"frontend-shared-token",
|
|
878
|
+
"frontend-workspace-scoping"
|
|
879
|
+
]
|
|
880
|
+
},
|
|
881
|
+
"react-customers-screens-wiring": {
|
|
882
|
+
"when": "managing customers/CRM records in a React web app with pre-built UI, not just the hooks",
|
|
883
|
+
"packages": [
|
|
884
|
+
"client",
|
|
885
|
+
"react-customers",
|
|
886
|
+
"react-customers-screens"
|
|
887
|
+
],
|
|
888
|
+
"invariants": [
|
|
889
|
+
"frontend-client-injection",
|
|
890
|
+
"frontend-shared-token",
|
|
891
|
+
"frontend-workspace-scoping"
|
|
892
|
+
]
|
|
893
|
+
},
|
|
894
|
+
"react-native-customers-wiring": {
|
|
895
|
+
"when": "managing customers/CRM records in a React Native app",
|
|
896
|
+
"packages": [
|
|
897
|
+
"client",
|
|
898
|
+
"react-native-customers"
|
|
899
|
+
],
|
|
900
|
+
"invariants": [
|
|
901
|
+
"frontend-client-injection",
|
|
902
|
+
"frontend-shared-token",
|
|
903
|
+
"frontend-workspace-scoping"
|
|
904
|
+
]
|
|
905
|
+
},
|
|
906
|
+
"react-native-customers-screens-wiring": {
|
|
907
|
+
"when": "managing customers/CRM records in a React Native app with pre-built UI, not just the hooks",
|
|
908
|
+
"packages": [
|
|
909
|
+
"client",
|
|
910
|
+
"react-native-customers",
|
|
911
|
+
"react-native-customers-screens"
|
|
912
|
+
],
|
|
913
|
+
"invariants": [
|
|
914
|
+
"frontend-client-injection",
|
|
915
|
+
"frontend-shared-token",
|
|
916
|
+
"frontend-workspace-scoping"
|
|
917
|
+
]
|
|
918
|
+
},
|
|
919
|
+
"vue-customers-wiring": {
|
|
920
|
+
"when": "managing customers/CRM records in a Vue 3 app",
|
|
921
|
+
"packages": [
|
|
922
|
+
"client",
|
|
923
|
+
"vue-customers"
|
|
924
|
+
],
|
|
925
|
+
"invariants": [
|
|
926
|
+
"frontend-client-injection",
|
|
927
|
+
"frontend-shared-token",
|
|
928
|
+
"frontend-workspace-scoping"
|
|
929
|
+
]
|
|
930
|
+
},
|
|
931
|
+
"vue-customers-screens-wiring": {
|
|
932
|
+
"when": "managing customers/CRM records in a Vue 3 app with pre-built UI, not just the composables",
|
|
933
|
+
"packages": [
|
|
934
|
+
"client",
|
|
935
|
+
"vue-customers",
|
|
936
|
+
"vue-customers-screens"
|
|
937
|
+
],
|
|
938
|
+
"invariants": [
|
|
939
|
+
"frontend-client-injection",
|
|
940
|
+
"frontend-shared-token",
|
|
941
|
+
"frontend-workspace-scoping"
|
|
942
|
+
]
|
|
201
943
|
}
|
|
202
944
|
},
|
|
203
945
|
"invariants": {
|
|
@@ -206,6 +948,12 @@
|
|
|
206
948
|
"logout-provided": "@fonderie/auth mounts POST /auth/logout with session invalidation — do not hand-roll stateless-JWT logout.",
|
|
207
949
|
"webhook-route-before-auth-mw": "Register the billing/Stripe webhook route before global auth middleware so signature-verified callbacks are not rejected as unauthenticated.",
|
|
208
950
|
"workspaces-requires-billing": "@fonderie/workspaces peer-depends on @fonderie/billing; register billing before workspaces.",
|
|
209
|
-
"email-provider-default": "Do NOT stop to ask which email provider to use. Default to SMTP via CourierModule's SMTP channel, configured from process.env (SMTP_URL or SMTP_HOST/PORT/USER/PASS), fail-fast if missing. Note the choice in a comment; the operator can swap providers later. Picking a sensible default and proceeding is required — a blocked task is a failed task."
|
|
951
|
+
"email-provider-default": "Do NOT stop to ask which email provider to use. Default to SMTP via CourierModule's SMTP channel, configured from process.env (SMTP_URL or SMTP_HOST/PORT/USER/PASS), fail-fast if missing. Note the choice in a comment; the operator can swap providers later. Picking a sensible default and proceeding is required — a blocked task is a failed task.",
|
|
952
|
+
"frontend-client-injection": "Every @fonderie/*-auth, @fonderie/*-billing, @fonderie/*-workspaces, @fonderie/*-audit, @fonderie/*-webhooks, and @fonderie/*-customers hook/composable takes the matching @fonderie/client sub-client instance (client.auth, client.billing, client.workspaces, client.audit, client.webhooks, or client.customers) as an argument — instantiate one @fonderie/client FonderieClient at the app root and pass the sub-client down (React context, Vue provide/inject, or a prop), do not construct a new client per hook call.",
|
|
953
|
+
"frontend-token-storage": "The access token is persisted client-side by the auth hook/composable itself on login/register and restored on mount (localStorage for react-auth and vue-auth, AsyncStorage for react-native-auth) — do not re-implement token persistence in app code, and do not read/write that storage key directly.",
|
|
954
|
+
"frontend-shared-token": "client.auth, client.billing, client.workspaces, client.audit, client.webhooks, and client.customers share one TokenStore inside FonderieClient — signing in via a *-auth package's useLogin/useRegister automatically authenticates client.billing/client.workspaces/client.audit/client.webhooks/client.customers requests too. Do not call setAccessToken on those sub-clients yourself or construct one outside FonderieClient.",
|
|
955
|
+
"frontend-workspace-scoping": "@fonderie/*-workspaces, @fonderie/*-billing, @fonderie/*-audit, @fonderie/*-webhooks, and @fonderie/*-customers requests are scoped to a team via client.workspaces.setWorkspaceId(id) / client.billing.setWorkspaceId(id) / client.audit.setWorkspaceId(id) / client.webhooks.setWorkspaceId(id) / client.customers.setWorkspaceId(id) — all five fall back to the caller's personal workspace when unset (same X-Workspace-ID header, same server-side fallback pattern in @fonderie/workspaces' withWorkspace, @fonderie/billing's resolveSubscriber, @fonderie/audit's route handler, @fonderie/webhooks' route handler, and @fonderie/customers' route handler). Do not thread a workspace id through individual hook calls.",
|
|
956
|
+
"frontend-admin-token": "@fonderie/*-courier-admin and @fonderie/*-config-admin hooks/composables take a CourierAdminClient or ConfigAdminClient, each constructed standalone with { baseUrl, adminToken } — NOT a sub-client of FonderieClient, and NOT covered by frontend-client-injection/frontend-shared-token. Each authenticates with its own server-configured static admin bearer token (CourierModule's / ConfigModule's adminToken config), not the signed-in user's session, and the two do not share a token with each other either. Never expose an admin token to a general end-user build; these clients are for an internal/admin-only app.",
|
|
957
|
+
"party-model": "Three distinct parties — never conflate them. A USER is the authenticated principal (@fonderie/auth, table fonderie_users, resolved to ctx.user by requireAuth). A MEMBER is a user's membership in a workspace/team (@fonderie/workspaces — where multi-tenancy and roles live). A CUSTOMER is a CRM record of someone the USER'S BUSINESS serves (@fonderie/customers, workspace-scoped); it never logs in and is never billed. Logins are users, tenancy is members, CRM records are customers. See docs/ARCHITECTURE.md."
|
|
210
958
|
}
|
|
211
959
|
}
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fonderie/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "The Fonderie CLI — teaches any coding agent the SDK without loading it eagerly. `fonderie skill` writes a lazy skill (a small router + per-package bodies read on demand); `fonderie query` answers what to install for a capability. Zero deps, runs anywhere.",
|
|
5
5
|
"keywords": [
|
|
6
|
-
"
|
|
6
|
+
"fonderiejs",
|
|
7
7
|
"cli",
|
|
8
8
|
"skill",
|
|
9
9
|
"ai-agent",
|
|
@@ -33,11 +33,11 @@
|
|
|
33
33
|
},
|
|
34
34
|
"repository": {
|
|
35
35
|
"type": "git",
|
|
36
|
-
"url": "git+https://github.com/fonderiejs/
|
|
36
|
+
"url": "git+https://github.com/fonderiejs/fonderie.git",
|
|
37
37
|
"directory": "packages/cli"
|
|
38
38
|
},
|
|
39
|
-
"homepage": "https://github.com/fonderiejs/
|
|
39
|
+
"homepage": "https://github.com/fonderiejs/fonderie/tree/main/packages/cli#readme",
|
|
40
40
|
"bugs": {
|
|
41
|
-
"url": "https://github.com/fonderiejs/
|
|
41
|
+
"url": "https://github.com/fonderiejs/fonderie/issues"
|
|
42
42
|
}
|
|
43
43
|
}
|