@starci/hfs 4.11.13 → 4.11.16
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/CHANGELOG.md +28 -0
- package/db/migrate.mjs +1 -1
- package/db/postgres.mjs +38 -3
- package/package.json +1 -1
- package/release/index.mjs +4 -3
- package/release/lint-baseline.mjs +123 -0
- package/release/urgent.mjs +19 -4
- package/runtime/knowledge/hfs/canon-pins.yaml +8 -8
- package/runtime/knowledge/hfs/rules.yaml +4 -4
- package/runtime/knowledge/patterns/be/webhooks.yaml +3 -2
- package/runtime/scripts/hfs/architecture/identity.mjs +1 -1
- package/runtime/scripts/hfs/architecture/jwt-ast.mjs +14 -9
- package/runtime/scripts/hfs/rules/canon-copy-drift.mjs +54 -7
- package/scaffold/add-compose.mjs +3 -0
- package/scaffold/add-inbox-lite.mjs +45 -23
- package/scaffold/lite-exports.mjs +13 -0
- package/src/main.mjs +2 -2
- package/stack/cli.mjs +5 -3
- package/stack/deploy.mjs +6 -2
- package/stack/urgent-floor.mjs +101 -7
- package/templates/be/inbox/entities.index.ts.tpl +4 -0
- package/templates/be/inbox/entity.ts.tpl +29 -0
- package/templates/be/inbox/index.ts.tpl +1 -0
- package/templates/be/inbox/platform/inbox/inbox.decorators.ts.tpl +5 -2
- package/templates/be/inbox/platform/inbox/inbox.port.ts.tpl +29 -1
- package/templates/be/inbox/platform/inbox/inbox.service.spec.ts.tpl +65 -1
- package/templates/be/inbox/platform/inbox/inbox.service.ts.tpl +48 -10
- package/templates/be/inbox/platform/inbox/index.ts.tpl +2 -2
- package/templates/be/inbox/service.spec.ts.tpl +39 -15
- package/templates/be/inbox/service.ts.tpl +13 -13
- package/templates/be/inbox/webhook-door.spec.ts.tpl +4 -1
- package/templates/be/platform/errors-graphql/graphql-error.mapper.spec.ts +18 -8
- package/templates/be/platform/graphql/graphql-depth.policy.spec.ts +12 -3
- package/templates/be/platform/graphql/localize-errors.mapper.spec.ts +39 -17
- package/templates/be/skeleton/src/modules/domain/note/note.service.ts +3 -4
- package/templates/be/skeleton/src/modules/domain/note/persistence/note.rows.ts +4 -0
- package/templates/be/skeleton/src/modules/platform/database/errors/database.error.ts +3 -0
- package/templates/be/skeleton/src/modules/platform/database/index.ts +1 -0
- package/templates/be/skeleton/src/modules/platform/database/returned-rows.policy.spec.ts +84 -0
- package/templates/be/skeleton/src/modules/platform/database/returned-rows.policy.ts +61 -0
- package/templates/be/skeleton/src/modules/platform/http-security/http-security.decorators.ts +8 -1
- package/templates/be/skeleton/src/modules/platform/http-security/origin.guard.spec.ts +121 -9
- package/templates/be/skeleton/src/modules/platform/http-security/origin.guard.ts +12 -6
- package/templates/be/skeleton/src/modules/platform/http-security/persistence/rate-limit.rows.ts +5 -0
- package/templates/be/skeleton/src/modules/platform/http-security/rate-limit.guard.ts +3 -3
- package/templates/be/skeleton-lite/src/modules/platform/database/errors/database.error.ts +3 -0
- package/templates/be/skeleton-lite/src/modules/platform/database/index.ts +1 -0
- package/templates/be/skeleton-lite/src/modules/platform/http-security/rate-limit.guard.spec.ts +41 -33
- package/templates/be/skeleton-lite/src/modules/platform/http-security/rate-limit.guard.ts +15 -9
- package/templates/be/inbox/database-client.spec.ts.tpl +0 -45
- package/templates/be/inbox/database-client.ts.tpl +0 -45
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import { mockEntityManager } from "@starci/jest-preset"
|
|
2
|
-
import type { EntityManager } from "typeorm"
|
|
3
|
-
import { DatabaseErrorCode } from "./errors/database.error"
|
|
4
|
-
import { recordWebhookDelivery, webhookReceiptInsert } from "./webhook-inbox.client"
|
|
5
|
-
|
|
6
|
-
const INSERT = webhookReceiptInsert("spec_inbox")
|
|
7
|
-
const PAYLOAD = { id: "delivery-1" }
|
|
8
|
-
|
|
9
|
-
const record = (manager: EntityManager, deliveryId: string | undefined) =>
|
|
10
|
-
recordWebhookDelivery({ manager, table: "spec_inbox", provider: "spec", deliveryId, payload: PAYLOAD })
|
|
11
|
-
|
|
12
|
-
describe("webhookReceiptInsert", () => {
|
|
13
|
-
it("refuses a table name that is not a lowercase identifier", () => {
|
|
14
|
-
expect(() => webhookReceiptInsert("spec; drop table x")).toThrow(TypeError)
|
|
15
|
-
})
|
|
16
|
-
})
|
|
17
|
-
|
|
18
|
-
describe("recordWebhookDelivery", () => {
|
|
19
|
-
it("records a new delivery through the caller's transaction manager", async () => {
|
|
20
|
-
const manager = mockEntityManager({ query: [INSERT, [{ id: "inbox-1" }]] })
|
|
21
|
-
|
|
22
|
-
const receiptId = await record(manager, " delivery-1 ")
|
|
23
|
-
|
|
24
|
-
expect(manager.query).toHaveBeenCalledTimes(1)
|
|
25
|
-
expect(manager.query).toHaveBeenCalledWith(INSERT, ["spec", "delivery-1", JSON.stringify(PAYLOAD)])
|
|
26
|
-
expect(receiptId).toBe("inbox-1")
|
|
27
|
-
})
|
|
28
|
-
|
|
29
|
-
it("acknowledges a duplicate without any completion or business write", async () => {
|
|
30
|
-
const manager = mockEntityManager({ query: [INSERT, []] })
|
|
31
|
-
|
|
32
|
-
const receiptId = await record(manager, "delivery-1")
|
|
33
|
-
|
|
34
|
-
expect(manager.query).toHaveBeenCalledTimes(1)
|
|
35
|
-
expect(receiptId).toBeUndefined()
|
|
36
|
-
})
|
|
37
|
-
|
|
38
|
-
it.each([["no", undefined], ["a blank", " "]])("refuses %s delivery id before writing a receipt", async (_label, deliveryId) => {
|
|
39
|
-
const manager = mockEntityManager()
|
|
40
|
-
|
|
41
|
-
await expect(record(manager, deliveryId)).rejects.toMatchObject({ code: DatabaseErrorCode.WebhookDeliveryIdRequired })
|
|
42
|
-
|
|
43
|
-
expect(manager.query).not.toHaveBeenCalled()
|
|
44
|
-
})
|
|
45
|
-
})
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import type { EntityManager } from "typeorm"
|
|
2
|
-
import { DatabaseError, DatabaseErrorCode } from "./errors/database.error"
|
|
3
|
-
|
|
4
|
-
interface RecordWebhookDelivery {
|
|
5
|
-
readonly manager: EntityManager
|
|
6
|
-
/** The provider inbox table under public, created by its db migration. */
|
|
7
|
-
readonly table: string
|
|
8
|
-
readonly provider: string
|
|
9
|
-
readonly deliveryId: string | undefined
|
|
10
|
-
readonly payload: object
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
type WebhookReceiptId = string | undefined
|
|
14
|
-
|
|
15
|
-
/** A provider inbox table name: a lowercase identifier, never a value. */
|
|
16
|
-
const TABLE = /^[a-z_][a-z0-9_]*$/
|
|
17
|
-
|
|
18
|
-
/** The conflict-safe insert of one pending delivery into `public.<table>`, answering its id only to the winning transaction. */
|
|
19
|
-
export const webhookReceiptInsert = (table: string): string => {
|
|
20
|
-
if (!TABLE.test(table)) throw new TypeError(`${table} is not a provider inbox table name`)
|
|
21
|
-
return `INSERT INTO public.${table} (provider, delivery_id, payload) VALUES ($1, $2, $3::jsonb) ON CONFLICT (provider, delivery_id) DO NOTHING RETURNING id`
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Records one pending delivery using the intake's transaction manager and returns its durable receipt identity.
|
|
26
|
-
* Business processing and the completion marker belong to the reactor or job that consumes the committed row.
|
|
27
|
-
*/
|
|
28
|
-
export const recordWebhookDelivery = async ({
|
|
29
|
-
manager,
|
|
30
|
-
table,
|
|
31
|
-
provider,
|
|
32
|
-
deliveryId,
|
|
33
|
-
payload,
|
|
34
|
-
}: RecordWebhookDelivery): Promise<WebhookReceiptId> => {
|
|
35
|
-
const normalizedDeliveryId = deliveryId?.trim()
|
|
36
|
-
if (!normalizedDeliveryId) {
|
|
37
|
-
throw new DatabaseError({ code: DatabaseErrorCode.WebhookDeliveryIdRequired })
|
|
38
|
-
}
|
|
39
|
-
const rows: Array<{ readonly id: string }> = await manager.query(webhookReceiptInsert(table), [
|
|
40
|
-
provider,
|
|
41
|
-
normalizedDeliveryId,
|
|
42
|
-
JSON.stringify(payload),
|
|
43
|
-
])
|
|
44
|
-
return rows[0]?.id
|
|
45
|
-
}
|