@teamscala/service-boot 0.23.327 → 0.23.328
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/package.json +524 -532
- package/src/agreement-gate.ts +12 -3
- package/src/auth-gate.test.ts +70 -0
- package/src/auth-gate.ts +68 -6
- package/src/build-client-assets.test.ts +1 -1
- package/src/build-client-assets.ts +1 -1
- package/src/discover-blocks.ts +1 -1
- package/src/fn-routers/index.ts +2 -0
- package/src/fn-routers/task-sync-assign.test.ts +2 -1
- package/src/fn-routers/task-sync-assign.ts +4 -4
- package/src/fn-routers/task-sync-bind.test.ts +18 -18
- package/src/fn-routers/task-sync-brief.test.ts +20 -17
- package/src/fn-routers/task-sync-brief.ts +15 -14
- package/src/fn-routers/task-sync-close.test.ts +44 -0
- package/src/fn-routers/task-sync-close.ts +82 -0
- package/src/fn-routers/task-sync-dispatch.test.ts +51 -33
- package/src/fn-routers/task-sync-lane.test.ts +36 -0
- package/src/fn-routers/task-sync-projection.test.ts +26 -0
- package/src/fn-routers/task-sync-projection.ts +51 -0
- package/src/fn-routers/task-sync-router.test.ts +14 -2
- package/src/handlers/singleton-tools-currency-watch.ts +114 -11
- package/src/handlers/sweep-host-cache.test.ts +133 -0
- package/src/handlers/sweep-host-cache.ts +143 -26
- package/src/install-logging.ts +3 -0
- package/src/mount-orpc-router.ts +1 -1
- package/src/register-page-routes.ts +0 -3
- package/src/resolve-brand-favicon.ts +1 -1
- package/src/resource-not-found.ts +10 -0
- package/src/serve/stamp-transport-identity.test.ts +24 -0
- package/src/serve/stamp-transport-identity.ts +14 -2
- package/src/two-phase-boot.ts +85 -17
- package/src/two-phase-health-gate-client-only.test.ts +77 -0
- package/src/two-phase-health-gate.test.ts +13 -2
- package/src/agreement-gate.d.ts +0 -19
- package/src/asset-cache-key.d.ts +0 -11
- package/src/asset-optimize.d.ts +0 -17
- package/src/asset-proxy.d.ts +0 -11
- package/src/asset-social-card.d.ts +0 -17
- package/src/attach-agreement-magic.d.ts +0 -20
- package/src/attach-portal-members.d.ts +0 -23
- package/src/attach-proposal-accept.d.ts +0 -26
- package/src/attach-proposal-magic.d.ts +0 -18
- package/src/attach-transfers-upload.d.ts +0 -27
- package/src/auth-gate.d.ts +0 -28
- package/src/bind-page-handler.d.ts +0 -18
- package/src/build-client-assets/input-hashing.d.ts +0 -25
- package/src/build-client-assets/source-candidates.d.ts +0 -27
- package/src/build-client-assets.d.ts +0 -50
- package/src/compose-page-title.d.ts +0 -41
- package/src/content-gate/access.d.ts +0 -15
- package/src/content-gate/config-types.d.ts +0 -99
- package/src/content-gate/gate.d.ts +0 -13
- package/src/content-gate/parse-cookie.d.ts +0 -9
- package/src/content-gate/token.d.ts +0 -48
- package/src/content-page-floor.d.ts +0 -39
- package/src/discover-blocks.d.ts +0 -28
- package/src/expand-roster.d.ts +0 -34
- package/src/fn-routers/agreement-completion-email.d.ts +0 -14
- package/src/fn-routers/agreement-send-router.d.ts +0 -82
- package/src/fn-routers/ai-health-router.d.ts +0 -35
- package/src/fn-routers/auth-router.d.ts +0 -47
- package/src/fn-routers/cache-admin-router.d.ts +0 -57
- package/src/fn-routers/chat-session-router.d.ts +0 -219
- package/src/fn-routers/email-defaults.d.ts +0 -1
- package/src/fn-routers/email-link-ttl.d.ts +0 -1
- package/src/fn-routers/index.d.ts +0 -18
- package/src/fn-routers/panel-data-router.d.ts +0 -19
- package/src/fn-routers/persist-chat-messages.d.ts +0 -36
- package/src/fn-routers/plans-router.d.ts +0 -25
- package/src/fn-routers/proposal-send-router.d.ts +0 -58
- package/src/fn-routers/public-agreement-router.d.ts +0 -289
- package/src/fn-routers/public-assessment-router.d.ts +0 -68
- package/src/fn-routers/public-gpt-session-router.d.ts +0 -143
- package/src/fn-routers/sign-in-flow-router.d.ts +0 -107
- package/src/fn-routers/task-sync-assign.d.ts +0 -305
- package/src/fn-routers/task-sync-brief.d.ts +0 -96
- package/src/fn-routers/task-sync-dispatch.d.ts +0 -61
- package/src/fn-routers/task-sync-dispatch.ts +0 -124
- package/src/fn-routers/task-sync-lane.d.ts +0 -49
- package/src/fn-routers/task-sync-lane.ts +0 -125
- package/src/fn-routers/task-sync-projection.d.ts +0 -121
- package/src/fn-routers/task-sync-rename.d.ts +0 -91
- package/src/fn-routers/task-sync-router.d.ts +0 -424
- package/src/fn-routers/task-sync-router.ts +0 -1106
- package/src/fn-routers/tasks-router.d.ts +0 -25
- package/src/fn-routers/user-preferences-router.d.ts +0 -77
- package/src/fn-routers/work-items-router.d.ts +0 -102
- package/src/gate-ttls.d.ts +0 -6
- package/src/gpt-gate.d.ts +0 -25
- package/src/handlers/bun-stable-watch.d.ts +0 -1
- package/src/handlers/pane-outbox-drain.d.ts +0 -1
- package/src/handlers/projects-digest.d.ts +0 -26
- package/src/handlers/prune-stale-data.d.ts +0 -30
- package/src/handlers/registry-stale-inactive-sweep.d.ts +0 -1
- package/src/handlers/scala-tools-currency-watch.d.ts +0 -1
- package/src/handlers/singleton-tools-currency-watch.d.ts +0 -1
- package/src/handlers/sweep-event-log.d.ts +0 -1
- package/src/handlers/sweep-host-cache.d.ts +0 -1
- package/src/handlers/upstream-issue-sync.d.ts +0 -1
- package/src/handlers/whatsapp-liveness-logic.d.ts +0 -34
- package/src/handlers/whatsapp-liveness.d.ts +0 -4
- package/src/hono-error-handler.d.ts +0 -25
- package/src/install-harness.d.ts +0 -45
- package/src/install-logging.d.ts +0 -34
- package/src/load-service-install-row.d.ts +0 -24
- package/src/load-service-prisma-client.d.ts +0 -18
- package/src/mount-orpc-router.d.ts +0 -15
- package/src/mount-server-packages.d.ts +0 -29
- package/src/mount.d.ts +0 -9
- package/src/mutable-app-ref.d.ts +0 -44
- package/src/page-route-shell-types.d.ts +0 -12
- package/src/page-server-orpc/audit-revert-router.d.ts +0 -37
- package/src/page-server-orpc/hub-mcp-client.d.ts +0 -12
- package/src/page-server-orpc/portal-diagnostics-router.d.ts +0 -49
- package/src/page-server-orpc/puck-pages-router.d.ts +0 -58
- package/src/page-server-orpc/server-client.d.ts +0 -16
- package/src/page-server-orpc/templates-router.d.ts +0 -34
- package/src/page-server-orpc/user-preferences-router.d.ts +0 -79
- package/src/pg-boss-handler-registry.d.ts +0 -27
- package/src/pg-boss-mount.d.ts +0 -42
- package/src/proposal-authorized-emails.d.ts +0 -28
- package/src/proposal-chat-inject.d.ts +0 -17
- package/src/proposal-gate.d.ts +0 -18
- package/src/read-html-template.d.ts +0 -38
- package/src/read-viewport-from-request.d.ts +0 -18
- package/src/readiness-gate.d.ts +0 -16
- package/src/register-api-routes.d.ts +0 -18
- package/src/register-crash-handlers.d.ts +0 -15
- package/src/register-page-routes.d.ts +0 -27
- package/src/register-page-server-client.d.ts +0 -11
- package/src/register-registry-page-route/ai-chat-prefetch.d.ts +0 -13
- package/src/register-registry-page-route/graph-cache.d.ts +0 -30
- package/src/register-registry-page-route/meta-title.d.ts +0 -2
- package/src/register-registry-page-route/proposal-approval-email-token.d.ts +0 -14
- package/src/register-registry-page-route/proposal-brand-stamping.d.ts +0 -28
- package/src/register-registry-page-route/resolve-page-data.d.ts +0 -1
- package/src/register-registry-page-route.d.ts +0 -27
- package/src/register-static-assets.d.ts +0 -13
- package/src/register-ws-routes.d.ts +0 -28
- package/src/resolve-app-base-url.d.ts +0 -13
- package/src/resolve-brand-favicon.d.ts +0 -28
- package/src/resolve-from-loader-config.d.ts +0 -32
- package/src/resolve-service-context.d.ts +0 -17
- package/src/resolve-service-port.d.ts +0 -75
- package/src/resolve-theme-mode.d.ts +0 -42
- package/src/resolvers/fetch-org-brand.d.ts +0 -2
- package/src/resolvers/portal-route-paths.d.ts +0 -39
- package/src/resolvers/website-by-host-map.d.ts +0 -12
- package/src/resource-chat-inject.d.ts +0 -46
- package/src/resource-not-found.d.ts +0 -60
- package/src/run-boot-hook-list.d.ts +0 -19
- package/src/run-boot-hooks.d.ts +0 -31
- package/src/scala-tools-currency-watchdog.d.ts +0 -10
- package/src/security-headers.d.ts +0 -12
- package/src/serve/serve.d.ts +0 -46
- package/src/serve/stamp-transport-identity.d.ts +0 -32
- package/src/server-error-page.d.ts +0 -29
- package/src/start-scheduled-jobs.d.ts +0 -18
- package/src/two-phase-boot.d.ts +0 -136
- package/src/types.d.ts +0 -46
- package/src/ui-service.d.ts +0 -46
- package/src/ws-boot-self-test.d.ts +0 -19
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @system server-handlers
|
|
3
|
-
* @status handwritten
|
|
4
|
-
* @edit edit directly
|
|
5
|
-
*
|
|
6
|
-
* Dynamic-import wrapper around image-optimizer's in-process sharp
|
|
7
|
-
* social-card op. Mirrors asset-optimize.ts's optional-dependency shape:
|
|
8
|
-
* services without image-optimizer installed transparently get null and
|
|
9
|
-
* fall back to the raw asset stream. In-process (not HTTP) because the
|
|
10
|
-
* og:image transform is a cold path per shared link — no auth handshake,
|
|
11
|
-
* no per-consumer service config.
|
|
12
|
-
*/
|
|
13
|
-
export interface SocialCardOutcome {
|
|
14
|
-
data: Buffer;
|
|
15
|
-
processedSize: number;
|
|
16
|
-
}
|
|
17
|
-
export declare function renderSocialCard(buffer: Buffer): Promise<SocialCardOutcome | null>;
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @system service-boot
|
|
3
|
-
* @status handwritten
|
|
4
|
-
* @edit edit directly
|
|
5
|
-
*
|
|
6
|
-
* The agreement MAGIC-LINK endpoint. A recipient who clicks an emailed
|
|
7
|
-
* "Review & sign" link — which carries a pre-authorised, signed ag_token for
|
|
8
|
-
* THEIR party — lands here: the token is verified for the agreement, the
|
|
9
|
-
* ag_token cookie is set on the shared parent domain, and the browser is
|
|
10
|
-
* 302-redirected straight into the signing page. No email-entry gate, no OTP —
|
|
11
|
-
* "came from our email" IS the proof of identity, exactly like the
|
|
12
|
-
* proposal-accept hand-off (attach-proposal-accept.ts).
|
|
13
|
-
*
|
|
14
|
-
* The token is the same HMAC ag_token the gate verifies (30-min TTL, scoped to
|
|
15
|
-
* {agreementId, email}); an invalid/expired/forged token sets no cookie and the
|
|
16
|
-
* destination page simply shows the normal email gate. GET so it is a plain
|
|
17
|
-
* clickable link in an email.
|
|
18
|
-
*/
|
|
19
|
-
import type { Hono } from "hono";
|
|
20
|
-
export declare function attachAgreementMagic(app: Hono, serviceSlug: string): Promise<void>;
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @system service-boot
|
|
3
|
-
* @status handwritten
|
|
4
|
-
* @edit edit directly
|
|
5
|
-
*
|
|
6
|
-
* Portal-secured member directory endpoint. Resolves members of an org via a
|
|
7
|
-
* parameterized raw join over better_auth_member + "user" — NOT the typed
|
|
8
|
-
* `member` ORPC model, which is deliberately omitted from the portal's
|
|
9
|
-
* service_schema (security: the raw table is not exposed as a typed CRUD
|
|
10
|
-
* surface). Mirrors the agreement-gate.ts:109-150 precedent.
|
|
11
|
-
*
|
|
12
|
-
* The portal's auth middleware (better-auth-cookie) gates the endpoint — only
|
|
13
|
-
* authenticated users can call it. The orgId comes from the caller's context
|
|
14
|
-
* (the portal resolves it from the session + passes it).
|
|
15
|
-
*
|
|
16
|
-
* Endpoint: GET /api/portal/members?orgId=<uuid>
|
|
17
|
-
* - orgId omitted: super-admin all-orgs mode (returns every member across
|
|
18
|
-
* all orgs, strictly gated to super-admin via getSession; used by the
|
|
19
|
-
* "View As" impersonation dropdown).
|
|
20
|
-
* Response: { members: Array<{ id, user_id, organization_id, role, email, name, image }> }
|
|
21
|
-
*/
|
|
22
|
-
import type { Hono } from "hono";
|
|
23
|
-
export declare function attachPortalMembers(app: Hono): Promise<void>;
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @system service-boot
|
|
3
|
-
* @status handwritten
|
|
4
|
-
* @edit edit directly
|
|
5
|
-
*
|
|
6
|
-
* The proposal ACCEPT endpoint. A viewer who has passed the proposal gate (holds
|
|
7
|
-
* a valid prop_token) POSTs {proposalId} here to accept; the server generates a
|
|
8
|
-
* signing document from the proposal (createAgreementFromProposal) and
|
|
9
|
-
* 302-redirects them straight into signing it on the sign site. This replaces
|
|
10
|
-
* the old mailto CTA. Mounted BEFORE the auth gate so it is publicly reachable —
|
|
11
|
-
* the prop_token (not a login) is the proof of identity, exactly like the
|
|
12
|
-
* content-gate access endpoint.
|
|
13
|
-
*
|
|
14
|
-
* Single sign-on across the journey: the viewer already proved their email at
|
|
15
|
-
* the proposal gate (prop_token), so we MUST NOT make them re-enter it on the
|
|
16
|
-
* sign site. Before redirecting, we mint the agreement's ag_token for that same
|
|
17
|
-
* verified email and set it on the SHARED parent domain (Domain=.scala.business)
|
|
18
|
-
* so the browser carries it from proposals.scala.business to sign.scala.business
|
|
19
|
-
* — the agreement gate then auto-reveals + seeds the signing session with zero
|
|
20
|
-
* extra prompts. This requires both hosts to resolve the SAME token secret
|
|
21
|
-
* (AUTH_SECRET→ENCRYPTION_KEY→DATABASE_URL): scala-sign must carry ENCRYPTION_KEY
|
|
22
|
-
* (also required to decrypt the org's Stripe key on full sign), so both hosts
|
|
23
|
-
* land on ENCRYPTION_KEY and the carried token verifies.
|
|
24
|
-
*/
|
|
25
|
-
import type { Hono } from "hono";
|
|
26
|
-
export declare function attachProposalAccept(app: Hono, serviceSlug: string): Promise<void>;
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @system service-boot
|
|
3
|
-
* @status handwritten
|
|
4
|
-
* @edit edit directly
|
|
5
|
-
*
|
|
6
|
-
* The proposal MAGIC-LINK endpoint — the proposal twin of attach-agreement-magic.
|
|
7
|
-
* A recipient who clicks an emailed "View your proposal" link (carrying a signed,
|
|
8
|
-
* per-recipient prop_token) lands here: the token is verified for the proposal,
|
|
9
|
-
* the prop_token cookie is set, and the browser is 302-redirected straight into
|
|
10
|
-
* the proposal page. No email-entry gate, no OTP. An invalid/expired token sets
|
|
11
|
-
* no cookie and the page falls through to the normal email gate.
|
|
12
|
-
*
|
|
13
|
-
* The prop_token is host-scoped (proposals are served on the proposals host only),
|
|
14
|
-
* unlike the agreement ag_token which spans .scala.business for the proposal→sign
|
|
15
|
-
* hand-off. GET so it is a plain clickable link in an email.
|
|
16
|
-
*/
|
|
17
|
-
import type { Hono } from "hono";
|
|
18
|
-
export declare function attachProposalMagic(app: Hono, serviceSlug: string): Promise<void>;
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @system service-boot
|
|
3
|
-
* @status handwritten
|
|
4
|
-
* @edit edit directly
|
|
5
|
-
*
|
|
6
|
-
* Authenticated asset upload — POST /api/transfers/upload. Restores the
|
|
7
|
-
* handler deleted with @teamscala/server-files (commit ca5643ef); avatar/logo
|
|
8
|
-
* upload had 404'd on every service since. Writes to S3 via
|
|
9
|
-
* @teamscala/object-storage/create/write-ops and returns the STORED-form URL
|
|
10
|
-
* (`/api/files/<key>`) the client persists into avatar_url/logo_url — the
|
|
11
|
-
* display path rewrites it to the public `/api/assets/<encoded-key>` proxy
|
|
12
|
-
* via `toAssetPath` (@teamscala/formatters/asset-url). Self-authenticates
|
|
13
|
-
* (getSession) so it mounts BEFORE the auth gate.
|
|
14
|
-
*
|
|
15
|
-
* Key scheme is USER-scoped (`users/<userId>/<type>/<file>-<ts>.<ext>`) per
|
|
16
|
-
* the operator ruling: a profile picture belongs to the individual, not any
|
|
17
|
-
* org (the prior handler's org-scoped `<orgId>/avatars/...` encoded the
|
|
18
|
-
* uploading org into a personal asset). Spec + history:
|
|
19
|
-
* `reference/asset-upload-system.md`.
|
|
20
|
-
*
|
|
21
|
-
* `thumbUrl` mirrors `url` — the full image is served for both; a separate
|
|
22
|
-
* generated thumbnail is a future refinement (the prior handler generated
|
|
23
|
-
* one, but the image-resize dependency is not wired here yet and a missing
|
|
24
|
-
* thumb must not block the upload restoring).
|
|
25
|
-
*/
|
|
26
|
-
import type { Hono } from "hono";
|
|
27
|
-
export declare function attachTransfersUpload(app: Hono): Promise<void>;
|
package/src/auth-gate.d.ts
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @system server-boot
|
|
3
|
-
* @status handwritten
|
|
4
|
-
* @edit edit directly
|
|
5
|
-
*
|
|
6
|
-
* Auth middleware factory. Three modes, same BetterAuth email-OTP mechanism:
|
|
7
|
-
*
|
|
8
|
-
* service_install.auth values:
|
|
9
|
-
* - omitted | "none" → no gate, no handler (scala-public, scala-sign)
|
|
10
|
-
* - "better-auth-cookie" → full session auth: mount handler + session gate
|
|
11
|
-
* - "email-otp-only" → mount handler (OTP send/verify), no session gate
|
|
12
|
-
*
|
|
13
|
-
* The sign-in block determines the UX per mode:
|
|
14
|
-
* - "full" → email → OTP → session → portal selection (portal, agents, docs, gpt)
|
|
15
|
-
* - "email-gate" → email → OTP → verify-only, no session (forms, proposals, quiz)
|
|
16
|
-
* - "capture-only" → email field only, no OTP (sign)
|
|
17
|
-
*
|
|
18
|
-
* There is NO localhost bypass: 127.0.0.1 is gated identically to the tunnel
|
|
19
|
-
* (no session → /sign-in). Tools needing an authed view sign in
|
|
20
|
-
* (getSuperAdminSessionCookie); the dev OTP is DB-readable.
|
|
21
|
-
*
|
|
22
|
-
* When SCALA_OTP_URL is set, /api/auth/* forwards to the centralised
|
|
23
|
-
* scala-otp service (per otp-centralised-via-otp-service). Otherwise
|
|
24
|
-
* the local better-auth handler is used (dev-host fallback).
|
|
25
|
-
*/
|
|
26
|
-
import type { ServiceInstallConfig } from "@teamscala/db/registry/loader/load-service-install-row";
|
|
27
|
-
import type { Hono } from "hono";
|
|
28
|
-
export declare function attachAuthGate(app: Hono, config: ServiceInstallConfig, serviceSlug: string): Promise<void>;
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @system ui-service-boot
|
|
3
|
-
* @status handwritten
|
|
4
|
-
* @edit edit directly
|
|
5
|
-
*
|
|
6
|
-
* Calls a createPageHandler() handler with the per-request extras the
|
|
7
|
-
* SSR pipeline needs: the resolved userId/orgId (from localhost-bypass
|
|
8
|
-
* or better-auth-cookie), and the htmlTemplate. Shared by the regions
|
|
9
|
-
* and page_slug shell variants.
|
|
10
|
-
*/
|
|
11
|
-
import type { Context } from "hono";
|
|
12
|
-
type PageHandler = (req: Request, extras: Record<string, unknown>) => Promise<{
|
|
13
|
-
body: unknown;
|
|
14
|
-
status: number;
|
|
15
|
-
headers: HeadersInit;
|
|
16
|
-
}>;
|
|
17
|
-
export declare function bindPageHandler(c: Context, handler: PageHandler, authMode: string, serviceSlug: string, label: string, resourceOrgId?: string): Promise<Response>;
|
|
18
|
-
export {};
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @system service-boot
|
|
3
|
-
* @status handwritten
|
|
4
|
-
* @edit edit directly
|
|
5
|
-
*
|
|
6
|
-
* Input hashing for the client-asset build fingerprint.
|
|
7
|
-
*
|
|
8
|
-
* Split out of build-client-assets.ts, which had grown to 1221 lines holding
|
|
9
|
-
* six distinct concerns (lock + status, manifest, hydrate bundle, source maps,
|
|
10
|
-
* stylesheet/tailwind, and this). `single-purpose-file` did not catch it: that
|
|
11
|
-
* rule flags a file whose top-level exports share no common name root, which
|
|
12
|
-
* measures export-NAME cohesion rather than how many concerns a file holds — so
|
|
13
|
-
* a large file with few tidily-named exports stays invisible to it.
|
|
14
|
-
*
|
|
15
|
-
* This module owns ONE concern: turning the build's real inputs into a stable
|
|
16
|
-
* hash. `computeInputFingerprint` (still in the parent, and still the only
|
|
17
|
-
* exported entry point) composes the two functions exported here; everything
|
|
18
|
-
* else is module-private because nothing outside needs it.
|
|
19
|
-
*
|
|
20
|
-
* Byte-for-byte move — imports adjusted, nothing else. No renames, no type
|
|
21
|
-
* changes (`migrations-copy-not-rewrite`).
|
|
22
|
-
*/
|
|
23
|
-
import { createHash } from "node:crypto";
|
|
24
|
-
export declare function hashResolvedPackageStylesheets(cwd: string, h: ReturnType<typeof createHash>): Promise<void>;
|
|
25
|
-
export declare function hashTeamgbgJsGraph(cwd: string, h: ReturnType<typeof createHash>): Promise<void>;
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @system service-boot
|
|
3
|
-
* @status handwritten
|
|
4
|
-
* @edit edit directly
|
|
5
|
-
*
|
|
6
|
-
* Tailwind source-candidate scanning for the client CSS build.
|
|
7
|
-
*
|
|
8
|
-
* Split out of build-client-assets.ts (1221 lines, six concerns). Owns ONE
|
|
9
|
-
* concern: turning the resolved `@source` directories into the candidate token
|
|
10
|
-
* set Tailwind's `build()` consumes.
|
|
11
|
-
*
|
|
12
|
-
* Why it exists at all, preserved from the original: Tailwind v4's low-level
|
|
13
|
-
* `compile()` does NOT scan content, and @tailwindcss/oxide's native Scanner is
|
|
14
|
-
* not a dependency of the bare `tailwindcss` lib — only of the integration
|
|
15
|
-
* packages. So the tokens are extracted here. Over-extraction is safe, because
|
|
16
|
-
* `build()` ignores any token that is not a valid utility. Dropping this scan is
|
|
17
|
-
* what shipped an unstyled page to the operator's tablet on 2026-06-13; it is
|
|
18
|
-
* enforced by `css-build-scans-source-candidates`.
|
|
19
|
-
*
|
|
20
|
-
* Byte-for-byte move — imports adjusted, nothing else.
|
|
21
|
-
*/
|
|
22
|
-
import { getAppLogger } from "@teamscala/logger/app-loggers";
|
|
23
|
-
export declare function scanSourceCandidates(sources: Array<{
|
|
24
|
-
base: string;
|
|
25
|
-
pattern: string;
|
|
26
|
-
negated?: boolean;
|
|
27
|
-
}>, log: ReturnType<typeof getAppLogger>): Promise<string[]>;
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @system server-handlers
|
|
3
|
-
* @status handwritten
|
|
4
|
-
* @edit edit directly
|
|
5
|
-
*
|
|
6
|
-
* Builds the per-service client bundle and stylesheet into `dist/client/`
|
|
7
|
-
* at UI-service boot time. Outputs are content-hashed so deployments
|
|
8
|
-
* naturally cache-bust:
|
|
9
|
-
*
|
|
10
|
-
* src/entry-client.ts ──bun build──> dist/client/hydrate-<hash>.js
|
|
11
|
-
* src/app.css ──tailwindcss──> dist/client/styles-<hash>.css
|
|
12
|
-
* (and) dist/client/asset-manifest.json
|
|
13
|
-
*
|
|
14
|
-
* The HTML template references `{{stylesPath}}` / `{{hydratePath}}` —
|
|
15
|
-
* read-html-template.ts substitutes from the manifest at template-read
|
|
16
|
-
* time. Bytes-level changes → new hash → new URL → browser refetch.
|
|
17
|
-
* Without this, `cache-control: immutable` on a fixed filename means
|
|
18
|
-
* returning visitors keep their stale copy forever.
|
|
19
|
-
*
|
|
20
|
-
* Content-fingerprint cache: the CLIENT-BUNDLE DEPENDENCY CLOSURE (source
|
|
21
|
-
* entrypoints + every @teamscala/* module/stylesheet the bundle reaches + the
|
|
22
|
-
* resolved versions of the third-party deps the closure imports) is hashed by
|
|
23
|
-
* CONTENT and stored in the manifest; the rebuild is skipped only when the
|
|
24
|
-
* current closure hashes to the same fingerprint (cache-key-hashes-source-
|
|
25
|
-
* inputs-only — never mtime; see computeInputFingerprint for why mtime silently
|
|
26
|
-
* served stale bundles on Railway). bun.lock is deliberately NOT hashed — it
|
|
27
|
-
* encodes every @teamscala/* version including backend packages outside this
|
|
28
|
-
* service's client bundle, so folding it in would rebuild on every publish
|
|
29
|
-
* (the publish→rebuild storm; `no-uncontrolled-repetition-or-cascade`). First
|
|
30
|
-
* pm2 restart after a real closure change pays the full build cost; unchanged
|
|
31
|
-
* restarts skip. Stale hashed outputs from a prior build are removed in the
|
|
32
|
-
* same pass so dist/client/ doesn't accumulate dead files.
|
|
33
|
-
*/
|
|
34
|
-
/**
|
|
35
|
-
* Read ONLY the tombstone state of the current manifest — the runtime
|
|
36
|
-
* (read-html-template, ui-service) calls this to decide whether to surface a
|
|
37
|
-
* build-failure signal. Returns null when the manifest is fresh (no
|
|
38
|
-
* `buildFailed`). Decoupled from the full AssetManifest read so the runtime
|
|
39
|
-
* never depends on the build internals.
|
|
40
|
-
*/
|
|
41
|
-
export declare function readClientBuildStatus(cwd?: string): Promise<{
|
|
42
|
-
failed: true;
|
|
43
|
-
reason?: string;
|
|
44
|
-
at?: string;
|
|
45
|
-
} | {
|
|
46
|
-
failed: false;
|
|
47
|
-
}>;
|
|
48
|
-
export declare function stripRemoteImports(css: string): string;
|
|
49
|
-
export declare function computeInputFingerprint(cwd: string): Promise<string>;
|
|
50
|
-
export declare function buildClientAssets(serviceSlug: string): Promise<void>;
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @system ui-service-boot
|
|
3
|
-
* @status handwritten
|
|
4
|
-
* @edit edit directly
|
|
5
|
-
*
|
|
6
|
-
* The single canonical page-title composer. Every SSR page handler routes
|
|
7
|
-
* through this (portal/region-shell, public shell, single-page resource). A
|
|
8
|
-
* page title is DERIVED from data that already exists — the website name +
|
|
9
|
-
* the page/entity name — with `builda_pages.meta_title` as an explicit
|
|
10
|
-
* per-page OVERRIDE only, never the primary source.
|
|
11
|
-
*
|
|
12
|
-
* Mirrors the brand-is-org-owned-full-scheme precedent: a value that should
|
|
13
|
-
* be DERIVED was instead hand-set per row, and when unset it silently fell
|
|
14
|
-
* back to something wrong. For themes the wrong fallback was the generic
|
|
15
|
-
* light palette; for titles it was the bare org name — the `default`
|
|
16
|
-
* page_meta_template `titleTemplate: "{org.name}"` produced "GBG Indo" with
|
|
17
|
-
* no site or page context, and per-row `meta_title` carried stale product
|
|
18
|
-
* literals like "Dashboard | scala Hub". The fix is identical in shape:
|
|
19
|
-
* derive by default, override explicitly.
|
|
20
|
-
*
|
|
21
|
-
* Canonical format: `<website.name>: <subject>` (subject = entity title or
|
|
22
|
-
* page name), site-first so a browser tab reads the surface then the page.
|
|
23
|
-
* A resource surface (forms/quiz/gpt) may supply a curated `templateTitle`
|
|
24
|
-
* (e.g. "{agent.name} — {org.name}"); it wins over the default derivation
|
|
25
|
-
* but NOT over an explicit per-page override. The composer NEVER returns a
|
|
26
|
-
* bare org name — that is the regression this closes, and the
|
|
27
|
-
* `page-title-not-bare-org` guard backstops it at the template layer.
|
|
28
|
-
*/
|
|
29
|
-
export interface TitleContext {
|
|
30
|
-
/** Per-page override (builda_pages.meta_title). Wins outright when set. */
|
|
31
|
-
pageMetaTitle?: string | null;
|
|
32
|
-
/** Resolved resource-template string (forms/quiz/gpt). Curated per-surface shape. */
|
|
33
|
-
templateTitle?: string | null;
|
|
34
|
-
/** builda_websites.name — the surface, the primary site context. */
|
|
35
|
-
websiteName?: string | null;
|
|
36
|
-
/** builda_pages.name — the page (e.g. "Dashboard"). */
|
|
37
|
-
pageName?: string | null;
|
|
38
|
-
/** Resource entity title (proposal/form/quiz/agent name) — preferred subject. */
|
|
39
|
-
entityTitle?: string | null;
|
|
40
|
-
}
|
|
41
|
-
export declare function composePageTitle(ctx: TitleContext): string;
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @system service-boot
|
|
3
|
-
* @status handwritten
|
|
4
|
-
* @edit edit directly
|
|
5
|
-
*
|
|
6
|
-
* The content-gate ACCESS endpoint mounter. One generic POST handler for every
|
|
7
|
-
* gate: a plain <form> posts {<recordIdField>, email}; on a match against the
|
|
8
|
-
* resource's authorized set it sets the signed access cookie and redirects back,
|
|
9
|
-
* so the page loader's gate then releases the content. No bespoke endpoint per
|
|
10
|
-
* type — each gate is one AccessConfig. Mounted BEFORE the auth gate so it is
|
|
11
|
-
* publicly reachable.
|
|
12
|
-
*/
|
|
13
|
-
import type { Hono } from "hono";
|
|
14
|
-
import type { AccessConfig } from "./config-types.ts";
|
|
15
|
-
export declare function attachContentGateAccess(app: Hono, serviceSlug: string, config: AccessConfig): Promise<void>;
|
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @system service-boot
|
|
3
|
-
* @status handwritten
|
|
4
|
-
* @edit edit directly
|
|
5
|
-
*
|
|
6
|
-
* The config contracts that PROGRAM a content gate. Each gated content type
|
|
7
|
-
* (agreement, proposal, …) is one ContentGateConfig + one AccessConfig — no
|
|
8
|
-
* bespoke gate functions per type; the engine (gate.ts) and the access mounter
|
|
9
|
-
* (access.ts) are the single shared primitive driven by these.
|
|
10
|
-
*/
|
|
11
|
-
type Resolved = Record<string, unknown>;
|
|
12
|
-
/** Drives the SSR-time gate (gate.ts / runContentGate). */
|
|
13
|
-
export interface ContentGateConfig {
|
|
14
|
-
/** Cookie that carries this gate's access token (e.g. "ag_token"). */
|
|
15
|
-
cookieName: string;
|
|
16
|
-
/**
|
|
17
|
-
* The gated resource id from the resolved graph, or "" when this gate does
|
|
18
|
-
* not apply to the current page (the engine then no-ops). This is also how a
|
|
19
|
-
* gate detects "is this my kind of page". Async to allow DB-backed resolution
|
|
20
|
-
* (e.g. agreement gate resolving the UUID from the page→agreement association
|
|
21
|
-
* when no pre-placed gate block exists).
|
|
22
|
-
*/
|
|
23
|
-
getResourceId(resolved: Resolved): string | Promise<string>;
|
|
24
|
-
/**
|
|
25
|
-
* Verify the cookie's token for this resource → the verified identity
|
|
26
|
-
* ({email, optional display name}), or null. Token-agnostic by design:
|
|
27
|
-
* proposals use the shared content-gate token; agreements keep their existing
|
|
28
|
-
* token (also minted by the signing ORPC), so the engine never assumes one
|
|
29
|
-
* token format. Allow-list gates return just {email}; the GPT lead-capture
|
|
30
|
-
* gate also returns the captured name (carried in its token).
|
|
31
|
-
*/
|
|
32
|
-
verifyToken(token: string | undefined, resourceId: string, nowMs: number): {
|
|
33
|
-
email: string;
|
|
34
|
-
name?: string;
|
|
35
|
-
} | null;
|
|
36
|
-
/**
|
|
37
|
-
* BAKED-IN unified auth. When a gate provides this resolver, the engine
|
|
38
|
-
* AUTOMATICALLY releases a logged-in viewer whose session email is in the
|
|
39
|
-
* authorized set — with no valid token and no per-gate code. This is the
|
|
40
|
-
* platform default for EVERY gated resource: any application surface with
|
|
41
|
-
* authentication gets "a signed-in, authorized viewer is never re-asked for
|
|
42
|
-
* their email/OTP" for free, just by exposing its authorized-email set (the
|
|
43
|
-
* same resolver its AccessConfig uses). Not called when the session is
|
|
44
|
-
* anonymous. Omit only for open-capture gates that have no authorized set.
|
|
45
|
-
*/
|
|
46
|
-
resolveAuthorizedEmails?(resourceId: string): Promise<Set<string>>;
|
|
47
|
-
/**
|
|
48
|
-
* OPTIONAL OVERRIDE of the baked-in session check above — for the rare gate
|
|
49
|
-
* whose session→identity rule isn't simply "session email ∈ authorized set".
|
|
50
|
-
* When present it wins; otherwise the engine uses `resolveAuthorizedEmails`.
|
|
51
|
-
* Called only when no valid access token is present.
|
|
52
|
-
*/
|
|
53
|
-
sessionAuthorize?(resolved: Resolved, resourceId: string): {
|
|
54
|
-
email: string;
|
|
55
|
-
name?: string;
|
|
56
|
-
} | null | Promise<{
|
|
57
|
-
email: string;
|
|
58
|
-
name?: string;
|
|
59
|
-
} | null>;
|
|
60
|
-
/** Reveal + seed the verified viewer's identity/session (token was valid). */
|
|
61
|
-
onAuthorized(resolved: Resolved, resourceId: string, identity: {
|
|
62
|
-
email: string;
|
|
63
|
-
name?: string;
|
|
64
|
-
}): void | Promise<void>;
|
|
65
|
-
/** Withhold content (strip/inject the gate) — token absent/invalid. Async-
|
|
66
|
-
* capable so a gate can load its display/behaviour settings from a registry
|
|
67
|
-
* row (DB-driven, not hardcoded); sync implementations remain valid. */
|
|
68
|
-
onUnauthorized(resolved: Resolved, resourceId: string): void | Promise<void>;
|
|
69
|
-
}
|
|
70
|
-
/** Drives the public access endpoint (access.ts / attachContentGateAccess). */
|
|
71
|
-
export interface AccessConfig {
|
|
72
|
-
/** Route to mount, e.g. "/api/proposal-access". */
|
|
73
|
-
path: string;
|
|
74
|
-
/** Cookie to set on a match. */
|
|
75
|
-
cookieName: string;
|
|
76
|
-
/** Cookie lifetime in ms (Max-Age). */
|
|
77
|
-
ttlMs: number;
|
|
78
|
-
/** Form field carrying the resource id, e.g. "proposalId". */
|
|
79
|
-
recordIdField: string;
|
|
80
|
-
/**
|
|
81
|
-
* Open lead-capture gate: ANY non-empty email is accepted (no allow-list).
|
|
82
|
-
* For surfaces whose "gate" captures a visitor rather than authorizing one
|
|
83
|
-
* against a fixed set (the public GPT). When true, `resolveAuthorizedEmails`
|
|
84
|
-
* is not called. Default/omitted = allow-list mode (proposals, agreements).
|
|
85
|
-
*/
|
|
86
|
-
openCapture?: boolean;
|
|
87
|
-
/**
|
|
88
|
-
* The authorized email set for a resource (lowercased), checked server-side.
|
|
89
|
-
* Not called when `openCapture` is true.
|
|
90
|
-
*/
|
|
91
|
-
resolveAuthorizedEmails(resourceId: string): Promise<Set<string>>;
|
|
92
|
-
/**
|
|
93
|
-
* Mint the access token for a matched email (token-agnostic per gate).
|
|
94
|
-
* `name` is the optional captured display name (open-capture gates carry it
|
|
95
|
-
* in the token; allow-list gates ignore it).
|
|
96
|
-
*/
|
|
97
|
-
signToken(resourceId: string, email: string, nowMs: number, name?: string): string | null;
|
|
98
|
-
}
|
|
99
|
-
export {};
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @system service-boot
|
|
3
|
-
* @status handwritten
|
|
4
|
-
* @edit edit directly
|
|
5
|
-
*
|
|
6
|
-
* The content-gate ENGINE. Runs in the page loader after the resource graph
|
|
7
|
-
* resolves, BEFORE SSR. Orchestration only — the per-type behaviour (which
|
|
8
|
-
* resource, who's authorized, what to seed, how to withhold) is supplied by a
|
|
9
|
-
* ContentGateConfig, so agreements/proposals/future gates are configs, not new
|
|
10
|
-
* functions. The single place that decides whether gated bytes reach the HTML.
|
|
11
|
-
*/
|
|
12
|
-
import type { ContentGateConfig } from "./config-types.ts";
|
|
13
|
-
export declare function runContentGate(resolved: Record<string, unknown>, cookieHeader: string | null, nowMs: number, config: ContentGateConfig): Promise<void>;
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @system service-boot
|
|
3
|
-
* @status handwritten
|
|
4
|
-
* @edit edit directly
|
|
5
|
-
*
|
|
6
|
-
* Parse a single cookie value out of a raw Cookie header — shared by the
|
|
7
|
-
* content-gate engine and any gate config.
|
|
8
|
-
*/
|
|
9
|
-
export declare function parseCookie(header: string | null, name: string): string | undefined;
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @system service-boot
|
|
3
|
-
* @status handwritten
|
|
4
|
-
* @edit edit directly
|
|
5
|
-
*
|
|
6
|
-
* The single signed, short-lived access token for EVERY content gate (agreement,
|
|
7
|
-
* proposal, and any future gated content). A gate withholds page content
|
|
8
|
-
* server-side until the request carries a valid token for that resource; this is
|
|
9
|
-
* the only thing that releases the content into the SSR, so without it a gated
|
|
10
|
-
* page is never readable/scrapable by a link holder.
|
|
11
|
-
*
|
|
12
|
-
* HMAC-SHA256 (Bun-native) over {c:cookieName, r:resourceId, e:email, x:exp}.
|
|
13
|
-
* `cookieName` is bound INTO the payload so a token minted for one gate
|
|
14
|
-
* (e.g. ag_token) can never satisfy another gate's check (e.g. prop_token).
|
|
15
|
-
*
|
|
16
|
-
* Secret resolver, in preference order: AUTH_SECRET → ENCRYPTION_KEY →
|
|
17
|
-
* DATABASE_URL (first one ≥16 chars). A gate signs AND verifies inside one
|
|
18
|
-
* service, so it only needs a stable per-deployment secret; the fallback keeps a
|
|
19
|
-
* gate working on a service that was never given AUTH_SECRET (e.g. the former
|
|
20
|
-
* public-only proposals viewer) instead of failing closed and locking out every
|
|
21
|
-
* authorized viewer. Any service that has AUTH_SECRET transparently prefers it.
|
|
22
|
-
* Fail-closed: no usable secret yields null (no token, no access).
|
|
23
|
-
*/
|
|
24
|
-
/** Mint a token proving `email` is authorized for `resourceId` under `cookieName`. */
|
|
25
|
-
export declare function signAccessToken(cookieName: string, resourceId: string, email: string, nowMs: number, ttlMs: number,
|
|
26
|
-
/**
|
|
27
|
-
* Optional display name to carry in the token (the public GPT lead-capture
|
|
28
|
-
* gate uses this so a returning visitor's name is known at SSR — first paint
|
|
29
|
-
* renders the full identity, not just the email). Allow-list gates
|
|
30
|
-
* (proposals/agreements) omit it.
|
|
31
|
-
*/
|
|
32
|
-
name?: string): string | null;
|
|
33
|
-
/**
|
|
34
|
-
* Validate a token for `cookieName` + `resourceId`. Returns the verified email
|
|
35
|
-
* on success, null otherwise (bad signature, wrong gate, wrong resource,
|
|
36
|
-
* expired, no secret).
|
|
37
|
-
*/
|
|
38
|
-
export declare function verifyAccessToken(token: string | undefined | null, cookieName: string, resourceId: string, nowMs: number): string | null;
|
|
39
|
-
/**
|
|
40
|
-
* Like `verifyAccessToken` but returns the full verified identity ({email, name})
|
|
41
|
-
* so a gate that carries a display name in the token (the public GPT lead-capture
|
|
42
|
-
* gate) can seed the visitor's name — not just the email — at SSR. Same
|
|
43
|
-
* signature/expiry/gate-binding checks; null on any failure.
|
|
44
|
-
*/
|
|
45
|
-
export declare function verifyAccessTokenIdentity(token: string | undefined | null, cookieName: string, resourceId: string, nowMs: number): {
|
|
46
|
-
email: string;
|
|
47
|
-
name?: string;
|
|
48
|
-
} | null;
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @system service-boot
|
|
3
|
-
* @status handwritten
|
|
4
|
-
* @edit edit directly
|
|
5
|
-
*
|
|
6
|
-
* Pure decision: does a CONTENT route (no resource_type) whose loader resolved
|
|
7
|
-
* a `page` body source warrant the branded not-found floor? Extracted from
|
|
8
|
-
* register-registry-page-route so the rule is unit-testable independent of the
|
|
9
|
-
* Hono/DB/graph machinery that wraps it (the fix's correctness does not depend
|
|
10
|
-
* on the publish — verify-before-done).
|
|
11
|
-
*
|
|
12
|
-
* Three outcomes:
|
|
13
|
-
* - no page row (deleted/unmatched path, e.g. /roadmap) → dead-link 404 floor
|
|
14
|
-
* - page row exists but zero content blocks → empty-page 200 floor
|
|
15
|
-
* - otherwise → null (render normally)
|
|
16
|
-
*
|
|
17
|
-
* The "Vision Toolbar" leak this closes: a content catchall synthesized an empty
|
|
18
|
-
* page for an unmatched path and served a cacheable 200; resource-not-found-is-
|
|
19
|
-
* the-root-floor only fired for resource_type routes, so dead content links fell
|
|
20
|
-
* through. See resource-not-found.ts for the floor + operator ruling 2026-07-21.
|
|
21
|
-
*/
|
|
22
|
-
import { PrimaryResourceMissingError } from "./resource-not-found.ts";
|
|
23
|
-
/**
|
|
24
|
-
* A page ROW exists but its body has zero content blocks — a content gap, not a
|
|
25
|
-
* dead link. True only when the row is present yet `puck_data` is absent or its
|
|
26
|
-
* `content` array is empty. Handles string (raw) and object (normalized) puck_data.
|
|
27
|
-
*/
|
|
28
|
-
export declare function pageBodyIsEmpty(page: unknown): boolean;
|
|
29
|
-
/**
|
|
30
|
-
* Decide whether a content route should fall to the branded not-found floor.
|
|
31
|
-
* Returns the error to throw (mapped to the floor by bind-page-handler), or null
|
|
32
|
-
* to render normally. `hasResourceType` routes are handled by the existing
|
|
33
|
-
* resource_type missing check (caller-side) — they return null here.
|
|
34
|
-
*/
|
|
35
|
-
export declare function decideContentPageFloor(opts: {
|
|
36
|
-
hasResourceType: boolean;
|
|
37
|
-
hasPageContentSource: boolean;
|
|
38
|
-
page: unknown;
|
|
39
|
-
}): PrimaryResourceMissingError | null;
|
package/src/discover-blocks.d.ts
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @system ui-service-boot
|
|
3
|
-
* @status handwritten
|
|
4
|
-
* @edit edit directly
|
|
5
|
-
*
|
|
6
|
-
* Surgical block discovery: at boot, queries every block_schema row in the
|
|
7
|
-
* registry whose componentPath starts with one of the service's declared
|
|
8
|
-
* block_packages, then dynamic-imports each one. Per-block try/catch — one
|
|
9
|
-
* dead componentPath logs and skips, the rest still register and the page
|
|
10
|
-
* renders the surviving blocks. This replaces the static
|
|
11
|
-
* `.scala-install/page-manifest.ts` codegen output, which had the failure
|
|
12
|
-
* mode of a single dead block_schema row crashing the whole manifest at
|
|
13
|
-
* compile time.
|
|
14
|
-
*
|
|
15
|
-
* Empty block_packages is NOT fatal here: it falls back to scanning all
|
|
16
|
-
* active block_schema (uninstalled packages skip via the per-block try/catch),
|
|
17
|
-
* so a service whose row is unpopulated but whose blocks are installed still
|
|
18
|
-
* renders. The real "booted with zero blocks" fail-closed is at the call site
|
|
19
|
-
* (loaded.length === 0 → BootFatalError). A DB-unreachable error still throws —
|
|
20
|
-
* no fallback to a package-side puckBlocks scan, which masked blockless boots.
|
|
21
|
-
*/
|
|
22
|
-
import type { RendererComponentEntry } from "./types.ts";
|
|
23
|
-
export interface DiscoveredBlocks {
|
|
24
|
-
components: Record<string, RendererComponentEntry>;
|
|
25
|
-
loaded: string[];
|
|
26
|
-
skipped: string[];
|
|
27
|
-
}
|
|
28
|
-
export declare function discoverBlocks(blockPackages: string[]): Promise<DiscoveredBlocks>;
|
package/src/expand-roster.d.ts
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @system server-boot
|
|
3
|
-
* @status handwritten
|
|
4
|
-
* @edit edit directly
|
|
5
|
-
*
|
|
6
|
-
* Server-side roster expansion — the executor that handles "render N of block X
|
|
7
|
-
* per data row" so the page never needs a domain-specific panel/list block. A
|
|
8
|
-
* block authored with `props.dataRepeat: "parties"` is a TEMPLATE; before SSR
|
|
9
|
-
* this clones it once per roster item into its parent slot (top-level content or
|
|
10
|
-
* any Container's `content` slot), then drops the marker. Each clone:
|
|
11
|
-
* - sets `role` + `dataKey` to the item's key, so a prop-driven block (the
|
|
12
|
-
* SignatureField cell) finds its own party with no per-clone wiring;
|
|
13
|
-
* - substitutes `{{name}}` / `{{role}}` / `{{company}}` / `{{date}}` /
|
|
14
|
-
* `{{status}}` placeholders in any string prop (so a recipient row is plain
|
|
15
|
-
* `Container` + `Text` primitives — the copy lives on the page, not here).
|
|
16
|
-
* `{{status}}` resolves from the template's own `signedLabel` /
|
|
17
|
-
* `awaitingLabel` props (DB-driven copy), never hardcoded.
|
|
18
|
-
* Generic over any roster; the agreement page passes its parties.
|
|
19
|
-
*/
|
|
20
|
-
export interface RosterItem {
|
|
21
|
-
key: string;
|
|
22
|
-
role: string;
|
|
23
|
-
name: string;
|
|
24
|
-
title: string | null;
|
|
25
|
-
company: string | null;
|
|
26
|
-
signedAt: string | null;
|
|
27
|
-
signature: string | null;
|
|
28
|
-
}
|
|
29
|
-
/** Agreement-level tokens (one substitution, not per-party). */
|
|
30
|
-
export interface RosterMeta {
|
|
31
|
-
[token: string]: string;
|
|
32
|
-
}
|
|
33
|
-
/** Expand roster templates + bind agreement-meta placeholders across regions. */
|
|
34
|
-
export declare function expandRosterTemplates(resolved: Record<string, unknown>, parties: RosterItem[], meta?: RosterMeta): void;
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @system service-boot
|
|
3
|
-
* @status handwritten
|
|
4
|
-
* @edit edit directly
|
|
5
|
-
*
|
|
6
|
-
* Completion delivery. When an agreement is fully EXECUTED (every party has
|
|
7
|
-
* signed), email each party their executed copy + a note to download the
|
|
8
|
-
* Certificate of Completion. Each link is a per-party magic-link (no email gate,
|
|
9
|
-
* no OTP — see attach-agreement-magic.ts). Best-effort and self-contained: it
|
|
10
|
-
* loads its own data and swallows every error, so a send failure is logged and
|
|
11
|
-
* NEVER undoes the signature (the payment-setup non-fatal rule, applied to mail).
|
|
12
|
-
* Fire-and-forget from the sign handler: `void sendAgreementCompletionEmails(...)`.
|
|
13
|
-
*/
|
|
14
|
-
export declare function sendAgreementCompletionEmails(agreementId: string, baseUrl: string): Promise<void>;
|