@lunora/advisor 1.0.0-alpha.18 → 1.0.0-alpha.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE.md CHANGED
@@ -103,3 +103,9 @@ Unless required by applicable law or agreed to in writing, software distributed
103
103
  under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
104
104
  CONDITIONS OF ANY KIND, either express or implied. See the License for the
105
105
  specific language governing permissions and limitations under the License.
106
+
107
+ <!-- DEPENDENCIES -->
108
+ <!-- /DEPENDENCIES -->
109
+
110
+ <!-- TYPE_DEPENDENCIES -->
111
+ <!-- /TYPE_DEPENDENCIES -->
package/dist/index.d.mts CHANGED
@@ -817,6 +817,45 @@ interface AdvisorQueryRead {
817
817
  table: string;
818
818
  }
819
819
  /**
820
+ * The queue-shaped input the `queue_*` lints consume, produced by the codegen
821
+ * feeder — one per `defineQueue` export in `lunora/queues.ts`. Runtime callers
822
+ * don't supply it, so the queue lints simply find nothing there.
823
+ *
824
+ * A structural subset of codegen's `QueueIR`, so the feeder passes the IR array
825
+ * straight through without conversion (mirrors how `AdvisorWorkflow` tracks
826
+ * `WorkflowIR` and `AdvisorContainer` tracks `ContainerIR`).
827
+ */
828
+ /**
829
+ * The push-consumer batch/retry tuning a queue lint inspects — the subset of
830
+ * `QueueIR["tuning"]` mirrored onto the wrangler `queues.consumers[]` entry.
831
+ */
832
+ interface AdvisorQueueTuning {
833
+ /**
834
+ * The wrangler name of the dead-letter queue exhausted messages are routed
835
+ * to. `undefined` when none is declared — a message that exhausts its
836
+ * retries is then dropped and permanently lost.
837
+ */
838
+ deadLetterQueue?: string;
839
+ /** Max delivery retries before a message is dead-lettered/dropped (Cloudflare default 3). */
840
+ maxRetries?: number;
841
+ }
842
+ /** One queue declared via a `defineQueue()` export in `lunora/queues.ts`. */
843
+ interface AdvisorQueue {
844
+ /** The `lunora/queues.ts` export name, e.g. `notifications`. */
845
+ exportName: string;
846
+ /** How the queue is consumed: `"push"` (a worker `queue()` handler) or `"pull"` (external HTTP). */
847
+ mode: "pull" | "push";
848
+ /**
849
+ * The stable wrangler queue name (kebab-cased export name unless a `name:`
850
+ * literal overrides it). Used to recognise a queue that is itself another
851
+ * queue's `deadLetterQueue` target — a terminal sink that must not be
852
+ * flagged for lacking its own DLQ.
853
+ */
854
+ name: string;
855
+ /** Push-consumer batch/retry tuning; the `deadLetterQueue`/`maxRetries` the queue lints read. */
856
+ tuning: AdvisorQueueTuning;
857
+ }
858
+ /**
820
859
  * One `ctx.r2sql` access discovered lexically inside a `query(...)` or
821
860
  * `mutation(...)` handler body — the input the `r2sql_outside_action` lint
822
861
  * consumes. Produced by the codegen feeder, which walks each exported function's
@@ -1711,6 +1750,13 @@ interface LintContext {
1711
1750
  */
1712
1751
  queries?: ReadonlyArray<AdvisorQueryRead>;
1713
1752
  /**
1753
+ * Queues declared via `defineQueue` exports in `lunora/queues.ts` — the
1754
+ * declaration-side input for the `queue_*` lints (`queue_without_dlq`).
1755
+ * Supplied by the codegen feeder; absent for runtime callers, where the
1756
+ * queue lints find nothing.
1757
+ */
1758
+ queues?: ReadonlyArray<AdvisorQueue>;
1759
+ /**
1714
1760
  * R2 SQL `ctx.r2sql` accesses discovered lexically inside `query`/`mutation`
1715
1761
  * handler bodies — the `r2sql_outside_action` input. Supplied by the codegen
1716
1762
  * feeder, which omits `action` handlers (where `ctx.r2sql` is the typed,
@@ -3035,6 +3081,26 @@ declare const publicMutationWithoutRatelimit: Lint;
3035
3081
  */
3036
3082
  declare const publicTableRlsOptoutConfusion: Lint;
3037
3083
  /**
3084
+ * Flags a declared queue — push or pull — that has no dead-letter queue.
3085
+ *
3086
+ * A Cloudflare Queues consumer retries a failing message up to `maxRetries`
3087
+ * times (default 3 — roughly four total delivery attempts); once that budget is
3088
+ * exhausted, a message with no `deadLetterQueue` is **deleted permanently** with
3089
+ * no record an operator can inspect. Routing exhausted messages to a DLQ turns
3090
+ * silent data loss into a backlog you can inspect, alert on, and replay. Hence
3091
+ * `WARN`/`INTERNAL`: an operator-facing reliability nudge, not a hard error — a
3092
+ * genuinely fire-and-forget queue may accept the loss.
3093
+ *
3094
+ * A queue that is itself some other queue's `deadLetterQueue` target is skipped:
3095
+ * a DLQ is a terminal sink and requiring it to have its own DLQ would recurse
3096
+ * forever (and mis-flag the best-practice scaffold, which pairs a queue with a
3097
+ * dedicated DLQ consumer).
3098
+ *
3099
+ * Only runs when the declaration feeder supplied evidence (`context.queues`
3100
+ * present); a runtime caller flags nothing.
3101
+ */
3102
+ declare const queueWithoutDlq: Lint;
3103
+ /**
3038
3104
  * Flags an R2 SQL `ctx.r2sql` access inside a `query(...)` or `mutation(...)`
3039
3105
  * handler body.
3040
3106
  *
@@ -3536,4 +3602,4 @@ interface RunAdvisorOptions {
3536
3602
  * `static` lints at build time and defer `runtime` lints to a live shard.
3537
3603
  */
