@happyvertical/smrt-cli 0.60.9 → 0.60.10
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/AGENTS.md +17 -53
- package/agents/db-drop-framework-base-tables.md +49 -0
- package/agents/db-migrate-concurrency.md +11 -0
- package/dist/{AuditLogCollection-BBbvr8Qc-CoDs0BaX.js → AuditLogCollection-BBbvr8Qc-DU-QXhH5.js} +1 -1
- package/dist/{OidcIdentity-COeMidoC-B-cVovG3.js → OidcIdentity-COeMidoC-BDr8b6iW.js} +2 -2
- package/dist/{OidcIdentityCollection-D4DIZv0K-CexIL7No.js → OidcIdentityCollection-D4DIZv0K-BvsaDTZY.js} +1 -1
- package/dist/{PasswordCredentialService-DHJNKEeJ-DQlR62e-.js → PasswordCredentialService-BSSP_kyT-DlxlWy6b.js} +40 -22
- package/dist/{ProfileAssetCollection-D5-tG9Mm-Bmn4-Urc.js → ProfileAssetCollection-D5-tG9Mm-Be7hQJJq.js} +3 -3
- package/dist/{ProfileCollection-CmRaiE9U-52qjwbhJ.js → ProfileCollection-CmRaiE9U-n8apgXIh.js} +17 -17
- package/dist/{ProfileLinkCollection-pvPTsysg-ocN3hj_M.js → ProfileLinkCollection-pvPTsysg-DCmnAd7m.js} +2 -2
- package/dist/{ProfileMetadataCollection-CAgJyjze-FX20yKjY.js → ProfileMetadataCollection-CAgJyjze-BKpcvrnf.js} +1 -1
- package/dist/{ProfileMetafieldCollection-19ae6Lpf-qg7eMcJk.js → ProfileMetafieldCollection-19ae6Lpf-BuTJKzmz.js} +1 -1
- package/dist/{ProfileRelationshipCollection-BFSlTQ7J-DlDILj3m.js → ProfileRelationshipCollection-BFSlTQ7J-DBbNdauk.js} +1 -1
- package/dist/{ProfileTypeCollection-BRLK8cHS-QVwjfqe8.js → ProfileTypeCollection-BRLK8cHS-COCy6yqF.js} +2 -2
- package/dist/commands/docs-claude.d.ts +1 -0
- package/dist/commands/docs-claude.d.ts.map +1 -1
- package/dist/commands/docs-knowledge-bundle.d.ts +87 -0
- package/dist/commands/docs-knowledge-bundle.d.ts.map +1 -0
- package/dist/{commands-DNssH5Dv.js → commands-CGfM14Uj.js} +265 -6
- package/dist/{dist-BJABhykg.js → dist-B00KCyNE.js} +2 -2
- package/dist/{dist-D25iWIXX.js → dist-BGEMcSs-.js} +5 -5
- package/dist/dist-D7vejSNK.js +1854 -0
- package/dist/dist-DEKj_L2B.js +1908 -0
- package/dist/index.js +11 -11
- package/dist/knowledge/intents/audit-trail.md +63 -0
- package/dist/knowledge/intents/auth-and-users.md +67 -0
- package/dist/knowledge/intents/background-work.md +72 -0
- package/dist/knowledge/intents/feature-flags-and-entitlements.md +60 -0
- package/dist/knowledge/intents/file-and-asset-storage.md +71 -0
- package/dist/knowledge/intents/human-approvals.md +56 -0
- package/dist/knowledge/intents/index.md +41 -0
- package/dist/knowledge/intents/money-and-rates.md +65 -0
- package/dist/knowledge/intents/outbound-messages.md +67 -0
- package/dist/knowledge/intents/prompts-and-ai-operations.md +72 -0
- package/dist/knowledge/intents/relationships-and-trees.md +56 -0
- package/dist/knowledge/intents/scheduled-runs.md +61 -0
- package/dist/knowledge/intents/search-facts-knowledge.md +68 -0
- package/dist/knowledge/intents/secrets-and-config.md +66 -0
- package/dist/knowledge/intents/tenant-scoping.md +63 -0
- package/dist/knowledge/intents/webhooks-and-events.md +71 -0
- package/dist/{oidcProvisioningPrimitives-KpIiLmG4-CnRTofeV.js → oidcProvisioningPrimitives-KpIiLmG4-Csnh1ENp.js} +3 -3
- package/dist/{operator-fwao3Y1j.js → operator-DCwooIiI.js} +2 -2
- package/dist/{resolveIdentity-j2WFuKDT-C9XtigVZ.js → resolveIdentity-j2WFuKDT-DZTwcb-u.js} +14 -14
- package/dist/smrt-knowledge.okf.md +57 -0
- package/package.json +15 -15
- package/dist/dist-B3gpMpBj.js +0 -1908
- package/dist/dist-BQI8s_yA.js +0 -1854
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: Capability
|
|
3
|
+
title: "Outbound email, SMS and chat messages"
|
|
4
|
+
description: "Reach for smrt-messages before calling a mailer or chat SDK directly from application code."
|
|
5
|
+
tags:
|
|
6
|
+
- smrt
|
|
7
|
+
- intent
|
|
8
|
+
status: draft
|
|
9
|
+
generated:
|
|
10
|
+
by: claude/smrt-4687
|
|
11
|
+
at: 2026-11-05T00:00:00Z
|
|
12
|
+
stale_after: 2027-02-03T00:00:00Z
|
|
13
|
+
audience: internal
|
|
14
|
+
evidence_level: source-inspected
|
|
15
|
+
package_version: 0.60.8
|
|
16
|
+
sources:
|
|
17
|
+
- id: s1
|
|
18
|
+
resource: https://github.com/happyvertical/smrt/blob/478ae3690052b825b79b28235369ee7a5f6d2f20/packages/messages/src/services/PersonaMessagingService.ts
|
|
19
|
+
path: packages/messages/src/services/PersonaMessagingService.ts
|
|
20
|
+
source_revision: 478ae3690052b825b79b28235369ee7a5f6d2f20
|
|
21
|
+
title: "packages/messages/src/services/PersonaMessagingService.ts (PersonaMessagingService.send)"
|
|
22
|
+
- id: s2
|
|
23
|
+
resource: https://github.com/happyvertical/smrt/blob/478ae3690052b825b79b28235369ee7a5f6d2f20/packages/messages/src/permissions.ts
|
|
24
|
+
path: packages/messages/src/permissions.ts
|
|
25
|
+
source_revision: 478ae3690052b825b79b28235369ee7a5f6d2f20
|
|
26
|
+
title: "packages/messages/src/permissions.ts (assertMessagingPermission, SEND_MESSAGES_PERMISSION)"
|
|
27
|
+
- id: s3
|
|
28
|
+
resource: https://github.com/happyvertical/smrt/blob/478ae3690052b825b79b28235369ee7a5f6d2f20/packages/messages/src/senders/EmailSender.ts
|
|
29
|
+
path: packages/messages/src/senders/EmailSender.ts
|
|
30
|
+
source_revision: 478ae3690052b825b79b28235369ee7a5f6d2f20
|
|
31
|
+
title: "packages/messages/src/senders/EmailSender.ts (EmailSender.send)"
|
|
32
|
+
- id: s4
|
|
33
|
+
resource: https://github.com/happyvertical/smrt/blob/478ae3690052b825b79b28235369ee7a5f6d2f20/packages/messages/src/index.ts
|
|
34
|
+
path: packages/messages/src/index.ts
|
|
35
|
+
source_revision: 478ae3690052b825b79b28235369ee7a5f6d2f20
|
|
36
|
+
title: "packages/messages/src/index.ts (public exports)"
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
# Outbound email, SMS and chat messages
|
|
40
|
+
|
|
41
|
+
# Entry point
|
|
42
|
+
|
|
43
|
+
Import from `@happyvertical/smrt-messages`. Send through `new PersonaMessagingService({ db, tenantId, principal }).send({ personaId, body, subject, attachments, routeId })`, which resolves a persona-owned route (account plus endpoint), persists a `Message` (or `Email`) row and delivers it. Channel transports are `EmailSender`, `SlackSender`, `TelegramSender`, `ZulipSender` and `TweetSender`; accounts and routes are managed through `MessagingSettingsService`, and in-app notices through `UserNotificationService`. Providers are registered with `registerMessagingProvider()`.[^s4]
|
|
44
|
+
|
|
45
|
+
# Why not hand-roll it
|
|
46
|
+
|
|
47
|
+
`PersonaMessagingService.send()` in `PersonaMessagingService.ts` checks `SEND_MESSAGES_PERMISSION` with `assertMessagingPermission` (a principal from another tenant is rejected), runs inside `withTenant`, refuses an account or endpoint that belongs to another tenant, is inactive, or whose channel does not match the route, rejects attachments on non-email routes, and saves the message with `sendStatus: 'pending'` before it calls the transport, so every send has a ledger row.[^s1][^s2] `EmailSender.send()` resolves every attachment before anything reaches the transport, so an unreadable file fails the send instead of leaving a message silently without it (#3808).[^s3] A direct SDK call skips the permission check, the tenant ownership checks and the persisted record.
|
|
48
|
+
|
|
49
|
+
# Component pages
|
|
50
|
+
|
|
51
|
+
- [smrt-messages](/components/smrt-messages.md)
|
|
52
|
+
- [smrt-tenancy](/components/smrt-tenancy.md)
|
|
53
|
+
|
|
54
|
+
# Detection signals
|
|
55
|
+
|
|
56
|
+
- `import:nodemailer`
|
|
57
|
+
- `import:@sendgrid/mail`
|
|
58
|
+
- `import:twilio`
|
|
59
|
+
- `import:@slack/web-api`
|
|
60
|
+
- `import:resend`
|
|
61
|
+
- `import:postmark`
|
|
62
|
+
- `import:mailgun.js`
|
|
63
|
+
|
|
64
|
+
[^s1]: `packages/messages/src/services/PersonaMessagingService.ts` at `478ae36900`: PersonaMessagingService.send.
|
|
65
|
+
[^s2]: `packages/messages/src/permissions.ts` at `478ae36900`: assertMessagingPermission, SEND_MESSAGES_PERMISSION.
|
|
66
|
+
[^s3]: `packages/messages/src/senders/EmailSender.ts` at `478ae36900`: EmailSender.send.
|
|
67
|
+
[^s4]: `packages/messages/src/index.ts` at `478ae36900`: public exports.
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: Capability
|
|
3
|
+
title: "Prompts and AI operations"
|
|
4
|
+
description: "Register prompts with smrt-prompts and expose AI-callable operations through @smrt({ ai }) instead of inline prompt strings and ad-hoc LLM clients."
|
|
5
|
+
tags:
|
|
6
|
+
- smrt
|
|
7
|
+
- intent
|
|
8
|
+
status: draft
|
|
9
|
+
generated:
|
|
10
|
+
by: claude/smrt-4687
|
|
11
|
+
at: 2026-11-05T00:00:00Z
|
|
12
|
+
stale_after: 2027-02-03T00:00:00Z
|
|
13
|
+
audience: internal
|
|
14
|
+
evidence_level: source-inspected
|
|
15
|
+
package_version: 0.60.8
|
|
16
|
+
sources:
|
|
17
|
+
- id: s1
|
|
18
|
+
resource: https://github.com/happyvertical/smrt/blob/478ae3690052b825b79b28235369ee7a5f6d2f20/packages/prompts/src/models/PromptOverride.ts
|
|
19
|
+
path: packages/prompts/src/models/PromptOverride.ts
|
|
20
|
+
source_revision: 478ae3690052b825b79b28235369ee7a5f6d2f20
|
|
21
|
+
title: "packages/prompts/src/models/PromptOverride.ts (PromptOverride.validatePromptOverride)"
|
|
22
|
+
- id: s2
|
|
23
|
+
resource: https://github.com/happyvertical/smrt/blob/478ae3690052b825b79b28235369ee7a5f6d2f20/packages/prompts/src/prompt-override-service.ts
|
|
24
|
+
path: packages/prompts/src/prompt-override-service.ts
|
|
25
|
+
source_revision: 478ae3690052b825b79b28235369ee7a5f6d2f20
|
|
26
|
+
title: "packages/prompts/src/prompt-override-service.ts (assertValidPromptScope, InvalidPromptScopeError)"
|
|
27
|
+
- id: s3
|
|
28
|
+
resource: https://github.com/happyvertical/smrt/blob/478ae3690052b825b79b28235369ee7a5f6d2f20/packages/prompts/src/prompt-resolver.ts
|
|
29
|
+
path: packages/prompts/src/prompt-resolver.ts
|
|
30
|
+
source_revision: 478ae3690052b825b79b28235369ee7a5f6d2f20
|
|
31
|
+
title: "packages/prompts/src/prompt-resolver.ts (resolvePrompt)"
|
|
32
|
+
- id: s4
|
|
33
|
+
resource: https://github.com/happyvertical/smrt/blob/478ae3690052b825b79b28235369ee7a5f6d2f20/packages/agents/src/ai-config.ts
|
|
34
|
+
path: packages/agents/src/ai-config.ts
|
|
35
|
+
source_revision: 478ae3690052b825b79b28235369ee7a5f6d2f20
|
|
36
|
+
title: "packages/agents/src/ai-config.ts (resolveAgentAIOptions)"
|
|
37
|
+
- id: s5
|
|
38
|
+
resource: https://github.com/happyvertical/smrt/blob/478ae3690052b825b79b28235369ee7a5f6d2f20/packages/core/src/registry/types.ts
|
|
39
|
+
path: packages/core/src/registry/types.ts
|
|
40
|
+
source_revision: 478ae3690052b825b79b28235369ee7a5f6d2f20
|
|
41
|
+
title: "packages/core/src/registry/types.ts (SmrtClassOptions.ai)"
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
# Prompts and AI operations
|
|
45
|
+
|
|
46
|
+
# Entry point
|
|
47
|
+
|
|
48
|
+
Prompts: `definePrompt({ key, template, ai })` registers a namespaced code default; `await resolvePrompt(key, { override })` returns the effective template, profile, model and params after layering code default, config file, app override, tenant override and runtime override field by field. Writes go through `PromptOverrideService` with a host-supplied authorizer; a management screen uses `PromptSettingsService`. AI operations on models: `@smrt({ ai: { callable: ['analyze'] } })` chooses which methods an AI may call, and `SmrtObject` provides `is()`, `do()` and `describe()`. Agents resolve per-tenant provider keys with `resolveAgentAIOptions()` (smrt-agents).[^s3][^s5]
|
|
49
|
+
|
|
50
|
+
# Why not hand-roll it
|
|
51
|
+
|
|
52
|
+
`PromptOverride` validates on save in `PromptOverride.ts` that the prompt key is registered and that no field the definition marks not editable is overridden, so a tenant cannot override a locked template or model.[^s1] `assertValidPromptScope()` in `prompt-override-service.ts` rejects an unknown scope type, an app id other than the app scope constant and blank or untrimmed tenant ids before the authorizer runs, so a malformed tenant write cannot land on the app-wide row, and every write fails closed without a `true` from the authorizer.[^s2] `resolveAgentAIOptions()` takes the provider key from `SecretService` for the current tenant with ancestor-tenant fallback by default, instead of reading one global environment key.[^s4] An inline prompt string has no override layering, no authorization of edits and no key management.
|
|
53
|
+
|
|
54
|
+
# Component pages
|
|
55
|
+
|
|
56
|
+
- [smrt-prompts](/components/smrt-prompts.md)
|
|
57
|
+
- [smrt-core](/components/smrt-core.md)
|
|
58
|
+
- [smrt-agents](/components/smrt-agents.md)
|
|
59
|
+
|
|
60
|
+
# Detection signals
|
|
61
|
+
|
|
62
|
+
- `import:openai`
|
|
63
|
+
- `import:@anthropic-ai/sdk`
|
|
64
|
+
- `import:langchain`
|
|
65
|
+
- `regex:You are an? [a-z ]+`
|
|
66
|
+
- `regex:role:\s*['"]system['"]`
|
|
67
|
+
|
|
68
|
+
[^s1]: `packages/prompts/src/models/PromptOverride.ts` at `478ae36900`: PromptOverride.validatePromptOverride.
|
|
69
|
+
[^s2]: `packages/prompts/src/prompt-override-service.ts` at `478ae36900`: assertValidPromptScope, InvalidPromptScopeError.
|
|
70
|
+
[^s3]: `packages/prompts/src/prompt-resolver.ts` at `478ae36900`: resolvePrompt.
|
|
71
|
+
[^s4]: `packages/agents/src/ai-config.ts` at `478ae36900`: resolveAgentAIOptions.
|
|
72
|
+
[^s5]: `packages/core/src/registry/types.ts` at `478ae36900`: SmrtClassOptions.ai.
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: Capability
|
|
3
|
+
title: "Polymorphic links, junctions and trees"
|
|
4
|
+
description: "Extend SmrtJunction, SmrtHierarchical and SmrtPolymorphicAssociation instead of writing link tables, parent_id traversal or type/id pairs by hand."
|
|
5
|
+
tags:
|
|
6
|
+
- smrt
|
|
7
|
+
- intent
|
|
8
|
+
status: draft
|
|
9
|
+
generated:
|
|
10
|
+
by: claude/smrt-4687
|
|
11
|
+
at: 2026-11-05T00:00:00Z
|
|
12
|
+
stale_after: 2027-02-03T00:00:00Z
|
|
13
|
+
audience: internal
|
|
14
|
+
evidence_level: source-inspected
|
|
15
|
+
package_version: 0.60.8
|
|
16
|
+
sources:
|
|
17
|
+
- id: s1
|
|
18
|
+
resource: https://github.com/happyvertical/smrt/blob/478ae3690052b825b79b28235369ee7a5f6d2f20/packages/core/src/hierarchical.ts
|
|
19
|
+
path: packages/core/src/hierarchical.ts
|
|
20
|
+
source_revision: 478ae3690052b825b79b28235369ee7a5f6d2f20
|
|
21
|
+
title: "packages/core/src/hierarchical.ts (SmrtHierarchical.moveTo, getDescendants)"
|
|
22
|
+
- id: s2
|
|
23
|
+
resource: https://github.com/happyvertical/smrt/blob/478ae3690052b825b79b28235369ee7a5f6d2f20/packages/core/src/junction.ts
|
|
24
|
+
path: packages/core/src/junction.ts
|
|
25
|
+
source_revision: 478ae3690052b825b79b28235369ee7a5f6d2f20
|
|
26
|
+
title: "packages/core/src/junction.ts (SmrtJunction.attach, setLinks)"
|
|
27
|
+
- id: s3
|
|
28
|
+
resource: https://github.com/happyvertical/smrt/blob/478ae3690052b825b79b28235369ee7a5f6d2f20/packages/core/src/polymorphic-association.ts
|
|
29
|
+
path: packages/core/src/polymorphic-association.ts
|
|
30
|
+
source_revision: 478ae3690052b825b79b28235369ee7a5f6d2f20
|
|
31
|
+
title: "packages/core/src/polymorphic-association.ts (SmrtPolymorphicAssociation)"
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
# Polymorphic links, junctions and trees
|
|
35
|
+
|
|
36
|
+
# Entry point
|
|
37
|
+
|
|
38
|
+
All three are exported from `@happyvertical/smrt-core`. Trees: `class Place extends SmrtHierarchical` (a `parentId` self-reference) gives `getAncestors()`, `getDescendants()`, `getHierarchy()` and a cycle-checked `moveTo()`. Many-to-many: a collection extending `SmrtJunction` declares `leftField`/`rightField` and gets `attach()`, `detach()`, `byLeft()`, `byRight()` and `setLinks()`; composite-key owners extend `SmrtJunctionBase`. Links to any model: `class CommentAssociation extends SmrtPolymorphicAssociation` stores `metaType` (qualified class name), `metaId` and `role`, and `hydrate()` resolves the target through the registry. Classes whose self-reference means something else (an evolution chain, a derivation DAG) must not extend `SmrtHierarchical`.
|
|
39
|
+
|
|
40
|
+
# Why not hand-roll it
|
|
41
|
+
|
|
42
|
+
`SmrtHierarchical.moveTo()` in `hierarchical.ts` refuses to move a node to itself or beneath one of its own descendants before it saves, which a bare `parentId` update does not, and traversal is breadth-first with one batched query per level.[^s1] `SmrtJunction.attach()` in `junction.ts` spreads caller options first so the fixed left and right keys always win and untrusted options cannot retarget the write, and it upserts on the model's `conflictColumns` (with the documented caveat that a duplicate rewrites the row id); `setLinks()` replaces a left id's full set and is documented as not transactional.[^s2] `SmrtPolymorphicAssociation` keeps `metaId` a bare string with `metaType` resolved through `ObjectRegistry`, rather than an untyped foreign key per target.[^s3]
|
|
43
|
+
|
|
44
|
+
# Component pages
|
|
45
|
+
|
|
46
|
+
- [smrt-core](/components/smrt-core.md)
|
|
47
|
+
|
|
48
|
+
# Detection signals
|
|
49
|
+
|
|
50
|
+
- `regex:parent_?[iI]d\s*[:=]`
|
|
51
|
+
- `regex:WITH RECURSIVE`
|
|
52
|
+
- `regex:entity_?type`
|
|
53
|
+
|
|
54
|
+
[^s1]: `packages/core/src/hierarchical.ts` at `478ae36900`: SmrtHierarchical.moveTo, getDescendants.
|
|
55
|
+
[^s2]: `packages/core/src/junction.ts` at `478ae36900`: SmrtJunction.attach, setLinks.
|
|
56
|
+
[^s3]: `packages/core/src/polymorphic-association.ts` at `478ae36900`: SmrtPolymorphicAssociation.
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: Capability
|
|
3
|
+
title: "Scheduled and recurring runs"
|
|
4
|
+
description: "Reach for the smrt-jobs ScheduleRunner and smrt-agents AgentSchedule before writing a cron loop or setInterval poller."
|
|
5
|
+
tags:
|
|
6
|
+
- smrt
|
|
7
|
+
- intent
|
|
8
|
+
status: draft
|
|
9
|
+
generated:
|
|
10
|
+
by: claude/smrt-4687
|
|
11
|
+
at: 2026-11-05T00:00:00Z
|
|
12
|
+
stale_after: 2027-02-03T00:00:00Z
|
|
13
|
+
audience: internal
|
|
14
|
+
evidence_level: source-inspected
|
|
15
|
+
package_version: 0.60.8
|
|
16
|
+
sources:
|
|
17
|
+
- id: s1
|
|
18
|
+
resource: https://github.com/happyvertical/smrt/blob/478ae3690052b825b79b28235369ee7a5f6d2f20/packages/jobs/src/schedule-runner.ts
|
|
19
|
+
path: packages/jobs/src/schedule-runner.ts
|
|
20
|
+
source_revision: 478ae3690052b825b79b28235369ee7a5f6d2f20
|
|
21
|
+
title: "packages/jobs/src/schedule-runner.ts (ScheduleRunner.triggerSchedule, validateCronExpression, getNextCronDate)"
|
|
22
|
+
- id: s2
|
|
23
|
+
resource: https://github.com/happyvertical/smrt/blob/478ae3690052b825b79b28235369ee7a5f6d2f20/packages/agents/src/schedule.ts
|
|
24
|
+
path: packages/agents/src/schedule.ts
|
|
25
|
+
source_revision: 478ae3690052b825b79b28235369ee7a5f6d2f20
|
|
26
|
+
title: "packages/agents/src/schedule.ts (AgentSchedule, getNextCronDate import)"
|
|
27
|
+
- id: s3
|
|
28
|
+
resource: https://github.com/happyvertical/smrt/blob/478ae3690052b825b79b28235369ee7a5f6d2f20/packages/jobs/src/index.ts
|
|
29
|
+
path: packages/jobs/src/index.ts
|
|
30
|
+
source_revision: 478ae3690052b825b79b28235369ee7a5f6d2f20
|
|
31
|
+
title: "packages/jobs/src/index.ts (ScheduleRunner, SCHEDULED_JOB_QUEUE exports)"
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
# Scheduled and recurring runs
|
|
35
|
+
|
|
36
|
+
# Entry point
|
|
37
|
+
|
|
38
|
+
Schedules are rows, not code. Define an `AgentSchedule` (`@happyvertical/smrt-agents`: agent type, method, args, 5-field `cron`, IANA `timezone`, optional `tenantId`) and run one `ScheduleRunner` (`createScheduleRunner()` from `@happyvertical/smrt-jobs`). Each due schedule is turned into a `SmrtJob` on the `SCHEDULED_JOB_QUEUE`, so a scheduled run gets the same retries, tenant cap and recovery as any other background job (see [background-work](/intents/background-work.md)). `validateCronExpression()` and `getNextCronDate()` are exported for write-time validation.[^s3]
|
|
39
|
+
|
|
40
|
+
# Why not hand-roll it
|
|
41
|
+
|
|
42
|
+
`ScheduleRunner.triggerSchedule()` in `schedule-runner.ts` validates the cron and time zone first and moves a schedule with an invalid expression to `status = 'error'` instead of retrying it on every poll; it then enqueues the job before advancing `next_run`, so a transient failure (a tenant-cap hit, a database blip) leaves the due slot to be retried rather than silently losing the run (#1401), and it enqueues through `enqueueJob` so the per-tenant cap and retry ceiling apply (#1402).[^s1] Cron is evaluated in the row's IANA zone with UTC as the default, never the host process zone (#3859).[^s1] `AgentSchedule.calculateNextRun()` imports `getNextCronDate` from smrt-jobs so the model and the runner cannot compute different next-run times.[^s2] A hand-written `setInterval` loop has none of this.
|
|
43
|
+
|
|
44
|
+
# Component pages
|
|
45
|
+
|
|
46
|
+
- [smrt-jobs](/components/smrt-jobs.md)
|
|
47
|
+
- [smrt-agents](/components/smrt-agents.md)
|
|
48
|
+
|
|
49
|
+
# Detection signals
|
|
50
|
+
|
|
51
|
+
- `import:node-cron`
|
|
52
|
+
- `import:cron`
|
|
53
|
+
- `import:node-schedule`
|
|
54
|
+
- `import:agenda`
|
|
55
|
+
- `import:croner`
|
|
56
|
+
- `call:setInterval`
|
|
57
|
+
- `regex:cron\.schedule\(`
|
|
58
|
+
|
|
59
|
+
[^s1]: `packages/jobs/src/schedule-runner.ts` at `478ae36900`: ScheduleRunner.triggerSchedule, validateCronExpression, getNextCronDate.
|
|
60
|
+
[^s2]: `packages/agents/src/schedule.ts` at `478ae36900`: AgentSchedule, getNextCronDate import.
|
|
61
|
+
[^s3]: `packages/jobs/src/index.ts` at `478ae36900`: ScheduleRunner, SCHEDULED_JOB_QUEUE exports.
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: Capability
|
|
3
|
+
title: "Search, facts and extracted knowledge"
|
|
4
|
+
description: "Reach for core semanticSearch, smrt-facts reconciliation and smrt-ingestion before writing embedding search or a facts table."
|
|
5
|
+
tags:
|
|
6
|
+
- smrt
|
|
7
|
+
- intent
|
|
8
|
+
status: draft
|
|
9
|
+
generated:
|
|
10
|
+
by: claude/smrt-4687
|
|
11
|
+
at: 2026-11-05T00:00:00Z
|
|
12
|
+
stale_after: 2027-02-03T00:00:00Z
|
|
13
|
+
audience: internal
|
|
14
|
+
evidence_level: source-inspected
|
|
15
|
+
package_version: 0.60.8
|
|
16
|
+
sources:
|
|
17
|
+
- id: s1
|
|
18
|
+
resource: https://github.com/happyvertical/smrt/blob/478ae3690052b825b79b28235369ee7a5f6d2f20/packages/facts/src/facts.ts
|
|
19
|
+
path: packages/facts/src/facts.ts
|
|
20
|
+
source_revision: 478ae3690052b825b79b28235369ee7a5f6d2f20
|
|
21
|
+
title: "packages/facts/src/facts.ts (FactCollection.reconcile)"
|
|
22
|
+
- id: s2
|
|
23
|
+
resource: https://github.com/happyvertical/smrt/blob/478ae3690052b825b79b28235369ee7a5f6d2f20/packages/core/src/collection.ts
|
|
24
|
+
path: packages/core/src/collection.ts
|
|
25
|
+
source_revision: 478ae3690052b825b79b28235369ee7a5f6d2f20
|
|
26
|
+
title: "packages/core/src/collection.ts (SmrtCollection.findSimilarToEmbedding, semanticSearch)"
|
|
27
|
+
- id: s3
|
|
28
|
+
resource: https://github.com/happyvertical/smrt/blob/478ae3690052b825b79b28235369ee7a5f6d2f20/packages/core/src/embeddings/storage.ts
|
|
29
|
+
path: packages/core/src/embeddings/storage.ts
|
|
30
|
+
source_revision: 478ae3690052b825b79b28235369ee7a5f6d2f20
|
|
31
|
+
title: "packages/core/src/embeddings/storage.ts (EmbeddingStorage.searchSimilar)"
|
|
32
|
+
- id: s4
|
|
33
|
+
resource: https://github.com/happyvertical/smrt/blob/478ae3690052b825b79b28235369ee7a5f6d2f20/packages/ingestion/AGENTS.md
|
|
34
|
+
path: packages/ingestion/AGENTS.md
|
|
35
|
+
source_revision: 478ae3690052b825b79b28235369ee7a5f6d2f20
|
|
36
|
+
title: "packages/ingestion/AGENTS.md (ingestion invariants)"
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
# Search, facts and extracted knowledge
|
|
40
|
+
|
|
41
|
+
# Entry point
|
|
42
|
+
|
|
43
|
+
Search: any SmrtCollection with embeddings configured exposes `semanticSearch(query, options)` (core). Knowledge: `FactCollection.reconcile(options)` from `@happyvertical/smrt-facts` decides whether new text creates, merges into or branches an existing `Fact`, with provenance in `FactSource`, entity links in `FactSubject` and document links in `FactContent` (to smrt-content `Content`). Extraction pipelines: smrt-ingestion owns sources, extraction attempts, proposals, review and execution; server-only services are under its `/server` subpath and generated mutation routes are disabled.
|
|
44
|
+
|
|
45
|
+
# Why not hand-roll it
|
|
46
|
+
|
|
47
|
+
`FactCollection.reconcile()` in `facts.ts` serializes under a PostgreSQL advisory lock keyed on the reconciliation identity and applies three zones over embedding similarity: at or above 0.85 merge (add a source, bump `sourceCount`), between 0.60 and 0.85 a typed decision or AI disambiguation, below 0.60 create.[^s1] In core, `findSimilarToEmbedding()` runs the tenant interceptor's list prefilter and ranks only that tenant's ids through `EmbeddingStorage.searchSimilar(..., { objectIds })`, where an empty id set returns no results rather than falling through to an unrestricted search, because `_smrt_embeddings` has no tenant column.[^s2][^s3] The ingestion package requires a tenant and confidentiality scope on every record and keeps analysis input, attempts, proposals and decisions append-only.[^s4] A hand-rolled vector search ranks across tenants first and filters afterwards, which both leaks and truncates.
|
|
48
|
+
|
|
49
|
+
# Component pages
|
|
50
|
+
|
|
51
|
+
- [smrt-facts](/components/smrt-facts.md)
|
|
52
|
+
- [smrt-content](/components/smrt-content.md)
|
|
53
|
+
- [smrt-ingestion](/components/smrt-ingestion.md)
|
|
54
|
+
- [smrt-core](/components/smrt-core.md)
|
|
55
|
+
|
|
56
|
+
# Detection signals
|
|
57
|
+
|
|
58
|
+
- `import:@pinecone-database/pinecone`
|
|
59
|
+
- `import:pgvector`
|
|
60
|
+
- `import:minisearch`
|
|
61
|
+
- `import:flexsearch`
|
|
62
|
+
- `import:lunr`
|
|
63
|
+
- `regex:cosine_?[sS]imilarity`
|
|
64
|
+
|
|
65
|
+
[^s1]: `packages/facts/src/facts.ts` at `478ae36900`: FactCollection.reconcile.
|
|
66
|
+
[^s2]: `packages/core/src/collection.ts` at `478ae36900`: SmrtCollection.findSimilarToEmbedding, semanticSearch.
|
|
67
|
+
[^s3]: `packages/core/src/embeddings/storage.ts` at `478ae36900`: EmbeddingStorage.searchSimilar.
|
|
68
|
+
[^s4]: `packages/ingestion/AGENTS.md` at `478ae36900`: ingestion invariants.
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: Capability
|
|
3
|
+
title: "Secrets and configuration"
|
|
4
|
+
description: "Reach for smrt-secrets for per-tenant encrypted secrets and smrt-config for application configuration instead of raw env reads and ad-hoc encryption."
|
|
5
|
+
tags:
|
|
6
|
+
- smrt
|
|
7
|
+
- intent
|
|
8
|
+
status: draft
|
|
9
|
+
generated:
|
|
10
|
+
by: claude/smrt-4687
|
|
11
|
+
at: 2026-11-05T00:00:00Z
|
|
12
|
+
stale_after: 2027-02-03T00:00:00Z
|
|
13
|
+
audience: internal
|
|
14
|
+
evidence_level: source-inspected
|
|
15
|
+
package_version: 0.60.8
|
|
16
|
+
sources:
|
|
17
|
+
- id: s1
|
|
18
|
+
resource: https://github.com/happyvertical/smrt/blob/478ae3690052b825b79b28235369ee7a5f6d2f20/packages/secrets/src/services/SecretService.ts
|
|
19
|
+
path: packages/secrets/src/services/SecretService.ts
|
|
20
|
+
source_revision: 478ae3690052b825b79b28235369ee7a5f6d2f20
|
|
21
|
+
title: "packages/secrets/src/services/SecretService.ts (SecretService.store)"
|
|
22
|
+
- id: s2
|
|
23
|
+
resource: https://github.com/happyvertical/smrt/blob/478ae3690052b825b79b28235369ee7a5f6d2f20/packages/secrets/src/index.ts
|
|
24
|
+
path: packages/secrets/src/index.ts
|
|
25
|
+
source_revision: 478ae3690052b825b79b28235369ee7a5f6d2f20
|
|
26
|
+
title: "packages/secrets/src/index.ts (public exports)"
|
|
27
|
+
- id: s3
|
|
28
|
+
resource: https://github.com/happyvertical/smrt/blob/478ae3690052b825b79b28235369ee7a5f6d2f20/packages/config/src/loaded-config.ts
|
|
29
|
+
path: packages/config/src/loaded-config.ts
|
|
30
|
+
source_revision: 478ae3690052b825b79b28235369ee7a5f6d2f20
|
|
31
|
+
title: "packages/config/src/loaded-config.ts (globalThis.__smrtConfigCache)"
|
|
32
|
+
- id: s4
|
|
33
|
+
resource: https://github.com/happyvertical/smrt/blob/478ae3690052b825b79b28235369ee7a5f6d2f20/packages/config/src/index.ts
|
|
34
|
+
path: packages/config/src/index.ts
|
|
35
|
+
source_revision: 478ae3690052b825b79b28235369ee7a5f6d2f20
|
|
36
|
+
title: "packages/config/src/index.ts (loadConfig)"
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
# Secrets and configuration
|
|
40
|
+
|
|
41
|
+
# Entry point
|
|
42
|
+
|
|
43
|
+
Secrets: `SecretService.create({ db, ... })` from `@happyvertical/smrt-secrets`, then `store(name, value, { description, category, expiresAt })` inside a tenant context (`storeForTenant()` outside one). Values are envelope-encrypted by the @happyvertical/secrets store under a per-tenant data key, and key drift is diagnosed with `diagnoseTenantSecretKeyDrift()`. Config: `await loadConfig()` once at startup (finds `smrt.config.*`), then `getConfig()`, `getModuleConfig()` or `getPackageConfig()` from `@happyvertical/smrt-config`; `defineConfig()` types the file.[^s2][^s4]
|
|
44
|
+
|
|
45
|
+
# Why not hand-roll it
|
|
46
|
+
|
|
47
|
+
`SecretService.store()` in `SecretService.ts` looks the secret up for the current tenant only (an unscoped lookup once found another tenant's same-named row and overwrote it with an envelope encrypted under the wrong key, #1501), refuses to save over a foreign row even if a lookup regresses, keys the upsert on slug plus `context = tenantId` so tenants can reuse names, and writes a `SecretAuditLog` row for create, update and failure alike, classifying tenant-key failures.[^s1] For config, `loaded-config.ts` keeps the parsed config on `globalThis.__smrtConfigCache` so every module instance, including pnpm workspace packages loaded from different paths, sees the same object.[^s3] Raw `process.env` reads and home-made AES have no tenant boundary, rotation or audit trail.
|
|
48
|
+
|
|
49
|
+
# Component pages
|
|
50
|
+
|
|
51
|
+
- [smrt-secrets](/components/smrt-secrets.md)
|
|
52
|
+
- [smrt-config](/components/smrt-config.md)
|
|
53
|
+
|
|
54
|
+
# Detection signals
|
|
55
|
+
|
|
56
|
+
- `import:dotenv`
|
|
57
|
+
- `import:node-vault`
|
|
58
|
+
- `import:cosmiconfig`
|
|
59
|
+
- `import:convict`
|
|
60
|
+
- `regex:process\.env\.\w*SECRET`
|
|
61
|
+
- `regex:createCipheriv\(`
|
|
62
|
+
|
|
63
|
+
[^s1]: `packages/secrets/src/services/SecretService.ts` at `478ae36900`: SecretService.store.
|
|
64
|
+
[^s2]: `packages/secrets/src/index.ts` at `478ae36900`: public exports.
|
|
65
|
+
[^s3]: `packages/config/src/loaded-config.ts` at `478ae36900`: globalThis.__smrtConfigCache.
|
|
66
|
+
[^s4]: `packages/config/src/index.ts` at `478ae36900`: loadConfig.
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: Capability
|
|
3
|
+
title: "Tenant scoping and cross-tenant reads"
|
|
4
|
+
description: "Reach for smrt-tenancy and the core allowCrossTenant opt-in instead of filtering by tenant_id by hand."
|
|
5
|
+
tags:
|
|
6
|
+
- smrt
|
|
7
|
+
- intent
|
|
8
|
+
status: draft
|
|
9
|
+
generated:
|
|
10
|
+
by: claude/smrt-4687
|
|
11
|
+
at: 2026-11-05T00:00:00Z
|
|
12
|
+
stale_after: 2027-02-03T00:00:00Z
|
|
13
|
+
audience: internal
|
|
14
|
+
evidence_level: source-inspected
|
|
15
|
+
package_version: 0.60.8
|
|
16
|
+
sources:
|
|
17
|
+
- id: s1
|
|
18
|
+
resource: https://github.com/happyvertical/smrt/blob/478ae3690052b825b79b28235369ee7a5f6d2f20/packages/tenancy/src/interceptor.ts
|
|
19
|
+
path: packages/tenancy/src/interceptor.ts
|
|
20
|
+
source_revision: 478ae3690052b825b79b28235369ee7a5f6d2f20
|
|
21
|
+
title: "packages/tenancy/src/interceptor.ts (createTenantInterceptor, rawQueryPolicy)"
|
|
22
|
+
- id: s2
|
|
23
|
+
resource: https://github.com/happyvertical/smrt/blob/478ae3690052b825b79b28235369ee7a5f6d2f20/packages/tenancy/src/index.ts
|
|
24
|
+
path: packages/tenancy/src/index.ts
|
|
25
|
+
source_revision: 478ae3690052b825b79b28235369ee7a5f6d2f20
|
|
26
|
+
title: "packages/tenancy/src/index.ts (withTenant, withSystemContext, queryGlobal, queryWithGlobals)"
|
|
27
|
+
- id: s3
|
|
28
|
+
resource: https://github.com/happyvertical/smrt/blob/478ae3690052b825b79b28235369ee7a5f6d2f20/packages/core/src/object.ts
|
|
29
|
+
path: packages/core/src/object.ts
|
|
30
|
+
source_revision: 478ae3690052b825b79b28235369ee7a5f6d2f20
|
|
31
|
+
title: "packages/core/src/object.ts (SmrtObject.assertRelatedTenant, allowCrossTenant)"
|
|
32
|
+
- id: s4
|
|
33
|
+
resource: https://github.com/happyvertical/smrt/blob/478ae3690052b825b79b28235369ee7a5f6d2f20/packages/core/src/collection.ts
|
|
34
|
+
path: packages/core/src/collection.ts
|
|
35
|
+
source_revision: 478ae3690052b825b79b28235369ee7a5f6d2f20
|
|
36
|
+
title: "packages/core/src/collection.ts (SmrtCollection.findSimilarToEmbedding tenant prefilter)"
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
# Tenant scoping and cross-tenant reads
|
|
40
|
+
|
|
41
|
+
# Entry point
|
|
42
|
+
|
|
43
|
+
Import from `@happyvertical/smrt-tenancy`. Declare a model with `@TenantScoped({ mode })` and a `@tenantId()` field, call `enableTenancy()` once at startup, and run request work inside `withTenant({ tenantId }, fn)` (adapters: `createSvelteKitHandle`, `createExpressMiddleware`, `createCliContext`). Collections then filter by tenant automatically. Read shared rows with `queryWithGlobals()`/`queryGlobal()`, use `withSystemContext()` only for reviewed system work, and opt into a cross-tenant relationship load with `{ allowCrossTenant: true }` on `loadRelated`/`getRelated` (core).[^s2]
|
|
44
|
+
|
|
45
|
+
# Why not hand-roll it
|
|
46
|
+
|
|
47
|
+
A hand-written `WHERE tenant_id = ?` covers only the query you wrote. The interceptor in `interceptor.ts` throws `TenantIsolationError` for any raw SQL against a tenant-scoped class unless the call passes `allowRawOnTenantScoped` (default `rawQueryPolicy: 'throw'`).[^s1] In core, `SmrtObject.assertRelatedTenant()` makes relationship loads, including cache hits from an earlier eager load, throw on a cross-tenant reference, and only the exact value `allowCrossTenant === true` bypasses it, not a truthy value from untyped callers (#1321).[^s3] Semantic search runs the tenant interceptor's list prefilter first and ranks only that tenant's ids, because the embeddings table has no tenant column.[^s4]
|
|
48
|
+
|
|
49
|
+
# Component pages
|
|
50
|
+
|
|
51
|
+
- [smrt-tenancy](/components/smrt-tenancy.md)
|
|
52
|
+
- [smrt-core](/components/smrt-core.md)
|
|
53
|
+
|
|
54
|
+
# Detection signals
|
|
55
|
+
|
|
56
|
+
- `regex:WHERE\s+tenant_id`
|
|
57
|
+
- `regex:tenant_?[iI]d\s*=\s*\?`
|
|
58
|
+
- `regex:tenantId\s*[!=]==`
|
|
59
|
+
|
|
60
|
+
[^s1]: `packages/tenancy/src/interceptor.ts` at `478ae36900`: createTenantInterceptor, rawQueryPolicy.
|
|
61
|
+
[^s2]: `packages/tenancy/src/index.ts` at `478ae36900`: withTenant, withSystemContext, queryGlobal, queryWithGlobals.
|
|
62
|
+
[^s3]: `packages/core/src/object.ts` at `478ae36900`: SmrtObject.assertRelatedTenant, allowCrossTenant.
|
|
63
|
+
[^s4]: `packages/core/src/collection.ts` at `478ae36900`: SmrtCollection.findSimilarToEmbedding tenant prefilter.
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: Capability
|
|
3
|
+
title: "Webhooks and events"
|
|
4
|
+
description: "Reach for smrt-webhooks for outbound signed delivery and the core DispatchBus for in-process events; there is no generic inbound webhook receiver at this revision."
|
|
5
|
+
tags:
|
|
6
|
+
- smrt
|
|
7
|
+
- intent
|
|
8
|
+
status: draft
|
|
9
|
+
generated:
|
|
10
|
+
by: claude/smrt-4687
|
|
11
|
+
at: 2026-11-05T00:00:00Z
|
|
12
|
+
stale_after: 2027-02-03T00:00:00Z
|
|
13
|
+
audience: internal
|
|
14
|
+
evidence_level: source-inspected
|
|
15
|
+
package_version: 0.60.8
|
|
16
|
+
sources:
|
|
17
|
+
- id: s1
|
|
18
|
+
resource: https://github.com/happyvertical/smrt/blob/478ae3690052b825b79b28235369ee7a5f6d2f20/packages/webhooks/src/security.ts
|
|
19
|
+
path: packages/webhooks/src/security.ts
|
|
20
|
+
source_revision: 478ae3690052b825b79b28235369ee7a5f6d2f20
|
|
21
|
+
title: "packages/webhooks/src/security.ts (assertWebhookUrl, assertHmacSecret, sendPublicWebhook)"
|
|
22
|
+
- id: s2
|
|
23
|
+
resource: https://github.com/happyvertical/smrt/blob/478ae3690052b825b79b28235369ee7a5f6d2f20/packages/webhooks/src/dispatcher.ts
|
|
24
|
+
path: packages/webhooks/src/dispatcher.ts
|
|
25
|
+
source_revision: 478ae3690052b825b79b28235369ee7a5f6d2f20
|
|
26
|
+
title: "packages/webhooks/src/dispatcher.ts (WebhookDispatcher.deliver)"
|
|
27
|
+
- id: s3
|
|
28
|
+
resource: https://github.com/happyvertical/smrt/blob/478ae3690052b825b79b28235369ee7a5f6d2f20/packages/core/src/dispatch/bus.ts
|
|
29
|
+
path: packages/core/src/dispatch/bus.ts
|
|
30
|
+
source_revision: 478ae3690052b825b79b28235369ee7a5f6d2f20
|
|
31
|
+
title: "packages/core/src/dispatch/bus.ts (DispatchBus.emit, process)"
|
|
32
|
+
- id: s4
|
|
33
|
+
resource: https://github.com/happyvertical/smrt/blob/478ae3690052b825b79b28235369ee7a5f6d2f20/packages/jobs/src/forge-projection.ts
|
|
34
|
+
path: packages/jobs/src/forge-projection.ts
|
|
35
|
+
source_revision: 478ae3690052b825b79b28235369ee7a5f6d2f20
|
|
36
|
+
title: "packages/jobs/src/forge-projection.ts (ForgeDelivery inbox)"
|
|
37
|
+
- id: s5
|
|
38
|
+
resource: https://github.com/happyvertical/smrt/blob/478ae3690052b825b79b28235369ee7a5f6d2f20/packages/events/package.json
|
|
39
|
+
path: packages/events/package.json
|
|
40
|
+
source_revision: 478ae3690052b825b79b28235369ee7a5f6d2f20
|
|
41
|
+
title: "packages/events/package.json (description)"
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
# Webhooks and events
|
|
45
|
+
|
|
46
|
+
# Entry point
|
|
47
|
+
|
|
48
|
+
Outbound: `@happyvertical/smrt-webhooks` is server-only. Subscribers are `WebhookSubscription` rows managed through `WebhookAdminService`; publish from the change feed with `WebhookChangeFeed` (preferred) or `registerWebhookModelEvents()` (never both for one model), and run deliveries with `runWebhookDeliveryJob` on the smrt-jobs queue. In-process events: `createDispatchBus()` / `DispatchBus` (`emit()`, `on()`, `subscribe()`, `process()`) in `@happyvertical/smrt-core`. Corrections to the expected home: [smrt-events](/components/smrt-events.md) is the calendar and event-hierarchy model, not an event bus; and no package provides a generic inbound webhook receiver at this revision. The closest inbound pattern is the provider-neutral forge delivery inbox in smrt-jobs (`ForgeDelivery`, `ForgeProjectionRuntime`).[^s4][^s5]
|
|
49
|
+
|
|
50
|
+
# Why not hand-roll it
|
|
51
|
+
|
|
52
|
+
`sendPublicWebhook()` in `security.ts` validates every DNS answer as a public address, pins the socket lookup to the validated answer so a second resolution cannot rebind, follows no redirects, uses no proxy or pooled sockets, and bounds DNS (5 s) and request (10 s) time; `assertWebhookUrl()` rejects non-HTTPS, ports other than 443, embedded credentials and localhost, and `assertHmacSecret()` requires a 32 to 4096 byte secret.[^s1] `WebhookDispatcher.deliver()` signs `timestamp.payload` with HMAC-SHA256 over the exact stored bytes and sends a stable `x-smrt-delivery` id because HTTP delivery is at-least-once and receivers must deduplicate.[^s2] `DispatchBus` derives the tenant server-side from the active context and claims a dispatch with a conditional UPDATE on `status = 'pending'`, so a subscriber in one tenant cannot see another tenant's dispatches.[^s3]
|
|
53
|
+
|
|
54
|
+
# Component pages
|
|
55
|
+
|
|
56
|
+
- [smrt-webhooks](/components/smrt-webhooks.md)
|
|
57
|
+
- [smrt-core](/components/smrt-core.md)
|
|
58
|
+
- [smrt-jobs](/components/smrt-jobs.md)
|
|
59
|
+
- [smrt-events](/components/smrt-events.md)
|
|
60
|
+
|
|
61
|
+
# Detection signals
|
|
62
|
+
|
|
63
|
+
- `import:svix`
|
|
64
|
+
- `regex:createHmac\(`
|
|
65
|
+
- `regex:x-[a-z-]*signature`
|
|
66
|
+
|
|
67
|
+
[^s1]: `packages/webhooks/src/security.ts` at `478ae36900`: assertWebhookUrl, assertHmacSecret, sendPublicWebhook.
|
|
68
|
+
[^s2]: `packages/webhooks/src/dispatcher.ts` at `478ae36900`: WebhookDispatcher.deliver.
|
|
69
|
+
[^s3]: `packages/core/src/dispatch/bus.ts` at `478ae36900`: DispatchBus.emit, process.
|
|
70
|
+
[^s4]: `packages/jobs/src/forge-projection.ts` at `478ae36900`: ForgeDelivery inbox.
|
|
71
|
+
[^s5]: `packages/events/package.json` at `478ae36900`: description.
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-8H4AJuhK.js";
|
|
2
2
|
import { n as __exportAll$1 } from "./NostrIdentity-RJaATTCt-BbRHWyee.js";
|
|
3
|
-
import { t as OidcIdentity } from "./OidcIdentity-COeMidoC-
|
|
4
|
-
import { l as saveOidcRaceArbiter, n as Profile, r as ProfileCollection } from "./ProfileCollection-CmRaiE9U-
|
|
5
|
-
import { t as ProfileTypeCollection } from "./ProfileTypeCollection-BRLK8cHS-
|
|
3
|
+
import { t as OidcIdentity } from "./OidcIdentity-COeMidoC-BDr8b6iW.js";
|
|
4
|
+
import { l as saveOidcRaceArbiter, n as Profile, r as ProfileCollection } from "./ProfileCollection-CmRaiE9U-n8apgXIh.js";
|
|
5
|
+
import { t as ProfileTypeCollection } from "./ProfileTypeCollection-BRLK8cHS-COCy6yqF.js";
|
|
6
6
|
import { smrt } from "@happyvertical/smrt-core";
|
|
7
7
|
//#region ../profiles/dist/chunks/oidcProvisioningPrimitives-KpIiLmG4.js
|
|
8
8
|
var oidcProvisioningPrimitives_KpIiLmG4_exports = /* @__PURE__ */ __exportAll({
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { m as withSystemContext } from "./dist-
|
|
2
|
-
import { Ct as TenantStatus, E as PasswordCredentialService, K as UserCollection, N as RoleCollection, Q as UsersPasswordCredentialCollection, V as TenantCollection, dt as normalizeUsername, g as MembershipCollection, ht as verifySecretHash, j as PermissionResolver, lt as normalizeEmail, st as isValidEmail, wt as UserStatus, yt as MembershipStatus } from "./PasswordCredentialService-
|
|
1
|
+
import { m as withSystemContext } from "./dist-B00KCyNE.js";
|
|
2
|
+
import { Ct as TenantStatus, E as PasswordCredentialService, K as UserCollection, N as RoleCollection, Q as UsersPasswordCredentialCollection, V as TenantCollection, dt as normalizeUsername, g as MembershipCollection, ht as verifySecretHash, j as PermissionResolver, lt as normalizeEmail, st as isValidEmail, wt as UserStatus, yt as MembershipStatus } from "./PasswordCredentialService-BSSP_kyT-DlxlWy6b.js";
|
|
3
3
|
import { isPostgresDatabase, withEmbeddedWriteTransaction } from "@happyvertical/smrt-core";
|
|
4
4
|
//#region ../users/dist/operator.js
|
|
5
5
|
var OperatorProvisioningError = class extends Error {
|