3538
3604
  declare const runAdvisor: (context: LintContext, options?: RunAdvisorOptions) => Finding[];
3539
- export { AE_METRIC_EVENTS, ALL_LINTS, type AdvisorAdminRoute, type AdvisorAiRawRun, type AdvisorAiToolSideEffect, type AdvisorArgumentDerivedFetch, type AdvisorArgumentValidator, type AdvisorAuthApiCall, type AdvisorAuthConfig, type AdvisorBrowserUrlAccess, type AdvisorConfigCall, type AdvisorContainer, type AdvisorContainerKeyAccess, type AdvisorContainerOverride, type AdvisorFailOpenGuard, type AdvisorFlagSecurityDefault, type AdvisorHttpActionGuard, type AdvisorHttpHeaderWrite, type AdvisorHyperdriveCall, type AdvisorIdentityClaimRead, type AdvisorImageDeliveryUrlAccess, type AdvisorIndex, type AdvisorIndexHit, type AdvisorInsertWrite, type AdvisorKvKeyAccess, type AdvisorMailRecipientAccess, type AdvisorMaskProcedure, type AdvisorMaskStrategy, type AdvisorMutatorWrite, type AdvisorNondeterministicCall, type AdvisorNormalizeIdAuthorization, type AdvisorOwnerFieldWrite, type AdvisorPaymentWebhook, type AdvisorPrivilegedDispatch, type AdvisorProcedureProtection, type AdvisorQueryRead, type AdvisorR2sqlCall, type AdvisorRatelimitKeySelector, type AdvisorRawRowReturn, type AdvisorRelation, type AdvisorRelationLoad, type AdvisorRlsProcedure, type AdvisorSchema, type AdvisorSecretLiteral, type AdvisorShape, type AdvisorShardTraffic, type AdvisorSoftDeleteRead, type AdvisorSqlInterpolation, type AdvisorStorageKeyAccess, type AdvisorStorageUpload, type AdvisorTable, type AdvisorTableSample, type AdvisorTableScan, type AdvisorVectorNamespaceAccess, type AdvisorWorkflow, type AdvisorWorkflowCall, type AdvisorWranglerVariable, type AnalyticsMetricsOptions, type AnalyticsMetricsSource, type AnalyticsRuntimeMetrics, type Category, type Facing, type Finding, type Level, type Lint, type LintContext, type LintSource, RUNTIME_LINTS, RunAdvisorOptions, STATIC_LINTS, actionFetchSsrf, adminRouteWithoutGuard, aiRawRunEscapeHatch, aiToolSideEffectPromptInjection, aiUnboundedGenerationPublic, allowUnauthenticatedShardAccessEnabled, authApiCallWithoutHeaders, authCsrfCheckDisabled, authEmailVerificationDisabled, authSecureCookiesDisabled, authSessionFreshageZero, authTrustedOriginsWildcard, browserAllowPrivateTargets, browserUserUrlWithoutAllowlist, circularFk, constraintValidator, containerInstanceKeyFromUserInput, containerOversizedInstance, containerPublicInternet, containerRuntimeEgressRelaxation, containerStartEnableInternetOverride, duplicateIndex, emptyIndex, externalSourceOnGlobal, externalSourceUnscoped, filterWithoutIndex, flagGatesSecurityWithUnsafeDefault, fromServerSchema, hardcodedSecret, hotShard, httpActionMissingAuthGuard, httpActionResponseHeaderInjection, hyperdriveOutsideAction, identityUndeclaredClaimTrusted, imagesUrlSourceFromUserInput, indexReferencesUnknownField, indexUtilization, insertManyUnsafeUserData, kvUnscopedUserKeyIdor, loadAnalyticsRuntimeMetrics, mailInboundDispatchWithoutVerify, mailRecipientFromRequestInput, maskUncoveredPiiColumn, maskWeakHashStrategyOnPii, maskedRelationLeakViaWith, mutatorFullRowReplace, nondeterministicQueryMutation, normalizeIdUsedAsAuthorization, outputProjectionMissingOnPublicRead, ownerFieldFromArgsNotAuth, paymentCreateWithoutAuthorize, paymentWebhookWideTolerance, plaintextSecretInWranglerVariables, policyReferencesUnknownTable, privilegedDispatchUnvalidatedPayload, privilegedFanoutFromPublicProcedure, publicArgumentUsesAny, publicMutationWithoutRatelimit, publicTableRlsOptoutConfusion, r2sqlOutsideAction, ratelimitDefaultMemoryStore, ratelimitKeySpoofableOrGlobal, ratelimitMiddlewareFailOpen, relationReferencesUnknownField, relationReferencesUnknownTable, rlsUncoveredTable, runAdvisor, shapeTargetsGlobalTable, shapeUnknownTable, softDeleteIncludeDeletedFromArgs, sqlInjectionRisk, storageGenerateUploadUrlNoContentTypePin, storageKeyFromUserArgs, storagePresignedUrlForPrivateContent, storageUploadWithoutContentTypeAllowlist, storageUploadWithoutMaxSize, tableWithoutInsert, unboundedStringArgument, unindexedForeignKey, unindexedRelationTarget, userCreatingMutationWithoutCaptcha, vectorsNamespaceFromUserInput, workflowDuplicateStepName, workflowUnknownTarget, workflowUnused };
3605
+ export { AE_METRIC_EVENTS, ALL_LINTS, type AdvisorAdminRoute, type AdvisorAiRawRun, type AdvisorAiToolSideEffect, type AdvisorArgumentDerivedFetch, type AdvisorArgumentValidator, type AdvisorAuthApiCall, type AdvisorAuthConfig, type AdvisorBrowserUrlAccess, type AdvisorConfigCall, type AdvisorContainer, type AdvisorContainerKeyAccess, type AdvisorContainerOverride, type AdvisorFailOpenGuard, type AdvisorFlagSecurityDefault, type AdvisorHttpActionGuard, type AdvisorHttpHeaderWrite, type AdvisorHyperdriveCall, type AdvisorIdentityClaimRead, type AdvisorImageDeliveryUrlAccess, type AdvisorIndex, type AdvisorIndexHit, type AdvisorInsertWrite, type AdvisorKvKeyAccess, type AdvisorMailRecipientAccess, type AdvisorMaskProcedure, type AdvisorMaskStrategy, type AdvisorMutatorWrite, type AdvisorNondeterministicCall, type AdvisorNormalizeIdAuthorization, type AdvisorOwnerFieldWrite, type AdvisorPaymentWebhook, type AdvisorPrivilegedDispatch, type AdvisorProcedureProtection, type AdvisorQueryRead, type AdvisorQueue, type AdvisorQueueTuning, type AdvisorR2sqlCall, type AdvisorRatelimitKeySelector, type AdvisorRawRowReturn, type AdvisorRelation, type AdvisorRelationLoad, type AdvisorRlsProcedure, type AdvisorSchema, type AdvisorSecretLiteral, type AdvisorShape, type AdvisorShardTraffic, type AdvisorSoftDeleteRead, type AdvisorSqlInterpolation, type AdvisorStorageKeyAccess, type AdvisorStorageUpload, type AdvisorTable, type AdvisorTableSample, type AdvisorTableScan, type AdvisorVectorNamespaceAccess, type AdvisorWorkflow, type AdvisorWorkflowCall, type AdvisorWranglerVariable, type AnalyticsMetricsOptions, type AnalyticsMetricsSource, type AnalyticsRuntimeMetrics, type Category, type Facing, type Finding, type Level, type Lint, type LintContext, type LintSource, RUNTIME_LINTS, RunAdvisorOptions, STATIC_LINTS, actionFetchSsrf, adminRouteWithoutGuard, aiRawRunEscapeHatch, aiToolSideEffectPromptInjection, aiUnboundedGenerationPublic, allowUnauthenticatedShardAccessEnabled, authApiCallWithoutHeaders, authCsrfCheckDisabled, authEmailVerificationDisabled, authSecureCookiesDisabled, authSessionFreshageZero, authTrustedOriginsWildcard, browserAllowPrivateTargets, browserUserUrlWithoutAllowlist, circularFk, constraintValidator, containerInstanceKeyFromUserInput, containerOversizedInstance, containerPublicInternet, containerRuntimeEgressRelaxation, containerStartEnableInternetOverride, duplicateIndex, emptyIndex, externalSourceOnGlobal, externalSourceUnscoped, filterWithoutIndex, flagGatesSecurityWithUnsafeDefault, fromServerSchema, hardcodedSecret, hotShard, httpActionMissingAuthGuard, httpActionResponseHeaderInjection, hyperdriveOutsideAction, identityUndeclaredClaimTrusted, imagesUrlSourceFromUserInput, indexReferencesUnknownField, indexUtilization, insertManyUnsafeUserData, kvUnscopedUserKeyIdor, loadAnalyticsRuntimeMetrics, mailInboundDispatchWithoutVerify, mailRecipientFromRequestInput, maskUncoveredPiiColumn, maskWeakHashStrategyOnPii, maskedRelationLeakViaWith, mutatorFullRowReplace, nondeterministicQueryMutation, normalizeIdUsedAsAuthorization, outputProjectionMissingOnPublicRead, ownerFieldFromArgsNotAuth, paymentCreateWithoutAuthorize, paymentWebhookWideTolerance, plaintextSecretInWranglerVariables, policyReferencesUnknownTable, privilegedDispatchUnvalidatedPayload, privilegedFanoutFromPublicProcedure, publicArgumentUsesAny, publicMutationWithoutRatelimit, publicTableRlsOptoutConfusion, queueWithoutDlq, r2sqlOutsideAction, ratelimitDefaultMemoryStore, ratelimitKeySpoofableOrGlobal, ratelimitMiddlewareFailOpen, relationReferencesUnknownField, relationReferencesUnknownTable, rlsUncoveredTable, runAdvisor, shapeTargetsGlobalTable, shapeUnknownTable, softDeleteIncludeDeletedFromArgs, sqlInjectionRisk, storageGenerateUploadUrlNoContentTypePin, storageKeyFromUserArgs, storagePresignedUrlForPrivateContent, storageUploadWithoutContentTypeAllowlist, storageUploadWithoutMaxSize, tableWithoutInsert, unboundedStringArgument, unindexedForeignKey, unindexedRelationTarget, userCreatingMutationWithoutCaptcha, vectorsNamespaceFromUserInput, workflowDuplicateStepName, workflowUnknownTarget, workflowUnused };
package/dist/index.d.ts CHANGED
@@ -817,6 +817,45 @@ interface AdvisorQueryRead {
817
817
  table: string;
818
818
  }
819
819
  /**
820
+ * The queue-shaped input the `queue_*` lints consume, produced by the codegen
821
+ * feeder — one per `defineQueue` export in `lunora/queues.ts`. Runtime callers
822
+ * don't supply it, so the queue lints simply find nothing there.
823
+ *
824
+ * A structural subset of codegen's `QueueIR`, so the feeder passes the IR array
825
+ * straight through without conversion (mirrors how `AdvisorWorkflow` tracks
826
+ * `WorkflowIR` and `AdvisorContainer` tracks `ContainerIR`).
827
+ */
828
+ /**
829
+ * The push-consumer batch/retry tuning a queue lint inspects — the subset of
830
+ * `QueueIR["tuning"]` mirrored onto the wrangler `queues.consumers[]` entry.
831
+ */
832
+ interface AdvisorQueueTuning {
833
+ /**
834
+ * The wrangler name of the dead-letter queue exhausted messages are routed
835
+ * to. `undefined` when none is declared — a message that exhausts its
836
+ * retries is then dropped and permanently lost.
837
+ */
838
+ deadLetterQueue?: string;
839
+ /** Max delivery retries before a message is dead-lettered/dropped (Cloudflare default 3). */
840
+ maxRetries?: number;
841
+ }
842
+ /** One queue declared via a `defineQueue()` export in `lunora/queues.ts`. */
843
+ interface AdvisorQueue {
844
+ /** The `lunora/queues.ts` export name, e.g. `notifications`. */
845
+ exportName: string;
846
+ /** How the queue is consumed: `"push"` (a worker `queue()` handler) or `"pull"` (external HTTP). */
847
+ mode: "pull" | "push";
848
+ /**
849
+ * The stable wrangler queue name (kebab-cased export name unless a `name:`
850
+ * literal overrides it). Used to recognise a queue that is itself another
851
+ * queue's `deadLetterQueue` target — a terminal sink that must not be
852
+ * flagged for lacking its own DLQ.
853
+ */
854
+ name: string;
855
+ /** Push-consumer batch/retry tuning; the `deadLetterQueue`/`maxRetries` the queue lints read. */
856
+ tuning: AdvisorQueueTuning;
857
+ }
858
+ /**
820
859
  * One `ctx.r2sql` access discovered lexically inside a `query(...)` or
821
860
  * `mutation(...)` handler body — the input the `r2sql_outside_action` lint
822
861
  * consumes. Produced by the codegen feeder, which walks each exported function's
@@ -1711,6 +1750,13 @@ interface LintContext {
1711
1750
  */
1712
1751
  queries?: ReadonlyArray<AdvisorQueryRead>;
1713
1752
  /**
1753
+ * Queues declared via `defineQueue` exports in `lunora/queues.ts` — the
1754
+ * declaration-side input for the `queue_*` lints (`queue_without_dlq`).
1755
+ * Supplied by the codegen feeder; absent for runtime callers, where the
1756
+ * queue lints find nothing.
1757
+ */
1758
+ queues?: ReadonlyArray<AdvisorQueue>;
1759
+ /**
1714
1760
  * R2 SQL `ctx.r2sql` accesses discovered lexically inside `query`/`mutation`
1715
1761
  * handler bodies — the `r2sql_outside_action` input. Supplied by the codegen
1716
1762
  * feeder, which omits `action` handlers (where `ctx.r2sql` is the typed,
@@ -3035,6 +3081,26 @@ declare const publicMutationWithoutRatelimit: Lint;
3035
3081
  */
3036
3082
  declare const publicTableRlsOptoutConfusion: Lint;
3037
3083
  /**
3084
+ * Flags a declared queue — push or pull — that has no dead-letter queue.
3085
+ *
3086
+ * A Cloudflare Queues consumer retries a failing message up to `maxRetries`
3087
+ * times (default 3 — roughly four total delivery attempts); once that budget is
3088
+ * exhausted, a message with no `deadLetterQueue` is **deleted permanently** with
3089
+ * no record an operator can inspect. Routing exhausted messages to a DLQ turns
3090
+ * silent data loss into a backlog you can inspect, alert on, and replay. Hence
3091
+ * `WARN`/`INTERNAL`: an operator-facing reliability nudge, not a hard error — a
3092
+ * genuinely fire-and-forget queue may accept the loss.
3093
+ *
3094
+ * A queue that is itself some other queue's `deadLetterQueue` target is skipped:
3095
+ * a DLQ is a terminal sink and requiring it to have its own DLQ would recurse
3096
+ * forever (and mis-flag the best-practice scaffold, which pairs a queue with a
3097
+ * dedicated DLQ consumer).
3098
+ *
3099
+ * Only runs when the declaration feeder supplied evidence (`context.queues`
3100
+ * present); a runtime caller flags nothing.
3101
+ */
3102
+ declare const queueWithoutDlq: Lint;
3103
+ /**
3038
3104
  * Flags an R2 SQL `ctx.r2sql` access inside a `query(...)` or `mutation(...)`
3039
3105
  * handler body.
3040
3106
  *
@@ -3536,4 +3602,4 @@ interface RunAdvisorOptions {
3536
3602
  * `static` lints at build time and defer `runtime` lints to a live shard.
3537
3603
  */
3538
3604
  declare const runAdvisor: (context: LintContext, options?: RunAdvisorOptions) => Finding[];
3539
- export { AE_METRIC_EVENTS, ALL_LINTS, type AdvisorAdminRoute, type AdvisorAiRawRun, type AdvisorAiToolSideEffect, type AdvisorArgumentDerivedFetch, type AdvisorArgumentValidator, type AdvisorAuthApiCall, type AdvisorAuthConfig, type AdvisorBrowserUrlAccess, type AdvisorConfigCall, type AdvisorContainer, type AdvisorContainerKeyAccess, type AdvisorContainerOverride, type AdvisorFailOpenGuard, type AdvisorFlagSecurityDefault, type AdvisorHttpActionGuard, type AdvisorHttpHeaderWrite, type AdvisorHyperdriveCall, type AdvisorIdentityClaimRead, type AdvisorImageDeliveryUrlAccess, type AdvisorIndex, type AdvisorIndexHit, type AdvisorInsertWrite, type AdvisorKvKeyAccess, type AdvisorMailRecipientAccess, type AdvisorMaskProcedure, type AdvisorMaskStrategy, type AdvisorMutatorWrite, type AdvisorNondeterministicCall, type AdvisorNormalizeIdAuthorization, type AdvisorOwnerFieldWrite, type AdvisorPaymentWebhook, type AdvisorPrivilegedDispatch, type AdvisorProcedureProtection, type AdvisorQueryRead, type AdvisorR2sqlCall, type AdvisorRatelimitKeySelector, type AdvisorRawRowReturn, type AdvisorRelation, type AdvisorRelationLoad, type AdvisorRlsProcedure, type AdvisorSchema, type AdvisorSecretLiteral, type AdvisorShape, type AdvisorShardTraffic, type AdvisorSoftDeleteRead, type AdvisorSqlInterpolation, type AdvisorStorageKeyAccess, type AdvisorStorageUpload, type AdvisorTable, type AdvisorTableSample, type AdvisorTableScan, type AdvisorVectorNamespaceAccess, type AdvisorWorkflow, type AdvisorWorkflowCall, type AdvisorWranglerVariable, type AnalyticsMetricsOptions, type AnalyticsMetricsSource, type AnalyticsRuntimeMetrics, type Category, type Facing, type Finding, type Level, type Lint, type LintContext, type LintSource, RUNTIME_LINTS, RunAdvisorOptions, STATIC_LINTS, actionFetchSsrf, adminRouteWithoutGuard, aiRawRunEscapeHatch, aiToolSideEffectPromptInjection, aiUnboundedGenerationPublic, allowUnauthenticatedShardAccessEnabled, authApiCallWithoutHeaders, authCsrfCheckDisabled, authEmailVerificationDisabled, authSecureCookiesDisabled, authSessionFreshageZero, authTrustedOriginsWildcard, browserAllowPrivateTargets, browserUserUrlWithoutAllowlist, circularFk, constraintValidator, containerInstanceKeyFromUserInput, containerOversizedInstance, containerPublicInternet, containerRuntimeEgressRelaxation, containerStartEnableInternetOverride, duplicateIndex, emptyIndex, externalSourceOnGlobal, externalSourceUnscoped, filterWithoutIndex, flagGatesSecurityWithUnsafeDefault, fromServerSchema, hardcodedSecret, hotShard, httpActionMissingAuthGuard, httpActionResponseHeaderInjection, hyperdriveOutsideAction, identityUndeclaredClaimTrusted, imagesUrlSourceFromUserInput, indexReferencesUnknownField, indexUtilization, insertManyUnsafeUserData, kvUnscopedUserKeyIdor, loadAnalyticsRuntimeMetrics, mailInboundDispatchWithoutVerify, mailRecipientFromRequestInput, maskUncoveredPiiColumn, maskWeakHashStrategyOnPii, maskedRelationLeakViaWith, mutatorFullRowReplace, nondeterministicQueryMutation, normalizeIdUsedAsAuthorization, outputProjectionMissingOnPublicRead, ownerFieldFromArgsNotAuth, paymentCreateWithoutAuthorize, paymentWebhookWideTolerance, plaintextSecretInWranglerVariables, policyReferencesUnknownTable, privilegedDispatchUnvalidatedPayload, privilegedFanoutFromPublicProcedure, publicArgumentUsesAny, publicMutationWithoutRatelimit, publicTableRlsOptoutConfusion, r2sqlOutsideAction, ratelimitDefaultMemoryStore, ratelimitKeySpoofableOrGlobal, ratelimitMiddlewareFailOpen, relationReferencesUnknownField, relationReferencesUnknownTable, rlsUncoveredTable, runAdvisor, shapeTargetsGlobalTable, shapeUnknownTable, softDeleteIncludeDeletedFromArgs, sqlInjectionRisk, storageGenerateUploadUrlNoContentTypePin, storageKeyFromUserArgs, storagePresignedUrlForPrivateContent, storageUploadWithoutContentTypeAllowlist, storageUploadWithoutMaxSize, tableWithoutInsert, unboundedStringArgument, unindexedForeignKey, unindexedRelationTarget, userCreatingMutationWithoutCaptcha, vectorsNamespaceFromUserInput, workflowDuplicateStepName, workflowUnknownTarget, workflowUnused };
3605
+ export { AE_METRIC_EVENTS, ALL_LINTS, type AdvisorAdminRoute, type AdvisorAiRawRun, type AdvisorAiToolSideEffect, type AdvisorArgumentDerivedFetch, type AdvisorArgumentValidator, type AdvisorAuthApiCall, type AdvisorAuthConfig, type AdvisorBrowserUrlAccess, type AdvisorConfigCall, type AdvisorContainer, type AdvisorContainerKeyAccess, type AdvisorContainerOverride, type AdvisorFailOpenGuard, type AdvisorFlagSecurityDefault, type AdvisorHttpActionGuard, type AdvisorHttpHeaderWrite, type AdvisorHyperdriveCall, type AdvisorIdentityClaimRead, type AdvisorImageDeliveryUrlAccess, type AdvisorIndex, type AdvisorIndexHit, type AdvisorInsertWrite, type AdvisorKvKeyAccess, type AdvisorMailRecipientAccess, type AdvisorMaskProcedure, type AdvisorMaskStrategy, type AdvisorMutatorWrite, type AdvisorNondeterministicCall, type AdvisorNormalizeIdAuthorization, type AdvisorOwnerFieldWrite, type AdvisorPaymentWebhook, type AdvisorPrivilegedDispatch, type AdvisorProcedureProtection, type AdvisorQueryRead, type AdvisorQueue, type AdvisorQueueTuning, type AdvisorR2sqlCall, type AdvisorRatelimitKeySelector, type AdvisorRawRowReturn, type AdvisorRelation, type AdvisorRelationLoad, type AdvisorRlsProcedure, type AdvisorSchema, type AdvisorSecretLiteral, type AdvisorShape, type AdvisorShardTraffic, type AdvisorSoftDeleteRead, type AdvisorSqlInterpolation, type AdvisorStorageKeyAccess, type AdvisorStorageUpload, type AdvisorTable, type AdvisorTableSample, type AdvisorTableScan, type AdvisorVectorNamespaceAccess, type AdvisorWorkflow, type AdvisorWorkflowCall, type AdvisorWranglerVariable, type AnalyticsMetricsOptions, type AnalyticsMetricsSource, type AnalyticsRuntimeMetrics, type Category, type Facing, type Finding, type Level, type Lint, type LintContext, type LintSource, RUNTIME_LINTS, RunAdvisorOptions, STATIC_LINTS, actionFetchSsrf, adminRouteWithoutGuard, aiRawRunEscapeHatch, aiToolSideEffectPromptInjection, aiUnboundedGenerationPublic, allowUnauthenticatedShardAccessEnabled, authApiCallWithoutHeaders, authCsrfCheckDisabled, authEmailVerificationDisabled, authSecureCookiesDisabled, authSessionFreshageZero, authTrustedOriginsWildcard, browserAllowPrivateTargets, browserUserUrlWithoutAllowlist, circularFk, constraintValidator, containerInstanceKeyFromUserInput, containerOversizedInstance, containerPublicInternet, containerRuntimeEgressRelaxation, containerStartEnableInternetOverride, duplicateIndex, emptyIndex, externalSourceOnGlobal, externalSourceUnscoped, filterWithoutIndex, flagGatesSecurityWithUnsafeDefault, fromServerSchema, hardcodedSecret, hotShard, httpActionMissingAuthGuard, httpActionResponseHeaderInjection, hyperdriveOutsideAction, identityUndeclaredClaimTrusted, imagesUrlSourceFromUserInput, indexReferencesUnknownField, indexUtilization, insertManyUnsafeUserData, kvUnscopedUserKeyIdor, loadAnalyticsRuntimeMetrics, mailInboundDispatchWithoutVerify, mailRecipientFromRequestInput, maskUncoveredPiiColumn, maskWeakHashStrategyOnPii, maskedRelationLeakViaWith, mutatorFullRowReplace, nondeterministicQueryMutation, normalizeIdUsedAsAuthorization, outputProjectionMissingOnPublicRead, ownerFieldFromArgsNotAuth, paymentCreateWithoutAuthorize, paymentWebhookWideTolerance, plaintextSecretInWranglerVariables, policyReferencesUnknownTable, privilegedDispatchUnvalidatedPayload, privilegedFanoutFromPublicProcedure, publicArgumentUsesAny, publicMutationWithoutRatelimit, publicTableRlsOptoutConfusion, queueWithoutDlq, r2sqlOutsideAction, ratelimitDefaultMemoryStore, ratelimitKeySpoofableOrGlobal, ratelimitMiddlewareFailOpen, relationReferencesUnknownField, relationReferencesUnknownTable, rlsUncoveredTable, runAdvisor, shapeTargetsGlobalTable, shapeUnknownTable, softDeleteIncludeDeletedFromArgs, sqlInjectionRisk, storageGenerateUploadUrlNoContentTypePin, storageKeyFromUserArgs, storagePresignedUrlForPrivateContent, storageUploadWithoutContentTypeAllowlist, storageUploadWithoutMaxSize, tableWithoutInsert, unboundedStringArgument, unindexedForeignKey, unindexedRelationTarget, userCreatingMutationWithoutCaptcha, vectorsNamespaceFromUserInput, workflowDuplicateStepName, workflowUnknownTarget, workflowUnused };
package/dist/index.mjs CHANGED
@@ -53,6 +53,7 @@ import privilegedFanoutFromPublicProcedure from './packem_shared/privilegedFanou
53
53
  import publicArgumentUsesAny from './packem_shared/publicArgumentUsesAny-C71b2NCf.mjs';
54
54
  import publicMutationWithoutRatelimit from './packem_shared/publicMutationWithoutRatelimit-xBpJ6GWK.mjs';
55
55
  import publicTableRlsOptoutConfusion from './packem_shared/publicTableRlsOptoutConfusion-DJ5GFSRD.mjs';
56
+ import queueWithoutDlq from './packem_shared/queueWithoutDlq-CSkGNb_0.mjs';
56
57
  import r2sqlOutsideAction from './packem_shared/r2sqlOutsideAction-CtqxvMuV.mjs';
57
58
  import ratelimitDefaultMemoryStore from './packem_shared/ratelimitDefaultMemoryStore-BISChG5C.mjs';
58
59
  import ratelimitKeySpoofableOrGlobal from './packem_shared/ratelimitKeySpoofableOrGlobal-DqlHYQQ3.mjs';
@@ -97,6 +98,7 @@ const STATIC_LINTS = [
97
98
  duplicateIndex,
98
99
  tableWithoutInsert,
99
100
  workflowUnused,
101
+ queueWithoutDlq,
100
102
  filterWithoutIndex,
101
103
  shapeTargetsGlobalTable,
102
104
  mutatorFullRowReplace,
@@ -176,4 +178,4 @@ const runAdvisor = (context, options = {}) => {
176
178
  return findings;
177
179
  };
178
180
 
179
- export { ALL_LINTS, RUNTIME_LINTS, STATIC_LINTS, actionFetchSsrf, adminRouteWithoutGuard, aiRawRunEscapeHatch, aiToolSideEffectPromptInjection, aiUnboundedGenerationPublic, allowUnauthenticatedShardAccessEnabled, authApiCallWithoutHeaders, authCsrfCheckDisabled, authEmailVerificationDisabled, authSecureCookiesDisabled, authSessionFreshageZero, authTrustedOriginsWildcard, browserAllowPrivateTargets, browserUserUrlWithoutAllowlist, circularFk, constraintValidator, containerInstanceKeyFromUserInput, containerOversizedInstance, containerPublicInternet, containerRuntimeEgressRelaxation, containerStartEnableInternetOverride, duplicateIndex, emptyIndex, filterWithoutIndex, flagGatesSecurityWithUnsafeDefault, hardcodedSecret, hotShard, httpActionMissingAuthGuard, httpActionResponseHeaderInjection, hyperdriveOutsideAction, identityUndeclaredClaimTrusted, imagesUrlSourceFromUserInput, indexReferencesUnknownField, indexUtilization, insertManyUnsafeUserData, kvUnscopedUserKeyIdor, mailInboundDispatchWithoutVerify, mailRecipientFromRequestInput, maskUncoveredPiiColumn, maskWeakHashStrategyOnPii, maskedRelationLeakViaWith, mutatorFullRowReplace, nondeterministicQueryMutation, normalizeIdUsedAsAuthorization, outputProjectionMissingOnPublicRead, ownerFieldFromArgsNotAuth, paymentCreateWithoutAuthorize, paymentWebhookWideTolerance, plaintextSecretInWranglerVariables, policyReferencesUnknownTable, privilegedDispatchUnvalidatedPayload, privilegedFanoutFromPublicProcedure, publicArgumentUsesAny, publicMutationWithoutRatelimit, publicTableRlsOptoutConfusion, r2sqlOutsideAction, ratelimitDefaultMemoryStore, ratelimitKeySpoofableOrGlobal, ratelimitMiddlewareFailOpen, relationReferencesUnknownField, relationReferencesUnknownTable, rlsUncoveredTable, runAdvisor, shapeTargetsGlobalTable, shapeUnknownTable, softDeleteIncludeDeletedFromArgs, sqlInjectionRisk, storageGenerateUploadUrlNoContentTypePin, storageKeyFromUserArgs, storagePresignedUrlForPrivateContent, storageUploadWithoutContentTypeAllowlist, storageUploadWithoutMaxSize, tableWithoutInsert, unboundedStringArgument, unindexedForeignKey, unindexedRelationTarget, userCreatingMutationWithoutCaptcha, vectorsNamespaceFromUserInput, workflowDuplicateStepName, workflowUnknownTarget, workflowUnused };
181
+ export { ALL_LINTS, RUNTIME_LINTS, STATIC_LINTS, actionFetchSsrf, adminRouteWithoutGuard, aiRawRunEscapeHatch, aiToolSideEffectPromptInjection, aiUnboundedGenerationPublic, allowUnauthenticatedShardAccessEnabled, authApiCallWithoutHeaders, authCsrfCheckDisabled, authEmailVerificationDisabled, authSecureCookiesDisabled, authSessionFreshageZero, authTrustedOriginsWildcard, browserAllowPrivateTargets, browserUserUrlWithoutAllowlist, circularFk, constraintValidator, containerInstanceKeyFromUserInput, containerOversizedInstance, containerPublicInternet, containerRuntimeEgressRelaxation, containerStartEnableInternetOverride, duplicateIndex, emptyIndex, filterWithoutIndex, flagGatesSecurityWithUnsafeDefault, hardcodedSecret, hotShard, httpActionMissingAuthGuard, httpActionResponseHeaderInjection, hyperdriveOutsideAction, identityUndeclaredClaimTrusted, imagesUrlSourceFromUserInput, indexReferencesUnknownField, indexUtilization, insertManyUnsafeUserData, kvUnscopedUserKeyIdor, mailInboundDispatchWithoutVerify, mailRecipientFromRequestInput, maskUncoveredPiiColumn, maskWeakHashStrategyOnPii, maskedRelationLeakViaWith, mutatorFullRowReplace, nondeterministicQueryMutation, normalizeIdUsedAsAuthorization, outputProjectionMissingOnPublicRead, ownerFieldFromArgsNotAuth, paymentCreateWithoutAuthorize, paymentWebhookWideTolerance, plaintextSecretInWranglerVariables, policyReferencesUnknownTable, privilegedDispatchUnvalidatedPayload, privilegedFanoutFromPublicProcedure, publicArgumentUsesAny, publicMutationWithoutRatelimit, publicTableRlsOptoutConfusion, queueWithoutDlq, r2sqlOutsideAction, ratelimitDefaultMemoryStore, ratelimitKeySpoofableOrGlobal, ratelimitMiddlewareFailOpen, relationReferencesUnknownField, relationReferencesUnknownTable, rlsUncoveredTable, runAdvisor, shapeTargetsGlobalTable, shapeUnknownTable, softDeleteIncludeDeletedFromArgs, sqlInjectionRisk, storageGenerateUploadUrlNoContentTypePin, storageKeyFromUserArgs, storagePresignedUrlForPrivateContent, storageUploadWithoutContentTypeAllowlist, storageUploadWithoutMaxSize, tableWithoutInsert, unboundedStringArgument, unindexedForeignKey, unindexedRelationTarget, userCreatingMutationWithoutCaptcha, vectorsNamespaceFromUserInput, workflowDuplicateStepName, workflowUnknownTarget, workflowUnused };
@@ -0,0 +1,41 @@
1
+ import { e as emit } from './finding-Dm_zvzS1.mjs';
2
+
3
+ const queueWithoutDlq = {
4
+ categories: ["SCHEMA"],
5
+ description: "A queue consumer drops a message once it exhausts `maxRetries` (default 3) delivery attempts. Without a `deadLetterQueue`, that message is deleted permanently with no record — route exhausted messages to a DLQ so you can inspect, alert on, and replay them.",
6
+ facing: "INTERNAL",
7
+ level: "WARN",
8
+ name: "queue_without_dlq",
9
+ remediation: 'Add `deadLetterQueue: "<name>-dlq"` to the `defineQueue({...})` options and declare a consumer for that queue so exhausted messages are inspectable (an unconsumed DLQ still expires at the retention window). `vis generate lunora-queue` with the best-practice setup scaffolds both. If the queue is fire-and-forget and message loss is acceptable, this advisory can be ignored.',
10
+ run: (context) => {
11
+ if (context.queues === void 0) {
12
+ return [];
13
+ }
14
+ const dlqTargets = new Set(
15
+ context.queues.map((queue) => queue.tuning.deadLetterQueue).filter((name) => name !== void 0 && name !== "")
16
+ );
17
+ const findings = [];
18
+ for (const queue of context.queues) {
19
+ const dlq = queue.tuning.deadLetterQueue;
20
+ if (dlq !== void 0 && dlq !== "") {
21
+ continue;
22
+ }
23
+ if (dlqTargets.has(queue.name)) {
24
+ continue;
25
+ }
26
+ const maxRetries = typeof queue.tuning.maxRetries === "number" ? queue.tuning.maxRetries : 3;
27
+ findings.push(
28
+ emit(queueWithoutDlq, {
29
+ cacheKey: `queue_without_dlq:${queue.exportName}`,
30
+ detail: `Queue "${queue.exportName}" declares no \`deadLetterQueue\`, so a message that exhausts its retries (\`maxRetries\` = ${String(maxRetries)}, ~${String(maxRetries + 1)} delivery attempts) is dropped and permanently lost.`,
31
+ metadata: { maxRetries, mode: queue.mode, queue: queue.exportName }
32
+ })
33
+ );
34
+ }
35
+ return findings;
36
+ },
37
+ source: "static",
38
+ title: "Queue has no dead-letter queue"
39
+ };
40
+
41
+ export { queueWithoutDlq as default };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lunora/advisor",
3
- "version": "1.0.0-alpha.18",
3
+ "version": "1.0.0-alpha.19",
4
4
  "description": "Schema & query lints (splinter-style advisors) for Lunora, feeding the Studio Advisors view",
5
5
  "keywords": [
6
6
  "advisor",