@murphai/murph 1.3.0 → 1.3.1
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 +3077 -0
- package/config.schema.json +650 -30
- package/dist/cli-entry.js +1 -1
- package/dist/cli-entry.js.map +1 -1
- package/dist/commands/automation.d.ts +143 -104
- package/dist/commands/automation.d.ts.map +1 -1
- package/dist/commands/automation.js +71 -13
- package/dist/commands/automation.js.map +1 -1
- package/dist/commands/batch.d.ts +3 -0
- package/dist/commands/batch.d.ts.map +1 -1
- package/dist/commands/batch.js +18 -45
- package/dist/commands/batch.js.map +1 -1
- package/dist/commands/clinical-imports.d.ts +103 -103
- package/dist/commands/command-factory-primitives.d.ts +1 -1
- package/dist/commands/command-factory-primitives.d.ts.map +1 -1
- package/dist/commands/command-factory-primitives.js +1 -1
- package/dist/commands/command-factory-primitives.js.map +1 -1
- package/dist/commands/commons.d.ts +59 -0
- package/dist/commands/commons.d.ts.map +1 -1
- package/dist/commands/commons.js +81 -1
- package/dist/commands/commons.js.map +1 -1
- package/dist/commands/document.d.ts.map +1 -1
- package/dist/commands/document.js +31 -1
- package/dist/commands/document.js.map +1 -1
- package/dist/commands/encounter.d.ts +128 -128
- package/dist/commands/event.d.ts.map +1 -1
- package/dist/commands/event.js +7 -1
- package/dist/commands/event.js.map +1 -1
- package/dist/commands/experiment-progress-card-image.d.ts.map +1 -1
- package/dist/commands/experiment-progress-card-image.js +13 -4
- package/dist/commands/experiment-progress-card-image.js.map +1 -1
- package/dist/commands/experiment.d.ts.map +1 -1
- package/dist/commands/experiment.js +6 -0
- package/dist/commands/experiment.js.map +1 -1
- package/dist/commands/export-intake-read-helpers.d.ts.map +1 -1
- package/dist/commands/export-intake-read-helpers.js +7 -3
- package/dist/commands/export-intake-read-helpers.js.map +1 -1
- package/dist/commands/food.d.ts.map +1 -1
- package/dist/commands/food.js +12 -4
- package/dist/commands/food.js.map +1 -1
- package/dist/commands/meal.d.ts.map +1 -1
- package/dist/commands/meal.js +54 -3
- package/dist/commands/meal.js.map +1 -1
- package/dist/commands/measurement.d.ts +1 -0
- package/dist/commands/measurement.d.ts.map +1 -1
- package/dist/commands/measurement.js +48 -2
- package/dist/commands/measurement.js.map +1 -1
- package/dist/commands/medication.d.ts +6 -6
- package/dist/commands/model.js +7 -11
- package/dist/commands/model.js.map +1 -1
- package/dist/commands/occurred-at-option.d.ts.map +1 -1
- package/dist/commands/occurred-at-option.js +7 -41
- package/dist/commands/occurred-at-option.js.map +1 -1
- package/dist/commands/payload-schema-command.d.ts +2 -2
- package/dist/commands/payload-schema-command.d.ts.map +1 -1
- package/dist/commands/payload-schema-command.js +1 -1
- package/dist/commands/payload-schema-command.js.map +1 -1
- package/dist/commands/research.d.ts.map +1 -1
- package/dist/commands/research.js +26 -28
- package/dist/commands/research.js.map +1 -1
- package/dist/commands/route.d.ts.map +1 -1
- package/dist/commands/route.js +45 -1
- package/dist/commands/route.js.map +1 -1
- package/dist/commands/scheduled-log.d.ts +130 -124
- package/dist/commands/scheduled-log.d.ts.map +1 -1
- package/dist/commands/wearables.d.ts +1109 -20
- package/dist/commands/wearables.d.ts.map +1 -1
- package/dist/commands/wearables.js +102 -2
- package/dist/commands/wearables.js.map +1 -1
- package/dist/commands/workout-live.d.ts +3 -0
- package/dist/commands/workout-live.d.ts.map +1 -0
- package/dist/commands/workout-live.js +291 -0
- package/dist/commands/workout-live.js.map +1 -0
- package/dist/commands/workout.d.ts.map +1 -1
- package/dist/commands/workout.js +35 -11
- package/dist/commands/workout.js.map +1 -1
- package/dist/food-labels.d.ts +549 -277
- package/dist/food-labels.d.ts.map +1 -1
- package/dist/food-labels.js +19 -3
- package/dist/food-labels.js.map +1 -1
- package/dist/foreground-terminal-logging.js +0 -2
- package/dist/foreground-terminal-logging.js.map +1 -1
- package/dist/hosted-data-api-labels.d.ts +1683 -871
- package/dist/hosted-data-api-labels.d.ts.map +1 -1
- package/dist/hosted-data-api-labels.js +63 -1
- package/dist/hosted-data-api-labels.js.map +1 -1
- package/dist/incur.generated.d.ts +148 -2
- package/dist/incur.generated.d.ts.map +1 -1
- package/dist/mapbox-address.d.ts +41 -0
- package/dist/mapbox-address.d.ts.map +1 -0
- package/dist/mapbox-address.js +470 -0
- package/dist/mapbox-address.js.map +1 -0
- package/dist/mapbox-route-contracts.d.ts +60 -60
- package/dist/mapbox-route-contracts.d.ts.map +1 -1
- package/dist/mapbox-route-contracts.js +1 -1
- package/dist/mapbox-route-contracts.js.map +1 -1
- package/dist/mapbox-route-directions.js +1 -1
- package/dist/mapbox-route-directions.js.map +1 -1
- package/dist/research-scout-client.d.ts +3 -2
- package/dist/research-scout-client.d.ts.map +1 -1
- package/dist/research-scout-client.js +166 -37
- package/dist/research-scout-client.js.map +1 -1
- package/dist/research-scout.d.ts +1 -1
- package/dist/research-scout.d.ts.map +1 -1
- package/dist/research-scout.js +1 -1
- package/dist/research-scout.js.map +1 -1
- package/dist/supplement-labels.d.ts +545 -275
- package/dist/supplement-labels.d.ts.map +1 -1
- package/dist/supplement-labels.js +0 -1
- package/dist/supplement-labels.js.map +1 -1
- package/dist/vault-cli-command-manifest.d.ts +1878 -404
- package/dist/vault-cli-command-manifest.d.ts.map +1 -1
- package/dist/vault-cli-command-manifest.js +35 -10
- package/dist/vault-cli-command-manifest.js.map +1 -1
- package/dist/vault-cli-skill-hash.generated.d.ts +1 -1
- package/dist/vault-cli-skill-hash.generated.js +1 -1
- package/dist/vault-cli-vault-context.js +0 -1
- package/dist/vault-cli-vault-context.js.map +1 -1
- package/node_modules/@murphai/assistant-cli/dist/assistant/service.d.ts +9 -0
- package/node_modules/@murphai/assistant-cli/dist/assistant/service.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-cli/dist/assistant/ui/chat-controller-models.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-cli/dist/assistant/ui/chat-controller-models.js +0 -1
- package/node_modules/@murphai/assistant-cli/dist/assistant/ui/chat-controller-models.js.map +1 -1
- package/node_modules/@murphai/assistant-cli/dist/assistant/ui/ink.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-cli/dist/assistant/ui/ink.js +4 -6
- package/node_modules/@murphai/assistant-cli/dist/assistant/ui/ink.js.map +1 -1
- package/node_modules/@murphai/assistant-cli/dist/assistant-daemon-client.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-cli/dist/assistant-daemon-client.js +19 -9
- package/node_modules/@murphai/assistant-cli/dist/assistant-daemon-client.js.map +1 -1
- package/node_modules/@murphai/assistant-cli/dist/commands/assistant.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-cli/dist/commands/assistant.js +20 -56
- package/node_modules/@murphai/assistant-cli/dist/commands/assistant.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/README.md +69 -13
- package/node_modules/@murphai/assistant-engine/dist/assistant/active-turn-input-controller.d.ts +6 -3
- package/node_modules/@murphai/assistant-engine/dist/assistant/active-turn-input-controller.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/active-turn-input-controller.js +52 -19
- package/node_modules/@murphai/assistant-engine/dist/assistant/active-turn-input-controller.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/active-turn-input-journal.d.ts +75 -70
- package/node_modules/@murphai/assistant-engine/dist/assistant/active-turn-input-journal.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/active-turn-input-journal.js +42 -17
- package/node_modules/@murphai/assistant-engine/dist/assistant/active-turn-input-journal.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/ask-continuation.d.ts +3 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/ask-continuation.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/ask-continuation.js +27 -7
- package/node_modules/@murphai/assistant-engine/dist/assistant/ask-continuation.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/attachment-evidence-model.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/attachment-evidence-model.js +4 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/attachment-evidence-model.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/automation/cross-session-route-state.d.ts +77 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/automation/cross-session-route-state.d.ts.map +1 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/automation/cross-session-route-state.js +777 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/automation/cross-session-route-state.js.map +1 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/automation/grouping.d.ts +1 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/automation/grouping.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/automation/grouping.js +36 -4
- package/node_modules/@murphai/assistant-engine/dist/assistant/automation/grouping.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/automation/input-summary.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/automation/input-summary.js +3 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/automation/input-summary.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/automation/operation-scope.d.ts +3 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/automation/operation-scope.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/automation/prompt-builder.d.ts +10 -2
- package/node_modules/@murphai/assistant-engine/dist/assistant/automation/prompt-builder.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/automation/prompt-builder.js +33 -13
- package/node_modules/@murphai/assistant-engine/dist/assistant/automation/prompt-builder.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/automation/reply.d.ts +12 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/automation/reply.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/automation/reply.js +803 -171
- package/node_modules/@murphai/assistant-engine/dist/assistant/automation/reply.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/automation/run-loop.d.ts +2 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/automation/run-loop.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/automation/run-loop.js +42 -17
- package/node_modules/@murphai/assistant-engine/dist/assistant/automation/run-loop.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/automation/scanner.d.ts +2 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/automation/scanner.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/automation/scanner.js +59 -30
- package/node_modules/@murphai/assistant-engine/dist/assistant/automation/scanner.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/automation/shared.d.ts +2 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/automation/shared.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/automation/shared.js +3 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/automation/shared.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/automation/target-override.d.ts +10 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/automation/target-override.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/automation/target-override.js +62 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/automation/target-override.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/automation.d.ts +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/automation.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/automation.js +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/automation.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/channel-adapters.d.ts +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/channel-adapters.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/channel-adapters.js +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/channel-adapters.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/channels/descriptors.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/channels/descriptors.js +107 -44
- package/node_modules/@murphai/assistant-engine/dist/assistant/channels/descriptors.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/channels/helpers.d.ts +3 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/channels/helpers.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/channels/helpers.js +34 -3
- package/node_modules/@murphai/assistant-engine/dist/assistant/channels/helpers.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/channels/runtime.d.ts +22 -14
- package/node_modules/@murphai/assistant-engine/dist/assistant/channels/runtime.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/channels/runtime.js +352 -78
- package/node_modules/@murphai/assistant-engine/dist/assistant/channels/runtime.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/channels/types.d.ts +43 -8
- package/node_modules/@murphai/assistant-engine/dist/assistant/channels/types.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/channels/types.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/cli-surface-bootstrap.d.ts +1 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/cli-surface-bootstrap.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/cli-surface-bootstrap.js +6 -5
- package/node_modules/@murphai/assistant-engine/dist/assistant/cli-surface-bootstrap.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/cli-surface-contract.generated.json +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/codex-base-instructions.d.ts +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/codex-base-instructions.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/codex-base-instructions.js +14 -7
- package/node_modules/@murphai/assistant-engine/dist/assistant/codex-base-instructions.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/codex-runtime.d.ts +17 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/codex-runtime.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/codex-runtime.js +25 -19
- package/node_modules/@murphai/assistant-engine/dist/assistant/codex-runtime.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/codex-thread-route.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/codex-thread-route.js +9 -9
- package/node_modules/@murphai/assistant-engine/dist/assistant/codex-thread-route.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/codex-turn/planning.d.ts +3 -7
- package/node_modules/@murphai/assistant-engine/dist/assistant/codex-turn/planning.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/codex-turn/planning.js +172 -48
- package/node_modules/@murphai/assistant-engine/dist/assistant/codex-turn/planning.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/codex-turn-runner.d.ts +5 -3
- package/node_modules/@murphai/assistant-engine/dist/assistant/codex-turn-runner.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/codex-turn-runner.js +124 -25
- package/node_modules/@murphai/assistant-engine/dist/assistant/codex-turn-runner.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/content-types.d.ts +2 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/content-types.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/context-snapshot.d.ts +4 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/context-snapshot.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/context-snapshot.js +75 -19
- package/node_modules/@murphai/assistant-engine/dist/assistant/context-snapshot.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/conversation-persistence.d.ts +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/conversation-persistence.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/conversation-persistence.js +0 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/conversation-persistence.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/conversation-ref.d.ts +1 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/conversation-ref.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/conversation-ref.js +2 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/conversation-ref.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/cron/authoring.d.ts +5 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/cron/authoring.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/cron/authoring.js +178 -31
- package/node_modules/@murphai/assistant-engine/dist/assistant/cron/authoring.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/cron/canonical-jobs.d.ts +32 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/cron/canonical-jobs.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/cron/canonical-jobs.js +147 -31
- package/node_modules/@murphai/assistant-engine/dist/assistant/cron/canonical-jobs.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/cron/delivery-reconciliation.d.ts +8 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/cron/delivery-reconciliation.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/cron/delivery-reconciliation.js +73 -15
- package/node_modules/@murphai/assistant-engine/dist/assistant/cron/delivery-reconciliation.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/cron/execution.d.ts +3 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/cron/execution.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/cron/execution.js +420 -112
- package/node_modules/@murphai/assistant-engine/dist/assistant/cron/execution.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/cron/mutations.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/cron/mutations.js +2 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/cron/mutations.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/cron/output-history.d.ts +11 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/cron/output-history.d.ts.map +1 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/cron/output-history.js +153 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/cron/output-history.js.map +1 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/cron/runtime-state.d.ts +47 -47
- package/node_modules/@murphai/assistant-engine/dist/assistant/cron/runtime-state.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/cron/runtime-state.js +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/cron/runtime-state.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/cron/schedule.d.ts +8 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/cron/schedule.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/cron/schedule.js +16 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/cron/schedule.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/cron/store.d.ts +49 -39
- package/node_modules/@murphai/assistant-engine/dist/assistant/cron/store.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/cron/store.js +19 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/cron/store.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/cron/targets.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/cron/targets.js +1 -3
- package/node_modules/@murphai/assistant-engine/dist/assistant/cron/targets.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/cron/timing-verification.d.ts +2 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/cron/timing-verification.d.ts.map +1 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/cron/timing-verification.js +2 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/cron/timing-verification.js.map +1 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/cron.d.ts +9 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/cron.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/cron.js +31 -2
- package/node_modules/@murphai/assistant-engine/dist/assistant/cron.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/delivery-service.d.ts +3 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/delivery-service.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/delivery-service.js +32 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/delivery-service.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/device-activity-cron-tags.d.ts +2 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/device-activity-cron-tags.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/device-activity-cron-tags.js +8 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/device-activity-cron-tags.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/execution-context.d.ts +91 -13
- package/node_modules/@murphai/assistant-engine/dist/assistant/execution-context.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/execution-context.js +48 -11
- package/node_modules/@murphai/assistant-engine/dist/assistant/execution-context.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/execution-plan.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/execution-plan.js +2 -8
- package/node_modules/@murphai/assistant-engine/dist/assistant/execution-plan.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/experiment-support-automations.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/experiment-support-automations.js +8 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/experiment-support-automations.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/group-challenge-response-card-schema.d.ts +115 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/group-challenge-response-card-schema.d.ts.map +1 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/group-challenge-response-card-schema.js +162 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/group-challenge-response-card-schema.js.map +1 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/group-challenge-response-card.d.ts +3 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/group-challenge-response-card.d.ts.map +1 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/group-challenge-response-card.js +118 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/group-challenge-response-card.js.map +1 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/group-challenge-scorecard-schema.d.ts +83 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/group-challenge-scorecard-schema.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/group-challenge-scorecard-schema.js +27 -22
- package/node_modules/@murphai/assistant-engine/dist/assistant/group-challenge-scorecard-schema.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/group-challenge-scorecard.js +8 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/group-challenge-scorecard.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/group-email-outbox.d.ts +20 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/group-email-outbox.d.ts.map +1 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/{newsletter-outbox.js → group-email-outbox.js} +65 -36
- package/node_modules/@murphai/assistant-engine/dist/assistant/group-email-outbox.js.map +1 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/group-newsletter-automation.d.ts +2 -48
- package/node_modules/@murphai/assistant-engine/dist/assistant/group-newsletter-automation.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/group-newsletter-automation.js +14 -98
- package/node_modules/@murphai/assistant-engine/dist/assistant/group-newsletter-automation.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/group-room-model.d.ts +22 -3
- package/node_modules/@murphai/assistant-engine/dist/assistant/group-room-model.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/group-room-model.js +87 -28
- package/node_modules/@murphai/assistant-engine/dist/assistant/group-room-model.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/group-shared-freshness.d.ts +2 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/group-shared-freshness.d.ts.map +1 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/group-shared-freshness.js +5 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/group-shared-freshness.js.map +1 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/group-shared-read-limits.d.ts +3 -2
- package/node_modules/@murphai/assistant-engine/dist/assistant/group-shared-read-limits.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/group-shared-read-limits.js +21 -2
- package/node_modules/@murphai/assistant-engine/dist/assistant/group-shared-read-limits.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/hosted-image-completion.d.ts +31 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/hosted-image-completion.d.ts.map +1 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/hosted-image-completion.js +164 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/hosted-image-completion.js.map +1 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/hosted-tool-context.d.ts +77 -24
- package/node_modules/@murphai/assistant-engine/dist/assistant/hosted-tool-context.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/hosted-tool-context.js +184 -63
- package/node_modules/@murphai/assistant-engine/dist/assistant/hosted-tool-context.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/input-source.d.ts +1 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/input-source.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/input-source.js +2 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/input-source.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/input-store.d.ts +273 -269
- package/node_modules/@murphai/assistant-engine/dist/assistant/input-store.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/input-store.js +6 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/input-store.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/linq-delivery-posture.d.ts +3 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/linq-delivery-posture.d.ts.map +1 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/linq-delivery-posture.js +20 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/linq-delivery-posture.js.map +1 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/local-service.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/local-service.js +217 -84
- package/node_modules/@murphai/assistant-engine/dist/assistant/local-service.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/maintenance-evidence.d.ts +3 -3
- package/node_modules/@murphai/assistant-engine/dist/assistant/maintenance-evidence.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/maintenance-evidence.js +245 -6
- package/node_modules/@murphai/assistant-engine/dist/assistant/maintenance-evidence.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/managed-automations.d.ts +22 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/managed-automations.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/managed-automations.js +289 -34
- package/node_modules/@murphai/assistant-engine/dist/assistant/managed-automations.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/message-target-selection.d.ts +13 -22
- package/node_modules/@murphai/assistant-engine/dist/assistant/message-target-selection.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/message-target-selection.js +8 -3
- package/node_modules/@murphai/assistant-engine/dist/assistant/message-target-selection.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/model-behavior.d.ts +3 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/model-behavior.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/model-behavior.js +40 -7
- package/node_modules/@murphai/assistant-engine/dist/assistant/model-behavior.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/notification-turn.d.ts +16 -14
- package/node_modules/@murphai/assistant-engine/dist/assistant/notification-turn.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/notification-turn.js +205 -56
- package/node_modules/@murphai/assistant-engine/dist/assistant/notification-turn.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/onboarding-first-personal-read-automation.d.ts +14 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/onboarding-first-personal-read-automation.d.ts.map +1 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/onboarding-first-personal-read-automation.js +94 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/onboarding-first-personal-read-automation.js.map +1 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/onboarding-followup-automation.d.ts +22 -3
- package/node_modules/@murphai/assistant-engine/dist/assistant/onboarding-followup-automation.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/onboarding-followup-automation.js +81 -7
- package/node_modules/@murphai/assistant-engine/dist/assistant/onboarding-followup-automation.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/onboarding-goal-checkin-automation.d.ts +1 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/onboarding-goal-checkin-automation.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/onboarding-goal-checkin-automation.js +184 -83
- package/node_modules/@murphai/assistant-engine/dist/assistant/onboarding-goal-checkin-automation.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/onboarding-state.js +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/onboarding-state.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/outbox/automation-authority.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/outbox/automation-authority.js +24 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/outbox/automation-authority.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/outbox/dispatch-state.d.ts +15 -3
- package/node_modules/@murphai/assistant-engine/dist/assistant/outbox/dispatch-state.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/outbox/dispatch-state.js +314 -53
- package/node_modules/@murphai/assistant-engine/dist/assistant/outbox/dispatch-state.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/outbox/intents.d.ts +2 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/outbox/intents.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/outbox/intents.js +1 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/outbox/intents.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/outbox/receipt-repair.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/outbox/receipt-repair.js +5 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/outbox/receipt-repair.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/outbox/retry-policy.d.ts +4 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/outbox/retry-policy.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/outbox/retry-policy.js +33 -8
- package/node_modules/@murphai/assistant-engine/dist/assistant/outbox/retry-policy.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/outbox/store.d.ts +37 -3
- package/node_modules/@murphai/assistant-engine/dist/assistant/outbox/store.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/outbox/store.js +1031 -41
- package/node_modules/@murphai/assistant-engine/dist/assistant/outbox/store.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/outbox/summary.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/outbox/summary.js +7 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/outbox/summary.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/outbox.d.ts +61 -8
- package/node_modules/@murphai/assistant-engine/dist/assistant/outbox.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/outbox.js +561 -67
- package/node_modules/@murphai/assistant-engine/dist/assistant/outbox.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/private-completion-continuity.d.ts +23 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/private-completion-continuity.d.ts.map +1 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/private-completion-continuity.js +293 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/private-completion-continuity.js.map +1 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/prompt-time.d.ts +12 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/prompt-time.d.ts.map +1 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/prompt-time.js +38 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/prompt-time.js.map +1 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/provider-catalog.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/provider-catalog.js +2 -2
- package/node_modules/@murphai/assistant-engine/dist/assistant/provider-catalog.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/provider-start-critical-path.d.ts +48 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/provider-start-critical-path.d.ts.map +1 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/provider-start-critical-path.js +101 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/provider-start-critical-path.js.map +1 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/providers/codex-cli.d.ts +6 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/providers/codex-cli.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/providers/codex-cli.js +62 -96
- package/node_modules/@murphai/assistant-engine/dist/assistant/providers/codex-cli.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/providers/helpers.d.ts +5 -2
- package/node_modules/@murphai/assistant-engine/dist/assistant/providers/helpers.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/providers/helpers.js +412 -568
- package/node_modules/@murphai/assistant-engine/dist/assistant/providers/helpers.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/providers/types.d.ts +23 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/providers/types.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/providers/types.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/redaction.d.ts +2 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/redaction.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/redaction.js +6 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/redaction.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/reminder-availability-maintenance.d.ts +17 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/reminder-availability-maintenance.d.ts.map +1 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/reminder-availability-maintenance.js +287 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/reminder-availability-maintenance.js.map +1 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/response-media.d.ts +33 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/response-media.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/response-media.js +173 -3
- package/node_modules/@murphai/assistant-engine/dist/assistant/response-media.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/runtime-residue.d.ts +6 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/runtime-residue.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/runtime-residue.js +61 -29
- package/node_modules/@murphai/assistant-engine/dist/assistant/runtime-residue.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/service-contracts.d.ts +17 -3
- package/node_modules/@murphai/assistant-engine/dist/assistant/service-contracts.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/service-turn-routes.d.ts +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/service-turn-routes.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/service-turn-routes.js +18 -8
- package/node_modules/@murphai/assistant-engine/dist/assistant/service-turn-routes.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/service-usage.d.ts +1 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/service-usage.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/service-usage.js +23 -4
- package/node_modules/@murphai/assistant-engine/dist/assistant/service-usage.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/service.d.ts +12 -2
- package/node_modules/@murphai/assistant-engine/dist/assistant/service.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/service.js +5 -3
- package/node_modules/@murphai/assistant-engine/dist/assistant/service.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/session-resolution.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/session-resolution.js +71 -16
- package/node_modules/@murphai/assistant-engine/dist/assistant/session-resolution.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/shared.d.ts +1 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/shared.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/shared.js +1 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/shared.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/state-secrets.d.ts +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/state-secrets.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/state-secrets.js +0 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/state-secrets.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/store/persistence.d.ts +11 -3
- package/node_modules/@murphai/assistant-engine/dist/assistant/store/persistence.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/store/persistence.js +410 -139
- package/node_modules/@murphai/assistant-engine/dist/assistant/store/persistence.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/store/types.d.ts +2 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/store/types.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/store.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/store.js +48 -13
- package/node_modules/@murphai/assistant-engine/dist/assistant/store.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/system-prompt.d.ts +4 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/system-prompt.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/system-prompt.js +274 -128
- package/node_modules/@murphai/assistant-engine/dist/assistant/system-prompt.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/tool-validation-digest.d.ts +9 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/tool-validation-digest.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/tool-validation-digest.js +133 -7
- package/node_modules/@murphai/assistant-engine/dist/assistant/tool-validation-digest.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/tool-validation-feedback.d.ts +11 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/tool-validation-feedback.d.ts.map +1 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/tool-validation-feedback.js +59 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/tool-validation-feedback.js.map +1 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/turn-finalizer.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/turn-finalizer.js +109 -16
- package/node_modules/@murphai/assistant-engine/dist/assistant/turn-finalizer.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/turn-input.d.ts +2 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/turn-input.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/turn-input.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/turn-progress.d.ts +9 -2
- package/node_modules/@murphai/assistant-engine/dist/assistant/turn-progress.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/turn-progress.js +49 -6
- package/node_modules/@murphai/assistant-engine/dist/assistant/turn-progress.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/turns.d.ts +1 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/turns.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/turns.js +62 -22
- package/node_modules/@murphai/assistant-engine/dist/assistant/turns.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/vault-file-send.d.ts +7 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/vault-file-send.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/vault-file-send.js +47 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/vault-file-send.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant-ask.d.ts +4 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant-ask.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant-ask.js +49 -23
- package/node_modules/@murphai/assistant-engine/dist/assistant-ask.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant-channel-adapters.d.ts +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant-channel-adapters.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant-channel-adapters.js +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant-channel-adapters.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant-channel-runtime.d.ts +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant-channel-runtime.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant-channel-runtime.js +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant-channel-runtime.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant-cli-access.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant-cli-access.js +12 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant-cli-access.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/action-diagnostics.d.ts +8 -4
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/action-diagnostics.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/action-diagnostics.js +136 -19
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/action-diagnostics.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/action-outcome.d.ts +5 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/action-outcome.d.ts.map +1 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/action-outcome.js +36 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/action-outcome.js.map +1 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/app-server-protocol.d.ts +59 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/app-server-protocol.d.ts.map +1 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/app-server-protocol.js +181 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/app-server-protocol.js.map +1 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/app-server-requests.d.ts +5 -3
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/app-server-requests.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/app-server-requests.js +19 -5
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/app-server-requests.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/app-server-rpc.d.ts +2 -3
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/app-server-rpc.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/app-server-rpc.js +7 -14
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/app-server-rpc.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/ask-grok-tool.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/ask-grok-tool.js +77 -11
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/ask-grok-tool.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/command-family.d.ts +17 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/command-family.d.ts.map +1 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/command-family.js +200 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/command-family.js.map +1 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/dynamic-tool-catalog.d.ts +3387 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/dynamic-tool-catalog.d.ts.map +1 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/dynamic-tool-catalog.js +1379 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/dynamic-tool-catalog.js.map +1 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/dynamic-tools/ask-grok.d.ts +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/dynamic-tools/ask-grok.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/dynamic-tools/ask-grok.js +2 -2
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/dynamic-tools/ask-grok.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/dynamic-tools/assistant-style.d.ts +15 -32
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/dynamic-tools/assistant-style.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/dynamic-tools/assistant-style.js +11 -7
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/dynamic-tools/assistant-style.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/dynamic-tools/automation.d.ts +26 -150
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/dynamic-tools/automation.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/dynamic-tools/automation.js +537 -103
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/dynamic-tools/automation.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/dynamic-tools/clinical-records.js +4 -4
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/dynamic-tools/clinical-records.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/dynamic-tools/connected-apps.d.ts +10 -54
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/dynamic-tools/connected-apps.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/dynamic-tools/connected-apps.js +134 -109
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/dynamic-tools/connected-apps.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/dynamic-tools/device.d.ts +2 -12
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/dynamic-tools/device.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/dynamic-tools/device.js +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/dynamic-tools/device.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/dynamic-tools/dynamic-tool-wrapper.d.ts +2 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/dynamic-tools/dynamic-tool-wrapper.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/dynamic-tools/dynamic-tool-wrapper.js +2 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/dynamic-tools/dynamic-tool-wrapper.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/dynamic-tools/generate-song.d.ts +9 -2
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/dynamic-tools/generate-song.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/dynamic-tools/generate-song.js +31 -3
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/dynamic-tools/generate-song.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/dynamic-tools/generate-voice-memo.d.ts +7 -6
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/dynamic-tools/generate-voice-memo.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/dynamic-tools/generate-voice-memo.js +12 -8
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/dynamic-tools/generate-voice-memo.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/dynamic-tools/group-room-model.d.ts +10 -19
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/dynamic-tools/group-room-model.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/dynamic-tools/group-room-model.js +19 -7
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/dynamic-tools/group-room-model.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/dynamic-tools/labs.d.ts +2 -16
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/dynamic-tools/labs.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/dynamic-tools/labs.js +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/dynamic-tools/labs.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/dynamic-tools/pending-vault-files.d.ts +65 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/dynamic-tools/pending-vault-files.d.ts.map +1 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/dynamic-tools/pending-vault-files.js +214 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/dynamic-tools/pending-vault-files.js.map +1 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/dynamic-tools/phone-calls.d.ts +24 -16
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/dynamic-tools/phone-calls.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/dynamic-tools/phone-calls.js +78 -7
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/dynamic-tools/phone-calls.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/dynamic-tools/physical-notes.d.ts +91 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/dynamic-tools/physical-notes.d.ts.map +1 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/dynamic-tools/physical-notes.js +199 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/dynamic-tools/physical-notes.js.map +1 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/dynamic-tools.d.ts +108 -2427
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/dynamic-tools.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/dynamic-tools.js +2248 -1509
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/dynamic-tools.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/failures.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/failures.js +39 -95
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/failures.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/generate-image-tool.d.ts +5 -2
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/generate-image-tool.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/generate-image-tool.js +88 -101
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/generate-image-tool.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/generate-voice-memo-tool.d.ts +58 -13
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/generate-voice-memo-tool.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/generate-voice-memo-tool.js +85 -122
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/generate-voice-memo-tool.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/image-reference-resolver.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/image-reference-resolver.js +5 -3
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/image-reference-resolver.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/images.d.ts +15 -2
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/images.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/images.js +99 -8
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/images.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/managed-voice-memo-runtime.d.ts +17 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/managed-voice-memo-runtime.d.ts.map +1 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/managed-voice-memo-runtime.js +12 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/managed-voice-memo-runtime.js.map +1 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/openai-image-generation.d.ts +7 -11
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/openai-image-generation.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/openai-image-generation.js +237 -52
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/openai-image-generation.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/response-card-validation-feedback.d.ts +3 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/response-card-validation-feedback.d.ts.map +1 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/response-card-validation-feedback.js +7 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex/response-card-validation-feedback.js.map +1 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex-events.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex-events.js +189 -486
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex-events.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex.d.ts +34 -6
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex.js +1014 -247
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant-runtime-residue.d.ts +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant-runtime-residue.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant-runtime-residue.js +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant-runtime-residue.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant-runtime.d.ts +2 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant-runtime.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant-runtime.js +1 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant-runtime.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant-skill-assets.d.ts +23 -23
- package/node_modules/@murphai/assistant-engine/dist/assistant-skill-assets.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant-skill-assets.js +26 -26
- package/node_modules/@murphai/assistant-engine/dist/assistant-skill-assets.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/attachment-prompt-contracts.d.ts +27 -27
- package/node_modules/@murphai/assistant-engine/dist/attachment-prompt-contracts.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/attachment-prompt-contracts.js +1 -1
- package/node_modules/@murphai/assistant-engine/dist/attachment-prompt-contracts.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/index.d.ts +8 -3
- package/node_modules/@murphai/assistant-engine/dist/index.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/index.js +6 -1
- package/node_modules/@murphai/assistant-engine/dist/index.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/knowledge/documents.d.ts +1 -1
- package/node_modules/@murphai/assistant-engine/dist/knowledge/documents.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/knowledge/documents.js +5 -1
- package/node_modules/@murphai/assistant-engine/dist/knowledge/documents.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/knowledge/service.d.ts +1 -0
- package/node_modules/@murphai/assistant-engine/dist/knowledge/service.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/knowledge/service.js +16 -2
- package/node_modules/@murphai/assistant-engine/dist/knowledge/service.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/outbound-channel.d.ts +5 -2
- package/node_modules/@murphai/assistant-engine/dist/outbound-channel.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/outbound-channel.js +4 -2
- package/node_modules/@murphai/assistant-engine/dist/outbound-channel.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/skills/README.md +29 -0
- package/node_modules/@murphai/assistant-engine/skills/appointment-scheduling/SKILL.md +23 -0
- package/node_modules/@murphai/assistant-engine/skills/automatic-meal-capture/SKILL.md +130 -5
- package/node_modules/@murphai/assistant-engine/skills/behavior-followthrough/SKILL.md +157 -116
- package/node_modules/@murphai/assistant-engine/skills/body-composition/SKILL.md +137 -27
- package/node_modules/@murphai/assistant-engine/skills/body-composition/references/evidence.md +150 -0
- package/node_modules/@murphai/assistant-engine/skills/body-composition/references/fat-loss.md +132 -0
- package/node_modules/@murphai/assistant-engine/skills/body-composition/references/muscle-gain.md +135 -0
- package/node_modules/@murphai/assistant-engine/skills/body-composition/references/safety.md +171 -0
- package/node_modules/@murphai/assistant-engine/skills/body-composition/references/tracking-and-adjustment.md +193 -0
- package/node_modules/@murphai/assistant-engine/skills/cardiometabolic-health/SKILL.md +10 -1
- package/node_modules/@murphai/assistant-engine/skills/computer-use/SKILL.md +0 -4
- package/node_modules/@murphai/assistant-engine/skills/connected-apps/SKILL.md +86 -12
- package/node_modules/@murphai/assistant-engine/skills/connected-apps/references/provider-data-exports.md +209 -0
- package/node_modules/@murphai/assistant-engine/skills/daily-activity/SKILL.md +16 -0
- package/node_modules/@murphai/assistant-engine/skills/experiment-onboarding/SKILL.md +22 -9
- package/node_modules/@murphai/assistant-engine/skills/food-journal/SKILL.md +140 -15
- package/node_modules/@murphai/assistant-engine/skills/group-challenge/SKILL.md +17 -737
- package/node_modules/@murphai/assistant-engine/skills/group-challenge-scorecards/SKILL.md +17 -328
- package/node_modules/@murphai/assistant-engine/skills/group-chat/SKILL.md +18 -912
- package/node_modules/@murphai/assistant-engine/skills/group-newsletter/SKILL.md +16 -237
- package/node_modules/@murphai/assistant-engine/skills/groupchat-comedy/SKILL.md +19 -351
- package/node_modules/@murphai/assistant-engine/skills/hosted-low-usage/SKILL.md +309 -117
- package/node_modules/@murphai/assistant-engine/skills/micronutrients-supplements/SKILL.md +30 -8
- package/node_modules/@murphai/assistant-engine/skills/mobility-posture/SKILL.md +1 -1
- package/node_modules/@murphai/assistant-engine/skills/murph-family/SKILL.md +91 -26
- package/node_modules/@murphai/assistant-engine/skills/murph-onboarding/SKILL.md +75 -751
- package/node_modules/@murphai/assistant-engine/skills/murph-onboarding/references/aspiration-foundation-delegation.md +443 -0
- package/node_modules/@murphai/assistant-engine/skills/murph-onboarding/references/persistence-recovery-follow-up.md +155 -0
- package/node_modules/@murphai/assistant-engine/skills/murph-onboarding/references/return-launch-completion.md +246 -0
- package/node_modules/@murphai/assistant-engine/skills/music-generation/SKILL.md +31 -163
- package/node_modules/@murphai/assistant-engine/skills/nutrition-strategy/SKILL.md +78 -7
- package/node_modules/@murphai/assistant-engine/skills/nutrition-strategy/references/daily-nutrition-card-goals.md +285 -0
- package/node_modules/@murphai/assistant-engine/skills/nutrition-strategy/references/daily-nutrition-card-safety.md +211 -0
- package/node_modules/@murphai/assistant-engine/skills/nutrition-strategy/references/named-diets/carnivore-animal-based.md +145 -0
- package/node_modules/@murphai/assistant-engine/skills/nutrition-strategy/references/named-diets/dash.md +183 -0
- package/node_modules/@murphai/assistant-engine/skills/nutrition-strategy/references/named-diets/intermittent-fasting.md +153 -0
- package/node_modules/@murphai/assistant-engine/skills/nutrition-strategy/references/named-diets/ketogenic.md +149 -0
- package/node_modules/@murphai/assistant-engine/skills/nutrition-strategy/references/named-diets/low-carbohydrate.md +167 -0
- package/node_modules/@murphai/assistant-engine/skills/nutrition-strategy/references/named-diets/mediterranean.md +141 -0
- package/node_modules/@murphai/assistant-engine/skills/nutrition-strategy/references/named-diets/vegan-plant-based.md +175 -0
- package/node_modules/@murphai/assistant-engine/skills/nutrition-strategy/references/named-diets/vegetarian-spectrum.md +131 -0
- package/node_modules/@murphai/assistant-engine/skills/phone-calls/SKILL.md +47 -67
- package/node_modules/@murphai/assistant-engine/skills/physical-notes/SKILL.md +120 -0
- package/node_modules/@murphai/assistant-engine/skills/physical-therapy/SKILL.md +4 -2
- package/node_modules/@murphai/assistant-engine/skills/self-management-experiments/SKILL.md +19 -3
- package/node_modules/@murphai/assistant-engine/skills/shared/exercise-catalog-runtime.md +30 -19
- package/node_modules/@murphai/assistant-engine/skills/signup-link/SKILL.md +30 -0
- package/node_modules/@murphai/assistant-engine/skills/strength-training/SKILL.md +9 -0
- package/node_modules/@murphai/assistant-engine/skills/tracked-table/SKILL.md +202 -0
- package/node_modules/@murphai/assistant-engine/skills/workout-csv-import/SKILL.md +129 -0
- package/node_modules/@murphai/assistantd/dist/client.d.ts +2 -0
- package/node_modules/@murphai/assistantd/dist/client.d.ts.map +1 -1
- package/node_modules/@murphai/assistantd/dist/client.js +33 -0
- package/node_modules/@murphai/assistantd/dist/client.js.map +1 -1
- package/node_modules/@murphai/assistantd/dist/http-protocol.d.ts.map +1 -1
- package/node_modules/@murphai/assistantd/dist/http-protocol.js +25 -1
- package/node_modules/@murphai/assistantd/dist/http-protocol.js.map +1 -1
- package/node_modules/@murphai/clinical-records/dist/index.d.ts +660 -660
- package/node_modules/@murphai/clinical-records/dist/index.d.ts.map +1 -1
- package/node_modules/@murphai/clinical-records/dist/index.js +1 -1
- package/node_modules/@murphai/clinical-records/dist/index.js.map +1 -1
- package/node_modules/@murphai/core/dist/automation-availability.d.ts +51 -0
- package/node_modules/@murphai/core/dist/automation-availability.d.ts.map +1 -0
- package/node_modules/@murphai/core/dist/automation-availability.js +226 -0
- package/node_modules/@murphai/core/dist/automation-availability.js.map +1 -0
- package/node_modules/@murphai/core/dist/automation.d.ts +9 -2
- package/node_modules/@murphai/core/dist/automation.d.ts.map +1 -1
- package/node_modules/@murphai/core/dist/automation.js +107 -13
- package/node_modules/@murphai/core/dist/automation.js.map +1 -1
- package/node_modules/@murphai/core/dist/bank/habitat.d.ts.map +1 -1
- package/node_modules/@murphai/core/dist/bank/habitat.js +8 -1
- package/node_modules/@murphai/core/dist/bank/habitat.js.map +1 -1
- package/node_modules/@murphai/core/dist/domains/events/attachment-backed.d.ts.map +1 -1
- package/node_modules/@murphai/core/dist/domains/events/attachment-backed.js +9 -123
- package/node_modules/@murphai/core/dist/domains/events/attachment-backed.js.map +1 -1
- package/node_modules/@murphai/core/dist/domains/events/capture-lookup.d.ts +33 -0
- package/node_modules/@murphai/core/dist/domains/events/capture-lookup.d.ts.map +1 -1
- package/node_modules/@murphai/core/dist/domains/events/capture-lookup.js +119 -0
- package/node_modules/@murphai/core/dist/domains/events/capture-lookup.js.map +1 -1
- package/node_modules/@murphai/core/dist/domains/events/generated-image-capture-retention.d.ts +24 -0
- package/node_modules/@murphai/core/dist/domains/events/generated-image-capture-retention.d.ts.map +1 -0
- package/node_modules/@murphai/core/dist/domains/events/generated-image-capture-retention.js +409 -0
- package/node_modules/@murphai/core/dist/domains/events/generated-image-capture-retention.js.map +1 -0
- package/node_modules/@murphai/core/dist/domains/events/ledger.d.ts +13 -0
- package/node_modules/@murphai/core/dist/domains/events/ledger.d.ts.map +1 -1
- package/node_modules/@murphai/core/dist/domains/events/ledger.js +86 -7
- package/node_modules/@murphai/core/dist/domains/events/ledger.js.map +1 -1
- package/node_modules/@murphai/core/dist/domains/events.d.ts +6 -2
- package/node_modules/@murphai/core/dist/domains/events.d.ts.map +1 -1
- package/node_modules/@murphai/core/dist/domains/events.js +3 -1
- package/node_modules/@murphai/core/dist/domains/events.js.map +1 -1
- package/node_modules/@murphai/core/dist/domains/experiments.d.ts.map +1 -1
- package/node_modules/@murphai/core/dist/domains/experiments.js +5 -1
- package/node_modules/@murphai/core/dist/domains/experiments.js.map +1 -1
- package/node_modules/@murphai/core/dist/history/api.d.ts +8 -5
- package/node_modules/@murphai/core/dist/history/api.d.ts.map +1 -1
- package/node_modules/@murphai/core/dist/history/api.js +253 -20
- package/node_modules/@murphai/core/dist/history/api.js.map +1 -1
- package/node_modules/@murphai/core/dist/index.d.ts +8 -5
- package/node_modules/@murphai/core/dist/index.d.ts.map +1 -1
- package/node_modules/@murphai/core/dist/index.js +5 -3
- package/node_modules/@murphai/core/dist/index.js.map +1 -1
- package/node_modules/@murphai/core/dist/memory.d.ts.map +1 -1
- package/node_modules/@murphai/core/dist/memory.js +1 -0
- package/node_modules/@murphai/core/dist/memory.js.map +1 -1
- package/node_modules/@murphai/core/dist/mutations.d.ts +20 -2
- package/node_modules/@murphai/core/dist/mutations.d.ts.map +1 -1
- package/node_modules/@murphai/core/dist/mutations.js +618 -21
- package/node_modules/@murphai/core/dist/mutations.js.map +1 -1
- package/node_modules/@murphai/core/dist/operations/write-batch.d.ts +3 -0
- package/node_modules/@murphai/core/dist/operations/write-batch.d.ts.map +1 -1
- package/node_modules/@murphai/core/dist/operations/write-batch.js +33 -2
- package/node_modules/@murphai/core/dist/operations/write-batch.js.map +1 -1
- package/node_modules/@murphai/core/dist/public-mutations.d.ts +2 -1
- package/node_modules/@murphai/core/dist/public-mutations.d.ts.map +1 -1
- package/node_modules/@murphai/core/dist/public-mutations.js +7 -2
- package/node_modules/@murphai/core/dist/public-mutations.js.map +1 -1
- package/node_modules/@murphai/device-syncd/README.md +143 -0
- package/node_modules/@murphai/device-syncd/dist/client.d.ts +1 -0
- package/node_modules/@murphai/device-syncd/dist/client.d.ts.map +1 -1
- package/node_modules/@murphai/device-syncd/dist/client.js.map +1 -1
- package/node_modules/@murphai/device-syncd/dist/config/connect-routes.d.ts +25 -0
- package/node_modules/@murphai/device-syncd/dist/config/connect-routes.d.ts.map +1 -1
- package/node_modules/@murphai/device-syncd/dist/config/connect-routes.js +54 -0
- package/node_modules/@murphai/device-syncd/dist/config/connect-routes.js.map +1 -1
- package/node_modules/@murphai/device-syncd/dist/config/connect-targets.js +1 -1
- package/node_modules/@murphai/device-syncd/dist/config/connect-targets.js.map +1 -1
- package/node_modules/@murphai/device-syncd/dist/config/junction-client-config.d.ts +2 -1
- package/node_modules/@murphai/device-syncd/dist/config/junction-client-config.d.ts.map +1 -1
- package/node_modules/@murphai/device-syncd/dist/config/junction-client-config.js +2 -1
- package/node_modules/@murphai/device-syncd/dist/config/junction-client-config.js.map +1 -1
- package/node_modules/@murphai/device-syncd/dist/config/junction-config.d.ts +1 -0
- package/node_modules/@murphai/device-syncd/dist/config/junction-config.d.ts.map +1 -1
- package/node_modules/@murphai/device-syncd/dist/config/junction-config.js +9 -1
- package/node_modules/@murphai/device-syncd/dist/config/junction-config.js.map +1 -1
- package/node_modules/@murphai/device-syncd/dist/config/provider-configs.d.ts +2 -2
- package/node_modules/@murphai/device-syncd/dist/config/provider-configs.d.ts.map +1 -1
- package/node_modules/@murphai/device-syncd/dist/config/provider-configs.js +2 -2
- package/node_modules/@murphai/device-syncd/dist/config/provider-configs.js.map +1 -1
- package/node_modules/@murphai/device-syncd/dist/config/provider-env.d.ts +4 -2
- package/node_modules/@murphai/device-syncd/dist/config/provider-env.d.ts.map +1 -1
- package/node_modules/@murphai/device-syncd/dist/config/provider-env.js +6 -0
- package/node_modules/@murphai/device-syncd/dist/config/provider-env.js.map +1 -1
- package/node_modules/@murphai/device-syncd/dist/config/provider-manifests.d.ts +561 -0
- package/node_modules/@murphai/device-syncd/dist/config/provider-manifests.d.ts.map +1 -1
- package/node_modules/@murphai/device-syncd/dist/config/provider-manifests.js +203 -148
- package/node_modules/@murphai/device-syncd/dist/config/provider-manifests.js.map +1 -1
- package/node_modules/@murphai/device-syncd/dist/config/provider-types.d.ts +11 -0
- package/node_modules/@murphai/device-syncd/dist/config/provider-types.d.ts.map +1 -1
- package/node_modules/@murphai/device-syncd/dist/config/runtime-config.d.ts.map +1 -1
- package/node_modules/@murphai/device-syncd/dist/config/runtime-config.js +2 -2
- package/node_modules/@murphai/device-syncd/dist/config/runtime-config.js.map +1 -1
- package/node_modules/@murphai/device-syncd/dist/config/serializable-provider-configs.d.ts.map +1 -1
- package/node_modules/@murphai/device-syncd/dist/config/serializable-provider-configs.js +2 -0
- package/node_modules/@murphai/device-syncd/dist/config/serializable-provider-configs.js.map +1 -1
- package/node_modules/@murphai/device-syncd/dist/config.d.ts +1 -1
- package/node_modules/@murphai/device-syncd/dist/config.d.ts.map +1 -1
- package/node_modules/@murphai/device-syncd/dist/config.js +1 -1
- package/node_modules/@murphai/device-syncd/dist/config.js.map +1 -1
- package/node_modules/@murphai/device-syncd/dist/configured-provider-runtime-descriptors.d.ts +1 -1
- package/node_modules/@murphai/device-syncd/dist/configured-provider-runtime-descriptors.d.ts.map +1 -1
- package/node_modules/@murphai/device-syncd/dist/configured-provider-runtime-descriptors.js +1 -1
- package/node_modules/@murphai/device-syncd/dist/configured-provider-runtime-descriptors.js.map +1 -1
- package/node_modules/@murphai/device-syncd/dist/connect-config.d.ts +1 -1
- package/node_modules/@murphai/device-syncd/dist/connect-config.d.ts.map +1 -1
- package/node_modules/@murphai/device-syncd/dist/connect-config.js +1 -1
- package/node_modules/@murphai/device-syncd/dist/connect-config.js.map +1 -1
- package/node_modules/@murphai/device-syncd/dist/hosted-runtime.d.ts +44 -0
- package/node_modules/@murphai/device-syncd/dist/hosted-runtime.d.ts.map +1 -1
- package/node_modules/@murphai/device-syncd/dist/hosted-runtime.js +167 -1
- package/node_modules/@murphai/device-syncd/dist/hosted-runtime.js.map +1 -1
- package/node_modules/@murphai/device-syncd/dist/index.d.ts +1 -1
- package/node_modules/@murphai/device-syncd/dist/index.d.ts.map +1 -1
- package/node_modules/@murphai/device-syncd/dist/index.js +1 -1
- package/node_modules/@murphai/device-syncd/dist/index.js.map +1 -1
- package/node_modules/@murphai/device-syncd/dist/junction-historical-backfill-progress.d.ts +24 -0
- package/node_modules/@murphai/device-syncd/dist/junction-historical-backfill-progress.d.ts.map +1 -1
- package/node_modules/@murphai/device-syncd/dist/junction-historical-backfill-progress.js +444 -9
- package/node_modules/@murphai/device-syncd/dist/junction-historical-backfill-progress.js.map +1 -1
- package/node_modules/@murphai/device-syncd/dist/junction-resources.d.ts +16 -0
- package/node_modules/@murphai/device-syncd/dist/junction-resources.d.ts.map +1 -1
- package/node_modules/@murphai/device-syncd/dist/junction-resources.js +32 -0
- package/node_modules/@murphai/device-syncd/dist/junction-resources.js.map +1 -1
- package/node_modules/@murphai/device-syncd/dist/junction-timeseries-progress.d.ts +8 -0
- package/node_modules/@murphai/device-syncd/dist/junction-timeseries-progress.d.ts.map +1 -0
- package/node_modules/@murphai/device-syncd/dist/junction-timeseries-progress.js +13 -0
- package/node_modules/@murphai/device-syncd/dist/junction-timeseries-progress.js.map +1 -0
- package/node_modules/@murphai/device-syncd/dist/prepared-webhook.d.ts +29 -0
- package/node_modules/@murphai/device-syncd/dist/prepared-webhook.d.ts.map +1 -0
- package/node_modules/@murphai/device-syncd/dist/prepared-webhook.js +263 -0
- package/node_modules/@murphai/device-syncd/dist/prepared-webhook.js.map +1 -0
- package/node_modules/@murphai/device-syncd/dist/provider-configs.d.ts +1 -1
- package/node_modules/@murphai/device-syncd/dist/provider-configs.d.ts.map +1 -1
- package/node_modules/@murphai/device-syncd/dist/provider-configs.js +1 -1
- package/node_modules/@murphai/device-syncd/dist/provider-configs.js.map +1 -1
- package/node_modules/@murphai/device-syncd/dist/provider-label.d.ts +1 -0
- package/node_modules/@murphai/device-syncd/dist/provider-label.d.ts.map +1 -1
- package/node_modules/@murphai/device-syncd/dist/provider-label.js +4 -2
- package/node_modules/@murphai/device-syncd/dist/provider-label.js.map +1 -1
- package/node_modules/@murphai/device-syncd/dist/providers/junction-client.d.ts +23 -1
- package/node_modules/@murphai/device-syncd/dist/providers/junction-client.d.ts.map +1 -1
- package/node_modules/@murphai/device-syncd/dist/providers/junction-client.js +765 -192
- package/node_modules/@murphai/device-syncd/dist/providers/junction-client.js.map +1 -1
- package/node_modules/@murphai/device-syncd/dist/providers/junction.d.ts +2 -2
- package/node_modules/@murphai/device-syncd/dist/providers/junction.d.ts.map +1 -1
- package/node_modules/@murphai/device-syncd/dist/providers/junction.js +3250 -205
- package/node_modules/@murphai/device-syncd/dist/providers/junction.js.map +1 -1
- package/node_modules/@murphai/device-syncd/dist/providers/oura.d.ts.map +1 -1
- package/node_modules/@murphai/device-syncd/dist/providers/oura.js +2 -1
- package/node_modules/@murphai/device-syncd/dist/providers/oura.js.map +1 -1
- package/node_modules/@murphai/device-syncd/dist/providers/shared-oauth.d.ts +12 -3
- package/node_modules/@murphai/device-syncd/dist/providers/shared-oauth.d.ts.map +1 -1
- package/node_modules/@murphai/device-syncd/dist/providers/shared-oauth.js +50 -12
- package/node_modules/@murphai/device-syncd/dist/providers/shared-oauth.js.map +1 -1
- package/node_modules/@murphai/device-syncd/dist/providers/strava.d.ts +3 -1
- package/node_modules/@murphai/device-syncd/dist/providers/strava.d.ts.map +1 -1
- package/node_modules/@murphai/device-syncd/dist/providers/strava.js +51 -38
- package/node_modules/@murphai/device-syncd/dist/providers/strava.js.map +1 -1
- package/node_modules/@murphai/device-syncd/dist/providers/whoop.d.ts.map +1 -1
- package/node_modules/@murphai/device-syncd/dist/providers/whoop.js +11 -1
- package/node_modules/@murphai/device-syncd/dist/providers/whoop.js.map +1 -1
- package/node_modules/@murphai/device-syncd/dist/public-account.d.ts +52 -2
- package/node_modules/@murphai/device-syncd/dist/public-account.d.ts.map +1 -1
- package/node_modules/@murphai/device-syncd/dist/public-account.js +147 -1
- package/node_modules/@murphai/device-syncd/dist/public-account.js.map +1 -1
- package/node_modules/@murphai/device-syncd/dist/public-ingress.d.ts +9 -2
- package/node_modules/@murphai/device-syncd/dist/public-ingress.d.ts.map +1 -1
- package/node_modules/@murphai/device-syncd/dist/public-ingress.js +632 -199
- package/node_modules/@murphai/device-syncd/dist/public-ingress.js.map +1 -1
- package/node_modules/@murphai/device-syncd/dist/service.d.ts +17 -4
- package/node_modules/@murphai/device-syncd/dist/service.d.ts.map +1 -1
- package/node_modules/@murphai/device-syncd/dist/service.js +362 -43
- package/node_modules/@murphai/device-syncd/dist/service.js.map +1 -1
- package/node_modules/@murphai/device-syncd/dist/store/accounts.d.ts +3 -1
- package/node_modules/@murphai/device-syncd/dist/store/accounts.d.ts.map +1 -1
- package/node_modules/@murphai/device-syncd/dist/store/accounts.js +25 -2
- package/node_modules/@murphai/device-syncd/dist/store/accounts.js.map +1 -1
- package/node_modules/@murphai/device-syncd/dist/store/hosted-account-hydration.d.ts.map +1 -1
- package/node_modules/@murphai/device-syncd/dist/store/hosted-account-hydration.js +7 -1
- package/node_modules/@murphai/device-syncd/dist/store/hosted-account-hydration.js.map +1 -1
- package/node_modules/@murphai/device-syncd/dist/store/jobs.d.ts +13 -3
- package/node_modules/@murphai/device-syncd/dist/store/jobs.d.ts.map +1 -1
- package/node_modules/@murphai/device-syncd/dist/store/jobs.js +171 -20
- package/node_modules/@murphai/device-syncd/dist/store/jobs.js.map +1 -1
- package/node_modules/@murphai/device-syncd/dist/store/oauth-states.d.ts +3 -1
- package/node_modules/@murphai/device-syncd/dist/store/oauth-states.d.ts.map +1 -1
- package/node_modules/@murphai/device-syncd/dist/store/oauth-states.js +62 -4
- package/node_modules/@murphai/device-syncd/dist/store/oauth-states.js.map +1 -1
- package/node_modules/@murphai/device-syncd/dist/store/sources.d.ts +1 -0
- package/node_modules/@murphai/device-syncd/dist/store/sources.d.ts.map +1 -1
- package/node_modules/@murphai/device-syncd/dist/store/sources.js +56 -55
- package/node_modules/@murphai/device-syncd/dist/store/sources.js.map +1 -1
- package/node_modules/@murphai/device-syncd/dist/store/sync-state.d.ts +7 -2
- package/node_modules/@murphai/device-syncd/dist/store/sync-state.d.ts.map +1 -1
- package/node_modules/@murphai/device-syncd/dist/store/sync-state.js +82 -28
- package/node_modules/@murphai/device-syncd/dist/store/sync-state.js.map +1 -1
- package/node_modules/@murphai/device-syncd/dist/store/webhook-traces.js +2 -2
- package/node_modules/@murphai/device-syncd/dist/store/webhook-traces.js.map +1 -1
- package/node_modules/@murphai/device-syncd/dist/store.d.ts +19 -4
- package/node_modules/@murphai/device-syncd/dist/store.d.ts.map +1 -1
- package/node_modules/@murphai/device-syncd/dist/store.js +62 -11
- package/node_modules/@murphai/device-syncd/dist/store.js.map +1 -1
- package/node_modules/@murphai/device-syncd/dist/types.d.ts +169 -4
- package/node_modules/@murphai/device-syncd/dist/types.d.ts.map +1 -1
- package/node_modules/@murphai/device-syncd/dist/types.js +3 -0
- package/node_modules/@murphai/device-syncd/dist/types.js.map +1 -1
- package/node_modules/@murphai/device-syncd/package.json +8 -0
- package/node_modules/@murphai/health-commons/content/biomarkers/bilirubin.md +18 -0
- package/node_modules/@murphai/health-commons/content/biomarkers/carbon-dioxide.md +18 -0
- package/node_modules/@murphai/health-commons/content/biomarkers/potassium.md +18 -0
- package/node_modules/@murphai/health-commons/content/biomarkers/sodium.md +18 -0
- package/node_modules/@murphai/health-commons/content/families/general-eye-health.md +190 -0
- package/node_modules/@murphai/health-commons/content/families/photobiomodulation.md +97 -0
- package/node_modules/@murphai/health-commons/content/families/recovery-modalities.md +73 -0
- package/node_modules/@murphai/health-commons/content/protocols/whole-body-photobiomodulation/whole-body-red-and-near-infrared-light-exposure.md +1 -1
- package/node_modules/@murphai/health-commons/content/sources/general-eye-health/cdc-contact-lens-infection-symptoms.md +20 -0
- package/node_modules/@murphai/health-commons/content/sources/general-eye-health/cdc-contact-lens-prevention.md +20 -0
- package/node_modules/@murphai/health-commons/content/sources/general-eye-health/cdc-stroke-signs.md +20 -0
- package/node_modules/@murphai/health-commons/content/sources/general-eye-health/cochrane-blue-light-filtering-lenses.md +21 -0
- package/node_modules/@murphai/health-commons/content/sources/general-eye-health/fda-buying-contact-lenses.md +20 -0
- package/node_modules/@murphai/health-commons/content/sources/general-eye-health/fda-eye-drops.md +20 -0
- package/node_modules/@murphai/health-commons/content/sources/general-eye-health/imi-myopia-interventions.md +20 -0
- package/node_modules/@murphai/health-commons/content/sources/general-eye-health/medlineplus-eye-emergencies.md +20 -0
- package/node_modules/@murphai/health-commons/content/sources/general-eye-health/medlineplus-eye-pain.md +20 -0
- package/node_modules/@murphai/health-commons/content/sources/general-eye-health/nei-angle-closure-glaucoma.md +20 -0
- package/node_modules/@murphai/health-commons/content/sources/general-eye-health/nei-areds2-faq.md +20 -0
- package/node_modules/@murphai/health-commons/content/sources/general-eye-health/nei-contact-lenses.md +20 -0
- package/node_modules/@murphai/health-commons/content/sources/general-eye-health/nei-dry-eye.md +20 -0
- package/node_modules/@murphai/health-commons/content/sources/general-eye-health/nei-healthy-vision.md +21 -0
- package/node_modules/@murphai/health-commons/content/sources/general-eye-health/nei-myopia.md +20 -0
- package/node_modules/@murphai/health-commons/content/sources/general-eye-health/nei-retinal-detachment.md +20 -0
- package/node_modules/@murphai/health-commons/content/sources/general-eye-health/nih-dream-omega3-dry-eye.md +21 -0
- package/node_modules/@murphai/health-commons/content/sources/general-eye-health/osha-computer-monitors.md +20 -0
- package/node_modules/@murphai/health-commons/content/sources/general-eye-health/pmc-9840372.md +22 -0
- package/node_modules/@murphai/health-commons/content/sources/general-eye-health/pmid-35597519.md +21 -0
- package/node_modules/@murphai/health-commons/content/sources/general-eye-health/pmid-36473088.md +21 -0
- package/node_modules/@murphai/health-commons/content/sources/general-eye-health/pmid-37062428.md +21 -0
- package/node_modules/@murphai/health-commons/content/sources/whole-body-photobiomodulation/clinicaltrials-gov-nct07047248-2026-04-23.md +0 -1
- package/node_modules/@murphai/health-commons/dist/biomarker-fallback-ranges.d.ts +3 -0
- package/node_modules/@murphai/health-commons/dist/biomarker-fallback-ranges.d.ts.map +1 -0
- package/node_modules/@murphai/health-commons/dist/biomarker-fallback-ranges.js +2 -0
- package/node_modules/@murphai/health-commons/dist/biomarker-fallback-ranges.js.map +1 -0
- package/node_modules/@murphai/health-commons/dist/biomarker-runtime-artifacts.d.ts +17 -0
- package/node_modules/@murphai/health-commons/dist/biomarker-runtime-artifacts.d.ts.map +1 -0
- package/node_modules/@murphai/health-commons/dist/biomarker-runtime-artifacts.js +16 -0
- package/node_modules/@murphai/health-commons/dist/biomarker-runtime-artifacts.js.map +1 -0
- package/node_modules/@murphai/health-commons/dist/build.d.ts.map +1 -1
- package/node_modules/@murphai/health-commons/dist/build.js +41 -7
- package/node_modules/@murphai/health-commons/dist/build.js.map +1 -1
- package/node_modules/@murphai/health-commons/dist/index.d.ts +1 -0
- package/node_modules/@murphai/health-commons/dist/index.d.ts.map +1 -1
- package/node_modules/@murphai/health-commons/dist/index.js +1 -0
- package/node_modules/@murphai/health-commons/dist/index.js.map +1 -1
- package/node_modules/@murphai/health-commons/dist/knowledge-index.d.ts +44 -0
- package/node_modules/@murphai/health-commons/dist/knowledge-index.d.ts.map +1 -0
- package/node_modules/@murphai/health-commons/dist/knowledge-index.js +540 -0
- package/node_modules/@murphai/health-commons/dist/knowledge-index.js.map +1 -0
- package/node_modules/@murphai/health-commons/dist/runtime.d.ts +17 -1
- package/node_modules/@murphai/health-commons/dist/runtime.d.ts.map +1 -1
- package/node_modules/@murphai/health-commons/dist/runtime.js +58 -4
- package/node_modules/@murphai/health-commons/dist/runtime.js.map +1 -1
- package/node_modules/@murphai/health-commons/generated/biomarker-desired-directions.json +410 -0
- package/node_modules/@murphai/health-commons/generated/catalog.hash +1 -1
- package/node_modules/@murphai/health-commons/generated/knowledge.sqlite +0 -0
- package/node_modules/@murphai/health-commons/generated/protocol-family-graph.json +187 -46
- package/node_modules/@murphai/health-commons/generated/protocol-index.json +47 -47
- package/node_modules/@murphai/health-commons/generated/protocol-run-specs.json +967 -967
- package/node_modules/@murphai/health-commons/generated/source-artifact-index.json +1 -1
- package/node_modules/@murphai/health-commons/generated/source-identities.ndjson +28 -0
- package/node_modules/@murphai/health-commons/generated/source-index.json +694 -2
- package/node_modules/@murphai/health-commons/generated/web/browse/biomarkers.json +77 -9
- package/node_modules/@murphai/health-commons/generated/web/browse/experiments.json +37 -37
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/absolute-basophils.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/absolute-eosinophils.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/absolute-immature-granulocytes.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/absolute-lymphocytes.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/absolute-monocytes.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/absolute-neutrophils.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/added-sugar-intake.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/adherence.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/adjusted-calcium.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/adverse-symptoms.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/alanine-aminotransferase.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/albumin-globulin-ratio.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/albumin.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/alcohol-craving.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/alcohol-free-days.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/alcohol-intake.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/alcohol-withdrawal-symptoms.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/alkaline-phosphatase.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/ana-screen.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/anion-gap.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/ankle-knee-to-wall-distance.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/apolipoprotein-b.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/arachidonic-acid-epa-ratio.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/arachidonic-acid.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/aspartate-aminotransferase.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/basophil-percentage.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/bedtime-delay.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/bilirubin.json +3 -3
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/blood-glucose.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/blood-ketones-beta-hydroxybutyrate.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/blood-oxygen-spo2.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/blood-pressure.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/blood-urea-nitrogen.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/body-fat-percent.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/body-weight.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/bun-creatinine-ratio.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/c-peptide.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/calcium.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/carbon-dioxide.json +3 -3
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/chloride.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/cholesterol-hdl-ratio.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/chosen-primary-outcome-score.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/continuous-glucose.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/cortisol.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/creatine-kinase.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/daily-energy-intake-kcal.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/daily-protein-g-per-kg.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/daily-protein-grams.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/daily-step-count.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/daytime-sleepiness.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/deep-sleep-minutes.json +4 -4
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/dha.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/dhea-sulfate.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/dietary-fiber-g-day.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/digestive-comfort.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/dpa.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/egfr-ckd-epi.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/egfr.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/eosinophil-percentage.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/epa.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/estimated-gfr.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/estimated-vo2max.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/estradiol.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/fasting-triglycerides.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/ferritin.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/fib4.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/follicle-stimulating-hormone.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/free-t3.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/free-t4.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/free-testosterone.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/gfr-mdrd-af-amer.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/gfr-mdrd-non-af-amer.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/ggt.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/gi-symptom-score.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/gi-tolerance.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/hba1c.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/hbot-session-tolerability.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/hdl-c.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/hematocrit.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/hemoglobin.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/homocysteine.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/hrv-rmssd.json +4 -4
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/hs-crp.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/immature-granulocyte-percentage.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/insulin.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/iron-saturation.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/iron.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/lateral-knee-pain.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/ldh.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/ldl-c.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/ldl-calculated.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/ldl-chol-calc-nih.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/ldl-cholesterol.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/ldl-large-particles.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/ldl-medium-particles.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/ldl-particle-number.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/ldl-pattern.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/ldl-peak-size.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/ldl-small-particles.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/lead.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/lean-body-mass.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/lean-mass.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/leg-heaviness-score.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/linoleic-acid.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/lipoprotein-a.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/liver-enzyme-panel.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/luteinizing-hormone.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/lymphocyte-percentage.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/macular-health-safety.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/magnesium-rbc.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/mean-corpuscular-hemoglobin-concentration.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/mean-corpuscular-hemoglobin.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/mean-corpuscular-volume.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/mean-platelet-volume.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/mercury.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/methylmalonic-acid.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/moderate-to-vigorous-activity-minutes.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/monocyte-percentage.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/mood-affect.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/morning-blood-pressure.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/muscle-soreness-score.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/musculoskeletal-pain.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/neutrophil-percentage.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/non-hdl-c.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/non-hdl-cholesterol.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/omega-3-index.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/omega-3-total-omegacheck.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/omega-6-3-ratio.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/omega-6-total.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/omegacheck-total.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/perceived-recovery-score.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/perceived-recovery.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/perceived-stiffness.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/perceived-stress.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/periocular-wrinkle-score.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/phosphate.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/platelet-count.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/poc-troponin-i.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/postprandial-glucose-excursion.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/potassium.json +3 -3
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/pre-sleep-arousal.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/prolactin.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/psa-free.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/psa-percent-free.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/psa-total.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/red-blood-cell-count.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/red-cell-distribution-width.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/rem-sleep-minutes.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/resting-heart-rate.json +4 -4
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/rheumatoid-factor.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/running-tolerance.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/saturated-fat-g-day.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/sedentary-time.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/self-reported-mood.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/serum-25-hydroxyvitamin-d.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/serum-creatinine.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/serum-uric-acid.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/sex-hormone-binding-globulin.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/shoulder-reach-distance.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/sit-and-reach-distance.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/skin-texture-roughness-score.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/skin-tolerability-symptoms.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/sleep-efficiency.json +4 -4
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/sleep-onset-latency.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/sleep-quality.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/sodium.json +3 -3
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/standardized-skin-photo-score.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/step-floor-days.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/stretching-adherence-sessions.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/stretching-session-burden.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/stretching-symptoms.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/subjective-eye-strain.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/subjective-satiety.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/supplement-adherence.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/task-performance.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/thyroglobulin-antibodies.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/thyroid-peroxidase-antibodies.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/thyroid-stimulating-hormone.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/toe-touch-distance.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/total-cholesterol.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/total-globulin.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/total-iron-binding-capacity.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/total-protein.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/total-sleep-time.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/total-testosterone.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/training-performance.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/training-volume.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/triglycerides.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/urine-albumin-creatinine-ratio.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/urine-albumin-random-without-creatinine.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/urine-protein.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/visual-fatigue.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/visual-performance.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/vldl-cholesterol-calculated.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/waist-circumference.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/wake-after-sleep-onset.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/wake-time-variability.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/walking-bout-minutes.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/walking-cadence.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/walking-safety-events.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/white-blood-cell-count.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/biomarker/zinc.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/measurement_method/clinic-imaging-upgrade.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/measurement_method/home-standardized-photo-roi-analysis.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/measurement_method/standardized-photo-score-workflow.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/protocol_variant/bryan-johnson-blueprint.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/protocol_variant/cold-plunge.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/protocol_variant/consistent-wake-time.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/protocol_variant/daily-step-floor.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/protocol_variant/finnish-sauna.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/protocol_variant/five-minute-tomorrow-list.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/protocol_variant/hyperbaric-oxygen-therapy.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/protocol_variant/morning-outdoor-light-exposure.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/protocol_variant/no-added-sugar-diet.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/protocol_variant/norwegian-4x4.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/protocol_variant/pneumatic-compression-pants.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/protocol_variant/protein-floor-high-protein-intake.json +3 -3
- package/node_modules/@murphai/health-commons/generated/web/bundles/protocol_variant/tabata-20-10-interval-training.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/protocol_variant/time-restricted-eating-18-6.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/protocol_variant/walking-after-every-meal.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/bundles/protocol_variant/whole-body-red-and-near-infrared-light-exposure.json +7 -8
- package/node_modules/@murphai/health-commons/generated/web/pages/biomarkers/blood-oxygen-spo2/overview.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/pages/biomarkers/blood-oxygen-spo2/research.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/pages/biomarkers/deep-sleep-minutes/overview.json +2 -2
- package/node_modules/@murphai/health-commons/generated/web/pages/biomarkers/deep-sleep-minutes/research.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/pages/biomarkers/estimated-vo2max/overview.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/pages/biomarkers/estimated-vo2max/research.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/pages/biomarkers/hrv-rmssd/overview.json +2 -2
- package/node_modules/@murphai/health-commons/generated/web/pages/biomarkers/hrv-rmssd/research.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/pages/biomarkers/rem-sleep-minutes/overview.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/pages/biomarkers/rem-sleep-minutes/research.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/pages/biomarkers/resting-heart-rate/overview.json +2 -2
- package/node_modules/@murphai/health-commons/generated/web/pages/biomarkers/resting-heart-rate/research.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/routes/index.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/shell/biomarkers/blood-oxygen-spo2.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/shell/biomarkers/deep-sleep-minutes.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/shell/biomarkers/estimated-vo2max.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/shell/biomarkers/hrv-rmssd.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/shell/biomarkers/rem-sleep-minutes.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/shell/biomarkers/resting-heart-rate.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/shell/experiments/bryan-johnson-blueprint.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/shell/experiments/cold-plunge.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/shell/experiments/consistent-wake-time.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/shell/experiments/daily-step-floor.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/shell/experiments/finnish-sauna.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/shell/experiments/five-minute-tomorrow-list.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/shell/experiments/hyperbaric-oxygen-therapy.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/shell/experiments/morning-outdoor-light-exposure.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/shell/experiments/no-added-sugar-diet.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/shell/experiments/norwegian-4x4.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/shell/experiments/pneumatic-compression-pants.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/shell/experiments/protein-floor-high-protein-intake.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/shell/experiments/tabata-20-10-interval-training.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/shell/experiments/time-restricted-eating-18-6.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/shell/experiments/walking-after-every-meal.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/shell/experiments/whole-body-red-and-near-infrared-light-exposure.json +3 -3
- package/node_modules/@murphai/health-commons/generated/web/tabs/experiments/bryan-johnson-blueprint/protocol.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/tabs/experiments/bryan-johnson-blueprint/research.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/tabs/experiments/bryan-johnson-blueprint/results-public.json +2 -2
- package/node_modules/@murphai/health-commons/generated/web/tabs/experiments/cold-plunge/protocol.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/tabs/experiments/cold-plunge/research.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/tabs/experiments/cold-plunge/results-public.json +2 -2
- package/node_modules/@murphai/health-commons/generated/web/tabs/experiments/consistent-wake-time/protocol.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/tabs/experiments/consistent-wake-time/research.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/tabs/experiments/consistent-wake-time/results-public.json +2 -2
- package/node_modules/@murphai/health-commons/generated/web/tabs/experiments/daily-step-floor/protocol.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/tabs/experiments/daily-step-floor/research.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/tabs/experiments/daily-step-floor/results-public.json +2 -2
- package/node_modules/@murphai/health-commons/generated/web/tabs/experiments/finnish-sauna/protocol.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/tabs/experiments/finnish-sauna/research.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/tabs/experiments/finnish-sauna/results-public.json +2 -2
- package/node_modules/@murphai/health-commons/generated/web/tabs/experiments/five-minute-tomorrow-list/protocol.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/tabs/experiments/five-minute-tomorrow-list/research.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/tabs/experiments/five-minute-tomorrow-list/results-public.json +2 -2
- package/node_modules/@murphai/health-commons/generated/web/tabs/experiments/hyperbaric-oxygen-therapy/protocol.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/tabs/experiments/hyperbaric-oxygen-therapy/research.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/tabs/experiments/hyperbaric-oxygen-therapy/results-public.json +2 -2
- package/node_modules/@murphai/health-commons/generated/web/tabs/experiments/morning-outdoor-light-exposure/protocol.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/tabs/experiments/morning-outdoor-light-exposure/research.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/tabs/experiments/morning-outdoor-light-exposure/results-public.json +2 -2
- package/node_modules/@murphai/health-commons/generated/web/tabs/experiments/no-added-sugar-diet/protocol.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/tabs/experiments/no-added-sugar-diet/research.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/tabs/experiments/no-added-sugar-diet/results-public.json +2 -2
- package/node_modules/@murphai/health-commons/generated/web/tabs/experiments/norwegian-4x4/protocol.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/tabs/experiments/norwegian-4x4/research.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/tabs/experiments/norwegian-4x4/results-public.json +2 -2
- package/node_modules/@murphai/health-commons/generated/web/tabs/experiments/pneumatic-compression-pants/protocol.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/tabs/experiments/pneumatic-compression-pants/research.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/tabs/experiments/pneumatic-compression-pants/results-public.json +2 -2
- package/node_modules/@murphai/health-commons/generated/web/tabs/experiments/protein-floor-high-protein-intake/protocol.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/tabs/experiments/protein-floor-high-protein-intake/research.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/tabs/experiments/protein-floor-high-protein-intake/results-public.json +2 -2
- package/node_modules/@murphai/health-commons/generated/web/tabs/experiments/tabata-20-10-interval-training/protocol.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/tabs/experiments/tabata-20-10-interval-training/research.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/tabs/experiments/tabata-20-10-interval-training/results-public.json +2 -2
- package/node_modules/@murphai/health-commons/generated/web/tabs/experiments/time-restricted-eating-18-6/protocol.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/tabs/experiments/time-restricted-eating-18-6/research.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/tabs/experiments/time-restricted-eating-18-6/results-public.json +2 -2
- package/node_modules/@murphai/health-commons/generated/web/tabs/experiments/walking-after-every-meal/protocol.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/tabs/experiments/walking-after-every-meal/research.json +1 -1
- package/node_modules/@murphai/health-commons/generated/web/tabs/experiments/walking-after-every-meal/results-public.json +2 -2
- package/node_modules/@murphai/health-commons/generated/web/tabs/experiments/whole-body-red-and-near-infrared-light-exposure/protocol.json +3 -3
- package/node_modules/@murphai/health-commons/generated/web/tabs/experiments/whole-body-red-and-near-infrared-light-exposure/research.json +3 -3
- package/node_modules/@murphai/health-commons/generated/web/tabs/experiments/whole-body-red-and-near-infrared-light-exposure/results-public.json +5 -5
- package/node_modules/@murphai/health-commons/package.json +5 -0
- package/node_modules/@murphai/health-metrics/dist/catalog.d.ts.map +1 -1
- package/node_modules/@murphai/health-metrics/dist/catalog.js +22 -2
- package/node_modules/@murphai/health-metrics/dist/catalog.js.map +1 -1
- package/node_modules/@murphai/health-metrics/dist/definitions/activity.d.ts.map +1 -1
- package/node_modules/@murphai/health-metrics/dist/definitions/activity.js +99 -0
- package/node_modules/@murphai/health-metrics/dist/definitions/activity.js.map +1 -1
- package/node_modules/@murphai/health-metrics/dist/definitions/body.d.ts.map +1 -1
- package/node_modules/@murphai/health-metrics/dist/definitions/body.js +69 -2
- package/node_modules/@murphai/health-metrics/dist/definitions/body.js.map +1 -1
- package/node_modules/@murphai/health-metrics/dist/definitions/physiology.d.ts +55 -0
- package/node_modules/@murphai/health-metrics/dist/definitions/physiology.d.ts.map +1 -0
- package/node_modules/@murphai/health-metrics/dist/definitions/physiology.js +92 -0
- package/node_modules/@murphai/health-metrics/dist/definitions/physiology.js.map +1 -0
- package/node_modules/@murphai/health-metrics/dist/definitions/vitals.d.ts +1 -1
- package/node_modules/@murphai/health-metrics/dist/index.d.ts +1 -0
- package/node_modules/@murphai/health-metrics/dist/index.d.ts.map +1 -1
- package/node_modules/@murphai/health-metrics/dist/index.js +1 -0
- package/node_modules/@murphai/health-metrics/dist/index.js.map +1 -1
- package/node_modules/@murphai/health-metrics/dist/lab-reference-ranges.d.ts +45 -0
- package/node_modules/@murphai/health-metrics/dist/lab-reference-ranges.d.ts.map +1 -0
- package/node_modules/@murphai/health-metrics/dist/lab-reference-ranges.js +502 -0
- package/node_modules/@murphai/health-metrics/dist/lab-reference-ranges.js.map +1 -0
- package/node_modules/@murphai/health-metrics/dist/normalize.d.ts.map +1 -1
- package/node_modules/@murphai/health-metrics/dist/normalize.js +2 -0
- package/node_modules/@murphai/health-metrics/dist/normalize.js.map +1 -1
- package/node_modules/@murphai/health-metrics/dist/selectors.d.ts +3 -0
- package/node_modules/@murphai/health-metrics/dist/selectors.d.ts.map +1 -1
- package/node_modules/@murphai/health-metrics/dist/selectors.js +52 -6
- package/node_modules/@murphai/health-metrics/dist/selectors.js.map +1 -1
- package/node_modules/@murphai/health-metrics/dist/types.d.ts +1 -0
- package/node_modules/@murphai/health-metrics/dist/types.d.ts.map +1 -1
- package/node_modules/@murphai/health-metrics/dist/wearable-metric-catalog.d.ts +10 -1
- package/node_modules/@murphai/health-metrics/dist/wearable-metric-catalog.d.ts.map +1 -1
- package/node_modules/@murphai/health-metrics/dist/wearable-metric-catalog.js +29 -0
- package/node_modules/@murphai/health-metrics/dist/wearable-metric-catalog.js.map +1 -1
- package/node_modules/@murphai/importers/README.md +2 -0
- package/node_modules/@murphai/importers/dist/assessment/import-assessment-response.js +1 -1
- package/node_modules/@murphai/importers/dist/assessment/import-assessment-response.js.map +1 -1
- package/node_modules/@murphai/importers/dist/core-port.d.ts +1 -0
- package/node_modules/@murphai/importers/dist/core-port.d.ts.map +1 -1
- package/node_modules/@murphai/importers/dist/core-port.js.map +1 -1
- package/node_modules/@murphai/importers/dist/csv-sample-import-planner.d.ts +1 -0
- package/node_modules/@murphai/importers/dist/csv-sample-import-planner.d.ts.map +1 -1
- package/node_modules/@murphai/importers/dist/csv-sample-import-planner.js +1 -1
- package/node_modules/@murphai/importers/dist/csv-sample-import-planner.js.map +1 -1
- package/node_modules/@murphai/importers/dist/device-providers/import-device-provider-snapshot.js +1 -1
- package/node_modules/@murphai/importers/dist/device-providers/import-device-provider-snapshot.js.map +1 -1
- package/node_modules/@murphai/importers/dist/device-providers/index.d.ts +1 -1
- package/node_modules/@murphai/importers/dist/device-providers/index.d.ts.map +1 -1
- package/node_modules/@murphai/importers/dist/device-providers/index.js +1 -1
- package/node_modules/@murphai/importers/dist/device-providers/index.js.map +1 -1
- package/node_modules/@murphai/importers/dist/device-providers/junction-bounded-features.d.ts +27 -0
- package/node_modules/@murphai/importers/dist/device-providers/junction-bounded-features.d.ts.map +1 -0
- package/node_modules/@murphai/importers/dist/device-providers/junction-bounded-features.js +403 -0
- package/node_modules/@murphai/importers/dist/device-providers/junction-bounded-features.js.map +1 -0
- package/node_modules/@murphai/importers/dist/device-providers/junction-resources.d.ts +4 -12
- package/node_modules/@murphai/importers/dist/device-providers/junction-resources.d.ts.map +1 -1
- package/node_modules/@murphai/importers/dist/device-providers/junction-resources.js +18 -107
- package/node_modules/@murphai/importers/dist/device-providers/junction-resources.js.map +1 -1
- package/node_modules/@murphai/importers/dist/device-providers/junction-timeseries-fidelity.d.ts +285 -0
- package/node_modules/@murphai/importers/dist/device-providers/junction-timeseries-fidelity.d.ts.map +1 -0
- package/node_modules/@murphai/importers/dist/device-providers/junction-timeseries-fidelity.js +870 -0
- package/node_modules/@murphai/importers/dist/device-providers/junction-timeseries-fidelity.js.map +1 -0
- package/node_modules/@murphai/importers/dist/device-providers/junction.d.ts +38 -0
- package/node_modules/@murphai/importers/dist/device-providers/junction.d.ts.map +1 -1
- package/node_modules/@murphai/importers/dist/device-providers/junction.js +2682 -259
- package/node_modules/@murphai/importers/dist/device-providers/junction.js.map +1 -1
- package/node_modules/@murphai/importers/dist/device-providers/oura.js +1 -1
- package/node_modules/@murphai/importers/dist/device-providers/oura.js.map +1 -1
- package/node_modules/@murphai/importers/dist/device-providers/whoop.js +1 -1
- package/node_modules/@murphai/importers/dist/device-providers/whoop.js.map +1 -1
- package/node_modules/@murphai/importers/dist/document-importer.d.ts +1 -0
- package/node_modules/@murphai/importers/dist/document-importer.d.ts.map +1 -1
- package/node_modules/@murphai/importers/dist/document-importer.js +3 -1
- package/node_modules/@murphai/importers/dist/document-importer.js.map +1 -1
- package/node_modules/@murphai/importers/dist/index.d.ts +1 -0
- package/node_modules/@murphai/importers/dist/index.d.ts.map +1 -1
- package/node_modules/@murphai/importers/dist/index.js +1 -0
- package/node_modules/@murphai/importers/dist/index.js.map +1 -1
- package/node_modules/@murphai/importers/dist/meal-importer.d.ts.map +1 -1
- package/node_modules/@murphai/importers/dist/meal-importer.js +2 -1
- package/node_modules/@murphai/importers/dist/meal-importer.js.map +1 -1
- package/node_modules/@murphai/importers/dist/preset-registry.js +1 -1
- package/node_modules/@murphai/importers/dist/preset-registry.js.map +1 -1
- package/node_modules/@murphai/importers/dist/shared.d.ts +1 -1
- package/node_modules/@murphai/importers/dist/shared.d.ts.map +1 -1
- package/node_modules/@murphai/importers/dist/shared.js +1 -1
- package/node_modules/@murphai/importers/dist/shared.js.map +1 -1
- package/node_modules/@murphai/importers/dist/workout-csv-planner.d.ts +49 -0
- package/node_modules/@murphai/importers/dist/workout-csv-planner.d.ts.map +1 -0
- package/node_modules/@murphai/importers/dist/workout-csv-planner.js +860 -0
- package/node_modules/@murphai/importers/dist/workout-csv-planner.js.map +1 -0
- package/node_modules/@murphai/inbox-services/dist/inbox-app/bootstrap-doctor-strategies.d.ts +2 -5
- package/node_modules/@murphai/inbox-services/dist/inbox-app/bootstrap-doctor-strategies.d.ts.map +1 -1
- package/node_modules/@murphai/inbox-services/dist/inbox-app/bootstrap-doctor-strategies.js +3 -50
- package/node_modules/@murphai/inbox-services/dist/inbox-app/bootstrap-doctor-strategies.js.map +1 -1
- package/node_modules/@murphai/inbox-services/dist/inbox-app/bootstrap-doctor.d.ts.map +1 -1
- package/node_modules/@murphai/inbox-services/dist/inbox-app/bootstrap-doctor.js +9 -11
- package/node_modules/@murphai/inbox-services/dist/inbox-app/bootstrap-doctor.js.map +1 -1
- package/node_modules/@murphai/inbox-services/dist/inbox-app/environment.d.ts.map +1 -1
- package/node_modules/@murphai/inbox-services/dist/inbox-app/environment.js +0 -160
- package/node_modules/@murphai/inbox-services/dist/inbox-app/environment.js.map +1 -1
- package/node_modules/@murphai/inbox-services/dist/inbox-app/runtime.d.ts.map +1 -1
- package/node_modules/@murphai/inbox-services/dist/inbox-app/runtime.js +2 -4
- package/node_modules/@murphai/inbox-services/dist/inbox-app/runtime.js.map +1 -1
- package/node_modules/@murphai/inbox-services/dist/inbox-app/sources.d.ts +1 -1
- package/node_modules/@murphai/inbox-services/dist/inbox-app/sources.d.ts.map +1 -1
- package/node_modules/@murphai/inbox-services/dist/inbox-app/sources.js +2 -32
- package/node_modules/@murphai/inbox-services/dist/inbox-app/sources.js.map +1 -1
- package/node_modules/@murphai/inbox-services/dist/inbox-app/types.d.ts +2 -79
- package/node_modules/@murphai/inbox-services/dist/inbox-app/types.d.ts.map +1 -1
- package/node_modules/@murphai/inbox-services/dist/inbox-app/types.js +0 -1
- package/node_modules/@murphai/inbox-services/dist/inbox-app/types.js.map +1 -1
- package/node_modules/@murphai/inbox-services/dist/inbox-services/connectors.d.ts +1 -2
- package/node_modules/@murphai/inbox-services/dist/inbox-services/connectors.d.ts.map +1 -1
- package/node_modules/@murphai/inbox-services/dist/inbox-services/connectors.js +15 -37
- package/node_modules/@murphai/inbox-services/dist/inbox-services/connectors.js.map +1 -1
- package/node_modules/@murphai/inbox-services/dist/inbox-services/promotions.d.ts +21 -21
- package/node_modules/@murphai/inbox-services/dist/inbox-services/promotions.d.ts.map +1 -1
- package/node_modules/@murphai/inbox-services/dist/inbox-services/promotions.js +1 -1
- package/node_modules/@murphai/inbox-services/dist/inbox-services/promotions.js.map +1 -1
- package/node_modules/@murphai/inbox-services/dist/inbox-services/shared.d.ts +1 -1
- package/node_modules/@murphai/inbox-services/dist/inbox-services/shared.d.ts.map +1 -1
- package/node_modules/@murphai/inbox-services/dist/inbox-services/shared.js +0 -1
- package/node_modules/@murphai/inbox-services/dist/inbox-services/shared.js.map +1 -1
- package/node_modules/@murphai/inbox-services/dist/index.d.ts +1 -1
- package/node_modules/@murphai/inbox-services/dist/index.d.ts.map +1 -1
- package/node_modules/@murphai/inboxd/README.md +3 -3
- package/node_modules/@murphai/inboxd/dist/connectors/email/normalize-parsed.d.ts.map +1 -1
- package/node_modules/@murphai/inboxd/dist/connectors/email/normalize-parsed.js +56 -5
- package/node_modules/@murphai/inboxd/dist/connectors/email/normalize-parsed.js.map +1 -1
- package/node_modules/@murphai/inboxd/dist/connectors/linq/normalize.js +8 -0
- package/node_modules/@murphai/inboxd/dist/connectors/linq/normalize.js.map +1 -1
- package/node_modules/@murphai/inboxd/dist/connectors/telegram/normalize.d.ts +1 -0
- package/node_modules/@murphai/inboxd/dist/connectors/telegram/normalize.d.ts.map +1 -1
- package/node_modules/@murphai/inboxd/dist/connectors/telegram/normalize.js +1 -0
- package/node_modules/@murphai/inboxd/dist/connectors/telegram/normalize.js.map +1 -1
- package/node_modules/@murphai/inboxd/dist/index.d.ts +0 -5
- package/node_modules/@murphai/inboxd/dist/index.d.ts.map +1 -1
- package/node_modules/@murphai/inboxd/dist/index.js +0 -2
- package/node_modules/@murphai/inboxd/dist/index.js.map +1 -1
- package/node_modules/@murphai/inboxd/dist/indexing/attachment-storage-normalizer.d.ts.map +1 -1
- package/node_modules/@murphai/inboxd/dist/indexing/attachment-storage-normalizer.js +141 -4
- package/node_modules/@murphai/inboxd/dist/indexing/attachment-storage-normalizer.js.map +1 -1
- package/node_modules/@murphai/messaging-ingress/README.md +5 -1
- package/node_modules/@murphai/messaging-ingress/dist/linq-webhook.d.ts +27 -1
- package/node_modules/@murphai/messaging-ingress/dist/linq-webhook.d.ts.map +1 -1
- package/node_modules/@murphai/messaging-ingress/dist/linq-webhook.js +164 -17
- package/node_modules/@murphai/messaging-ingress/dist/linq-webhook.js.map +1 -1
- package/node_modules/@murphai/messaging-ingress/dist/telegram-webhook-payload.d.ts +1 -0
- package/node_modules/@murphai/messaging-ingress/dist/telegram-webhook-payload.d.ts.map +1 -1
- package/node_modules/@murphai/messaging-ingress/dist/telegram-webhook-payload.js +2 -0
- package/node_modules/@murphai/messaging-ingress/dist/telegram-webhook-payload.js.map +1 -1
- package/node_modules/@murphai/operator-config/dist/assistant/codex-resume-state.d.ts +3 -3
- package/node_modules/@murphai/operator-config/dist/assistant/codex-resume-state.d.ts.map +1 -1
- package/node_modules/@murphai/operator-config/dist/assistant/codex-resume-state.js +1 -1
- package/node_modules/@murphai/operator-config/dist/assistant/codex-resume-state.js.map +1 -1
- package/node_modules/@murphai/operator-config/dist/assistant/current-delivery-route.d.ts +1 -1
- package/node_modules/@murphai/operator-config/dist/assistant/current-delivery-route.d.ts.map +1 -1
- package/node_modules/@murphai/operator-config/dist/assistant/current-delivery-route.js +7 -19
- package/node_modules/@murphai/operator-config/dist/assistant/current-delivery-route.js.map +1 -1
- package/node_modules/@murphai/operator-config/dist/assistant/hosted-config.d.ts +31 -33
- package/node_modules/@murphai/operator-config/dist/assistant/hosted-config.d.ts.map +1 -1
- package/node_modules/@murphai/operator-config/dist/assistant/hosted-config.js +5 -8
- package/node_modules/@murphai/operator-config/dist/assistant/hosted-config.js.map +1 -1
- package/node_modules/@murphai/operator-config/dist/assistant/provider-config.d.ts +1 -15
- package/node_modules/@murphai/operator-config/dist/assistant/provider-config.d.ts.map +1 -1
- package/node_modules/@murphai/operator-config/dist/assistant/provider-config.js +52 -84
- package/node_modules/@murphai/operator-config/dist/assistant/provider-config.js.map +1 -1
- package/node_modules/@murphai/operator-config/dist/assistant/target-runtime.d.ts +31 -48
- package/node_modules/@murphai/operator-config/dist/assistant/target-runtime.d.ts.map +1 -1
- package/node_modules/@murphai/operator-config/dist/assistant/target-runtime.js +33 -56
- package/node_modules/@murphai/operator-config/dist/assistant/target-runtime.js.map +1 -1
- package/node_modules/@murphai/operator-config/dist/assistant-backend.d.ts +11 -11
- package/node_modules/@murphai/operator-config/dist/assistant-backend.d.ts.map +1 -1
- package/node_modules/@murphai/operator-config/dist/assistant-backend.js +33 -45
- package/node_modules/@murphai/operator-config/dist/assistant-backend.js.map +1 -1
- package/node_modules/@murphai/operator-config/dist/assistant-cli-contracts.d.ts +1713 -1566
- package/node_modules/@murphai/operator-config/dist/assistant-cli-contracts.d.ts.map +1 -1
- package/node_modules/@murphai/operator-config/dist/assistant-cli-contracts.js +193 -23
- package/node_modules/@murphai/operator-config/dist/assistant-cli-contracts.js.map +1 -1
- package/node_modules/@murphai/operator-config/dist/assistant-response-cards.d.ts +445 -0
- package/node_modules/@murphai/operator-config/dist/assistant-response-cards.d.ts.map +1 -0
- package/node_modules/@murphai/operator-config/dist/assistant-response-cards.js +1030 -0
- package/node_modules/@murphai/operator-config/dist/assistant-response-cards.js.map +1 -0
- package/node_modules/@murphai/operator-config/dist/command-helpers.d.ts +4 -2
- package/node_modules/@murphai/operator-config/dist/command-helpers.d.ts.map +1 -1
- package/node_modules/@murphai/operator-config/dist/command-helpers.js +36 -1
- package/node_modules/@murphai/operator-config/dist/command-helpers.js.map +1 -1
- package/node_modules/@murphai/operator-config/dist/device-cli-contracts.d.ts +181 -181
- package/node_modules/@murphai/operator-config/dist/device-cli-contracts.d.ts.map +1 -1
- package/node_modules/@murphai/operator-config/dist/device-cli-contracts.js +1 -1
- package/node_modules/@murphai/operator-config/dist/device-cli-contracts.js.map +1 -1
- package/node_modules/@murphai/operator-config/dist/device-sync-client.js +1 -1
- package/node_modules/@murphai/operator-config/dist/device-sync-client.js.map +1 -1
- package/node_modules/@murphai/operator-config/dist/elevenlabs-runtime.d.ts +3 -0
- package/node_modules/@murphai/operator-config/dist/elevenlabs-runtime.d.ts.map +1 -1
- package/node_modules/@murphai/operator-config/dist/elevenlabs-runtime.js +301 -63
- package/node_modules/@murphai/operator-config/dist/elevenlabs-runtime.js.map +1 -1
- package/node_modules/@murphai/operator-config/dist/hosted-assistant-config-constants.d.ts +3 -2
- package/node_modules/@murphai/operator-config/dist/hosted-assistant-config-constants.d.ts.map +1 -1
- package/node_modules/@murphai/operator-config/dist/hosted-assistant-config-constants.js +3 -0
- package/node_modules/@murphai/operator-config/dist/hosted-assistant-config-constants.js.map +1 -1
- package/node_modules/@murphai/operator-config/dist/hosted-assistant-config.d.ts.map +1 -1
- package/node_modules/@murphai/operator-config/dist/hosted-assistant-config.js +2 -6
- package/node_modules/@murphai/operator-config/dist/hosted-assistant-config.js.map +1 -1
- package/node_modules/@murphai/operator-config/dist/http-json-retry.d.ts +7 -2
- package/node_modules/@murphai/operator-config/dist/http-json-retry.d.ts.map +1 -1
- package/node_modules/@murphai/operator-config/dist/http-json-retry.js +33 -14
- package/node_modules/@murphai/operator-config/dist/http-json-retry.js.map +1 -1
- package/node_modules/@murphai/operator-config/dist/inbox-cli-contracts.d.ts +427 -462
- package/node_modules/@murphai/operator-config/dist/inbox-cli-contracts.d.ts.map +1 -1
- package/node_modules/@murphai/operator-config/dist/inbox-cli-contracts.js +2 -14
- package/node_modules/@murphai/operator-config/dist/inbox-cli-contracts.js.map +1 -1
- package/node_modules/@murphai/operator-config/dist/linq-runtime.d.ts +35 -1
- package/node_modules/@murphai/operator-config/dist/linq-runtime.d.ts.map +1 -1
- package/node_modules/@murphai/operator-config/dist/linq-runtime.js +1115 -180
- package/node_modules/@murphai/operator-config/dist/linq-runtime.js.map +1 -1
- package/node_modules/@murphai/operator-config/dist/message-formatting.d.ts +1 -0
- package/node_modules/@murphai/operator-config/dist/message-formatting.d.ts.map +1 -1
- package/node_modules/@murphai/operator-config/dist/message-formatting.js +3 -1
- package/node_modules/@murphai/operator-config/dist/message-formatting.js.map +1 -1
- package/node_modules/@murphai/operator-config/dist/message-table-fallback.d.ts +7 -0
- package/node_modules/@murphai/operator-config/dist/message-table-fallback.d.ts.map +1 -0
- package/node_modules/@murphai/operator-config/dist/message-table-fallback.js +109 -0
- package/node_modules/@murphai/operator-config/dist/message-table-fallback.js.map +1 -0
- package/node_modules/@murphai/operator-config/dist/operator-config/self-delivery-targets.d.ts +12 -12
- package/node_modules/@murphai/operator-config/dist/operator-config/self-delivery-targets.d.ts.map +1 -1
- package/node_modules/@murphai/operator-config/dist/operator-config/self-delivery-targets.js +1 -1
- package/node_modules/@murphai/operator-config/dist/operator-config/self-delivery-targets.js.map +1 -1
- package/node_modules/@murphai/operator-config/dist/operator-config.d.ts +50 -53
- package/node_modules/@murphai/operator-config/dist/operator-config.d.ts.map +1 -1
- package/node_modules/@murphai/operator-config/dist/operator-config.js +4 -5
- package/node_modules/@murphai/operator-config/dist/operator-config.js.map +1 -1
- package/node_modules/@murphai/operator-config/dist/setup-cli-contracts.d.ts +225 -226
- package/node_modules/@murphai/operator-config/dist/setup-cli-contracts.d.ts.map +1 -1
- package/node_modules/@murphai/operator-config/dist/setup-cli-contracts.js +2 -2
- package/node_modules/@murphai/operator-config/dist/setup-cli-contracts.js.map +1 -1
- package/node_modules/@murphai/operator-config/dist/setup-runtime-env.d.ts.map +1 -1
- package/node_modules/@murphai/operator-config/dist/setup-runtime-env.js +0 -19
- package/node_modules/@murphai/operator-config/dist/setup-runtime-env.js.map +1 -1
- package/node_modules/@murphai/operator-config/dist/vault-cli-contracts.d.ts +336 -294
- package/node_modules/@murphai/operator-config/dist/vault-cli-contracts.d.ts.map +1 -1
- package/node_modules/@murphai/operator-config/dist/vault-cli-contracts.js +36 -8
- package/node_modules/@murphai/operator-config/dist/vault-cli-contracts.js.map +1 -1
- package/node_modules/@murphai/operator-config/dist/workout-action-binding.d.ts +5 -0
- package/node_modules/@murphai/operator-config/dist/workout-action-binding.d.ts.map +1 -0
- package/node_modules/@murphai/operator-config/dist/workout-action-binding.js +84 -0
- package/node_modules/@murphai/operator-config/dist/workout-action-binding.js.map +1 -0
- package/node_modules/@murphai/operator-config/package.json +10 -5
- package/node_modules/@murphai/parsers/dist/adapters/ffmpeg.d.ts +2 -0
- package/node_modules/@murphai/parsers/dist/adapters/ffmpeg.d.ts.map +1 -1
- package/node_modules/@murphai/parsers/dist/adapters/ffmpeg.js +18 -0
- package/node_modules/@murphai/parsers/dist/adapters/ffmpeg.js.map +1 -1
- package/node_modules/@murphai/query/README.md +9 -0
- package/node_modules/@murphai/query/dist/automation.d.ts +5 -2
- package/node_modules/@murphai/query/dist/automation.d.ts.map +1 -1
- package/node_modules/@murphai/query/dist/automation.js +33 -8
- package/node_modules/@murphai/query/dist/automation.js.map +1 -1
- package/node_modules/@murphai/query/dist/browser-biomarkers.d.ts +2 -2
- package/node_modules/@murphai/query/dist/browser-biomarkers.d.ts.map +1 -1
- package/node_modules/@murphai/query/dist/browser-biomarkers.js +1 -1
- package/node_modules/@murphai/query/dist/browser-biomarkers.js.map +1 -1
- package/node_modules/@murphai/query/dist/browser-experiments.d.ts +2 -2
- package/node_modules/@murphai/query/dist/browser-experiments.d.ts.map +1 -1
- package/node_modules/@murphai/query/dist/browser-experiments.js +1 -1
- package/node_modules/@murphai/query/dist/browser-experiments.js.map +1 -1
- package/node_modules/@murphai/query/dist/browser-murph-age.d.ts +1 -1
- package/node_modules/@murphai/query/dist/browser-murph-age.d.ts.map +1 -1
- package/node_modules/@murphai/query/dist/browser-overview.d.ts +2 -1
- package/node_modules/@murphai/query/dist/browser-overview.d.ts.map +1 -1
- package/node_modules/@murphai/query/dist/browser-replica/biomarker-panel.d.ts +2 -2
- package/node_modules/@murphai/query/dist/browser-replica/biomarker-panel.d.ts.map +1 -1
- package/node_modules/@murphai/query/dist/browser-replica/build.d.ts.map +1 -1
- package/node_modules/@murphai/query/dist/browser-replica/build.js +45 -27
- package/node_modules/@murphai/query/dist/browser-replica/build.js.map +1 -1
- package/node_modules/@murphai/query/dist/browser-replica/client-overview.d.ts +3 -3
- package/node_modules/@murphai/query/dist/browser-replica/client-overview.d.ts.map +1 -1
- package/node_modules/@murphai/query/dist/browser-replica/client-overview.js +3 -0
- package/node_modules/@murphai/query/dist/browser-replica/client-overview.js.map +1 -1
- package/node_modules/@murphai/query/dist/browser-replica/device-metrics.d.ts +2 -2
- package/node_modules/@murphai/query/dist/browser-replica/device-metrics.d.ts.map +1 -1
- package/node_modules/@murphai/query/dist/browser-replica/device-metrics.js.map +1 -1
- package/node_modules/@murphai/query/dist/browser-replica/experiment-run-cards.d.ts +8 -0
- package/node_modules/@murphai/query/dist/browser-replica/experiment-run-cards.d.ts.map +1 -0
- package/node_modules/@murphai/query/dist/browser-replica/experiment-run-cards.js +548 -0
- package/node_modules/@murphai/query/dist/browser-replica/experiment-run-cards.js.map +1 -0
- package/node_modules/@murphai/query/dist/browser-replica/experiments.d.ts +22 -2
- package/node_modules/@murphai/query/dist/browser-replica/experiments.d.ts.map +1 -1
- package/node_modules/@murphai/query/dist/browser-replica/experiments.js +209 -63
- package/node_modules/@murphai/query/dist/browser-replica/experiments.js.map +1 -1
- package/node_modules/@murphai/query/dist/browser-replica/lab-result-status.d.ts +11 -0
- package/node_modules/@murphai/query/dist/browser-replica/lab-result-status.d.ts.map +1 -0
- package/node_modules/@murphai/query/dist/browser-replica/lab-result-status.js +233 -0
- package/node_modules/@murphai/query/dist/browser-replica/lab-result-status.js.map +1 -0
- package/node_modules/@murphai/query/dist/browser-replica/lab-results.d.ts +4 -3
- package/node_modules/@murphai/query/dist/browser-replica/lab-results.d.ts.map +1 -1
- package/node_modules/@murphai/query/dist/browser-replica/lab-results.js +24 -5
- package/node_modules/@murphai/query/dist/browser-replica/lab-results.js.map +1 -1
- package/node_modules/@murphai/query/dist/browser-replica/metric-buckets.d.ts +14 -0
- package/node_modules/@murphai/query/dist/browser-replica/metric-buckets.d.ts.map +1 -0
- package/node_modules/@murphai/query/dist/browser-replica/metric-buckets.js +25 -0
- package/node_modules/@murphai/query/dist/browser-replica/metric-buckets.js.map +1 -0
- package/node_modules/@murphai/query/dist/browser-replica/murph-age.d.ts +2 -2
- package/node_modules/@murphai/query/dist/browser-replica/murph-age.d.ts.map +1 -1
- package/node_modules/@murphai/query/dist/browser-replica/murph-age.js.map +1 -1
- package/node_modules/@murphai/query/dist/browser-replica/parse.d.ts +8 -0
- package/node_modules/@murphai/query/dist/browser-replica/parse.d.ts.map +1 -1
- package/node_modules/@murphai/query/dist/browser-replica/parse.js +327 -7
- package/node_modules/@murphai/query/dist/browser-replica/parse.js.map +1 -1
- package/node_modules/@murphai/query/dist/browser-replica/query.d.ts +24 -1
- package/node_modules/@murphai/query/dist/browser-replica/query.d.ts.map +1 -1
- package/node_modules/@murphai/query/dist/browser-replica/query.js +246 -41
- package/node_modules/@murphai/query/dist/browser-replica/query.js.map +1 -1
- package/node_modules/@murphai/query/dist/browser-replica/search-row.d.ts +3 -0
- package/node_modules/@murphai/query/dist/browser-replica/search-row.d.ts.map +1 -0
- package/node_modules/@murphai/query/dist/browser-replica/search-row.js +16 -0
- package/node_modules/@murphai/query/dist/browser-replica/search-row.js.map +1 -0
- package/node_modules/@murphai/query/dist/browser-replica/shards.d.ts +76 -0
- package/node_modules/@murphai/query/dist/browser-replica/shards.d.ts.map +1 -0
- package/node_modules/@murphai/query/dist/browser-replica/shards.js +232 -0
- package/node_modules/@murphai/query/dist/browser-replica/shards.js.map +1 -0
- package/node_modules/@murphai/query/dist/browser-replica/shared.d.ts +143 -9
- package/node_modules/@murphai/query/dist/browser-replica/shared.d.ts.map +1 -1
- package/node_modules/@murphai/query/dist/browser-replica/shared.js +1 -0
- package/node_modules/@murphai/query/dist/browser-replica/shared.js.map +1 -1
- package/node_modules/@murphai/query/dist/browser-replica/tracked-experiments.d.ts +3 -3
- package/node_modules/@murphai/query/dist/browser-replica/tracked-experiments.d.ts.map +1 -1
- package/node_modules/@murphai/query/dist/browser-replica/tracked-experiments.js.map +1 -1
- package/node_modules/@murphai/query/dist/browser-replica/training.d.ts +7 -0
- package/node_modules/@murphai/query/dist/browser-replica/training.d.ts.map +1 -0
- package/node_modules/@murphai/query/dist/browser-replica/training.js +241 -0
- package/node_modules/@murphai/query/dist/browser-replica/training.js.map +1 -0
- package/node_modules/@murphai/query/dist/browser-replica/views.d.ts +5 -5
- package/node_modules/@murphai/query/dist/browser-replica/views.d.ts.map +1 -1
- package/node_modules/@murphai/query/dist/browser-replica/views.js +3 -0
- package/node_modules/@murphai/query/dist/browser-replica/views.js.map +1 -1
- package/node_modules/@murphai/query/dist/browser-replica-client.d.ts +11 -4
- package/node_modules/@murphai/query/dist/browser-replica-client.d.ts.map +1 -1
- package/node_modules/@murphai/query/dist/browser-replica-client.js +7 -3
- package/node_modules/@murphai/query/dist/browser-replica-client.js.map +1 -1
- package/node_modules/@murphai/query/dist/browser-replica-server.d.ts +5 -0
- package/node_modules/@murphai/query/dist/browser-replica-server.d.ts.map +1 -0
- package/node_modules/@murphai/query/dist/browser-replica-server.js +5 -0
- package/node_modules/@murphai/query/dist/browser-replica-server.js.map +1 -0
- package/node_modules/@murphai/query/dist/browser-replica.d.ts +13 -5
- package/node_modules/@murphai/query/dist/browser-replica.d.ts.map +1 -1
- package/node_modules/@murphai/query/dist/browser-replica.js +9 -4
- package/node_modules/@murphai/query/dist/browser-replica.js.map +1 -1
- package/node_modules/@murphai/query/dist/browser.d.ts +2 -2
- package/node_modules/@murphai/query/dist/browser.d.ts.map +1 -1
- package/node_modules/@murphai/query/dist/browser.js +1 -1
- package/node_modules/@murphai/query/dist/browser.js.map +1 -1
- package/node_modules/@murphai/query/dist/canonical-observation-metrics.d.ts +16 -0
- package/node_modules/@murphai/query/dist/canonical-observation-metrics.d.ts.map +1 -0
- package/node_modules/@murphai/query/dist/canonical-observation-metrics.js +70 -0
- package/node_modules/@murphai/query/dist/canonical-observation-metrics.js.map +1 -0
- package/node_modules/@murphai/query/dist/experiment-adherence.d.ts +20 -0
- package/node_modules/@murphai/query/dist/experiment-adherence.d.ts.map +1 -1
- package/node_modules/@murphai/query/dist/experiment-adherence.js +175 -29
- package/node_modules/@murphai/query/dist/experiment-adherence.js.map +1 -1
- package/node_modules/@murphai/query/dist/experiment-progress-card.d.ts +1 -0
- package/node_modules/@murphai/query/dist/experiment-progress-card.d.ts.map +1 -1
- package/node_modules/@murphai/query/dist/experiment-progress-card.js +1 -0
- package/node_modules/@murphai/query/dist/experiment-progress-card.js.map +1 -1
- package/node_modules/@murphai/query/dist/experiments.d.ts.map +1 -1
- package/node_modules/@murphai/query/dist/experiments.js +46 -22
- package/node_modules/@murphai/query/dist/experiments.js.map +1 -1
- package/node_modules/@murphai/query/dist/group-weekly.d.ts.map +1 -1
- package/node_modules/@murphai/query/dist/group-weekly.js +52 -1
- package/node_modules/@murphai/query/dist/group-weekly.js.map +1 -1
- package/node_modules/@murphai/query/dist/health/shared.js +1 -1
- package/node_modules/@murphai/query/dist/health/shared.js.map +1 -1
- package/node_modules/@murphai/query/dist/index.d.ts +21 -4
- package/node_modules/@murphai/query/dist/index.d.ts.map +1 -1
- package/node_modules/@murphai/query/dist/index.js +14 -3
- package/node_modules/@murphai/query/dist/index.js.map +1 -1
- package/node_modules/@murphai/query/dist/knowledge-contracts.d.ts +78 -75
- package/node_modules/@murphai/query/dist/knowledge-contracts.d.ts.map +1 -1
- package/node_modules/@murphai/query/dist/knowledge-contracts.js +2 -1
- package/node_modules/@murphai/query/dist/knowledge-contracts.js.map +1 -1
- package/node_modules/@murphai/query/dist/knowledge-graph.d.ts +1 -0
- package/node_modules/@murphai/query/dist/knowledge-graph.d.ts.map +1 -1
- package/node_modules/@murphai/query/dist/knowledge-graph.js +17 -1
- package/node_modules/@murphai/query/dist/knowledge-graph.js.map +1 -1
- package/node_modules/@murphai/query/dist/meal-nutrition.d.ts +26 -0
- package/node_modules/@murphai/query/dist/meal-nutrition.d.ts.map +1 -1
- package/node_modules/@murphai/query/dist/meal-nutrition.js +111 -5
- package/node_modules/@murphai/query/dist/meal-nutrition.js.map +1 -1
- package/node_modules/@murphai/query/dist/metrics/index.d.ts.map +1 -1
- package/node_modules/@murphai/query/dist/metrics/index.js +14 -1
- package/node_modules/@murphai/query/dist/metrics/index.js.map +1 -1
- package/node_modules/@murphai/query/dist/metrics/projection.d.ts.map +1 -1
- package/node_modules/@murphai/query/dist/metrics/projection.js +110 -3
- package/node_modules/@murphai/query/dist/metrics/projection.js.map +1 -1
- package/node_modules/@murphai/query/dist/personal-patterns.d.ts +55 -0
- package/node_modules/@murphai/query/dist/personal-patterns.d.ts.map +1 -0
- package/node_modules/@murphai/query/dist/personal-patterns.js +401 -0
- package/node_modules/@murphai/query/dist/personal-patterns.js.map +1 -0
- package/node_modules/@murphai/query/dist/projection/schema.d.ts +1 -1
- package/node_modules/@murphai/query/dist/projection/schema.d.ts.map +1 -1
- package/node_modules/@murphai/query/dist/projection/schema.js +3 -1
- package/node_modules/@murphai/query/dist/projection/schema.js.map +1 -1
- package/node_modules/@murphai/query/dist/projection/wearable-summary-compose.js +4 -0
- package/node_modules/@murphai/query/dist/projection/wearable-summary-compose.js.map +1 -1
- package/node_modules/@murphai/query/dist/projection/wearable-summary-projector.d.ts.map +1 -1
- package/node_modules/@murphai/query/dist/projection/wearable-summary-projector.js +2 -2
- package/node_modules/@murphai/query/dist/projection/wearable-summary-projector.js.map +1 -1
- package/node_modules/@murphai/query/dist/projection/wearable-summary-stored-codec.js +1 -1
- package/node_modules/@murphai/query/dist/projection/wearable-summary-stored-codec.js.map +1 -1
- package/node_modules/@murphai/query/dist/query-projection.d.ts +14 -0
- package/node_modules/@murphai/query/dist/query-projection.d.ts.map +1 -1
- package/node_modules/@murphai/query/dist/query-projection.js +31 -0
- package/node_modules/@murphai/query/dist/query-projection.js.map +1 -1
- package/node_modules/@murphai/query/dist/wearables/candidates.d.ts.map +1 -1
- package/node_modules/@murphai/query/dist/wearables/candidates.js +6 -0
- package/node_modules/@murphai/query/dist/wearables/candidates.js.map +1 -1
- package/node_modules/@murphai/query/dist/wearables/public-output.d.ts.map +1 -1
- package/node_modules/@murphai/query/dist/wearables/public-output.js +37 -2
- package/node_modules/@murphai/query/dist/wearables/public-output.js.map +1 -1
- package/node_modules/@murphai/query/dist/wearables/sleep-pattern.d.ts +5 -1
- package/node_modules/@murphai/query/dist/wearables/sleep-pattern.d.ts.map +1 -1
- package/node_modules/@murphai/query/dist/wearables/sleep-pattern.js +16 -3
- package/node_modules/@murphai/query/dist/wearables/sleep-pattern.js.map +1 -1
- package/node_modules/@murphai/query/dist/wearables/source-health.d.ts.map +1 -1
- package/node_modules/@murphai/query/dist/wearables/source-health.js +27 -4
- package/node_modules/@murphai/query/dist/wearables/source-health.js.map +1 -1
- package/node_modules/@murphai/query/dist/wearables/types.d.ts +17 -4
- package/node_modules/@murphai/query/dist/wearables/types.d.ts.map +1 -1
- package/node_modules/@murphai/query/dist/wearables/types.js +34 -0
- package/node_modules/@murphai/query/dist/wearables/types.js.map +1 -1
- package/node_modules/@murphai/query/dist/wearables.d.ts.map +1 -1
- package/node_modules/@murphai/query/dist/wearables.js +55 -4
- package/node_modules/@murphai/query/dist/wearables.js.map +1 -1
- package/node_modules/@murphai/query/package.json +10 -0
- package/node_modules/@murphai/runtime-state/README.md +2 -2
- package/node_modules/@murphai/runtime-state/dist/assistant-local-state-descriptors.d.ts.map +1 -1
- package/node_modules/@murphai/runtime-state/dist/assistant-local-state-descriptors.js +15 -2
- package/node_modules/@murphai/runtime-state/dist/assistant-local-state-descriptors.js.map +1 -1
- package/node_modules/@murphai/runtime-state/dist/hosted-bundles.d.ts +1 -0
- package/node_modules/@murphai/runtime-state/dist/hosted-bundles.d.ts.map +1 -1
- package/node_modules/@murphai/runtime-state/dist/hosted-bundles.js +45 -20
- package/node_modules/@murphai/runtime-state/dist/hosted-bundles.js.map +1 -1
- package/node_modules/@murphai/runtime-state/dist/hosted-crypto-keyrings.d.ts +32 -1
- package/node_modules/@murphai/runtime-state/dist/hosted-crypto-keyrings.d.ts.map +1 -1
- package/node_modules/@murphai/runtime-state/dist/hosted-crypto-keyrings.js +327 -0
- package/node_modules/@murphai/runtime-state/dist/hosted-crypto-keyrings.js.map +1 -1
- package/node_modules/@murphai/runtime-state/dist/hosted-domain-crypto.d.ts +3 -1
- package/node_modules/@murphai/runtime-state/dist/hosted-domain-crypto.d.ts.map +1 -1
- package/node_modules/@murphai/runtime-state/dist/hosted-domain-crypto.js +23 -3
- package/node_modules/@murphai/runtime-state/dist/hosted-domain-crypto.js.map +1 -1
- package/node_modules/@murphai/runtime-state/dist/hosted-storage.d.ts +1 -1
- package/node_modules/@murphai/runtime-state/dist/hosted-storage.d.ts.map +1 -1
- package/node_modules/@murphai/runtime-state/dist/hosted-storage.js +1 -0
- package/node_modules/@murphai/runtime-state/dist/hosted-storage.js.map +1 -1
- package/node_modules/@murphai/runtime-state/dist/sqlite.d.ts.map +1 -1
- package/node_modules/@murphai/runtime-state/dist/sqlite.js +22 -6
- package/node_modules/@murphai/runtime-state/dist/sqlite.js.map +1 -1
- package/node_modules/@murphai/setup-cli/README.md +1 -1
- package/node_modules/@murphai/setup-cli/dist/index.d.ts +0 -1
- package/node_modules/@murphai/setup-cli/dist/index.d.ts.map +1 -1
- package/node_modules/@murphai/setup-cli/dist/index.js +0 -1
- package/node_modules/@murphai/setup-cli/dist/index.js.map +1 -1
- package/node_modules/@murphai/setup-cli/dist/setup-assistant-account.js +1 -1
- package/node_modules/@murphai/setup-cli/dist/setup-assistant-account.js.map +1 -1
- package/node_modules/@murphai/setup-cli/dist/setup-assistant-defaults.d.ts.map +1 -1
- package/node_modules/@murphai/setup-cli/dist/setup-assistant-defaults.js +14 -24
- package/node_modules/@murphai/setup-cli/dist/setup-assistant-defaults.js.map +1 -1
- package/node_modules/@murphai/setup-cli/dist/setup-assistant.js +1 -1
- package/node_modules/@murphai/setup-cli/dist/setup-assistant.js.map +1 -1
- package/node_modules/@murphai/setup-cli/dist/setup-cli.d.ts +1 -2
- package/node_modules/@murphai/setup-cli/dist/setup-cli.d.ts.map +1 -1
- package/node_modules/@murphai/setup-cli/dist/setup-cli.js +2 -4
- package/node_modules/@murphai/setup-cli/dist/setup-cli.js.map +1 -1
- package/node_modules/@murphai/setup-cli/dist/setup-services/channels.d.ts +0 -4
- package/node_modules/@murphai/setup-cli/dist/setup-services/channels.d.ts.map +1 -1
- package/node_modules/@murphai/setup-cli/dist/setup-services/channels.js +126 -420
- package/node_modules/@murphai/setup-cli/dist/setup-services/channels.js.map +1 -1
- package/node_modules/@murphai/setup-cli/dist/setup-services.d.ts +0 -3
- package/node_modules/@murphai/setup-cli/dist/setup-services.d.ts.map +1 -1
- package/node_modules/@murphai/setup-cli/dist/setup-services.js +0 -7
- package/node_modules/@murphai/setup-cli/dist/setup-services.js.map +1 -1
- package/node_modules/@murphai/setup-cli/dist/setup-wizard-options.d.ts.map +1 -1
- package/node_modules/@murphai/setup-cli/dist/setup-wizard-options.js +0 -7
- package/node_modules/@murphai/setup-cli/dist/setup-wizard-options.js.map +1 -1
- package/node_modules/@murphai/vault-usecases/dist/clinical-records.js +1 -1
- package/node_modules/@murphai/vault-usecases/dist/clinical-records.js.map +1 -1
- package/node_modules/@murphai/vault-usecases/dist/experiment-onboarding-options.d.ts +3 -3
- package/node_modules/@murphai/vault-usecases/dist/experiment-onboarding-options.d.ts.map +1 -1
- package/node_modules/@murphai/vault-usecases/dist/experiment-onboarding-options.js +1 -1
- package/node_modules/@murphai/vault-usecases/dist/experiment-onboarding-options.js.map +1 -1
- package/node_modules/@murphai/vault-usecases/dist/export-packs.d.ts +7 -0
- package/node_modules/@murphai/vault-usecases/dist/export-packs.d.ts.map +1 -0
- package/node_modules/@murphai/vault-usecases/dist/export-packs.js +45 -0
- package/node_modules/@murphai/vault-usecases/dist/export-packs.js.map +1 -0
- package/node_modules/@murphai/vault-usecases/dist/health-cli-descriptors.d.ts +28 -28
- package/node_modules/@murphai/vault-usecases/dist/health-cli-descriptors.d.ts.map +1 -1
- package/node_modules/@murphai/vault-usecases/dist/health-cli-descriptors.js +1 -1
- package/node_modules/@murphai/vault-usecases/dist/health-cli-descriptors.js.map +1 -1
- package/node_modules/@murphai/vault-usecases/dist/json-input.d.ts +1 -1
- package/node_modules/@murphai/vault-usecases/dist/json-input.d.ts.map +1 -1
- package/node_modules/@murphai/vault-usecases/dist/json-input.js +1 -1
- package/node_modules/@murphai/vault-usecases/dist/json-input.js.map +1 -1
- package/node_modules/@murphai/vault-usecases/dist/query-runtime.d.ts +5 -1
- package/node_modules/@murphai/vault-usecases/dist/query-runtime.d.ts.map +1 -1
- package/node_modules/@murphai/vault-usecases/dist/query-runtime.js.map +1 -1
- package/node_modules/@murphai/vault-usecases/dist/testing/junction-wearable-fixture.d.ts +1 -1
- package/node_modules/@murphai/vault-usecases/dist/testing/junction-wearable-fixture.d.ts.map +1 -1
- package/node_modules/@murphai/vault-usecases/dist/usecases/capture.d.ts +21 -21
- package/node_modules/@murphai/vault-usecases/dist/usecases/capture.d.ts.map +1 -1
- package/node_modules/@murphai/vault-usecases/dist/usecases/capture.js +1 -1
- package/node_modules/@murphai/vault-usecases/dist/usecases/capture.js.map +1 -1
- package/node_modules/@murphai/vault-usecases/dist/usecases/clinical-imports.d.ts +193 -193
- package/node_modules/@murphai/vault-usecases/dist/usecases/clinical-imports.d.ts.map +1 -1
- package/node_modules/@murphai/vault-usecases/dist/usecases/clinical-imports.js +1 -1
- package/node_modules/@murphai/vault-usecases/dist/usecases/clinical-imports.js.map +1 -1
- package/node_modules/@murphai/vault-usecases/dist/usecases/document-meal-read.d.ts +12 -12
- package/node_modules/@murphai/vault-usecases/dist/usecases/document-meal-read.d.ts.map +1 -1
- package/node_modules/@murphai/vault-usecases/dist/usecases/document-meal-read.js +1 -1
- package/node_modules/@murphai/vault-usecases/dist/usecases/document-meal-read.js.map +1 -1
- package/node_modules/@murphai/vault-usecases/dist/usecases/encounter.d.ts +130 -130
- package/node_modules/@murphai/vault-usecases/dist/usecases/encounter.d.ts.map +1 -1
- package/node_modules/@murphai/vault-usecases/dist/usecases/encounter.js +1 -1
- package/node_modules/@murphai/vault-usecases/dist/usecases/encounter.js.map +1 -1
- package/node_modules/@murphai/vault-usecases/dist/usecases/event-record-mutations.d.ts +1 -0
- package/node_modules/@murphai/vault-usecases/dist/usecases/event-record-mutations.d.ts.map +1 -1
- package/node_modules/@murphai/vault-usecases/dist/usecases/event-record-mutations.js +22 -0
- package/node_modules/@murphai/vault-usecases/dist/usecases/event-record-mutations.js.map +1 -1
- package/node_modules/@murphai/vault-usecases/dist/usecases/experiment-journal-vault.d.ts +28 -5
- package/node_modules/@murphai/vault-usecases/dist/usecases/experiment-journal-vault.d.ts.map +1 -1
- package/node_modules/@murphai/vault-usecases/dist/usecases/experiment-journal-vault.js +225 -37
- package/node_modules/@murphai/vault-usecases/dist/usecases/experiment-journal-vault.js.map +1 -1
- package/node_modules/@murphai/vault-usecases/dist/usecases/food-autolog.d.ts +1 -1
- package/node_modules/@murphai/vault-usecases/dist/usecases/food-autolog.d.ts.map +1 -1
- package/node_modules/@murphai/vault-usecases/dist/usecases/food-autolog.js +1 -1
- package/node_modules/@murphai/vault-usecases/dist/usecases/food-autolog.js.map +1 -1
- package/node_modules/@murphai/vault-usecases/dist/usecases/food.d.ts.map +1 -1
- package/node_modules/@murphai/vault-usecases/dist/usecases/food.js +0 -1
- package/node_modules/@murphai/vault-usecases/dist/usecases/food.js.map +1 -1
- package/node_modules/@murphai/vault-usecases/dist/usecases/integrated-services.d.ts.map +1 -1
- package/node_modules/@murphai/vault-usecases/dist/usecases/integrated-services.js +77 -9
- package/node_modules/@murphai/vault-usecases/dist/usecases/integrated-services.js.map +1 -1
- package/node_modules/@murphai/vault-usecases/dist/usecases/measurement-read.d.ts +95 -13
- package/node_modules/@murphai/vault-usecases/dist/usecases/measurement-read.d.ts.map +1 -1
- package/node_modules/@murphai/vault-usecases/dist/usecases/measurement-read.js +136 -3
- package/node_modules/@murphai/vault-usecases/dist/usecases/measurement-read.js.map +1 -1
- package/node_modules/@murphai/vault-usecases/dist/usecases/measurement.d.ts.map +1 -1
- package/node_modules/@murphai/vault-usecases/dist/usecases/measurement.js +3 -1
- package/node_modules/@murphai/vault-usecases/dist/usecases/measurement.js.map +1 -1
- package/node_modules/@murphai/vault-usecases/dist/usecases/provider-event.d.ts +4 -4
- package/node_modules/@murphai/vault-usecases/dist/usecases/provider-event.d.ts.map +1 -1
- package/node_modules/@murphai/vault-usecases/dist/usecases/provider-event.js +1 -1
- package/node_modules/@murphai/vault-usecases/dist/usecases/provider-event.js.map +1 -1
- package/node_modules/@murphai/vault-usecases/dist/usecases/recipe.d.ts +3 -3
- package/node_modules/@murphai/vault-usecases/dist/usecases/recipe.d.ts.map +1 -1
- package/node_modules/@murphai/vault-usecases/dist/usecases/recipe.js +1 -1
- package/node_modules/@murphai/vault-usecases/dist/usecases/recipe.js.map +1 -1
- package/node_modules/@murphai/vault-usecases/dist/usecases/runtime.d.ts.map +1 -1
- package/node_modules/@murphai/vault-usecases/dist/usecases/runtime.js +2 -0
- package/node_modules/@murphai/vault-usecases/dist/usecases/runtime.js.map +1 -1
- package/node_modules/@murphai/vault-usecases/dist/usecases/types.d.ts +44 -1
- package/node_modules/@murphai/vault-usecases/dist/usecases/types.d.ts.map +1 -1
- package/node_modules/@murphai/vault-usecases/dist/usecases/workout-core.d.ts +7 -1
- package/node_modules/@murphai/vault-usecases/dist/usecases/workout-core.d.ts.map +1 -1
- package/node_modules/@murphai/vault-usecases/dist/usecases/workout-core.js.map +1 -1
- package/node_modules/@murphai/vault-usecases/dist/usecases/workout-format.d.ts +2 -0
- package/node_modules/@murphai/vault-usecases/dist/usecases/workout-format.d.ts.map +1 -1
- package/node_modules/@murphai/vault-usecases/dist/usecases/workout-import.d.ts +60 -7
- package/node_modules/@murphai/vault-usecases/dist/usecases/workout-import.d.ts.map +1 -1
- package/node_modules/@murphai/vault-usecases/dist/usecases/workout-import.js +1282 -494
- package/node_modules/@murphai/vault-usecases/dist/usecases/workout-import.js.map +1 -1
- package/node_modules/@murphai/vault-usecases/dist/usecases/workout-live-model.d.ts +84 -0
- package/node_modules/@murphai/vault-usecases/dist/usecases/workout-live-model.d.ts.map +1 -0
- package/node_modules/@murphai/vault-usecases/dist/usecases/workout-live-model.js +195 -0
- package/node_modules/@murphai/vault-usecases/dist/usecases/workout-live-model.js.map +1 -0
- package/node_modules/@murphai/vault-usecases/dist/usecases/workout-live-state.d.ts +36 -0
- package/node_modules/@murphai/vault-usecases/dist/usecases/workout-live-state.d.ts.map +1 -0
- package/node_modules/@murphai/vault-usecases/dist/usecases/workout-live-state.js +285 -0
- package/node_modules/@murphai/vault-usecases/dist/usecases/workout-live-state.js.map +1 -0
- package/node_modules/@murphai/vault-usecases/dist/usecases/workout-live.d.ts +122 -0
- package/node_modules/@murphai/vault-usecases/dist/usecases/workout-live.d.ts.map +1 -0
- package/node_modules/@murphai/vault-usecases/dist/usecases/workout-live.js +507 -0
- package/node_modules/@murphai/vault-usecases/dist/usecases/workout-live.js.map +1 -0
- package/node_modules/@murphai/vault-usecases/dist/usecases/workout-model.d.ts +1 -1
- package/node_modules/@murphai/vault-usecases/dist/usecases/workout-model.d.ts.map +1 -1
- package/node_modules/@murphai/vault-usecases/dist/usecases/workout-model.js +2 -0
- package/node_modules/@murphai/vault-usecases/dist/usecases/workout-model.js.map +1 -1
- package/node_modules/@murphai/vault-usecases/dist/usecases/workout-read.d.ts +13 -13
- package/node_modules/@murphai/vault-usecases/dist/usecases/workout-read.d.ts.map +1 -1
- package/node_modules/@murphai/vault-usecases/dist/usecases/workout-read.js +3 -2
- package/node_modules/@murphai/vault-usecases/dist/usecases/workout-read.js.map +1 -1
- package/node_modules/@murphai/vault-usecases/dist/usecases/workout.d.ts +25 -1
- package/node_modules/@murphai/vault-usecases/dist/usecases/workout.d.ts.map +1 -1
- package/node_modules/@murphai/vault-usecases/dist/usecases/workout.js +118 -3
- package/node_modules/@murphai/vault-usecases/dist/usecases/workout.js.map +1 -1
- package/node_modules/@murphai/vault-usecases/dist/vault-services.d.ts.map +1 -1
- package/node_modules/@murphai/vault-usecases/dist/vault-services.js +3 -0
- package/node_modules/@murphai/vault-usecases/dist/vault-services.js.map +1 -1
- package/node_modules/@murphai/vault-usecases/dist/workouts.d.ts +1 -0
- package/node_modules/@murphai/vault-usecases/dist/workouts.d.ts.map +1 -1
- package/node_modules/@murphai/vault-usecases/dist/workouts.js +1 -0
- package/node_modules/@murphai/vault-usecases/dist/workouts.js.map +1 -1
- package/node_modules/@murphai/vault-usecases/package.json +4 -0
- package/node_modules/ink/build/ansi-tokenizer.d.ts +38 -0
- package/node_modules/ink/build/ansi-tokenizer.js +316 -0
- package/node_modules/ink/build/ansi-tokenizer.js.map +1 -0
- package/node_modules/ink/build/apply-styles.js +175 -0
- package/node_modules/ink/build/build-layout.js +77 -0
- package/node_modules/ink/build/calculate-wrapped-text.js +53 -0
- package/node_modules/ink/build/colorize.d.ts +3 -0
- package/node_modules/ink/build/colorize.js +48 -0
- package/node_modules/ink/build/colorize.js.map +1 -0
- package/node_modules/ink/build/components/AccessibilityContext.d.ts +3 -0
- package/node_modules/ink/build/components/AccessibilityContext.js +5 -0
- package/node_modules/ink/build/components/AccessibilityContext.js.map +1 -0
- package/node_modules/ink/build/components/App.d.ts +18 -0
- package/node_modules/ink/build/components/App.js +351 -0
- package/node_modules/ink/build/components/App.js.map +1 -0
- package/node_modules/ink/build/components/AppContext.d.ts +15 -0
- package/node_modules/ink/build/components/AppContext.js +11 -0
- package/node_modules/ink/build/components/AppContext.js.map +1 -0
- package/node_modules/ink/build/components/BackgroundContext.d.ts +4 -0
- package/node_modules/ink/build/components/BackgroundContext.js +3 -0
- package/node_modules/ink/build/components/BackgroundContext.js.map +1 -0
- package/node_modules/ink/build/components/Box.d.ts +117 -0
- package/node_modules/ink/build/components/Box.js +34 -0
- package/node_modules/ink/build/components/Box.js.map +1 -0
- package/node_modules/ink/build/components/Color.js +62 -0
- package/node_modules/ink/build/components/Cursor.d.ts +83 -0
- package/node_modules/ink/build/components/Cursor.js +53 -0
- package/node_modules/ink/build/components/Cursor.js.map +1 -0
- package/node_modules/ink/build/components/CursorContext.d.ts +11 -0
- package/node_modules/ink/build/components/CursorContext.js +8 -0
- package/node_modules/ink/build/components/CursorContext.js.map +1 -0
- package/node_modules/ink/build/components/ErrorBoundary.d.ts +18 -0
- package/node_modules/ink/build/components/ErrorBoundary.js +23 -0
- package/node_modules/ink/build/components/ErrorBoundary.js.map +1 -0
- package/node_modules/ink/build/components/ErrorOverview.d.ts +6 -0
- package/node_modules/ink/build/components/ErrorOverview.js +84 -0
- package/node_modules/ink/build/components/ErrorOverview.js.map +1 -0
- package/node_modules/ink/build/components/FocusContext.d.ts +16 -0
- package/node_modules/ink/build/components/FocusContext.js +17 -0
- package/node_modules/ink/build/components/FocusContext.js.map +1 -0
- package/node_modules/ink/build/components/Newline.d.ts +13 -0
- package/node_modules/ink/build/components/Newline.js +8 -0
- package/node_modules/ink/build/components/Newline.js.map +1 -0
- package/node_modules/ink/build/components/Spacer.d.ts +7 -0
- package/node_modules/ink/build/components/Spacer.js +11 -0
- package/node_modules/ink/build/components/Spacer.js.map +1 -0
- package/node_modules/ink/build/components/Static.d.ts +24 -0
- package/node_modules/ink/build/components/Static.js +28 -0
- package/node_modules/ink/build/components/Static.js.map +1 -0
- package/node_modules/ink/build/components/StderrContext.d.ts +15 -0
- package/node_modules/ink/build/components/StderrContext.js +13 -0
- package/node_modules/ink/build/components/StderrContext.js.map +1 -0
- package/node_modules/ink/build/components/StdinContext.d.ts +22 -0
- package/node_modules/ink/build/components/StdinContext.js +19 -0
- package/node_modules/ink/build/components/StdinContext.js.map +1 -0
- package/node_modules/ink/build/components/StdoutContext.d.ts +15 -0
- package/node_modules/ink/build/components/StdoutContext.js +13 -0
- package/node_modules/ink/build/components/StdoutContext.js.map +1 -0
- package/node_modules/ink/build/components/Text.d.ts +55 -0
- package/node_modules/ink/build/components/Text.js +50 -0
- package/node_modules/ink/build/components/Text.js.map +1 -0
- package/node_modules/ink/build/components/Transform.d.ts +16 -0
- package/node_modules/ink/build/components/Transform.js +15 -0
- package/node_modules/ink/build/components/Transform.js.map +1 -0
- package/node_modules/ink/build/cursor-helpers.d.ts +38 -0
- package/node_modules/ink/build/cursor-helpers.js +56 -0
- package/node_modules/ink/build/cursor-helpers.js.map +1 -0
- package/node_modules/ink/build/devtools-window-polyfill.d.ts +1 -0
- package/node_modules/ink/build/devtools-window-polyfill.js +65 -0
- package/node_modules/ink/build/devtools-window-polyfill.js.map +1 -0
- package/node_modules/ink/build/devtools.d.ts +1 -0
- package/node_modules/ink/build/devtools.js +11 -0
- package/node_modules/ink/build/devtools.js.map +1 -0
- package/node_modules/ink/build/dom.d.ts +56 -0
- package/node_modules/ink/build/dom.js +124 -0
- package/node_modules/ink/build/dom.js.map +1 -0
- package/node_modules/ink/build/experimental/apply-style.js +140 -0
- package/node_modules/ink/build/experimental/dom.js +123 -0
- package/node_modules/ink/build/experimental/output.js +91 -0
- package/node_modules/ink/build/experimental/reconciler.js +141 -0
- package/node_modules/ink/build/experimental/renderer.js +81 -0
- package/node_modules/ink/build/get-max-width.d.ts +3 -0
- package/node_modules/ink/build/get-max-width.js +10 -0
- package/node_modules/ink/build/get-max-width.js.map +1 -0
- package/node_modules/ink/build/hooks/use-app.d.ts +5 -0
- package/node_modules/ink/build/hooks/use-app.js +8 -0
- package/node_modules/ink/build/hooks/use-app.js.map +1 -0
- package/node_modules/ink/build/hooks/use-cursor.d.ts +12 -0
- package/node_modules/ink/build/hooks/use-cursor.js +29 -0
- package/node_modules/ink/build/hooks/use-cursor.js.map +1 -0
- package/node_modules/ink/build/hooks/use-focus-manager.d.ts +28 -0
- package/node_modules/ink/build/hooks/use-focus-manager.js +17 -0
- package/node_modules/ink/build/hooks/use-focus-manager.js.map +1 -0
- package/node_modules/ink/build/hooks/use-focus.d.ts +29 -0
- package/node_modules/ink/build/hooks/use-focus.js +42 -0
- package/node_modules/ink/build/hooks/use-focus.js.map +1 -0
- package/node_modules/ink/build/hooks/use-input.d.ts +131 -0
- package/node_modules/ink/build/hooks/use-input.js +124 -0
- package/node_modules/ink/build/hooks/use-input.js.map +1 -0
- package/node_modules/ink/build/hooks/use-is-screen-reader-enabled.d.ts +5 -0
- package/node_modules/ink/build/hooks/use-is-screen-reader-enabled.js +11 -0
- package/node_modules/ink/build/hooks/use-is-screen-reader-enabled.js.map +1 -0
- package/node_modules/ink/build/hooks/use-stderr.d.ts +5 -0
- package/node_modules/ink/build/hooks/use-stderr.js +8 -0
- package/node_modules/ink/build/hooks/use-stderr.js.map +1 -0
- package/node_modules/ink/build/hooks/use-stdin.d.ts +5 -0
- package/node_modules/ink/build/hooks/use-stdin.js +8 -0
- package/node_modules/ink/build/hooks/use-stdin.js.map +1 -0
- package/node_modules/ink/build/hooks/use-stdout.d.ts +5 -0
- package/node_modules/ink/build/hooks/use-stdout.js +8 -0
- package/node_modules/ink/build/hooks/use-stdout.js.map +1 -0
- package/node_modules/ink/build/hooks/useInput.js +38 -0
- package/node_modules/ink/build/index.d.ts +34 -0
- package/node_modules/ink/build/index.js +20 -0
- package/node_modules/ink/build/index.js.map +1 -0
- package/node_modules/ink/build/ink.d.ts +90 -0
- package/node_modules/ink/build/ink.js +637 -0
- package/node_modules/ink/build/ink.js.map +1 -0
- package/node_modules/ink/build/input-parser.d.ts +7 -0
- package/node_modules/ink/build/input-parser.js +154 -0
- package/node_modules/ink/build/input-parser.js.map +1 -0
- package/node_modules/ink/build/instance.js +205 -0
- package/node_modules/ink/build/instances.d.ts +3 -0
- package/node_modules/ink/build/instances.js +8 -0
- package/node_modules/ink/build/instances.js.map +1 -0
- package/node_modules/ink/build/kitty-keyboard.d.ts +23 -0
- package/node_modules/ink/build/kitty-keyboard.js +32 -0
- package/node_modules/ink/build/kitty-keyboard.js.map +1 -0
- package/node_modules/ink/build/layout.d.ts +7 -0
- package/node_modules/ink/build/layout.js +33 -0
- package/node_modules/ink/build/layout.js.map +1 -0
- package/node_modules/ink/build/log-update.d.ts +19 -0
- package/node_modules/ink/build/log-update.js +242 -0
- package/node_modules/ink/build/log-update.js.map +1 -0
- package/node_modules/ink/build/measure-element.d.ts +16 -0
- package/node_modules/ink/build/measure-element.js +9 -0
- package/node_modules/ink/build/measure-element.js.map +1 -0
- package/node_modules/ink/build/measure-text.d.ts +6 -0
- package/node_modules/ink/build/measure-text.js +21 -0
- package/node_modules/ink/build/measure-text.js.map +1 -0
- package/node_modules/ink/build/options.d.ts +52 -0
- package/node_modules/ink/build/options.js +2 -0
- package/node_modules/ink/build/options.js.map +1 -0
- package/node_modules/ink/build/output.d.ts +35 -0
- package/node_modules/ink/build/output.js +183 -0
- package/node_modules/ink/build/output.js.map +1 -0
- package/node_modules/ink/build/parse-keypress.d.ts +22 -0
- package/node_modules/ink/build/parse-keypress.js +493 -0
- package/node_modules/ink/build/parse-keypress.js.map +1 -0
- package/node_modules/ink/build/reconciler.d.ts +4 -0
- package/node_modules/ink/build/reconciler.js +274 -0
- package/node_modules/ink/build/reconciler.js.map +1 -0
- package/node_modules/ink/build/render-background.d.ts +4 -0
- package/node_modules/ink/build/render-background.js +25 -0
- package/node_modules/ink/build/render-background.js.map +1 -0
- package/node_modules/ink/build/render-border.d.ts +4 -0
- package/node_modules/ink/build/render-border.js +73 -0
- package/node_modules/ink/build/render-border.js.map +1 -0
- package/node_modules/ink/build/render-node-to-output.d.ts +14 -0
- package/node_modules/ink/build/render-node-to-output.js +147 -0
- package/node_modules/ink/build/render-node-to-output.js.map +1 -0
- package/node_modules/ink/build/render-to-string.d.ts +38 -0
- package/node_modules/ink/build/render-to-string.js +115 -0
- package/node_modules/ink/build/render-to-string.js.map +1 -0
- package/node_modules/ink/build/render.d.ts +121 -0
- package/node_modules/ink/build/render.js +55 -0
- package/node_modules/ink/build/render.js.map +1 -0
- package/node_modules/ink/build/renderer.d.ts +8 -0
- package/node_modules/ink/build/renderer.js +55 -0
- package/node_modules/ink/build/renderer.js.map +1 -0
- package/node_modules/ink/build/sanitize-ansi.d.ts +2 -0
- package/node_modules/ink/build/sanitize-ansi.js +27 -0
- package/node_modules/ink/build/sanitize-ansi.js.map +1 -0
- package/node_modules/ink/build/screen-reader-update.d.ts +13 -0
- package/node_modules/ink/build/screen-reader-update.js +38 -0
- package/node_modules/ink/build/screen-reader-update.js.map +1 -0
- package/node_modules/ink/build/squash-text-nodes.d.ts +3 -0
- package/node_modules/ink/build/squash-text-nodes.js +36 -0
- package/node_modules/ink/build/squash-text-nodes.js.map +1 -0
- package/node_modules/ink/build/styles.d.ts +240 -0
- package/node_modules/ink/build/styles.js +232 -0
- package/node_modules/ink/build/styles.js.map +1 -0
- package/node_modules/ink/build/utils.d.ts +2 -0
- package/node_modules/ink/build/utils.js +4 -0
- package/node_modules/ink/build/utils.js.map +1 -0
- package/node_modules/ink/build/wrap-text.d.ts +3 -0
- package/node_modules/ink/build/wrap-text.js +31 -0
- package/node_modules/ink/build/wrap-text.js.map +1 -0
- package/node_modules/ink/build/write-synchronized.d.ts +4 -0
- package/node_modules/ink/build/write-synchronized.js +7 -0
- package/node_modules/ink/build/write-synchronized.js.map +1 -0
- package/node_modules/ink/package.json +126 -0
- package/package.json +35 -5
- package/node_modules/@murphai/assistant-engine/dist/assistant/group-phone-call-preview-authority.d.ts +0 -24
- package/node_modules/@murphai/assistant-engine/dist/assistant/group-phone-call-preview-authority.d.ts.map +0 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/group-phone-call-preview-authority.js +0 -125
- package/node_modules/@murphai/assistant-engine/dist/assistant/group-phone-call-preview-authority.js.map +0 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/newsletter-outbox.d.ts +0 -19
- package/node_modules/@murphai/assistant-engine/dist/assistant/newsletter-outbox.d.ts.map +0 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/newsletter-outbox.js.map +0 -1
- package/node_modules/@murphai/assistant-engine/skills/general-eye-health/SKILL.md +0 -77
- package/node_modules/@murphai/assistant-engine/skills/general-eye-health/references/evidence-register.md +0 -34
- package/node_modules/@murphai/assistant-engine/skills/general-eye-health/references/triage-and-contact-lenses.md +0 -103
- package/node_modules/@murphai/assistant-engine/skills/recovery-modalities/SKILL.md +0 -57
- package/node_modules/@murphai/assistant-engine/skills/red-light-therapy/SKILL.md +0 -145
- package/node_modules/@murphai/assistant-engine/skills/red-light-therapy/device-seeds.json +0 -259
- package/node_modules/@murphai/inboxd/dist/connectors/email/connector.d.ts +0 -57
- package/node_modules/@murphai/inboxd/dist/connectors/email/connector.d.ts.map +0 -1
- package/node_modules/@murphai/inboxd/dist/connectors/email/connector.js +0 -259
- package/node_modules/@murphai/inboxd/dist/connectors/email/connector.js.map +0 -1
- package/node_modules/@murphai/inboxd/dist/connectors/email/normalize.d.ts +0 -44
- package/node_modules/@murphai/inboxd/dist/connectors/email/normalize.d.ts.map +0 -1
- package/node_modules/@murphai/inboxd/dist/connectors/email/normalize.js +0 -212
- package/node_modules/@murphai/inboxd/dist/connectors/email/normalize.js.map +0 -1
- package/node_modules/@murphai/inboxd/dist/connectors/email/types.d.ts +0 -69
- package/node_modules/@murphai/inboxd/dist/connectors/email/types.d.ts.map +0 -1
- package/node_modules/@murphai/inboxd/dist/connectors/email/types.js +0 -2
- package/node_modules/@murphai/inboxd/dist/connectors/email/types.js.map +0 -1
- package/node_modules/@murphai/operator-config/dist/agentmail-runtime.d.ts +0 -194
- package/node_modules/@murphai/operator-config/dist/agentmail-runtime.d.ts.map +0 -1
- package/node_modules/@murphai/operator-config/dist/agentmail-runtime.js +0 -385
- package/node_modules/@murphai/operator-config/dist/agentmail-runtime.js.map +0 -1
- package/node_modules/@murphai/setup-cli/dist/setup-agentmail.d.ts +0 -30
- package/node_modules/@murphai/setup-cli/dist/setup-agentmail.d.ts.map +0 -1
- package/node_modules/@murphai/setup-cli/dist/setup-agentmail.js +0 -135
- package/node_modules/@murphai/setup-cli/dist/setup-agentmail.js.map +0 -1
- package/node_modules/incur/src/Cli.test.ts +0 -4808
- package/node_modules/incur/src/Completions.test.ts +0 -543
- package/node_modules/incur/src/Errors.test.ts +0 -100
- package/node_modules/incur/src/Fetch.test.ts +0 -285
- package/node_modules/incur/src/Filter.test.ts +0 -237
- package/node_modules/incur/src/Formatter.test.ts +0 -326
- package/node_modules/incur/src/Help.test.ts +0 -414
- package/node_modules/incur/src/Mcp.test.ts +0 -413
- package/node_modules/incur/src/Openapi.test.ts +0 -389
- package/node_modules/incur/src/Parser.test.ts +0 -378
- package/node_modules/incur/src/Schema.test.ts +0 -167
- package/node_modules/incur/src/Skill.test.ts +0 -441
- package/node_modules/incur/src/Skillgen.test.ts +0 -77
- package/node_modules/incur/src/SyncMcp.test.ts +0 -136
- package/node_modules/incur/src/SyncSkills.test.ts +0 -301
- package/node_modules/incur/src/Typegen.test.ts +0 -205
- package/node_modules/incur/src/bun-compile.test.ts +0 -84
- package/node_modules/incur/src/e2e.test.ts +0 -3441
- package/node_modules/incur/src/internal/configSchema.test.ts +0 -193
- package/node_modules/incur/src/internal/dereference.test.ts +0 -695
- package/node_modules/incur/src/internal/helpers.test.ts +0 -75
- package/node_modules/incur/src/internal/pm.test.ts +0 -38
- package/node_modules/incur/src/internal/utils.test.ts +0 -50
- package/node_modules/incur/src/middleware.test.ts +0 -6
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
import { createHmac, createHash, timingSafeEqual } from "node:crypto";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import { JUNCTION_ALLOWED_SUMMARY_RESOURCES, JUNCTION_ALLOWED_TIMESERIES_RESOURCES, JUNCTION_DEFAULT_SUMMARY_RESOURCES, JUNCTION_DEFAULT_TIMESERIES_RESOURCES, JUNCTION_KNOWN_TIMESERIES_RESOURCES, isJunctionRawDirectIdentityContainerKey, isJunctionRawDirectIdentityKey, normalizeJunctionResourceName, } from "@murphai/importers/device-providers/junction-resources";
|
|
2
|
+
import { COMPANION_HRV_RMSSD_RESOURCE, JUNCTION_ALLOWED_SUMMARY_RESOURCES, JUNCTION_ALLOWED_TIMESERIES_RESOURCES, JUNCTION_DEFAULT_SUMMARY_RESOURCES, JUNCTION_DEFAULT_TIMESERIES_RESOURCES, JUNCTION_KNOWN_TIMESERIES_RESOURCES, normalizeJunctionResourceName, resolveJunctionTimeseriesResourcePolicy, usesJunctionTimeseriesIntervalStartOwnership, parseCompanionHrvRmssdAdmissionId, parseSerializedCompanionHrvRmssdObservation, serializeCompanionHrvRmssdObservation, } from "@murphai/contracts";
|
|
3
|
+
import { JUNCTION_ECG_VOLTAGE_FEATURE_SCHEMA, JUNCTION_WORKOUT_STREAM_FEATURE_SCHEMA, buildJunctionBoundedFeatureIdentity, buildJunctionDailyTimeseriesAggregateResourceId, canNormalizeJunctionSleepCycleRecordToCompactStages, classifyJunctionSummaryNormalizationEvidence, countAcceptedJunctionDailyTimeseriesProviderRecords, identifyJunctionBloodPressureProviderRecords, JUNCTION_DENSE_FIDELITY_RESOURCES, reduceJunctionElectrocardiogramVoltageRecords, reduceJunctionWorkoutStreamPayload, resolveJunctionBoundedFeatureRecords, resolveJunctionWeightProviderRecordIdentity, selectJunctionWorkoutStreamCandidates, } from "@murphai/importers/device-providers/junction";
|
|
4
|
+
import { normalizeJunctionSourceProviderSlug, resolveJunctionOrigin, } from "@murphai/importers/device-providers/junction-origin";
|
|
5
|
+
import { isJunctionRawDirectIdentityContainerKey, isJunctionRawDirectIdentityKey, } from "@murphai/importers/device-providers/junction-resources";
|
|
7
6
|
import { JUNCTION_DEVICE_PROVIDER_DESCRIPTOR } from "@murphai/importers/device-providers/provider-descriptors";
|
|
8
7
|
import { deviceSyncError, isDeviceSyncError } from "../errors.js";
|
|
8
|
+
import { JunctionTimeseriesProgressError } from "../junction-timeseries-progress.js";
|
|
9
9
|
import { isHostedRuntimeIdShapedDiagnosticToken, sanitizeHostedRuntimeDiagnosticText, } from "../hosted-runtime.js";
|
|
10
10
|
import { isJunctionCredentialIndependentInlineImportJob, resolveDeviceSyncJunctionInlineSourceProviderSlug, } from "../junction-inline-authority.js";
|
|
11
|
-
import { addJunctionHistoricalBackfillEvidence, canCurrentRuntimeMutateJunctionHistoricalBackfillProgress, encodeJunctionHistoricalBackfillStatus, hasJunctionHistoricalBackfillEvidence, JUNCTION_HISTORICAL_BACKFILL_COVERAGE_VERSION, JUNCTION_HISTORICAL_BACKFILL_METADATA_KEYS, readJunctionHistoricalBackfillEvidence, readJunctionHistoricalBackfillStatus, } from "../junction-historical-backfill-progress.js";
|
|
11
|
+
import { addJunctionExtendedTimeseriesHistoryBackfillCoverage, addJunctionHistoricalBackfillEvidence, canRepresentJunctionExtendedTimeseriesHistoryBackfillCoverage, canCurrentRuntimeMutateJunctionExtendedTimeseriesHistoryBackfillCoverage, canCurrentRuntimeMutateJunctionHistoricalBackfillProgress, encodeJunctionHistoricalBackfillStatus, hasJunctionExtendedTimeseriesHistoryBackfillCoverage, hasJunctionHistoricalBackfillEvidence, JUNCTION_HISTORICAL_BACKFILL_COVERAGE_VERSION, JUNCTION_HISTORICAL_BACKFILL_METADATA_KEYS, readJunctionHistoricalBackfillEvidence, readJunctionHistoricalBackfillStatus, } from "../junction-historical-backfill-progress.js";
|
|
12
12
|
import { DEVICE_SYNC_METADATA_MAX_STRING_LENGTH } from "../metadata.js";
|
|
13
|
-
import { DEVICE_SYNC_HISTORICAL_DATA_RECONNECT_REQUIRED_ERROR_CODE, isJunctionHistoricalResetProviderSlug, requiresHistoricalResetDeviceSyncSource, } from "../public-account.js";
|
|
14
|
-
import { assertValidJunctionClientUserIdSecret, normalizeJunctionDeviceSyncRuntimeConfig, } from "../configured-provider-runtime-descriptors.js";
|
|
13
|
+
import { DEVICE_SYNC_HISTORICAL_DATA_RECONNECT_REQUIRED_ERROR_CODE, DEVICE_SYNC_SOURCE_USER_DISCONNECTED_ERROR_CODE, resolveDeviceSyncSourceState, isDeviceSyncSourceAdmitted, isDeviceSyncSourceDisconnectFenced, isJunctionHistoricalResetProviderSlug, requiresHistoricalResetDeviceSyncSource, } from "../public-account.js";
|
|
14
|
+
import { assertValidJunctionClientUserIdSecret, buildJunctionDeviceSyncRuntimeDescriptor, normalizeJunctionClientUserIdNamespace, normalizeJunctionDeviceSyncRuntimeConfig, } from "../configured-provider-runtime-descriptors.js";
|
|
15
15
|
import { addMilliseconds, normalizeString, sha256Text, subtractDays, } from "../shared.js";
|
|
16
|
-
import { JUNCTION_COMPANION_HRV_OBSERVATION_INVALID_CODE, JUNCTION_COMPANION_HEALTH_METADATA_EVENT_TYPE, JUNCTION_COMPANION_HEALTH_METADATA_MAX_BATCH_BYTES, JUNCTION_COMPANION_HEALTH_METADATA_RESOURCE, JUNCTION_COMPANION_HEALTH_METADATA_SOURCE_PROVIDER, JUNCTION_COMPANION_HEALTH_METADATA_SOURCE_TYPE, JunctionCompanionHealthMetadataParseError, parseJunctionCompanionHealthMetadataBatch, } from "../junction-resources.js";
|
|
17
|
-
import { JunctionClient, } from "./junction-client.js";
|
|
18
|
-
import { resolveJunctionDeviceConnectRouteByProviderSlug } from "../config/connect-routes.js";
|
|
16
|
+
import { JUNCTION_COMPANION_HRV_OBSERVATION_INVALID_CODE, JUNCTION_COMPANION_HRV_SOURCE_PROVIDER, JUNCTION_COMPANION_HEALTH_METADATA_EVENT_TYPE, JUNCTION_COMPANION_HEALTH_METADATA_MAX_BATCH_BYTES, JUNCTION_COMPANION_HEALTH_METADATA_RESOURCE, JUNCTION_COMPANION_HEALTH_METADATA_SOURCE_PROVIDER, JUNCTION_COMPANION_HEALTH_METADATA_SOURCE_TYPE, JUNCTION_CALENDAR_REFRESH_EMPTY_IDENTITY_INVALID_CODE, JUNCTION_CALENDAR_REFRESH_JOB_INVALID_CODE, JunctionCompanionHealthMetadataParseError, parseJunctionCompanionHealthMetadataBatch, } from "../junction-resources.js";
|
|
17
|
+
import { JunctionClient, JUNCTION_MAX_USER_PROVIDERS, } from "./junction-client.js";
|
|
18
|
+
import { areJunctionDeviceConnectProviderSlugsEquivalent, resolveJunctionDeviceConnectRouteByProviderSlug, } from "../config/connect-routes.js";
|
|
19
19
|
import { buildJunctionProviderSourceInstanceKey, JUNCTION_DEFAULT_PROVIDER_FILTER, normalizeJunctionProviderFilter, } from "../config/junction-connect-sources.js";
|
|
20
20
|
import { classifyDeviceSyncWebhookAcceptanceMode } from "../types.js";
|
|
21
21
|
import { evaluatePushPrimarySourceStaleness } from "../source-staleness.js";
|
|
@@ -24,14 +24,23 @@ export { JUNCTION_DEVICE_PROVIDER_DESCRIPTOR };
|
|
|
24
24
|
export { JUNCTION_CONNECT_SOURCE_TARGETS, JUNCTION_DEFAULT_PROVIDER_FILTER, JUNCTION_LINK_PROVIDER_SLUGS, normalizeJunctionProviderFilter, resolveJunctionConnectSourceLabel, resolveJunctionConnectTargetForSourceId, } from "../config/junction-connect-sources.js";
|
|
25
25
|
export const JUNCTION_PROVIDER_CONFIG_KEY = "junction";
|
|
26
26
|
export { JUNCTION_DEFAULT_SUMMARY_RESOURCES, JUNCTION_DEFAULT_TIMESERIES_RESOURCES, };
|
|
27
|
+
const JUNCTION_WORKOUT_STREAM_PROGRESS_VERSION = 1;
|
|
28
|
+
const JUNCTION_DEPLOYED_FULL_JOB_PROGRESS_VERSION = 1;
|
|
29
|
+
const JUNCTION_ALLOWED_TIMESERIES_RESOURCE_SET = new Set(JUNCTION_ALLOWED_TIMESERIES_RESOURCES);
|
|
27
30
|
const JUNCTION_WEBHOOK_ROOT_FIELDS = Object.freeze({
|
|
28
31
|
eventType: "event_type",
|
|
29
32
|
userId: "user_id",
|
|
30
33
|
clientUserId: "client_user_id",
|
|
31
34
|
data: "data",
|
|
32
35
|
});
|
|
36
|
+
// Mirrors the pinned Junction SDK's `serialization.date()` wire validation.
|
|
37
|
+
// Keeping this predicate local avoids loading the SDK's generated runtime tree
|
|
38
|
+
// merely to identify one five-field completion envelope.
|
|
39
|
+
const JUNCTION_SDK_ISO_8601_DATE_PATTERN = /^([+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-2])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-3])((:?)[0-5]\d)?|24:?00)([.,]\d+(?!:))?)?(\17[0-5]\d([.,]\d+)?)?([zZ]|([+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/;
|
|
33
40
|
const JUNCTION_PROFILE_SUMMARY_RESOURCE = "profile";
|
|
34
41
|
const JUNCTION_PROFILE_SUMMARY_CHECKED_AT_METADATA_KEY = "junctionProfileSummaryCheckedAt";
|
|
42
|
+
const JUNCTION_PROFILE_SUMMARY_NORMALIZATION_REVISION = 1;
|
|
43
|
+
const JUNCTION_PROFILE_SUMMARY_NORMALIZATION_REVISION_METADATA_KEY = "junctionProfileSummaryNormalizationRevision";
|
|
35
44
|
// `profile` is deliberately excluded: it is a current-state snapshot, so
|
|
36
45
|
// counting it as completion evidence would mark every backfill useful and
|
|
37
46
|
// defeat empty-history detection. The provider fetches it through the separate
|
|
@@ -66,6 +75,12 @@ const JUNCTION_WEBHOOK_NESTED_RECORD_KEYS = Object.freeze([
|
|
|
66
75
|
const JUNCTION_TIMESERIES_RESOURCE_NAMES = new Set([
|
|
67
76
|
...JUNCTION_KNOWN_TIMESERIES_RESOURCES,
|
|
68
77
|
]);
|
|
78
|
+
const JUNCTION_CLOSED_DAY_TIMESERIES_RESOURCES = new Set([
|
|
79
|
+
"steps",
|
|
80
|
+
"distance",
|
|
81
|
+
"calories_active",
|
|
82
|
+
"heartrate",
|
|
83
|
+
]);
|
|
69
84
|
const JUNCTION_KNOWN_WEBHOOK_RESOURCE_NAMES = new Set([
|
|
70
85
|
...JUNCTION_ALLOWED_SUMMARY_RESOURCES,
|
|
71
86
|
...JUNCTION_ALLOWED_TIMESERIES_RESOURCES,
|
|
@@ -73,12 +88,143 @@ const JUNCTION_KNOWN_WEBHOOK_RESOURCE_NAMES = new Set([
|
|
|
73
88
|
]);
|
|
74
89
|
const DEFAULT_SUMMARY_BACKFILL_DAYS = JUNCTION_DEVICE_PROVIDER_DESCRIPTOR.sync.windows.backfillDays;
|
|
75
90
|
const DEFAULT_TIMESERIES_BACKFILL_DAYS = 14;
|
|
91
|
+
const JUNCTION_NOTE_HISTORY_BACKFILL_VERSION = 2;
|
|
92
|
+
const JUNCTION_BOUNDED_TIMESERIES_BACKFILL_POLICY = Object.freeze({
|
|
93
|
+
history: "bounded",
|
|
94
|
+
});
|
|
95
|
+
const JUNCTION_SPARSE_DAILY_TIMESERIES_BACKFILL_POLICY = Object.freeze({
|
|
96
|
+
anchor: "current_day",
|
|
97
|
+
completion: "daily_aggregate",
|
|
98
|
+
history: "extended",
|
|
99
|
+
version: 1,
|
|
100
|
+
});
|
|
101
|
+
// This is the history-depth decision for every admitted resource. Only the
|
|
102
|
+
// sparse resources represented by the package-owned source/resource matrix
|
|
103
|
+
// receive extended history; all other resources use the bounded sync window.
|
|
104
|
+
const JUNCTION_TIMESERIES_BACKFILL_POLICIES = Object.freeze({
|
|
105
|
+
afib_burden: JUNCTION_SPARSE_DAILY_TIMESERIES_BACKFILL_POLICY,
|
|
106
|
+
basal_body_temperature: JUNCTION_SPARSE_DAILY_TIMESERIES_BACKFILL_POLICY,
|
|
107
|
+
blood_oxygen: JUNCTION_BOUNDED_TIMESERIES_BACKFILL_POLICY,
|
|
108
|
+
blood_pressure: {
|
|
109
|
+
anchor: "source_first_seen",
|
|
110
|
+
completion: "exact_records",
|
|
111
|
+
history: "extended",
|
|
112
|
+
version: 1,
|
|
113
|
+
},
|
|
114
|
+
body_temperature: JUNCTION_SPARSE_DAILY_TIMESERIES_BACKFILL_POLICY,
|
|
115
|
+
body_temperature_delta: JUNCTION_SPARSE_DAILY_TIMESERIES_BACKFILL_POLICY,
|
|
116
|
+
caffeine: JUNCTION_SPARSE_DAILY_TIMESERIES_BACKFILL_POLICY,
|
|
117
|
+
calories_active: JUNCTION_BOUNDED_TIMESERIES_BACKFILL_POLICY,
|
|
118
|
+
distance: JUNCTION_BOUNDED_TIMESERIES_BACKFILL_POLICY,
|
|
119
|
+
glucose: JUNCTION_BOUNDED_TIMESERIES_BACKFILL_POLICY,
|
|
120
|
+
heartrate: JUNCTION_BOUNDED_TIMESERIES_BACKFILL_POLICY,
|
|
121
|
+
heart_rate_recovery_one_minute: JUNCTION_SPARSE_DAILY_TIMESERIES_BACKFILL_POLICY,
|
|
122
|
+
hrv: JUNCTION_BOUNDED_TIMESERIES_BACKFILL_POLICY,
|
|
123
|
+
mindfulness_minutes: JUNCTION_SPARSE_DAILY_TIMESERIES_BACKFILL_POLICY,
|
|
124
|
+
note: {
|
|
125
|
+
anchor: "current_day",
|
|
126
|
+
completion: "fetch_complete",
|
|
127
|
+
history: "extended",
|
|
128
|
+
version: JUNCTION_NOTE_HISTORY_BACKFILL_VERSION,
|
|
129
|
+
},
|
|
130
|
+
respiratory_rate: JUNCTION_BOUNDED_TIMESERIES_BACKFILL_POLICY,
|
|
131
|
+
sleep_breathing_disturbance: JUNCTION_SPARSE_DAILY_TIMESERIES_BACKFILL_POLICY,
|
|
132
|
+
steps: JUNCTION_BOUNDED_TIMESERIES_BACKFILL_POLICY,
|
|
133
|
+
stress_level: JUNCTION_BOUNDED_TIMESERIES_BACKFILL_POLICY,
|
|
134
|
+
vo2_max: JUNCTION_SPARSE_DAILY_TIMESERIES_BACKFILL_POLICY,
|
|
135
|
+
water: JUNCTION_SPARSE_DAILY_TIMESERIES_BACKFILL_POLICY,
|
|
136
|
+
weight: {
|
|
137
|
+
anchor: "current_day",
|
|
138
|
+
completion: "exact_records",
|
|
139
|
+
history: "extended",
|
|
140
|
+
version: 1,
|
|
141
|
+
},
|
|
142
|
+
body_mass_index: JUNCTION_BOUNDED_TIMESERIES_BACKFILL_POLICY,
|
|
143
|
+
carbohydrates: JUNCTION_BOUNDED_TIMESERIES_BACKFILL_POLICY,
|
|
144
|
+
fat: JUNCTION_BOUNDED_TIMESERIES_BACKFILL_POLICY,
|
|
145
|
+
forced_expiratory_volume_1: JUNCTION_BOUNDED_TIMESERIES_BACKFILL_POLICY,
|
|
146
|
+
forced_vital_capacity: JUNCTION_BOUNDED_TIMESERIES_BACKFILL_POLICY,
|
|
147
|
+
heart_rate_alert: JUNCTION_BOUNDED_TIMESERIES_BACKFILL_POLICY,
|
|
148
|
+
inhaler_usage: JUNCTION_BOUNDED_TIMESERIES_BACKFILL_POLICY,
|
|
149
|
+
insulin_injection: JUNCTION_BOUNDED_TIMESERIES_BACKFILL_POLICY,
|
|
150
|
+
lean_body_mass: JUNCTION_BOUNDED_TIMESERIES_BACKFILL_POLICY,
|
|
151
|
+
peak_expiratory_flow_rate: JUNCTION_BOUNDED_TIMESERIES_BACKFILL_POLICY,
|
|
152
|
+
sleep_apnea_alert: JUNCTION_BOUNDED_TIMESERIES_BACKFILL_POLICY,
|
|
153
|
+
waist_circumference: JUNCTION_BOUNDED_TIMESERIES_BACKFILL_POLICY,
|
|
154
|
+
calories_basal: JUNCTION_BOUNDED_TIMESERIES_BACKFILL_POLICY,
|
|
155
|
+
daylight_exposure: JUNCTION_BOUNDED_TIMESERIES_BACKFILL_POLICY,
|
|
156
|
+
fall: JUNCTION_BOUNDED_TIMESERIES_BACKFILL_POLICY,
|
|
157
|
+
floors_climbed: JUNCTION_BOUNDED_TIMESERIES_BACKFILL_POLICY,
|
|
158
|
+
handwashing: JUNCTION_BOUNDED_TIMESERIES_BACKFILL_POLICY,
|
|
159
|
+
stand_duration: JUNCTION_BOUNDED_TIMESERIES_BACKFILL_POLICY,
|
|
160
|
+
stand_hour: JUNCTION_BOUNDED_TIMESERIES_BACKFILL_POLICY,
|
|
161
|
+
uv_exposure: JUNCTION_BOUNDED_TIMESERIES_BACKFILL_POLICY,
|
|
162
|
+
wheelchair_push: JUNCTION_BOUNDED_TIMESERIES_BACKFILL_POLICY,
|
|
163
|
+
workout_distance: JUNCTION_BOUNDED_TIMESERIES_BACKFILL_POLICY,
|
|
164
|
+
workout_duration: JUNCTION_BOUNDED_TIMESERIES_BACKFILL_POLICY,
|
|
165
|
+
workout_swimming_stroke: JUNCTION_BOUNDED_TIMESERIES_BACKFILL_POLICY,
|
|
166
|
+
electrocardiogram_voltage: JUNCTION_BOUNDED_TIMESERIES_BACKFILL_POLICY,
|
|
167
|
+
workout_stream: JUNCTION_BOUNDED_TIMESERIES_BACKFILL_POLICY,
|
|
168
|
+
});
|
|
169
|
+
function resolveJunctionExtendedTimeseriesBackfillPolicy(resource) {
|
|
170
|
+
if (!Object.prototype.hasOwnProperty.call(JUNCTION_TIMESERIES_BACKFILL_POLICIES, resource)) {
|
|
171
|
+
return null;
|
|
172
|
+
}
|
|
173
|
+
const policy = JUNCTION_TIMESERIES_BACKFILL_POLICIES[resource];
|
|
174
|
+
return policy.history === "extended" ? policy : null;
|
|
175
|
+
}
|
|
176
|
+
const JUNCTION_DENSE_FIDELITY_RESOURCE_SET = new Set(JUNCTION_DENSE_FIDELITY_RESOURCES);
|
|
177
|
+
const JUNCTION_CALENDAR_DAY_AGGREGATE_RESOURCE_SET = new Set([
|
|
178
|
+
...JUNCTION_DENSE_FIDELITY_RESOURCES,
|
|
179
|
+
"caffeine",
|
|
180
|
+
"water",
|
|
181
|
+
"mindfulness_minutes",
|
|
182
|
+
]);
|
|
76
183
|
const DEFAULT_RECONCILE_DAYS = JUNCTION_DEVICE_PROVIDER_DESCRIPTOR.sync.windows.reconcileDays;
|
|
77
|
-
const DEFAULT_RECONCILE_INTERVAL_MS = JUNCTION_DEVICE_PROVIDER_DESCRIPTOR.sync.windows.reconcileIntervalMs;
|
|
78
184
|
const DEFAULT_REQUEST_TIMEOUT_MS = 15_000;
|
|
79
185
|
const DEFAULT_SETUP_TTL_MS = 30 * 60_000;
|
|
80
186
|
const DEFAULT_WEBHOOK_TIMESTAMP_TOLERANCE_MS = 5 * 60_000;
|
|
81
187
|
const TIMESERIES_CHUNK_MS = 24 * 60 * 60_000;
|
|
188
|
+
// A date-only provider query can contain source-local records from UTC-12.
|
|
189
|
+
// Delay calendar-day ownership until that date has closed in every admitted
|
|
190
|
+
// civil offset instead of treating UTC midnight as globally complete.
|
|
191
|
+
const JUNCTION_PROVIDER_CALENDAR_DAY_CLOSE_LAG_MS = 12 * 60 * 60_000;
|
|
192
|
+
const JUNCTION_MAX_SPARSE_CALENDAR_REFRESH_DAYS = 64;
|
|
193
|
+
const JUNCTION_SPARSE_CALENDAR_AGGREGATE_RESOURCE_SET = new Set([
|
|
194
|
+
"caffeine",
|
|
195
|
+
"water",
|
|
196
|
+
"mindfulness_minutes",
|
|
197
|
+
]);
|
|
198
|
+
const TIMESERIES_HOUR_MS = 60 * 60_000;
|
|
199
|
+
// Three single-attempt pages allow ordinary pagination while capping provider
|
|
200
|
+
// wait at 24 seconds, below the hosted job's 45-second outer budget.
|
|
201
|
+
const JUNCTION_FULL_JOB_TIMESERIES_COLLECTION_WORK_LIMIT = Object.freeze({
|
|
202
|
+
maxAttemptsPerPage: 1,
|
|
203
|
+
maxPages: 3,
|
|
204
|
+
requestTimeoutMs: 8_000,
|
|
205
|
+
});
|
|
206
|
+
// Most hosted summary continuation units contain one resource. Match the
|
|
207
|
+
// bounded timeseries contract so a complete three-page unit remains below the
|
|
208
|
+
// 45-second outer maintenance budget and can persist its next cursor.
|
|
209
|
+
const JUNCTION_FULL_JOB_SUMMARY_COLLECTION_WORK_LIMIT = Object.freeze({
|
|
210
|
+
maxAttemptsPerPage: 1,
|
|
211
|
+
maxPages: 3,
|
|
212
|
+
requestTimeoutMs: 8_000,
|
|
213
|
+
});
|
|
214
|
+
// Sleep summaries and sleep cycles share canonical stage ownership, so they
|
|
215
|
+
// must be normalized in one import. Keep their combined worst-case provider
|
|
216
|
+
// wait at 30 seconds to leave room for projection/import inside the hosted
|
|
217
|
+
// worker's 45-second outer maintenance budget.
|
|
218
|
+
const JUNCTION_FULL_JOB_COUPLED_SUMMARY_COLLECTION_WORK_LIMIT = Object.freeze({
|
|
219
|
+
maxAttemptsPerPage: 1,
|
|
220
|
+
maxPages: 3,
|
|
221
|
+
requestTimeoutMs: 5_000,
|
|
222
|
+
});
|
|
223
|
+
const JUNCTION_FULL_JOB_INVENTORY_COLLECTION_WORK_LIMIT = Object.freeze({
|
|
224
|
+
maxAttemptsPerPage: 1,
|
|
225
|
+
maxPages: 1,
|
|
226
|
+
requestTimeoutMs: 8_000,
|
|
227
|
+
});
|
|
82
228
|
const JUNCTION_MAX_DIAGNOSTIC_TIMESERIES_PROBE_DAYS = 14;
|
|
83
229
|
const JUNCTION_DIAGNOSTIC_SHAPE_KEY_LIMIT = 24;
|
|
84
230
|
const JUNCTION_DIAGNOSTIC_RESOURCE_NAME_LIMIT = 64;
|
|
@@ -88,18 +234,21 @@ const EMPTY_HISTORICAL_BACKFILL_RETRY_DELAYS_MS = Object.freeze([
|
|
|
88
234
|
6 * 60 * 60_000,
|
|
89
235
|
24 * 60 * 60_000,
|
|
90
236
|
]);
|
|
237
|
+
const JUNCTION_HISTORICAL_UNRESOLVED_PROVIDER_RECORD_IDENTITIES_VERSION = 1;
|
|
238
|
+
const JUNCTION_BLOOD_PRESSURE_PROVIDER_RECORD_IDENTITY_PATTERN = /^blood-pressure-[0-9a-f]{16}$/u;
|
|
91
239
|
const JUNCTION_SCHEDULED_RECONCILE_PRIORITY = 40;
|
|
92
240
|
const JUNCTION_HISTORICAL_BACKFILL_PRIORITY = 30;
|
|
93
241
|
const JUNCTION_HISTORICAL_BACKFILL_RETRY_PRIORITY = 50;
|
|
94
242
|
export function createJunctionDeviceSyncProvider(config) {
|
|
95
243
|
const runtimeConfig = normalizeJunctionDeviceSyncRuntimeConfig(config);
|
|
96
244
|
const client = new JunctionClient(toClientConfig(config));
|
|
97
|
-
const { providerFilter, summaryResources, timeseriesResources } = runtimeConfig;
|
|
245
|
+
const { clientUserIdNamespace, providerFilter, reconcileIntervalMs, summaryResources, timeseriesResources, } = runtimeConfig;
|
|
98
246
|
const summaryBackfillDays = config.summaryBackfillDays ?? DEFAULT_SUMMARY_BACKFILL_DAYS;
|
|
99
247
|
const timeseriesBackfillDays = config.timeseriesBackfillDays ?? DEFAULT_TIMESERIES_BACKFILL_DAYS;
|
|
248
|
+
const extendedTimeseriesBackfillDays = config.timeseriesBackfillDays ?? summaryBackfillDays;
|
|
249
|
+
const extendedBackfillTimeseriesResources = timeseriesResources.filter((resource) => resolveJunctionExtendedTimeseriesBackfillPolicy(resource) !== null);
|
|
100
250
|
const reconcileDays = config.reconcileDays ?? DEFAULT_RECONCILE_DAYS;
|
|
101
251
|
const pushSourceRecoveryEnabled = config.pushSourceRecoveryEnabled === true;
|
|
102
|
-
const reconcileIntervalMs = config.reconcileIntervalMs ?? DEFAULT_RECONCILE_INTERVAL_MS;
|
|
103
252
|
const webhookTimestampToleranceMs = config.webhookTimestampToleranceMs ?? DEFAULT_WEBHOOK_TIMESTAMP_TOLERANCE_MS;
|
|
104
253
|
async function beginConnection(context) {
|
|
105
254
|
const ownerId = normalizeString(context.ownerId);
|
|
@@ -112,7 +261,7 @@ export function createJunctionDeviceSyncProvider(config) {
|
|
|
112
261
|
});
|
|
113
262
|
}
|
|
114
263
|
const linkProvider = resolveJunctionLinkDirectProvider(providerFilter, context.sourceProviderSlug);
|
|
115
|
-
const clientUserId = buildJunctionClientUserId(config.clientUserIdSecret, ownerId);
|
|
264
|
+
const clientUserId = buildJunctionClientUserId(config.clientUserIdSecret, ownerId, clientUserIdNamespace);
|
|
116
265
|
const user = await client.createOrResolveUser(clientUserId);
|
|
117
266
|
const linkToken = await client.createLinkToken({
|
|
118
267
|
userId: user.userId,
|
|
@@ -152,7 +301,7 @@ export function createJunctionDeviceSyncProvider(config) {
|
|
|
152
301
|
httpStatus: 400,
|
|
153
302
|
});
|
|
154
303
|
}
|
|
155
|
-
const clientUserId = buildJunctionClientUserId(config.clientUserIdSecret, ownerId);
|
|
304
|
+
const clientUserId = buildJunctionClientUserId(config.clientUserIdSecret, ownerId, clientUserIdNamespace);
|
|
156
305
|
const user = await client.createOrResolveUser(clientUserId);
|
|
157
306
|
return {
|
|
158
307
|
externalAccountId: user.userId,
|
|
@@ -206,6 +355,10 @@ export function createJunctionDeviceSyncProvider(config) {
|
|
|
206
355
|
httpStatus: 400,
|
|
207
356
|
});
|
|
208
357
|
}
|
|
358
|
+
const sourceConnectionWork = buildSourceConnectionWork({
|
|
359
|
+
now: context.now,
|
|
360
|
+
sourceProviderSlug: context.sourceProviderSlug,
|
|
361
|
+
});
|
|
209
362
|
return {
|
|
210
363
|
externalAccountId,
|
|
211
364
|
displayName: "Junction",
|
|
@@ -215,8 +368,7 @@ export function createJunctionDeviceSyncProvider(config) {
|
|
|
215
368
|
providerConfigKey: JUNCTION_PROVIDER_CONFIG_KEY,
|
|
216
369
|
},
|
|
217
370
|
setupPhase: "link_returned",
|
|
218
|
-
|
|
219
|
-
nextReconcileAt: addMilliseconds(context.now, reconcileIntervalMs),
|
|
371
|
+
...sourceConnectionWork,
|
|
220
372
|
};
|
|
221
373
|
}
|
|
222
374
|
async function revokeAccess(account) {
|
|
@@ -261,8 +413,47 @@ export function createJunctionDeviceSyncProvider(config) {
|
|
|
261
413
|
});
|
|
262
414
|
}
|
|
263
415
|
}
|
|
416
|
+
async function revokeSourceAccess(account, sourceProviderSlug) {
|
|
417
|
+
const userId = normalizeString(account.externalAccountId);
|
|
418
|
+
const targetProviderSlug = normalizeProviderSlug(sourceProviderSlug);
|
|
419
|
+
if (!userId || !targetProviderSlug) {
|
|
420
|
+
throw deviceSyncError({
|
|
421
|
+
code: "JUNCTION_SOURCE_DEREGISTER_INPUT_INVALID",
|
|
422
|
+
message: "Junction source cleanup requires a stored user and provider slug.",
|
|
423
|
+
retryable: false,
|
|
424
|
+
httpStatus: 409,
|
|
425
|
+
});
|
|
426
|
+
}
|
|
427
|
+
const providers = await client.listUserProviders(userId);
|
|
428
|
+
const targetIsRegistered = providers.some((provider) => mapJunctionSourceStatus(provider.status) !== "disconnected"
|
|
429
|
+
&& (normalizeProviderSlug(provider.origin.sourceProviderSlug)
|
|
430
|
+
?? normalizeProviderSlug(provider.slug)) === targetProviderSlug);
|
|
431
|
+
if (!targetIsRegistered) {
|
|
432
|
+
return;
|
|
433
|
+
}
|
|
434
|
+
await client.deregisterProvider({
|
|
435
|
+
providerSlug: targetProviderSlug,
|
|
436
|
+
userId,
|
|
437
|
+
});
|
|
438
|
+
}
|
|
439
|
+
async function isSourceAccessActive(account, sourceProviderSlug) {
|
|
440
|
+
const userId = normalizeString(account.externalAccountId);
|
|
441
|
+
const targetProviderSlug = normalizeProviderSlug(sourceProviderSlug);
|
|
442
|
+
if (!userId || !targetProviderSlug) {
|
|
443
|
+
throw deviceSyncError({
|
|
444
|
+
code: "JUNCTION_SOURCE_STATUS_INPUT_INVALID",
|
|
445
|
+
message: "Junction source status requires a stored user and provider slug.",
|
|
446
|
+
retryable: false,
|
|
447
|
+
httpStatus: 409,
|
|
448
|
+
});
|
|
449
|
+
}
|
|
450
|
+
return (await client.listUserProviders(userId)).some((provider) => mapJunctionSourceStatus(provider.status) === "connected"
|
|
451
|
+
&& (normalizeProviderSlug(provider.origin.sourceProviderSlug)
|
|
452
|
+
?? normalizeProviderSlug(provider.slug)) === targetProviderSlug);
|
|
453
|
+
}
|
|
264
454
|
function createScheduledJobs(account, now) {
|
|
265
455
|
const scheduledHistoricalBackfillJobs = buildScheduledHistoricalBackfillJobs(account, now);
|
|
456
|
+
const scheduledExtendedTimeseriesBackfillJobs = buildScheduledExtendedTimeseriesBackfillJobs(account, now);
|
|
266
457
|
const nextReconcileAt = resolveJunctionNextReconcileAt(account, now, addMilliseconds(now, reconcileIntervalMs));
|
|
267
458
|
return {
|
|
268
459
|
jobs: [
|
|
@@ -273,11 +464,61 @@ export function createJunctionDeviceSyncProvider(config) {
|
|
|
273
464
|
priority: JUNCTION_SCHEDULED_RECONCILE_PRIORITY,
|
|
274
465
|
}),
|
|
275
466
|
...scheduledHistoricalBackfillJobs,
|
|
467
|
+
...scheduledExtendedTimeseriesBackfillJobs,
|
|
276
468
|
...buildPushSourceRecoveryJobs(account, now),
|
|
277
469
|
],
|
|
278
470
|
nextReconcileAt,
|
|
279
471
|
};
|
|
280
472
|
}
|
|
473
|
+
function buildScheduledExtendedTimeseriesBackfillJobs(account, now) {
|
|
474
|
+
return extendedBackfillTimeseriesResources.flatMap((resource) => {
|
|
475
|
+
const policy = resolveJunctionExtendedTimeseriesBackfillPolicy(resource);
|
|
476
|
+
if (!policy) {
|
|
477
|
+
return [];
|
|
478
|
+
}
|
|
479
|
+
if (!canCurrentRuntimeMutateJunctionExtendedTimeseriesHistoryBackfillCoverage(account.metadata, resource, policy.version)) {
|
|
480
|
+
return [];
|
|
481
|
+
}
|
|
482
|
+
const scheduledSources = new Map();
|
|
483
|
+
for (const sourceState of resolveJunctionAccountSourceStates(account.sources ?? [])) {
|
|
484
|
+
const identitySource = sourceState.identitySource;
|
|
485
|
+
const lifecycleSource = sourceState.lifecycleSource;
|
|
486
|
+
const sourceProviderSlug = normalizeProviderSlug(identitySource.sourceProviderSlug);
|
|
487
|
+
if (!sourceProviderSlug
|
|
488
|
+
|| !isDeviceSyncSourceAdmitted([lifecycleSource], lifecycleSource.sourceProviderSlug)
|
|
489
|
+
|| !isJunctionResourceAvailableInSummary(lifecycleSource.resourceAvailabilitySummary, resource)
|
|
490
|
+
|| hasJunctionExtendedTimeseriesHistoryBackfillCoverage(account.metadata, sourceProviderSlug, resource, policy.version)
|
|
491
|
+
|| !canRepresentJunctionExtendedTimeseriesHistoryBackfillCoverage(account.metadata, sourceProviderSlug, resource, policy.version)) {
|
|
492
|
+
continue;
|
|
493
|
+
}
|
|
494
|
+
const sourceFirstSeenAt = identitySource.firstSeenAt;
|
|
495
|
+
if (!sourceFirstSeenAt) {
|
|
496
|
+
throw junctionSourceStateUnavailableError();
|
|
497
|
+
}
|
|
498
|
+
const existingFirstSeenAt = scheduledSources.get(sourceProviderSlug);
|
|
499
|
+
if (!existingFirstSeenAt || Date.parse(sourceFirstSeenAt) < Date.parse(existingFirstSeenAt)) {
|
|
500
|
+
scheduledSources.set(sourceProviderSlug, sourceFirstSeenAt);
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
return [...scheduledSources.entries()].map(([sourceProviderSlug, firstSeenAt]) => {
|
|
504
|
+
// Exact blood-pressure history is anchored to source admission. Other
|
|
505
|
+
// sparse resources catch up the current extended-history window once.
|
|
506
|
+
const window = buildExtendedTimeseriesBackfillWindow({
|
|
507
|
+
anchorAt: policy.anchor === "source_first_seen" ? firstSeenAt : now,
|
|
508
|
+
days: extendedTimeseriesBackfillDays,
|
|
509
|
+
});
|
|
510
|
+
return buildExtendedTimeseriesBackfillJob({
|
|
511
|
+
availableAt: now,
|
|
512
|
+
...(resource === "note" ? { historicalBackfillVersion: policy.version } : {}),
|
|
513
|
+
historicalWindowStart: window.windowStart,
|
|
514
|
+
resource,
|
|
515
|
+
sourceProviderSlug,
|
|
516
|
+
windowEnd: window.windowEnd,
|
|
517
|
+
windowStart: window.windowStart,
|
|
518
|
+
});
|
|
519
|
+
});
|
|
520
|
+
});
|
|
521
|
+
}
|
|
281
522
|
/**
|
|
282
523
|
* A dead push carrier cannot recover on its own and no pull can rediscover
|
|
283
524
|
* its data, so the scheduler turns a detected stall into a bounded recovery
|
|
@@ -507,15 +748,22 @@ export function createJunctionDeviceSyncProvider(config) {
|
|
|
507
748
|
}
|
|
508
749
|
async function executeJob(context, job) {
|
|
509
750
|
const skippedOptionalResources = [];
|
|
751
|
+
const completedWorkoutStreamIdentities = readJunctionWorkoutStreamCompletedIdentities(job);
|
|
510
752
|
if (job.kind === "resource") {
|
|
511
|
-
return executeResourceJob(context, job, skippedOptionalResources);
|
|
753
|
+
return executeResourceJob(context, job, skippedOptionalResources, completedWorkoutStreamIdentities);
|
|
512
754
|
}
|
|
513
755
|
if (job.kind === JUNCTION_PUSH_SOURCE_RECOVERY_JOB_KIND) {
|
|
514
756
|
return executePushSourceRecoveryJob(context, job);
|
|
515
757
|
}
|
|
758
|
+
if (isFullJobTimeseriesContinuation(job)) {
|
|
759
|
+
return executeFullJobTimeseriesContinuation(context, job, skippedOptionalResources, completedWorkoutStreamIdentities);
|
|
760
|
+
}
|
|
516
761
|
const window = resolveJobWindow(job, context.now, job.kind === "backfill" ? summaryBackfillDays : reconcileDays);
|
|
517
762
|
const isConnectHistoricalBackfill = isConnectHistoricalBackfillWindow(context.account, window);
|
|
518
763
|
const sourceProviders = await client.listUserProviders(context.account.externalAccountId, {
|
|
764
|
+
...(job.kind === "reconcile" && context.shouldYield
|
|
765
|
+
? { collectionWorkLimit: JUNCTION_FULL_JOB_INVENTORY_COLLECTION_WORK_LIMIT }
|
|
766
|
+
: {}),
|
|
519
767
|
signal: context.signal ?? null,
|
|
520
768
|
});
|
|
521
769
|
await projectJunctionSources(context, sourceProviders);
|
|
@@ -526,16 +774,43 @@ export function createJunctionDeviceSyncProvider(config) {
|
|
|
526
774
|
const summaryDateQueryFormat = job.kind === "reconcile" && !isCurrentSummaryReconcile && isFullUtcDayWindow(summaryWindow)
|
|
527
775
|
? "date"
|
|
528
776
|
: "datetime";
|
|
529
|
-
|
|
530
|
-
|
|
777
|
+
if (job.kind === "reconcile"
|
|
778
|
+
&& context.shouldYield
|
|
779
|
+
&& job.payload.summaryPhaseComplete !== true) {
|
|
780
|
+
const boundedSummaryResult = await executeBoundedSummaryReconcile({
|
|
781
|
+
context,
|
|
782
|
+
dateQueryFormat: summaryDateQueryFormat,
|
|
783
|
+
job,
|
|
784
|
+
skippedOptionalResources,
|
|
785
|
+
sourceProviders,
|
|
786
|
+
summaryWindow,
|
|
787
|
+
window,
|
|
788
|
+
});
|
|
789
|
+
if (boundedSummaryResult) {
|
|
790
|
+
return boundedSummaryResult;
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
const summaryPhaseComplete = job.kind === "reconcile" && job.payload.summaryPhaseComplete === true;
|
|
794
|
+
const summaries = summaryPhaseComplete
|
|
795
|
+
? {}
|
|
796
|
+
: await fetchSummarySnapshots(context, summaryWindow.windowStart, summaryWindow.windowEnd, skippedOptionalResources, { dateQueryFormat: summaryDateQueryFormat });
|
|
797
|
+
const profileSummaryResult = summaryPhaseComplete
|
|
798
|
+
? { checked: false, records: [] }
|
|
799
|
+
: await fetchProfileSummaryOnce(context, skippedOptionalResources);
|
|
531
800
|
const profileMetadataPatch = profileSummaryResult.checked
|
|
532
801
|
? buildJunctionProfileSummaryCheckedMetadataPatch(context)
|
|
533
802
|
: {};
|
|
534
803
|
if (profileSummaryResult.records.length > 0) {
|
|
535
804
|
summaries[JUNCTION_PROFILE_SUMMARY_RESOURCE] = profileSummaryResult.records;
|
|
536
805
|
}
|
|
537
|
-
const
|
|
538
|
-
const
|
|
806
|
+
const summaryHasFetchedRecords = hasJunctionSnapshotRecords(summaries);
|
|
807
|
+
const preparedSummaryImport = job.kind === "backfill"
|
|
808
|
+
&& !summaryHasFetchedRecords
|
|
809
|
+
&& context.shouldYield?.() === true
|
|
810
|
+
? prepareJunctionImportSnapshotForSources(summaries, sourceProviders, context.account.sources ?? [])
|
|
811
|
+
: await prepareJunctionImportSnapshot(context, summaries, sourceProviders);
|
|
812
|
+
const importConnections = preparedSummaryImport.connections;
|
|
813
|
+
const importSummaries = preparedSummaryImport.snapshots;
|
|
539
814
|
const summaryNormalizationEvidence = classifyJunctionSummaryNormalizationEvidence({
|
|
540
815
|
connections: importConnections,
|
|
541
816
|
importedAt: summaryWindow.windowEnd,
|
|
@@ -544,16 +819,9 @@ export function createJunctionDeviceSyncProvider(config) {
|
|
|
544
819
|
windowStart: summaryWindow.windowStart,
|
|
545
820
|
});
|
|
546
821
|
const historicalSummaryHasRecords = hasJunctionHistoricalBackfillSummaryRecords(summaryNormalizationEvidence);
|
|
547
|
-
const summaryHasFetchedRecords = hasJunctionSnapshotRecords(summaries);
|
|
548
822
|
const baseTimeseriesWindowStart = job.kind === "backfill"
|
|
549
823
|
? maxIsoTimestamp(window.windowStart, subtractDays(window.windowEnd, timeseriesBackfillDays))
|
|
550
824
|
: window.windowStart;
|
|
551
|
-
const timeseriesCursor = job.kind === "backfill"
|
|
552
|
-
? readBackfillTimeseriesCursor(job, window)
|
|
553
|
-
: null;
|
|
554
|
-
const timeseriesWindowStart = timeseriesCursor
|
|
555
|
-
? maxIsoTimestamp(baseTimeseriesWindowStart, timeseriesCursor)
|
|
556
|
-
: baseTimeseriesWindowStart;
|
|
557
825
|
if (job.kind !== "backfill" || summaryHasFetchedRecords) {
|
|
558
826
|
await context.importSnapshot({
|
|
559
827
|
provider: "junction",
|
|
@@ -572,19 +840,24 @@ export function createJunctionDeviceSyncProvider(config) {
|
|
|
572
840
|
const historicalPullSnapshot = isConnectHistoricalBackfill && !context.shouldYield?.()
|
|
573
841
|
? await loadJunctionHistoricalPullSnapshot(context)
|
|
574
842
|
: null;
|
|
575
|
-
const historicalSummaryCoverage = evaluateJunctionHistoricalBackfillCoverage(summaryNormalizationEvidence, sourceProviders, summaryResources, providerFilter, historicalPullSnapshot, isConnectHistoricalBackfill
|
|
843
|
+
const historicalSummaryCoverage = evaluateJunctionHistoricalBackfillCoverage(summaryNormalizationEvidence, preparedSummaryImport.sourceProviders, summaryResources, providerFilter, historicalPullSnapshot, isConnectHistoricalBackfill
|
|
576
844
|
? readJunctionHistoricalBackfillEvidence(context.account.metadata[JUNCTION_HISTORICAL_BACKFILL_METADATA_KEYS.evidence])
|
|
577
845
|
: null, window);
|
|
578
|
-
|
|
579
|
-
|| shouldImportClosedTimeseriesForReconcile(context.account.lastSyncCompletedAt, window.windowEnd)
|
|
580
|
-
|
|
846
|
+
const shouldImportBroadClosedTimeseries = job.kind === "backfill"
|
|
847
|
+
|| shouldImportClosedTimeseriesForReconcile(context.account.lastSyncCompletedAt, window.windowEnd);
|
|
848
|
+
const hourlyFidelityWindow = shouldImportBroadClosedTimeseries
|
|
849
|
+
? null
|
|
850
|
+
: resolveLatestGloballyClosedProviderDayWindow(baseTimeseriesWindowStart, window.windowEnd, context.now);
|
|
851
|
+
const dailyTimeseriesResources = timeseriesResources.filter((resource) => JUNCTION_CALENDAR_DAY_AGGREGATE_RESOURCE_SET.has(resource));
|
|
852
|
+
if (dailyTimeseriesResources.length > 0
|
|
853
|
+
&& hourlyFidelityWindow) {
|
|
854
|
+
const timeseriesImport = await importTimeseriesDailyAggregateSnapshots(context, sourceProviders, hourlyFidelityWindow.windowStart, hourlyFidelityWindow.windowEnd, skippedOptionalResources, dailyTimeseriesResources);
|
|
581
855
|
if (timeseriesImport.yieldedAt) {
|
|
582
856
|
return withJunctionSkippedResourceMetadata(context, withJunctionMetadataPatch(buildYieldedJunctionJobResult({
|
|
583
857
|
context,
|
|
584
858
|
job,
|
|
585
859
|
windowEnd: window.windowEnd,
|
|
586
|
-
windowStart:
|
|
587
|
-
timeseriesCursor: job.kind === "backfill" ? timeseriesImport.yieldedAt : null,
|
|
860
|
+
windowStart: timeseriesImport.yieldedAt,
|
|
588
861
|
}), profileMetadataPatch), skippedOptionalResources);
|
|
589
862
|
}
|
|
590
863
|
}
|
|
@@ -623,7 +896,7 @@ export function createJunctionDeviceSyncProvider(config) {
|
|
|
623
896
|
|| (historicalSummaryCoverage.complete
|
|
624
897
|
&& historicalStatusBeforeJob?.status === "exhausted"))) {
|
|
625
898
|
const pendingProviderSlugs = new Set(historicalSummaryCoverage.pendingProviderSlugs);
|
|
626
|
-
const hasCoveredProvider = sourceProviders.some((provider) => {
|
|
899
|
+
const hasCoveredProvider = preparedSummaryImport.sourceProviders.some((provider) => {
|
|
627
900
|
const providerSlug = resolveJunctionHistoricalCoverageProviderSlug(provider.origin.sourceProviderSlug ?? provider.slug, providerFilter);
|
|
628
901
|
return providerSlug !== null
|
|
629
902
|
&& mapJunctionSourceStatus(provider.status) !== "disconnected"
|
|
@@ -639,6 +912,29 @@ export function createJunctionDeviceSyncProvider(config) {
|
|
|
639
912
|
}
|
|
640
913
|
}
|
|
641
914
|
const nextReconcileAt = backfillFollowUp.nextReconcileAt ?? resolveJunctionNextReconcileAt(context.account, context.now, addMilliseconds(context.now, reconcileIntervalMs));
|
|
915
|
+
const shouldScheduleTimeseries = timeseriesResources.length > 0
|
|
916
|
+
&& (job.kind === "backfill"
|
|
917
|
+
|| shouldImportClosedTimeseriesForReconcile(context.account.lastSyncCompletedAt, window.windowEnd));
|
|
918
|
+
const timeseriesContinuation = shouldScheduleTimeseries
|
|
919
|
+
? buildFullJobTimeseriesContinuationJob({
|
|
920
|
+
deferredEmptyBackfillAttempts: readDeferredEmptyBackfillAttempts(backfillFollowUp),
|
|
921
|
+
job,
|
|
922
|
+
timeseriesCursor: baseTimeseriesWindowStart,
|
|
923
|
+
timeseriesResourceCursor: timeseriesResources[0] ?? null,
|
|
924
|
+
timeseriesWindowHours: 24,
|
|
925
|
+
window,
|
|
926
|
+
workoutStreamCursor: null,
|
|
927
|
+
})
|
|
928
|
+
: null;
|
|
929
|
+
if (timeseriesContinuation) {
|
|
930
|
+
return withJunctionSkippedResourceMetadata(context, withJunctionMetadataPatch({
|
|
931
|
+
...(backfillFollowUp.metadataPatch
|
|
932
|
+
? { metadataPatch: backfillFollowUp.metadataPatch }
|
|
933
|
+
: {}),
|
|
934
|
+
nextReconcileAt,
|
|
935
|
+
scheduledJobs: [{ ...timeseriesContinuation, availableAt: context.now }],
|
|
936
|
+
}, profileMetadataPatch), skippedOptionalResources);
|
|
937
|
+
}
|
|
642
938
|
return withJunctionSkippedResourceMetadata(context, withJunctionMetadataPatch({
|
|
643
939
|
...backfillFollowUp,
|
|
644
940
|
nextReconcileAt,
|
|
@@ -772,7 +1068,7 @@ export function createJunctionDeviceSyncProvider(config) {
|
|
|
772
1068
|
const timeseriesDiagnostics = [];
|
|
773
1069
|
if (timeseriesProbeWindow) {
|
|
774
1070
|
for (const resource of timeseriesResources) {
|
|
775
|
-
const resourceResult = await runJunctionDiagnosticCall(() => client
|
|
1071
|
+
const resourceResult = await runJunctionDiagnosticCall(() => fetchJunctionTimeseriesWindow(client, {
|
|
776
1072
|
resource,
|
|
777
1073
|
userId: context.account.externalAccountId,
|
|
778
1074
|
windowStart: timeseriesProbeWindow.windowStart,
|
|
@@ -969,7 +1265,7 @@ export function createJunctionDeviceSyncProvider(config) {
|
|
|
969
1265
|
const sourceProviderSlug = normalizeProviderSlug(context.sourceProviderSlug);
|
|
970
1266
|
const resourceCategory = endpoint;
|
|
971
1267
|
const resourceResult = await runJunctionDiagnosticCall(() => resourceCategory === "timeseries"
|
|
972
|
-
? client
|
|
1268
|
+
? fetchJunctionTimeseriesWindow(client, {
|
|
973
1269
|
resource: normalizedResource,
|
|
974
1270
|
sourceProviderSlug,
|
|
975
1271
|
userId: context.account.externalAccountId,
|
|
@@ -990,9 +1286,7 @@ export function createJunctionDeviceSyncProvider(config) {
|
|
|
990
1286
|
request: {
|
|
991
1287
|
configuredResource: isConfiguredJunctionResource(resourceCategory, normalizedResource),
|
|
992
1288
|
endpoint: resourceCategory,
|
|
993
|
-
endpointKind: resourceCategory
|
|
994
|
-
? "junction_timeseries_collection"
|
|
995
|
-
: "junction_summary_collection",
|
|
1289
|
+
endpointKind: resolveJunctionDiagnosticEndpointKind(resourceCategory, normalizedResource),
|
|
996
1290
|
queryParameterNames: resolveJunctionDiagnosticResourceQueryParameterNames(resourceCategory, normalizedResource, sourceProviderSlug),
|
|
997
1291
|
resource: normalizedResource,
|
|
998
1292
|
resourceCategory,
|
|
@@ -1003,8 +1297,9 @@ export function createJunctionDeviceSyncProvider(config) {
|
|
|
1003
1297
|
},
|
|
1004
1298
|
};
|
|
1005
1299
|
}
|
|
1006
|
-
async function executeResourceJob(context, job, skippedOptionalResources) {
|
|
1007
|
-
|
|
1300
|
+
async function executeResourceJob(context, job, skippedOptionalResources, completedWorkoutStreamIdentities) {
|
|
1301
|
+
const resourceName = normalizeString(job.payload.resource);
|
|
1302
|
+
if (resourceName === COMPANION_HRV_RMSSD_RESOURCE) {
|
|
1008
1303
|
let observation;
|
|
1009
1304
|
let admissionId;
|
|
1010
1305
|
try {
|
|
@@ -1024,6 +1319,9 @@ export function createJunctionDeviceSyncProvider(config) {
|
|
|
1024
1319
|
retryable: false,
|
|
1025
1320
|
});
|
|
1026
1321
|
}
|
|
1322
|
+
if (!await isJunctionCompanionSourceCurrentlyAdmitted(context, JUNCTION_COMPANION_HRV_SOURCE_PROVIDER)) {
|
|
1323
|
+
return {};
|
|
1324
|
+
}
|
|
1027
1325
|
await context.importSnapshot({
|
|
1028
1326
|
provider: "junction",
|
|
1029
1327
|
accountId: buildJunctionImportAccountId(context.account.externalAccountId),
|
|
@@ -1036,14 +1334,26 @@ export function createJunctionDeviceSyncProvider(config) {
|
|
|
1036
1334
|
const window = resolveJobWindow(job, context.now, reconcileDays);
|
|
1037
1335
|
if (normalizeString(job.payload.resource) === JUNCTION_COMPANION_HEALTH_METADATA_RESOURCE) {
|
|
1038
1336
|
const records = parseJunctionCompanionHealthMetadataJob(job);
|
|
1337
|
+
if (!await isJunctionCompanionSourceCurrentlyAdmitted(context, JUNCTION_COMPANION_HEALTH_METADATA_SOURCE_PROVIDER)) {
|
|
1338
|
+
return {};
|
|
1339
|
+
}
|
|
1039
1340
|
await importJunctionCompanionHealthMetadataSnapshot(context, records);
|
|
1040
1341
|
return {
|
|
1041
1342
|
nextReconcileAt: clampWebhookJobNextReconcileAt(context),
|
|
1042
1343
|
};
|
|
1043
1344
|
}
|
|
1345
|
+
const calendarRefreshDay = readJunctionSparseCalendarRefreshDay(job);
|
|
1044
1346
|
const resource = normalizeJunctionResourceName(job.payload.resource);
|
|
1045
1347
|
const resourceCategory = normalizeString(job.payload.resourceCategory);
|
|
1046
1348
|
const sourceProviderSlug = normalizeProviderSlug(job.payload.sourceProviderSlug);
|
|
1349
|
+
if (!calendarRefreshDay
|
|
1350
|
+
&& sourceProviderSlug
|
|
1351
|
+
&& !isJunctionSourceAdmittedForImport(context.account.sources ?? [], sourceProviderSlug)
|
|
1352
|
+
&& (resource === null
|
|
1353
|
+
|| !isJunctionExtendedTimeseriesBackfillJob(job, resource)
|
|
1354
|
+
|| isJunctionSourceProjectionFenced(context.account.sources ?? [], sourceProviderSlug))) {
|
|
1355
|
+
return {};
|
|
1356
|
+
}
|
|
1047
1357
|
let listedSourceProviders = null;
|
|
1048
1358
|
let projectedSourceProviders = null;
|
|
1049
1359
|
const loadSourceProviders = async () => {
|
|
@@ -1065,10 +1375,73 @@ export function createJunctionDeviceSyncProvider(config) {
|
|
|
1065
1375
|
projectedSourceProviders = sourceProviders;
|
|
1066
1376
|
return sourceProviders;
|
|
1067
1377
|
};
|
|
1378
|
+
if (calendarRefreshDay) {
|
|
1379
|
+
if (!resource
|
|
1380
|
+
|| !JUNCTION_SPARSE_CALENDAR_AGGREGATE_RESOURCE_SET.has(resource)
|
|
1381
|
+
|| !isConfiguredJunctionResource("timeseries", resource)) {
|
|
1382
|
+
throw deviceSyncError({
|
|
1383
|
+
code: JUNCTION_CALENDAR_REFRESH_JOB_INVALID_CODE,
|
|
1384
|
+
message: "Junction calendar refresh job did not name an admitted sparse resource.",
|
|
1385
|
+
retryable: false,
|
|
1386
|
+
});
|
|
1387
|
+
}
|
|
1388
|
+
const queuedCalendarSourceIdentity = readJunctionSparseCalendarSourceIdentity(job);
|
|
1389
|
+
const currentSources = context.listConnectionSources
|
|
1390
|
+
? await context.listConnectionSources()
|
|
1391
|
+
: context.account.sources ?? [];
|
|
1392
|
+
const accountSourceIdentity = resolveJunctionAccountSourceIdentity(currentSources, queuedCalendarSourceIdentity.sourceProviderSlug, context.connectionSourceAdmissionMode !== "listed_only");
|
|
1393
|
+
if (!accountSourceIdentity
|
|
1394
|
+
|| !isJunctionSourceAdmittedForImport(currentSources, sourceProviderSlug, context.connectionSourceAdmissionMode !== "listed_only", "connected")) {
|
|
1395
|
+
throw deviceSyncError({
|
|
1396
|
+
code: "JUNCTION_CALENDAR_REFRESH_SOURCE_AUTHORITY_UNAVAILABLE",
|
|
1397
|
+
message: "Junction calendar source authority is temporarily unavailable.",
|
|
1398
|
+
retryable: true,
|
|
1399
|
+
});
|
|
1400
|
+
}
|
|
1401
|
+
const sourceProviders = await loadAndProjectSourceProviders();
|
|
1402
|
+
const calendarSourceIdentity = {
|
|
1403
|
+
...queuedCalendarSourceIdentity,
|
|
1404
|
+
sourceProviderSlug: accountSourceIdentity.sourceProviderSlug,
|
|
1405
|
+
...(accountSourceIdentity.sourceInstanceId
|
|
1406
|
+
? { sourceInstanceId: accountSourceIdentity.sourceInstanceId }
|
|
1407
|
+
: {}),
|
|
1408
|
+
};
|
|
1409
|
+
const calendarFetchSourceProviderSlug = resolveJunctionProviderRouteSlug(queuedCalendarSourceIdentity.sourceProviderSlug);
|
|
1410
|
+
const windowStart = `${calendarRefreshDay}T00:00:00.000Z`;
|
|
1411
|
+
const dailyImport = await importTimeseriesDailyAggregateSnapshots(context, sourceProviders, windowStart, addMilliseconds(windowStart, TIMESERIES_CHUNK_MS), skippedOptionalResources, [resource], calendarFetchSourceProviderSlug, calendarSourceIdentity);
|
|
1412
|
+
const expectedDailyAggregateResourceId = buildJunctionDailyTimeseriesAggregateResourceId({
|
|
1413
|
+
dayKey: calendarRefreshDay,
|
|
1414
|
+
resource,
|
|
1415
|
+
...calendarSourceIdentity,
|
|
1416
|
+
});
|
|
1417
|
+
if (!dailyImport.yieldedAt
|
|
1418
|
+
&& !dailyImport.appliedDailyAggregateResourceIds?.includes(expectedDailyAggregateResourceId)) {
|
|
1419
|
+
throw deviceSyncError({
|
|
1420
|
+
code: "JUNCTION_CALENDAR_REFRESH_DAILY_STATE_NOT_APPLIED",
|
|
1421
|
+
message: "Junction calendar refresh did not apply its owned daily state.",
|
|
1422
|
+
retryable: true,
|
|
1423
|
+
});
|
|
1424
|
+
}
|
|
1425
|
+
const followUp = dailyImport.yieldedAt
|
|
1426
|
+
? buildJunctionSparseCalendarRefreshJob({
|
|
1427
|
+
dayKey: calendarRefreshDay,
|
|
1428
|
+
priority: job.priority,
|
|
1429
|
+
resource,
|
|
1430
|
+
...calendarSourceIdentity,
|
|
1431
|
+
})
|
|
1432
|
+
: null;
|
|
1433
|
+
return withJunctionSkippedResourceMetadata(context, {
|
|
1434
|
+
...(followUp ? { scheduledJobs: [followUp] } : {}),
|
|
1435
|
+
nextReconcileAt: clampWebhookJobNextReconcileAt(context),
|
|
1436
|
+
}, skippedOptionalResources);
|
|
1437
|
+
}
|
|
1068
1438
|
const summaries = {};
|
|
1069
1439
|
if (resource) {
|
|
1070
1440
|
const directInput = readJunctionDirectResourceJobInput(job, window);
|
|
1071
1441
|
if (directInput) {
|
|
1442
|
+
if (!isJunctionSourceAdmittedForImport(context.account.sources ?? [], directInput.sourceProviderSlug)) {
|
|
1443
|
+
return {};
|
|
1444
|
+
}
|
|
1072
1445
|
// This lookup uses the stable provider-config authority, not the
|
|
1073
1446
|
// replaceable per-connection credential epoch. It resolves source
|
|
1074
1447
|
// provenance only; the accepted inline payload remains the data
|
|
@@ -1132,19 +1505,307 @@ export function createJunctionDeviceSyncProvider(config) {
|
|
|
1132
1505
|
inferredCategory = fallback.category;
|
|
1133
1506
|
}
|
|
1134
1507
|
if (inferredCategory === "timeseries") {
|
|
1135
|
-
const
|
|
1136
|
-
const
|
|
1508
|
+
const extendedHistoricalBackfill = isJunctionExtendedTimeseriesBackfillJob(job, effectiveResource);
|
|
1509
|
+
const extendedHistoricalPolicy = extendedHistoricalBackfill
|
|
1510
|
+
? resolveJunctionExtendedTimeseriesBackfillPolicy(effectiveResource)
|
|
1511
|
+
: null;
|
|
1512
|
+
if (extendedHistoricalPolicy
|
|
1513
|
+
&& !canCurrentRuntimeMutateJunctionExtendedTimeseriesHistoryBackfillCoverage(context.account.metadata, effectiveResource, extendedHistoricalPolicy.version)) {
|
|
1514
|
+
return {};
|
|
1515
|
+
}
|
|
1516
|
+
if (extendedHistoricalPolicy
|
|
1517
|
+
&& sourceProviderSlug
|
|
1518
|
+
&& !canRepresentJunctionExtendedTimeseriesHistoryBackfillCoverage(context.account.metadata, sourceProviderSlug, effectiveResource, extendedHistoricalPolicy.version)) {
|
|
1519
|
+
throw deviceSyncError({
|
|
1520
|
+
code: "JUNCTION_EXTENDED_HISTORY_COVERAGE_UNREPRESENTABLE",
|
|
1521
|
+
message: "Junction extended-history completion could not be retained exactly.",
|
|
1522
|
+
retryable: false,
|
|
1523
|
+
});
|
|
1524
|
+
}
|
|
1525
|
+
const historicalWindowStart = toIsoTimestampIfValid(normalizeString(job.payload.historicalWindowStart))
|
|
1526
|
+
?? window.windowStart;
|
|
1527
|
+
const dailyAggregateRetryAttempts = readHistoricalBackfillJobEmptyAttempts(job);
|
|
1528
|
+
let sourceProviders;
|
|
1529
|
+
let sourceIdentityAuthority;
|
|
1530
|
+
let currentSourceAdmission = "admitted";
|
|
1531
|
+
try {
|
|
1532
|
+
sourceProviders = await loadAndProjectSourceProviders();
|
|
1533
|
+
if (extendedHistoricalBackfill && sourceProviderSlug) {
|
|
1534
|
+
sourceIdentityAuthority = context.listConnectionSources
|
|
1535
|
+
? await context.listConnectionSources()
|
|
1536
|
+
: context.account.sources ?? [];
|
|
1537
|
+
currentSourceAdmission = resolveJunctionCurrentSourceAdmissionFromSources(sourceIdentityAuthority, sourceProviderSlug, context.connectionSourceAdmissionMode !== "listed_only");
|
|
1538
|
+
}
|
|
1539
|
+
}
|
|
1540
|
+
catch (error) {
|
|
1541
|
+
if (extendedHistoricalBackfill
|
|
1542
|
+
&& (job.payload.historicalProviderRecordsSeen === true
|
|
1543
|
+
|| job.payload.historicalRecordsSeen === true)
|
|
1544
|
+
&& isRetryableDeviceSyncFailure(error)) {
|
|
1545
|
+
return withJunctionExtendedTimeseriesBackfillFollowUp({
|
|
1546
|
+
context,
|
|
1547
|
+
importResult: {
|
|
1548
|
+
acceptedProviderRecordCount: 0,
|
|
1549
|
+
canonicalProviderRecordIdentities: [],
|
|
1550
|
+
canonicalEventCount: 0,
|
|
1551
|
+
canonicalEventDayKeys: [],
|
|
1552
|
+
canonicalSparseCalendarTargets: [],
|
|
1553
|
+
fetchComplete: false,
|
|
1554
|
+
providerRecordsExamined: false,
|
|
1555
|
+
providerRecordCount: 0,
|
|
1556
|
+
unresolvedProviderRecordIdentities: [],
|
|
1557
|
+
unresolvedProviderRecordCount: 0,
|
|
1558
|
+
unresolvedProviderRecordsWithoutStableIdentity: false,
|
|
1559
|
+
yieldedAt: null,
|
|
1560
|
+
},
|
|
1561
|
+
job,
|
|
1562
|
+
resource: effectiveResource,
|
|
1563
|
+
result: {
|
|
1564
|
+
nextReconcileAt: clampWebhookJobNextReconcileAt(context),
|
|
1565
|
+
},
|
|
1566
|
+
window,
|
|
1567
|
+
});
|
|
1568
|
+
}
|
|
1569
|
+
throw error;
|
|
1570
|
+
}
|
|
1571
|
+
if (currentSourceAdmission === "fenced") {
|
|
1572
|
+
return {};
|
|
1573
|
+
}
|
|
1574
|
+
if (extendedHistoricalBackfill
|
|
1575
|
+
&& (currentSourceAdmission !== "admitted"
|
|
1576
|
+
|| !isJunctionSourceResourceCurrentlyAvailable({
|
|
1577
|
+
connectionId: context.account.id,
|
|
1578
|
+
providers: sourceProviders,
|
|
1579
|
+
resource: effectiveResource,
|
|
1580
|
+
sourceProviderSlug,
|
|
1581
|
+
}))) {
|
|
1582
|
+
const result = {
|
|
1583
|
+
nextReconcileAt: clampWebhookJobNextReconcileAt(context),
|
|
1584
|
+
};
|
|
1585
|
+
if (job.payload.historicalProviderRecordsSeen !== true
|
|
1586
|
+
&& job.payload.historicalRecordsSeen !== true) {
|
|
1587
|
+
return result;
|
|
1588
|
+
}
|
|
1589
|
+
return withJunctionExtendedTimeseriesBackfillFollowUp({
|
|
1590
|
+
context,
|
|
1591
|
+
importResult: {
|
|
1592
|
+
acceptedProviderRecordCount: 0,
|
|
1593
|
+
canonicalProviderRecordIdentities: [],
|
|
1594
|
+
canonicalEventCount: 0,
|
|
1595
|
+
canonicalEventDayKeys: [],
|
|
1596
|
+
canonicalSparseCalendarTargets: [],
|
|
1597
|
+
fetchComplete: false,
|
|
1598
|
+
providerRecordsExamined: false,
|
|
1599
|
+
providerRecordCount: 0,
|
|
1600
|
+
unresolvedProviderRecordIdentities: [],
|
|
1601
|
+
unresolvedProviderRecordCount: 0,
|
|
1602
|
+
unresolvedProviderRecordsWithoutStableIdentity: false,
|
|
1603
|
+
yieldedAt: null,
|
|
1604
|
+
},
|
|
1605
|
+
job,
|
|
1606
|
+
resource: effectiveResource,
|
|
1607
|
+
result,
|
|
1608
|
+
window,
|
|
1609
|
+
});
|
|
1610
|
+
}
|
|
1611
|
+
if (extendedHistoricalPolicy?.completion === "daily_aggregate"
|
|
1612
|
+
&& window.windowStart === historicalWindowStart) {
|
|
1613
|
+
const historicalPullReadiness = resolveJunctionHistoricalPullReadiness({
|
|
1614
|
+
resource: effectiveResource,
|
|
1615
|
+
snapshot: await loadJunctionHistoricalPullSnapshot(context),
|
|
1616
|
+
sourceProviderSlug,
|
|
1617
|
+
});
|
|
1618
|
+
if (historicalPullReadiness === "no_obligation") {
|
|
1619
|
+
return withJunctionExtendedTimeseriesBackfillFollowUp({
|
|
1620
|
+
context,
|
|
1621
|
+
historicalPullReadiness,
|
|
1622
|
+
importResult: {
|
|
1623
|
+
acceptedProviderRecordCount: 0,
|
|
1624
|
+
canonicalProviderRecordIdentities: [],
|
|
1625
|
+
canonicalEventCount: 0,
|
|
1626
|
+
canonicalEventDayKeys: [],
|
|
1627
|
+
canonicalSparseCalendarTargets: [],
|
|
1628
|
+
fetchComplete: true,
|
|
1629
|
+
providerRecordsExamined: false,
|
|
1630
|
+
providerRecordCount: 0,
|
|
1631
|
+
unresolvedProviderRecordIdentities: [],
|
|
1632
|
+
unresolvedProviderRecordCount: 0,
|
|
1633
|
+
unresolvedProviderRecordsWithoutStableIdentity: false,
|
|
1634
|
+
yieldedAt: null,
|
|
1635
|
+
},
|
|
1636
|
+
job,
|
|
1637
|
+
resource: effectiveResource,
|
|
1638
|
+
result: { nextReconcileAt: clampWebhookJobNextReconcileAt(context) },
|
|
1639
|
+
window,
|
|
1640
|
+
});
|
|
1641
|
+
}
|
|
1642
|
+
if (historicalPullReadiness === "pending") {
|
|
1643
|
+
const retryDelayMs = EMPTY_HISTORICAL_BACKFILL_RETRY_DELAYS_MS.at(-1) ?? 0;
|
|
1644
|
+
return {
|
|
1645
|
+
nextReconcileAt: clampWebhookJobNextReconcileAt(context),
|
|
1646
|
+
scheduledJobs: [buildExtendedTimeseriesBackfillJob({
|
|
1647
|
+
availableAt: addMilliseconds(context.now, retryDelayMs),
|
|
1648
|
+
dedupeKey: job.dedupeKey,
|
|
1649
|
+
historicalWindowStart,
|
|
1650
|
+
resource: effectiveResource,
|
|
1651
|
+
sourceProviderSlug,
|
|
1652
|
+
windowEnd: window.windowEnd,
|
|
1653
|
+
windowStart: window.windowStart,
|
|
1654
|
+
})],
|
|
1655
|
+
};
|
|
1656
|
+
}
|
|
1657
|
+
if (historicalPullReadiness === "terminal_failure") {
|
|
1658
|
+
return { nextReconcileAt: clampWebhookJobNextReconcileAt(context) };
|
|
1659
|
+
}
|
|
1660
|
+
}
|
|
1661
|
+
const timeseriesPolicy = resolveJunctionTimeseriesResourcePolicy(effectiveResource);
|
|
1662
|
+
if (JUNCTION_DENSE_FIDELITY_RESOURCE_SET.has(effectiveResource)) {
|
|
1663
|
+
const dailyImport = await importTimeseriesDailyAggregateSnapshots(context, sourceProviders, window.windowStart, window.windowEnd, skippedOptionalResources, [effectiveResource], sourceProviderSlug);
|
|
1664
|
+
if (dailyImport.yieldedAt) {
|
|
1665
|
+
return withJunctionSkippedResourceMetadata(context, buildYieldedJunctionJobResult({
|
|
1666
|
+
context,
|
|
1667
|
+
job,
|
|
1668
|
+
windowEnd: window.windowEnd,
|
|
1669
|
+
windowStart: dailyImport.yieldedAt,
|
|
1670
|
+
}), skippedOptionalResources);
|
|
1671
|
+
}
|
|
1672
|
+
return withJunctionHistoricalCoverageVerification(context, job, window, withJunctionSkippedResourceMetadata(context, { nextReconcileAt: clampWebhookJobNextReconcileAt(context) }, skippedOptionalResources));
|
|
1673
|
+
}
|
|
1674
|
+
if (timeseriesPolicy?.historyWindow === "dense_timeseries"
|
|
1675
|
+
&& (timeseriesPolicy.enabledByDefault === false
|
|
1676
|
+
|| JUNCTION_CLOSED_DAY_TIMESERIES_RESOURCES.has(effectiveResource))) {
|
|
1677
|
+
const dailyImport = await importTimeseriesDailySnapshots(context, sourceProviders, window.windowStart, window.windowEnd, skippedOptionalResources, effectiveResource, sourceProviderSlug, completedWorkoutStreamIdentities);
|
|
1678
|
+
const result = withJunctionSkippedResourceMetadata(context, dailyImport.yieldedAt
|
|
1679
|
+
? buildYieldedJunctionJobResult({
|
|
1680
|
+
context,
|
|
1681
|
+
job,
|
|
1682
|
+
windowEnd: window.windowEnd,
|
|
1683
|
+
windowStart: dailyImport.yieldedAt,
|
|
1684
|
+
workoutStreamCursor: effectiveResource === "workout_stream"
|
|
1685
|
+
? dailyImport.workoutStreamCursor
|
|
1686
|
+
: undefined,
|
|
1687
|
+
})
|
|
1688
|
+
: { nextReconcileAt: clampWebhookJobNextReconcileAt(context) }, skippedOptionalResources);
|
|
1689
|
+
return result;
|
|
1690
|
+
}
|
|
1691
|
+
const timeseriesImport = await importTimeseriesPreciseSnapshots(context, sourceProviders, window.windowStart, window.windowEnd, skippedOptionalResources, [effectiveResource], sourceProviderSlug, {
|
|
1692
|
+
dateQueryFormat: extendedHistoricalPolicy?.completion === "daily_aggregate"
|
|
1693
|
+
? "date"
|
|
1694
|
+
: "datetime",
|
|
1695
|
+
historicalProviderRecordsSeen: job.payload.historicalProviderRecordsSeen === true,
|
|
1696
|
+
preservePartialRetryableFailure: extendedHistoricalBackfill,
|
|
1697
|
+
...(sourceIdentityAuthority ? { sourceIdentityAuthority } : {}),
|
|
1698
|
+
sourceStatusRequirement: extendedHistoricalBackfill
|
|
1699
|
+
? "connected"
|
|
1700
|
+
: undefined,
|
|
1701
|
+
});
|
|
1702
|
+
const calendarRefreshJobs = JUNCTION_SPARSE_CALENDAR_AGGREGATE_RESOURCE_SET.has(effectiveResource)
|
|
1703
|
+
? buildJunctionSparseCalendarRefreshJobs({
|
|
1704
|
+
asOf: context.now,
|
|
1705
|
+
priority: job.priority,
|
|
1706
|
+
resource: effectiveResource,
|
|
1707
|
+
targets: timeseriesImport.canonicalSparseCalendarTargets,
|
|
1708
|
+
})
|
|
1709
|
+
: [];
|
|
1710
|
+
const finalizePreciseImportResult = (result) => calendarRefreshJobs.length === 0
|
|
1711
|
+
? result
|
|
1712
|
+
: {
|
|
1713
|
+
...result,
|
|
1714
|
+
scheduledJobs: [
|
|
1715
|
+
...(result.scheduledJobs ?? []),
|
|
1716
|
+
...calendarRefreshJobs,
|
|
1717
|
+
],
|
|
1718
|
+
};
|
|
1719
|
+
if (extendedHistoricalBackfill
|
|
1720
|
+
&& timeseriesImport.postFetchSourceAdmission === "fenced") {
|
|
1721
|
+
return finalizePreciseImportResult({});
|
|
1722
|
+
}
|
|
1723
|
+
if (extendedHistoricalBackfill
|
|
1724
|
+
&& timeseriesImport.postFetchSourceAdmission === "pending"
|
|
1725
|
+
&& job.payload.historicalProviderRecordsSeen !== true
|
|
1726
|
+
&& job.payload.historicalRecordsSeen !== true
|
|
1727
|
+
&& timeseriesImport.providerRecordCount === 0) {
|
|
1728
|
+
return finalizePreciseImportResult(withJunctionSkippedResourceMetadata(context, {
|
|
1729
|
+
nextReconcileAt: clampWebhookJobNextReconcileAt(context),
|
|
1730
|
+
}, skippedOptionalResources));
|
|
1731
|
+
}
|
|
1732
|
+
const historicalRecordsSeen = extendedHistoricalBackfill
|
|
1733
|
+
? job.payload.historicalRecordsSeen === true
|
|
1734
|
+
|| timeseriesImport.canonicalEventCount > 0
|
|
1735
|
+
|| (effectiveResource === "weight"
|
|
1736
|
+
&& timeseriesImport.providerRecordsExamined)
|
|
1737
|
+
: undefined;
|
|
1738
|
+
const dailyAggregateNeedsRetry = extendedHistoricalPolicy?.completion === "daily_aggregate"
|
|
1739
|
+
&& timeseriesImport.providerRecordCount > 0
|
|
1740
|
+
&& timeseriesImport.acceptedProviderRecordCount < timeseriesImport.providerRecordCount
|
|
1741
|
+
&& dailyAggregateRetryAttempts < EMPTY_HISTORICAL_BACKFILL_RETRY_DELAYS_MS.length;
|
|
1742
|
+
if (dailyAggregateNeedsRetry) {
|
|
1743
|
+
const retryAttempts = dailyAggregateRetryAttempts + 1;
|
|
1744
|
+
const retryDelayMs = EMPTY_HISTORICAL_BACKFILL_RETRY_DELAYS_MS[retryAttempts - 1] ?? 0;
|
|
1745
|
+
return finalizePreciseImportResult(withJunctionSkippedResourceMetadata(context, {
|
|
1746
|
+
nextReconcileAt: clampWebhookJobNextReconcileAt(context),
|
|
1747
|
+
scheduledJobs: [buildExtendedTimeseriesBackfillJob({
|
|
1748
|
+
availableAt: addMilliseconds(context.now, retryDelayMs),
|
|
1749
|
+
dedupeKey: job.dedupeKey,
|
|
1750
|
+
emptyBackfillAttempts: retryAttempts,
|
|
1751
|
+
historicalRecordsSeen,
|
|
1752
|
+
historicalWindowStart,
|
|
1753
|
+
resource: effectiveResource,
|
|
1754
|
+
sourceProviderSlug,
|
|
1755
|
+
windowEnd: window.windowEnd,
|
|
1756
|
+
windowStart: window.windowStart,
|
|
1757
|
+
})],
|
|
1758
|
+
}, skippedOptionalResources));
|
|
1759
|
+
}
|
|
1760
|
+
const historicalUnresolvedProviderRecords = extendedHistoricalBackfill
|
|
1761
|
+
&& extendedHistoricalPolicy?.completion !== "daily_aggregate"
|
|
1762
|
+
? resolveJunctionHistoricalUnresolvedProviderRecords(job, timeseriesImport)
|
|
1763
|
+
: undefined;
|
|
1764
|
+
const historicalUnresolvedProviderRecordCount = historicalUnresolvedProviderRecords === undefined
|
|
1765
|
+
? undefined
|
|
1766
|
+
: countJunctionHistoricalUnresolvedProviderRecords(historicalUnresolvedProviderRecords);
|
|
1767
|
+
const historicalUnresolvedProviderRecordIdentitiesJson = historicalUnresolvedProviderRecords === undefined
|
|
1768
|
+
? undefined
|
|
1769
|
+
: encodeJunctionHistoricalUnresolvedProviderRecords(historicalUnresolvedProviderRecords);
|
|
1770
|
+
const historicalProviderRecordsSeen = historicalUnresolvedProviderRecordCount === undefined
|
|
1771
|
+
? undefined
|
|
1772
|
+
: historicalUnresolvedProviderRecordCount > 0;
|
|
1137
1773
|
if (timeseriesImport.yieldedAt) {
|
|
1138
|
-
|
|
1774
|
+
const yieldedResult = buildYieldedJunctionJobResult({
|
|
1139
1775
|
context,
|
|
1776
|
+
emptyBackfillAttempts: extendedHistoricalPolicy?.completion === "daily_aggregate"
|
|
1777
|
+
? 0
|
|
1778
|
+
: undefined,
|
|
1779
|
+
historicalProviderRecordsSeen,
|
|
1780
|
+
historicalRecordsSeen,
|
|
1781
|
+
historicalUnresolvedProviderRecordIdentitiesJson,
|
|
1782
|
+
historicalUnresolvedProviderRecordCount,
|
|
1140
1783
|
job,
|
|
1141
1784
|
windowEnd: window.windowEnd,
|
|
1142
1785
|
windowStart: timeseriesImport.yieldedAt,
|
|
1143
|
-
})
|
|
1786
|
+
});
|
|
1787
|
+
return finalizePreciseImportResult(withJunctionSkippedResourceMetadata(context, yieldedResult, skippedOptionalResources));
|
|
1144
1788
|
}
|
|
1145
|
-
|
|
1789
|
+
const result = withJunctionSkippedResourceMetadata(context, {
|
|
1146
1790
|
nextReconcileAt: clampWebhookJobNextReconcileAt(context),
|
|
1147
|
-
}, skippedOptionalResources)
|
|
1791
|
+
}, skippedOptionalResources);
|
|
1792
|
+
const historicalPullReadiness = extendedHistoricalPolicy?.completion === "daily_aggregate"
|
|
1793
|
+
&& timeseriesImport.fetchComplete
|
|
1794
|
+
? resolveJunctionHistoricalPullReadiness({
|
|
1795
|
+
resource: effectiveResource,
|
|
1796
|
+
snapshot: await loadJunctionHistoricalPullSnapshot(context),
|
|
1797
|
+
sourceProviderSlug,
|
|
1798
|
+
})
|
|
1799
|
+
: undefined;
|
|
1800
|
+
return finalizePreciseImportResult(withJunctionHistoricalCoverageVerification(context, job, window, withJunctionExtendedTimeseriesBackfillFollowUp({
|
|
1801
|
+
context,
|
|
1802
|
+
historicalPullReadiness,
|
|
1803
|
+
importResult: timeseriesImport,
|
|
1804
|
+
job,
|
|
1805
|
+
resource: effectiveResource,
|
|
1806
|
+
result,
|
|
1807
|
+
window,
|
|
1808
|
+
})));
|
|
1148
1809
|
}
|
|
1149
1810
|
const dateQueryFormat = isFullUtcDayWindow(window) ? "date" : "datetime";
|
|
1150
1811
|
summaries[effectiveResource] = await fetchOptionalJunctionResourceRecords(context, "summary", effectiveResource, skippedOptionalResources, () => client.listSummary({
|
|
@@ -1158,6 +1819,7 @@ export function createJunctionDeviceSyncProvider(config) {
|
|
|
1158
1819
|
}));
|
|
1159
1820
|
}
|
|
1160
1821
|
const sourceProviders = await loadAndProjectSourceProviders();
|
|
1822
|
+
const preparedImport = await prepareJunctionImportSnapshot(context, summaries, sourceProviders);
|
|
1161
1823
|
await context.importSnapshot({
|
|
1162
1824
|
provider: "junction",
|
|
1163
1825
|
accountId: buildJunctionImportAccountId(context.account.externalAccountId),
|
|
@@ -1165,8 +1827,8 @@ export function createJunctionDeviceSyncProvider(config) {
|
|
|
1165
1827
|
importedAt: context.now,
|
|
1166
1828
|
windowStart: window.windowStart,
|
|
1167
1829
|
windowEnd: window.windowEnd,
|
|
1168
|
-
connections:
|
|
1169
|
-
summaries:
|
|
1830
|
+
connections: preparedImport.connections,
|
|
1831
|
+
summaries: preparedImport.snapshots,
|
|
1170
1832
|
timeseries: {},
|
|
1171
1833
|
});
|
|
1172
1834
|
return withJunctionHistoricalCoverageVerification(context, job, window, withJunctionSkippedResourceMetadata(context, {
|
|
@@ -1211,6 +1873,167 @@ export function createJunctionDeviceSyncProvider(config) {
|
|
|
1211
1873
|
? scheduledAt
|
|
1212
1874
|
: latestAt;
|
|
1213
1875
|
}
|
|
1876
|
+
function withJunctionExtendedTimeseriesBackfillFollowUp(input) {
|
|
1877
|
+
if (!isJunctionExtendedTimeseriesBackfillJob(input.job, input.resource)) {
|
|
1878
|
+
return input.result;
|
|
1879
|
+
}
|
|
1880
|
+
const policy = resolveJunctionExtendedTimeseriesBackfillPolicy(input.resource);
|
|
1881
|
+
if (!policy) {
|
|
1882
|
+
return input.result;
|
|
1883
|
+
}
|
|
1884
|
+
const sourceProviderSlug = normalizeProviderSlug(input.job.payload.sourceProviderSlug);
|
|
1885
|
+
const historicalWindowStart = toIsoTimestampIfValid(normalizeString(input.job.payload.historicalWindowStart))
|
|
1886
|
+
?? input.window.windowStart;
|
|
1887
|
+
const recordsSeen = input.job.payload.historicalRecordsSeen === true
|
|
1888
|
+
|| input.importResult.canonicalEventCount > 0
|
|
1889
|
+
|| (input.resource === "weight"
|
|
1890
|
+
&& input.importResult.providerRecordsExamined);
|
|
1891
|
+
const unresolvedProviderRecords = input.resource === "weight"
|
|
1892
|
+
&& input.importResult.fetchComplete
|
|
1893
|
+
&& input.importResult.unresolvedProviderRecordCount === 0
|
|
1894
|
+
? { identities: [], withoutStableIdentity: false }
|
|
1895
|
+
: resolveJunctionHistoricalUnresolvedProviderRecords(input.job, input.importResult);
|
|
1896
|
+
const unresolvedProviderRecordCount = countJunctionHistoricalUnresolvedProviderRecords(unresolvedProviderRecords);
|
|
1897
|
+
const unresolvedProviderRecordIdentitiesJson = encodeJunctionHistoricalUnresolvedProviderRecords(unresolvedProviderRecords);
|
|
1898
|
+
const unresolvedProviderRecordsSeen = unresolvedProviderRecordCount > 0;
|
|
1899
|
+
if (policy.completion === "daily_aggregate" && input.importResult.fetchComplete) {
|
|
1900
|
+
const historicalPullReadiness = input.historicalPullReadiness ?? "unavailable";
|
|
1901
|
+
const currentReconcileWindowStart = floorUtcDayTimestamp(subtractDays(floorUtcDayTimestamp(input.context.now), reconcileDays));
|
|
1902
|
+
if (historicalPullReadiness === "pending"
|
|
1903
|
+
|| (historicalPullReadiness === "unavailable" && !recordsSeen)) {
|
|
1904
|
+
const retryDelayMs = EMPTY_HISTORICAL_BACKFILL_RETRY_DELAYS_MS.at(-1) ?? 0;
|
|
1905
|
+
return {
|
|
1906
|
+
...input.result,
|
|
1907
|
+
scheduledJobs: [
|
|
1908
|
+
...(input.result.scheduledJobs ?? []),
|
|
1909
|
+
buildExtendedTimeseriesBackfillJob({
|
|
1910
|
+
availableAt: addMilliseconds(input.context.now, retryDelayMs),
|
|
1911
|
+
dedupeKey: input.job.dedupeKey,
|
|
1912
|
+
historicalWindowStart,
|
|
1913
|
+
resource: input.resource,
|
|
1914
|
+
sourceProviderSlug,
|
|
1915
|
+
windowEnd: maxIsoTimestamp(input.window.windowEnd, currentReconcileWindowStart),
|
|
1916
|
+
windowStart: historicalWindowStart,
|
|
1917
|
+
}),
|
|
1918
|
+
],
|
|
1919
|
+
};
|
|
1920
|
+
}
|
|
1921
|
+
if (Date.parse(input.window.windowEnd) < Date.parse(currentReconcileWindowStart)) {
|
|
1922
|
+
return {
|
|
1923
|
+
...input.result,
|
|
1924
|
+
scheduledJobs: [
|
|
1925
|
+
...(input.result.scheduledJobs ?? []),
|
|
1926
|
+
buildExtendedTimeseriesBackfillJob({
|
|
1927
|
+
availableAt: input.context.now,
|
|
1928
|
+
dedupeKey: input.job.dedupeKey,
|
|
1929
|
+
historicalRecordsSeen: recordsSeen,
|
|
1930
|
+
historicalWindowStart,
|
|
1931
|
+
resource: input.resource,
|
|
1932
|
+
sourceProviderSlug,
|
|
1933
|
+
windowEnd: currentReconcileWindowStart,
|
|
1934
|
+
windowStart: input.window.windowEnd,
|
|
1935
|
+
}),
|
|
1936
|
+
],
|
|
1937
|
+
};
|
|
1938
|
+
}
|
|
1939
|
+
if (historicalPullReadiness === "terminal_failure") {
|
|
1940
|
+
return input.result;
|
|
1941
|
+
}
|
|
1942
|
+
return withJunctionMetadataPatch(input.result, buildJunctionExtendedTimeseriesBackfillCompletionMetadataPatch(input.context, input.job, input.resource, sourceProviderSlug));
|
|
1943
|
+
}
|
|
1944
|
+
// A complete note scan can close its one-time source coverage even when
|
|
1945
|
+
// no action-like tags exist. Neutral wearable-tag notes, including a
|
|
1946
|
+
// cleared tag state, do not create a separate backfill repair obligation.
|
|
1947
|
+
if (input.resource === "note" && input.importResult.fetchComplete) {
|
|
1948
|
+
return withJunctionMetadataPatch(input.result, buildJunctionExtendedTimeseriesBackfillCompletionMetadataPatch(input.context, input.job, input.resource, sourceProviderSlug));
|
|
1949
|
+
}
|
|
1950
|
+
const completionProven = input.importResult.fetchComplete && (policy.completion === "fetch_complete"
|
|
1951
|
+
|| (policy.completion === "exact_records"
|
|
1952
|
+
&& recordsSeen
|
|
1953
|
+
&& unresolvedProviderRecordCount === 0));
|
|
1954
|
+
if (completionProven) {
|
|
1955
|
+
return withJunctionMetadataPatch(input.result, buildJunctionExtendedTimeseriesBackfillCompletionMetadataPatch(input.context, input.job, input.resource, sourceProviderSlug));
|
|
1956
|
+
}
|
|
1957
|
+
let emptyBackfillAttempts = readHistoricalBackfillJobEmptyAttempts(input.job) + 1;
|
|
1958
|
+
let retryDelayMs = EMPTY_HISTORICAL_BACKFILL_RETRY_DELAYS_MS[emptyBackfillAttempts - 1]
|
|
1959
|
+
?? null;
|
|
1960
|
+
if (retryDelayMs === null
|
|
1961
|
+
&& (!input.importResult.fetchComplete || unresolvedProviderRecordsSeen)) {
|
|
1962
|
+
emptyBackfillAttempts = EMPTY_HISTORICAL_BACKFILL_RETRY_DELAYS_MS.length;
|
|
1963
|
+
retryDelayMs =
|
|
1964
|
+
EMPTY_HISTORICAL_BACKFILL_RETRY_DELAYS_MS[emptyBackfillAttempts - 1]
|
|
1965
|
+
?? null;
|
|
1966
|
+
}
|
|
1967
|
+
if (retryDelayMs === null) {
|
|
1968
|
+
return withJunctionMetadataPatch(input.result, buildJunctionExtendedTimeseriesBackfillCompletionMetadataPatch(input.context, input.job, input.resource, sourceProviderSlug));
|
|
1969
|
+
}
|
|
1970
|
+
return {
|
|
1971
|
+
...input.result,
|
|
1972
|
+
scheduledJobs: [
|
|
1973
|
+
...(input.result.scheduledJobs ?? []),
|
|
1974
|
+
buildExtendedTimeseriesBackfillJob({
|
|
1975
|
+
availableAt: addMilliseconds(input.context.now, retryDelayMs),
|
|
1976
|
+
dedupeKey: input.job.dedupeKey,
|
|
1977
|
+
emptyBackfillAttempts,
|
|
1978
|
+
...(input.resource === "note"
|
|
1979
|
+
? {
|
|
1980
|
+
historicalBackfillVersion: readJunctionNoteHistoryBackfillVersion(input.job.payload),
|
|
1981
|
+
}
|
|
1982
|
+
: {}),
|
|
1983
|
+
historicalProviderRecordsSeen: unresolvedProviderRecordsSeen,
|
|
1984
|
+
historicalRecordsSeen: recordsSeen,
|
|
1985
|
+
historicalUnresolvedProviderRecordIdentitiesJson: unresolvedProviderRecordIdentitiesJson,
|
|
1986
|
+
historicalUnresolvedProviderRecordCount: unresolvedProviderRecordCount,
|
|
1987
|
+
historicalWindowStart,
|
|
1988
|
+
resource: input.resource,
|
|
1989
|
+
sourceProviderSlug,
|
|
1990
|
+
windowEnd: input.window.windowEnd,
|
|
1991
|
+
windowStart: input.importResult.fetchComplete
|
|
1992
|
+
? historicalWindowStart
|
|
1993
|
+
: input.window.windowStart,
|
|
1994
|
+
}),
|
|
1995
|
+
],
|
|
1996
|
+
};
|
|
1997
|
+
}
|
|
1998
|
+
function buildJunctionExtendedTimeseriesBackfillCompletionMetadataPatch(context, job, resource, sourceProviderSlug) {
|
|
1999
|
+
if (!sourceProviderSlug) {
|
|
2000
|
+
return {};
|
|
2001
|
+
}
|
|
2002
|
+
const policy = resolveJunctionExtendedTimeseriesBackfillPolicy(resource);
|
|
2003
|
+
if (!policy) {
|
|
2004
|
+
return {};
|
|
2005
|
+
}
|
|
2006
|
+
if (!canCurrentRuntimeMutateJunctionExtendedTimeseriesHistoryBackfillCoverage(context.account.metadata, resource, policy.version)) {
|
|
2007
|
+
return {};
|
|
2008
|
+
}
|
|
2009
|
+
const admittedVersion = resource === "note"
|
|
2010
|
+
? readJunctionNoteHistoryBackfillVersion(job.payload)
|
|
2011
|
+
: policy.version;
|
|
2012
|
+
if (admittedVersion !== policy.version) {
|
|
2013
|
+
// A semantic generation can only certify its own coverage. Older jobs
|
|
2014
|
+
// may still import facts without closing the current generation's bit.
|
|
2015
|
+
return {};
|
|
2016
|
+
}
|
|
2017
|
+
const coverage = addJunctionExtendedTimeseriesHistoryBackfillCoverage({
|
|
2018
|
+
metadata: context.account.metadata,
|
|
2019
|
+
providerSlug: sourceProviderSlug,
|
|
2020
|
+
resource,
|
|
2021
|
+
version: admittedVersion,
|
|
2022
|
+
});
|
|
2023
|
+
if (!coverage) {
|
|
2024
|
+
throw deviceSyncError({
|
|
2025
|
+
code: "JUNCTION_EXTENDED_HISTORY_COVERAGE_UNREPRESENTABLE",
|
|
2026
|
+
message: "Junction extended-history completion could not be retained exactly.",
|
|
2027
|
+
retryable: false,
|
|
2028
|
+
});
|
|
2029
|
+
}
|
|
2030
|
+
return { [coverage.metadataKey]: coverage.value };
|
|
2031
|
+
}
|
|
2032
|
+
function isJunctionExtendedTimeseriesBackfillJob(job, resource) {
|
|
2033
|
+
return job.kind === "resource"
|
|
2034
|
+
&& job.payload.historicalBackfill === true
|
|
2035
|
+
&& resolveJunctionExtendedTimeseriesBackfillPolicy(resource) !== null;
|
|
2036
|
+
}
|
|
1214
2037
|
function withJunctionHistoricalCoverageVerification(context, job, resourceWindow, result) {
|
|
1215
2038
|
const historicalState = readHistoricalBackfillStatus(context.account.metadata);
|
|
1216
2039
|
const eventType = normalizeString(job.payload.eventType);
|
|
@@ -1303,7 +2126,8 @@ export function createJunctionDeviceSyncProvider(config) {
|
|
|
1303
2126
|
const resource = inferJunctionWebhookResource(eventType, data);
|
|
1304
2127
|
const sourceProviderSlug = extractJunctionWebhookSourceProviderSlug(data);
|
|
1305
2128
|
const objectId = extractJunctionWebhookObjectId(data);
|
|
1306
|
-
const
|
|
2129
|
+
const eventOccurredAt = extractJunctionWebhookOccurredAt(data);
|
|
2130
|
+
const occurredAt = eventOccurredAt ?? context.now;
|
|
1307
2131
|
const window = buildJunctionWebhookWindow(data, occurredAt, context.now, resource);
|
|
1308
2132
|
const webhookDataJsons = buildJunctionWebhookDataJobJsons({
|
|
1309
2133
|
data,
|
|
@@ -1329,8 +2153,10 @@ export function createJunctionDeviceSyncProvider(config) {
|
|
|
1329
2153
|
externalAccountDiagnostic: buildJunctionWebhookExternalAccountDiagnostic(externalAccountSelection),
|
|
1330
2154
|
eventType,
|
|
1331
2155
|
traceId: verified.messageId,
|
|
1332
|
-
occurredAt,
|
|
2156
|
+
...(eventOccurredAt ? { occurredAt: eventOccurredAt } : {}),
|
|
2157
|
+
providerSentAt: verified.providerSentAt,
|
|
1333
2158
|
resourceCategory: resource?.category ?? null,
|
|
2159
|
+
sourceProviderSlug,
|
|
1334
2160
|
// A historical-pull completion is a data-less notification, so accepting
|
|
1335
2161
|
// its fetch job proves nothing arrived. Treating it as delivery would
|
|
1336
2162
|
// refresh the arrival signal and hide the very stall this detects.
|
|
@@ -1350,23 +2176,109 @@ export function createJunctionDeviceSyncProvider(config) {
|
|
|
1350
2176
|
if (isJunctionProfileSummaryResource(resource)) {
|
|
1351
2177
|
continue;
|
|
1352
2178
|
}
|
|
1353
|
-
|
|
2179
|
+
const request = {
|
|
1354
2180
|
resource,
|
|
1355
2181
|
signal: context.signal ?? null,
|
|
1356
2182
|
userId: context.account.externalAccountId,
|
|
1357
2183
|
windowStart,
|
|
1358
2184
|
windowEnd,
|
|
1359
|
-
|
|
1360
|
-
|
|
2185
|
+
};
|
|
2186
|
+
if (options.dateQueryFormat) {
|
|
2187
|
+
request.dateQueryFormat = options.dateQueryFormat;
|
|
2188
|
+
}
|
|
2189
|
+
snapshots[resource] = await fetchOptionalJunctionResourceRecords(context, "summary", resource, skippedOptionalResources, () => client.listSummary(request));
|
|
1361
2190
|
}
|
|
1362
2191
|
return snapshots;
|
|
1363
2192
|
}
|
|
1364
|
-
async function
|
|
2193
|
+
async function executeBoundedSummaryReconcile(input) {
|
|
2194
|
+
const profileAlreadyChecked = hasCheckedJunctionProfileSummary(input.context.account.metadata);
|
|
2195
|
+
const eligibleResources = summaryResources.filter((resource) => !isJunctionProfileSummaryResource(resource) || !profileAlreadyChecked);
|
|
2196
|
+
const eligibleUnits = eligibleResources.reduce((units, resource) => {
|
|
2197
|
+
if (resource === "sleep_cycle" && eligibleResources.includes("sleep")) {
|
|
2198
|
+
return units;
|
|
2199
|
+
}
|
|
2200
|
+
units.push(resource === "sleep" && eligibleResources.includes("sleep_cycle")
|
|
2201
|
+
? ["sleep", "sleep_cycle"]
|
|
2202
|
+
: [resource]);
|
|
2203
|
+
return units;
|
|
2204
|
+
}, []);
|
|
2205
|
+
const requestedCursor = normalizeString(input.job.payload.summaryResourceCursor);
|
|
2206
|
+
const cursorIndex = requestedCursor
|
|
2207
|
+
? eligibleUnits.findIndex((unit) => unit.includes(requestedCursor))
|
|
2208
|
+
: 0;
|
|
2209
|
+
const resources = eligibleUnits[cursorIndex >= 0 ? cursorIndex : 0] ?? null;
|
|
2210
|
+
if (!resources) {
|
|
2211
|
+
return null;
|
|
2212
|
+
}
|
|
2213
|
+
const summaries = {};
|
|
2214
|
+
let profileMetadataPatch = {};
|
|
2215
|
+
const profileResource = resources.find(isJunctionProfileSummaryResource);
|
|
2216
|
+
if (profileResource) {
|
|
2217
|
+
const profileSummaryResult = await fetchProfileSummaryOnce(input.context, input.skippedOptionalResources, { collectionWorkLimit: JUNCTION_FULL_JOB_SUMMARY_COLLECTION_WORK_LIMIT });
|
|
2218
|
+
if (profileSummaryResult.checked) {
|
|
2219
|
+
profileMetadataPatch = buildJunctionProfileSummaryCheckedMetadataPatch(input.context);
|
|
2220
|
+
}
|
|
2221
|
+
if (profileSummaryResult.records.length > 0) {
|
|
2222
|
+
summaries[profileResource] = profileSummaryResult.records;
|
|
2223
|
+
}
|
|
2224
|
+
}
|
|
2225
|
+
else {
|
|
2226
|
+
const collectionWorkLimit = resources.length > 1
|
|
2227
|
+
? JUNCTION_FULL_JOB_COUPLED_SUMMARY_COLLECTION_WORK_LIMIT
|
|
2228
|
+
: JUNCTION_FULL_JOB_SUMMARY_COLLECTION_WORK_LIMIT;
|
|
2229
|
+
for (const resource of resources) {
|
|
2230
|
+
summaries[resource] = await fetchOptionalJunctionResourceRecords(input.context, "summary", resource, input.skippedOptionalResources, () => client.listSummary({
|
|
2231
|
+
collectionWorkLimit,
|
|
2232
|
+
dateQueryFormat: input.dateQueryFormat,
|
|
2233
|
+
resource,
|
|
2234
|
+
signal: input.context.signal ?? null,
|
|
2235
|
+
userId: input.context.account.externalAccountId,
|
|
2236
|
+
windowEnd: input.summaryWindow.windowEnd,
|
|
2237
|
+
windowStart: input.summaryWindow.windowStart,
|
|
2238
|
+
}));
|
|
2239
|
+
}
|
|
2240
|
+
}
|
|
2241
|
+
const preparedSummaryImport = await prepareJunctionImportSnapshot(input.context, summaries, input.sourceProviders);
|
|
2242
|
+
await input.context.importSnapshot({
|
|
2243
|
+
provider: "junction",
|
|
2244
|
+
accountId: buildJunctionImportAccountId(input.context.account.externalAccountId),
|
|
2245
|
+
connectionId: input.context.account.id,
|
|
2246
|
+
importedAt: input.summaryWindow.windowEnd,
|
|
2247
|
+
windowStart: input.summaryWindow.windowStart,
|
|
2248
|
+
windowEnd: input.summaryWindow.windowEnd,
|
|
2249
|
+
connections: preparedSummaryImport.connections,
|
|
2250
|
+
summaries: preparedSummaryImport.snapshots,
|
|
2251
|
+
timeseries: {},
|
|
2252
|
+
});
|
|
2253
|
+
const nextResource = eligibleUnits[cursorIndex >= 0 ? cursorIndex + 1 : 1]?.[0] ?? null;
|
|
2254
|
+
const sourceProviderSlug = normalizeProviderSlug(input.job.payload.sourceProviderSlug);
|
|
2255
|
+
const continuation = buildExactWindowJob({
|
|
2256
|
+
availableAt: input.context.now,
|
|
2257
|
+
kind: "reconcile",
|
|
2258
|
+
payload: {
|
|
2259
|
+
...(sourceProviderSlug ? { sourceProviderSlug } : {}),
|
|
2260
|
+
...(nextResource
|
|
2261
|
+
? { summaryResourceCursor: nextResource }
|
|
2262
|
+
: { summaryPhaseComplete: true }),
|
|
2263
|
+
},
|
|
2264
|
+
priority: input.job.priority,
|
|
2265
|
+
windowEnd: input.window.windowEnd,
|
|
2266
|
+
windowStart: input.window.windowStart,
|
|
2267
|
+
});
|
|
2268
|
+
return withJunctionSkippedResourceMetadata(input.context, withJunctionMetadataPatch({
|
|
2269
|
+
nextReconcileAt: resolveJunctionNextReconcileAt(input.context.account, input.context.now, addMilliseconds(input.context.now, reconcileIntervalMs)),
|
|
2270
|
+
scheduledJobs: [continuation],
|
|
2271
|
+
}, profileMetadataPatch), input.skippedOptionalResources);
|
|
2272
|
+
}
|
|
2273
|
+
async function fetchProfileSummaryOnce(context, skippedOptionalResources, options = {}) {
|
|
1365
2274
|
if (!summaryResources.some(isJunctionProfileSummaryResource)
|
|
1366
2275
|
|| hasCheckedJunctionProfileSummary(context.account.metadata)) {
|
|
1367
2276
|
return { checked: false, records: [] };
|
|
1368
2277
|
}
|
|
1369
2278
|
const records = await fetchOptionalJunctionResourceRecords(context, "summary", JUNCTION_PROFILE_SUMMARY_RESOURCE, skippedOptionalResources, () => client.listProfileSummary({
|
|
2279
|
+
...(options.collectionWorkLimit
|
|
2280
|
+
? { collectionWorkLimit: options.collectionWorkLimit }
|
|
2281
|
+
: {}),
|
|
1370
2282
|
signal: context.signal ?? null,
|
|
1371
2283
|
userId: context.account.externalAccountId,
|
|
1372
2284
|
}));
|
|
@@ -1384,21 +2296,29 @@ export function createJunctionDeviceSyncProvider(config) {
|
|
|
1384
2296
|
let chunkStart = Date.parse(windowStart);
|
|
1385
2297
|
const end = Date.parse(windowEnd);
|
|
1386
2298
|
let optionalFailureLogged = false;
|
|
2299
|
+
const fetchChunkMs = resolveJunctionTimeseriesFetchChunkMs(resource);
|
|
1387
2300
|
while (chunkStart < end) {
|
|
1388
|
-
const chunkEnd = Math.min(chunkStart +
|
|
2301
|
+
const chunkEnd = Math.min(chunkStart + fetchChunkMs, end);
|
|
1389
2302
|
const chunkWindowStart = new Date(chunkStart).toISOString();
|
|
1390
2303
|
const chunkWindowEnd = new Date(chunkEnd).toISOString();
|
|
1391
2304
|
try {
|
|
1392
|
-
const
|
|
2305
|
+
const request = {
|
|
2306
|
+
collectionWorkLimit: options.collectionWorkLimit,
|
|
1393
2307
|
resource,
|
|
1394
2308
|
signal: context.signal ?? null,
|
|
1395
2309
|
sourceProviderSlug,
|
|
1396
2310
|
userId: context.account.externalAccountId,
|
|
1397
2311
|
windowStart: chunkWindowStart,
|
|
1398
2312
|
windowEnd: chunkWindowEnd,
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
2313
|
+
};
|
|
2314
|
+
if (options.dateQueryFormat) {
|
|
2315
|
+
request.dateQueryFormat = options.dateQueryFormat;
|
|
2316
|
+
}
|
|
2317
|
+
if (options.requireStructurallyCompleteCollection) {
|
|
2318
|
+
request.requireStructurallyCompleteCollection = true;
|
|
2319
|
+
}
|
|
2320
|
+
const chunkRecords = await fetchJunctionTimeseriesWindow(client, request);
|
|
2321
|
+
records.push(...filterJunctionTimeseriesRecordsToWindow(resource, chunkRecords, chunkWindowStart, chunkWindowEnd, options.dateQueryFormat));
|
|
1402
2322
|
}
|
|
1403
2323
|
catch (error) {
|
|
1404
2324
|
const failure = classifyOptionalJunctionResourceFailure(error, "timeseries", resource, context.account.externalAccountId);
|
|
@@ -1418,21 +2338,55 @@ export function createJunctionDeviceSyncProvider(config) {
|
|
|
1418
2338
|
}
|
|
1419
2339
|
chunkStart = chunkEnd;
|
|
1420
2340
|
}
|
|
2341
|
+
if (resource === "electrocardiogram_voltage" || resource === "workout_stream") {
|
|
2342
|
+
return resolveJunctionBoundedFeatureRecords(resource, records);
|
|
2343
|
+
}
|
|
1421
2344
|
return dedupeJunctionTimeseriesRecords(resource, records);
|
|
1422
2345
|
}
|
|
1423
|
-
async function importTimeseriesPreciseSnapshots(context, sourceProviders, windowStart, windowEnd, skippedOptionalResources, resources, sourceProviderSlug) {
|
|
2346
|
+
async function importTimeseriesPreciseSnapshots(context, sourceProviders, windowStart, windowEnd, skippedOptionalResources, resources, sourceProviderSlug, options = {}) {
|
|
1424
2347
|
const accumulatedTimeseries = {};
|
|
2348
|
+
let acceptedProviderRecordCount = 0;
|
|
1425
2349
|
let executionWindowEnd = null;
|
|
1426
2350
|
let executionWindowStart = null;
|
|
2351
|
+
let fetchComplete = true;
|
|
1427
2352
|
let yieldedAt = null;
|
|
1428
|
-
|
|
2353
|
+
let canonicalEventDayKeys = [];
|
|
2354
|
+
let canonicalSparseCalendarTargets = [];
|
|
2355
|
+
let canonicalProviderRecordIdentities = [];
|
|
2356
|
+
let canonicalEventCount = 0;
|
|
2357
|
+
let providerRecordsExamined = false;
|
|
2358
|
+
let postFetchSourceAdmission;
|
|
2359
|
+
if (resources.length !== 1) {
|
|
2360
|
+
throw new TypeError("Precise Junction timeseries imports require exactly one resource.");
|
|
2361
|
+
}
|
|
2362
|
+
const resource = resources[0];
|
|
2363
|
+
const preciseWindows = buildPreciseTimeseriesWindows(windowStart, windowEnd, resolveJunctionTimeseriesImportChunkMs(resources));
|
|
2364
|
+
for (const [index, window] of preciseWindows.entries()) {
|
|
1429
2365
|
if (context.shouldYield?.()) {
|
|
2366
|
+
fetchComplete = false;
|
|
1430
2367
|
yieldedAt = window.windowStart;
|
|
1431
2368
|
break;
|
|
1432
2369
|
}
|
|
1433
2370
|
const skippedResourceCountBeforeFetch = skippedOptionalResources.length;
|
|
1434
|
-
|
|
2371
|
+
let timeseries;
|
|
2372
|
+
try {
|
|
2373
|
+
timeseries = {
|
|
2374
|
+
[resource]: await fetchTimeseriesResourceInChunks(context, resource, window.windowStart, window.windowEnd, skippedOptionalResources, sourceProviderSlug, { dateQueryFormat: options.dateQueryFormat ?? "datetime" }),
|
|
2375
|
+
};
|
|
2376
|
+
}
|
|
2377
|
+
catch (error) {
|
|
2378
|
+
if (options.preservePartialRetryableFailure === true
|
|
2379
|
+
&& (options.historicalProviderRecordsSeen === true
|
|
2380
|
+
|| hasJunctionSnapshotRecords(accumulatedTimeseries))
|
|
2381
|
+
&& (isRetryableDeviceSyncFailure(error)
|
|
2382
|
+
|| isJunctionJobSignalAbort(error, context.signal))) {
|
|
2383
|
+
fetchComplete = false;
|
|
2384
|
+
break;
|
|
2385
|
+
}
|
|
2386
|
+
throw error;
|
|
2387
|
+
}
|
|
1435
2388
|
if (skippedOptionalResources.length > skippedResourceCountBeforeFetch) {
|
|
2389
|
+
fetchComplete = false;
|
|
1436
2390
|
break;
|
|
1437
2391
|
}
|
|
1438
2392
|
executionWindowStart ??= window.windowStart;
|
|
@@ -1443,58 +2397,654 @@ export function createJunctionDeviceSyncProvider(config) {
|
|
|
1443
2397
|
...records,
|
|
1444
2398
|
];
|
|
1445
2399
|
}
|
|
2400
|
+
if (options.preservePartialRetryableFailure === true
|
|
2401
|
+
&& index < preciseWindows.length - 1) {
|
|
2402
|
+
fetchComplete = false;
|
|
2403
|
+
yieldedAt = window.windowEnd;
|
|
2404
|
+
break;
|
|
2405
|
+
}
|
|
1446
2406
|
}
|
|
1447
2407
|
const dedupedTimeseries = dedupeJunctionTimeseriesSnapshotRecords(accumulatedTimeseries);
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
2408
|
+
const providerRecordCount = countJunctionSnapshotRecords(dedupedTimeseries);
|
|
2409
|
+
let unresolvedProviderRecordIdentities = [];
|
|
2410
|
+
let unresolvedProviderRecordCount = providerRecordCount;
|
|
2411
|
+
let unresolvedProviderRecordsWithoutStableIdentity = providerRecordCount > 0;
|
|
2412
|
+
const requiresBloodPressureRecordResolution = resources.includes("blood_pressure");
|
|
2413
|
+
const successfulImportTerminatesWeightRows = resources.length === 1 && resources[0] === "weight";
|
|
2414
|
+
if (executionWindowStart && executionWindowEnd) {
|
|
2415
|
+
const identifyFetchedProviderRecords = (sourceIdentities) => requiresBloodPressureRecordResolution && providerRecordCount > 0
|
|
2416
|
+
? identifyJunctionBloodPressureProviderRecords({
|
|
2417
|
+
connections: sanitizeJunctionImportConnections(sourceProviders, sourceIdentities),
|
|
2418
|
+
importedAt: executionWindowEnd,
|
|
2419
|
+
timeseries: sanitizeJunctionImportSnapshots(dedupedTimeseries, sourceProviders, { sourceIdentities }),
|
|
2420
|
+
windowStart: executionWindowStart,
|
|
2421
|
+
windowEnd: executionWindowEnd,
|
|
2422
|
+
})
|
|
2423
|
+
: null;
|
|
2424
|
+
const applyFetchedProviderRecordEvidence = (evidence) => {
|
|
2425
|
+
if (!evidence) {
|
|
2426
|
+
return;
|
|
2427
|
+
}
|
|
2428
|
+
unresolvedProviderRecordIdentities = uniqueJunctionProviderRecordIdentities(evidence.repairStableExternalRefResourceIds);
|
|
2429
|
+
unresolvedProviderRecordsWithoutStableIdentity =
|
|
2430
|
+
evidence.providerRecordCount !== providerRecordCount
|
|
2431
|
+
|| evidence.repairStableExternalRefResourceIds.some((identity) => identity === null);
|
|
2432
|
+
unresolvedProviderRecordCount =
|
|
2433
|
+
unresolvedProviderRecordIdentities.length
|
|
2434
|
+
+ (unresolvedProviderRecordsWithoutStableIdentity ? 1 : 0);
|
|
2435
|
+
};
|
|
2436
|
+
let fetchedProviderRecordIdentityEvidence = identifyFetchedProviderRecords(resolveJunctionAccountSourceIdentities(options.sourceIdentityAuthority ?? []));
|
|
2437
|
+
applyFetchedProviderRecordEvidence(fetchedProviderRecordIdentityEvidence);
|
|
2438
|
+
try {
|
|
2439
|
+
const currentSources = context.listConnectionSources
|
|
2440
|
+
? await context.listConnectionSources()
|
|
2441
|
+
: context.account.sources ?? [];
|
|
2442
|
+
const importSourceIdentities = resolveJunctionAccountSourceIdentities(currentSources);
|
|
2443
|
+
if (sourceProviderSlug
|
|
2444
|
+
&& options.sourceStatusRequirement === "connected") {
|
|
2445
|
+
postFetchSourceAdmission = resolveJunctionCurrentSourceAdmissionFromSources(currentSources, sourceProviderSlug, context.connectionSourceAdmissionMode !== "listed_only");
|
|
2446
|
+
if (postFetchSourceAdmission !== "admitted") {
|
|
2447
|
+
return {
|
|
2448
|
+
acceptedProviderRecordCount: 0,
|
|
2449
|
+
canonicalProviderRecordIdentities: [],
|
|
2450
|
+
canonicalEventCount: 0,
|
|
2451
|
+
canonicalEventDayKeys: [],
|
|
2452
|
+
canonicalSparseCalendarTargets: [],
|
|
2453
|
+
fetchComplete: false,
|
|
2454
|
+
postFetchSourceAdmission,
|
|
2455
|
+
providerRecordsExamined: false,
|
|
2456
|
+
providerRecordCount,
|
|
2457
|
+
unresolvedProviderRecordIdentities,
|
|
2458
|
+
unresolvedProviderRecordCount,
|
|
2459
|
+
unresolvedProviderRecordsWithoutStableIdentity,
|
|
2460
|
+
yieldedAt: null,
|
|
2461
|
+
};
|
|
2462
|
+
}
|
|
2463
|
+
}
|
|
2464
|
+
fetchedProviderRecordIdentityEvidence = identifyFetchedProviderRecords(importSourceIdentities);
|
|
2465
|
+
applyFetchedProviderRecordEvidence(fetchedProviderRecordIdentityEvidence);
|
|
2466
|
+
const preparedImport = prepareJunctionImportSnapshotForSources(dedupedTimeseries, sourceProviders, currentSources, {
|
|
2467
|
+
sourceIdentities: importSourceIdentities,
|
|
2468
|
+
}, {
|
|
2469
|
+
allowUnlistedSources: context.connectionSourceAdmissionMode !== "listed_only",
|
|
2470
|
+
sourceStatusRequirement: options.sourceStatusRequirement,
|
|
2471
|
+
});
|
|
2472
|
+
acceptedProviderRecordCount = countAcceptedJunctionDailyTimeseriesProviderRecords({
|
|
2473
|
+
connections: preparedImport.connections,
|
|
2474
|
+
importedAt: executionWindowEnd,
|
|
2475
|
+
timeseries: preparedImport.snapshots,
|
|
2476
|
+
windowEnd: executionWindowEnd,
|
|
2477
|
+
windowStart: executionWindowStart,
|
|
2478
|
+
});
|
|
2479
|
+
if (hasJunctionSnapshotRecords(preparedImport.snapshots)) {
|
|
2480
|
+
const receipt = await context.importSnapshot({
|
|
2481
|
+
provider: "junction",
|
|
2482
|
+
accountId: buildJunctionImportAccountId(context.account.externalAccountId),
|
|
2483
|
+
connectionId: context.account.id,
|
|
2484
|
+
importedAt: executionWindowEnd,
|
|
2485
|
+
windowStart: executionWindowStart,
|
|
2486
|
+
windowEnd: executionWindowEnd,
|
|
2487
|
+
timeseriesWindowKind: "precise",
|
|
2488
|
+
connections: preparedImport.connections,
|
|
2489
|
+
summaries: {},
|
|
2490
|
+
timeseries: preparedImport.snapshots,
|
|
2491
|
+
});
|
|
2492
|
+
providerRecordsExamined = true;
|
|
2493
|
+
canonicalEventCount = readProviderSnapshotCanonicalEventCount(receipt);
|
|
2494
|
+
canonicalEventDayKeys = readProviderSnapshotCanonicalEventDayKeys(receipt);
|
|
2495
|
+
canonicalSparseCalendarTargets = readProviderSnapshotCanonicalSparseCalendarTargets(receipt);
|
|
2496
|
+
if (fetchedProviderRecordIdentityEvidence) {
|
|
2497
|
+
const resolutionEvidence = resolveJunctionBloodPressureProviderRecordResolutionEvidence({
|
|
2498
|
+
canonicalEventCount,
|
|
2499
|
+
canonicalEventExternalRefResourceIds: readProviderSnapshotCanonicalEventExternalRefResourceIds(receipt),
|
|
2500
|
+
providerRecordCount,
|
|
2501
|
+
providerRecordIdentityEvidence: fetchedProviderRecordIdentityEvidence,
|
|
2502
|
+
});
|
|
2503
|
+
canonicalProviderRecordIdentities =
|
|
2504
|
+
resolutionEvidence.canonicalProviderRecordIdentities;
|
|
2505
|
+
unresolvedProviderRecordIdentities =
|
|
2506
|
+
resolutionEvidence.unresolvedProviderRecordIdentities;
|
|
2507
|
+
unresolvedProviderRecordsWithoutStableIdentity =
|
|
2508
|
+
resolutionEvidence.unresolvedProviderRecordsWithoutStableIdentity;
|
|
2509
|
+
unresolvedProviderRecordCount =
|
|
2510
|
+
unresolvedProviderRecordIdentities.length
|
|
2511
|
+
+ (unresolvedProviderRecordsWithoutStableIdentity ? 1 : 0);
|
|
2512
|
+
}
|
|
2513
|
+
else if (successfulImportTerminatesWeightRows) {
|
|
2514
|
+
// A resolved import receipt means the weight normalizer examined
|
|
2515
|
+
// every delivered row. Valid readings became canonical events and
|
|
2516
|
+
// deterministic validation rejects are terminal; delivery errors
|
|
2517
|
+
// throw before this branch and retain the retry obligation.
|
|
2518
|
+
unresolvedProviderRecordCount = 0;
|
|
2519
|
+
unresolvedProviderRecordsWithoutStableIdentity = false;
|
|
2520
|
+
}
|
|
2521
|
+
else {
|
|
2522
|
+
unresolvedProviderRecordCount =
|
|
2523
|
+
canonicalEventCount >= providerRecordCount ? 0 : providerRecordCount;
|
|
2524
|
+
unresolvedProviderRecordsWithoutStableIdentity = unresolvedProviderRecordCount > 0;
|
|
2525
|
+
}
|
|
2526
|
+
}
|
|
2527
|
+
}
|
|
2528
|
+
catch (error) {
|
|
2529
|
+
if (options.preservePartialRetryableFailure === true
|
|
2530
|
+
&& (options.historicalProviderRecordsSeen === true
|
|
2531
|
+
|| providerRecordCount > 0)
|
|
2532
|
+
&& (isRetryableDeviceSyncFailure(error)
|
|
2533
|
+
|| isJunctionJobSignalAbort(error, context.signal))) {
|
|
2534
|
+
return {
|
|
2535
|
+
acceptedProviderRecordCount: 0,
|
|
2536
|
+
canonicalProviderRecordIdentities: [],
|
|
2537
|
+
canonicalEventCount: 0,
|
|
2538
|
+
canonicalEventDayKeys: [],
|
|
2539
|
+
canonicalSparseCalendarTargets: [],
|
|
2540
|
+
fetchComplete: false,
|
|
2541
|
+
providerRecordsExamined: false,
|
|
2542
|
+
providerRecordCount,
|
|
2543
|
+
unresolvedProviderRecordIdentities,
|
|
2544
|
+
unresolvedProviderRecordCount,
|
|
2545
|
+
unresolvedProviderRecordsWithoutStableIdentity,
|
|
2546
|
+
yieldedAt: null,
|
|
2547
|
+
};
|
|
2548
|
+
}
|
|
2549
|
+
throw error;
|
|
2550
|
+
}
|
|
1460
2551
|
}
|
|
1461
2552
|
return {
|
|
2553
|
+
acceptedProviderRecordCount,
|
|
2554
|
+
canonicalEventDayKeys,
|
|
2555
|
+
canonicalSparseCalendarTargets,
|
|
2556
|
+
canonicalProviderRecordIdentities,
|
|
2557
|
+
canonicalEventCount,
|
|
2558
|
+
fetchComplete,
|
|
2559
|
+
...(postFetchSourceAdmission === undefined
|
|
2560
|
+
? {}
|
|
2561
|
+
: { postFetchSourceAdmission }),
|
|
2562
|
+
providerRecordsExamined,
|
|
2563
|
+
providerRecordCount,
|
|
2564
|
+
unresolvedProviderRecordIdentities,
|
|
2565
|
+
unresolvedProviderRecordCount,
|
|
2566
|
+
unresolvedProviderRecordsWithoutStableIdentity,
|
|
1462
2567
|
yieldedAt,
|
|
1463
2568
|
};
|
|
1464
2569
|
}
|
|
1465
|
-
async function
|
|
2570
|
+
async function importTimeseriesDailyAggregateSnapshots(context, sourceProviders, windowStart, windowEnd, skippedOptionalResources, resources, sourceProviderSlug, emptySparseCalendarSource) {
|
|
2571
|
+
const requestedResources = resources ?? timeseriesResources;
|
|
2572
|
+
const globallyClosedEndMs = resolveGloballyClosedProviderDayEnd(windowEnd, context.now);
|
|
2573
|
+
const appliedDailyAggregateResourceIds = new Set();
|
|
1466
2574
|
for (const window of buildClosedDailyWindows(windowStart, windowEnd)) {
|
|
1467
2575
|
if (context.shouldYield?.()) {
|
|
1468
2576
|
return {
|
|
2577
|
+
appliedDailyAggregateResourceIds: [...appliedDailyAggregateResourceIds],
|
|
1469
2578
|
yieldedAt: window.windowStart,
|
|
1470
2579
|
};
|
|
1471
2580
|
}
|
|
1472
|
-
const
|
|
1473
|
-
|
|
2581
|
+
const windowResources = Date.parse(window.windowEnd) <= globallyClosedEndMs
|
|
2582
|
+
? requestedResources
|
|
2583
|
+
: requestedResources.filter((resource) => !JUNCTION_CALENDAR_DAY_AGGREGATE_RESOURCE_SET.has(resource));
|
|
2584
|
+
if (windowResources.length === 0) {
|
|
1474
2585
|
continue;
|
|
1475
2586
|
}
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
2587
|
+
const skippedResourceCountBeforeFetch = skippedOptionalResources.length;
|
|
2588
|
+
const timeseries = await fetchTimeseriesSnapshots(context, window.windowStart, window.windowEnd, skippedOptionalResources, windowResources, sourceProviderSlug, {
|
|
2589
|
+
dateQueryFormat: "date",
|
|
2590
|
+
requireStructurallyCompleteCollection: Boolean(emptySparseCalendarSource),
|
|
2591
|
+
});
|
|
2592
|
+
if (emptySparseCalendarSource
|
|
2593
|
+
&& skippedOptionalResources.length > skippedResourceCountBeforeFetch) {
|
|
2594
|
+
throw deviceSyncError({
|
|
2595
|
+
code: "JUNCTION_CALENDAR_REFRESH_UNAVAILABLE",
|
|
2596
|
+
message: "Junction calendar refresh is temporarily unavailable.",
|
|
2597
|
+
retryable: true,
|
|
2598
|
+
});
|
|
2599
|
+
}
|
|
2600
|
+
if (emptySparseCalendarSource) {
|
|
2601
|
+
for (const resource of windowResources) {
|
|
2602
|
+
timeseries[resource] = filterJunctionSparseCalendarRecordsToSource(timeseries[resource] ?? [], {
|
|
2603
|
+
sourceProviderSlug: emptySparseCalendarSource.sourceProviderSlug,
|
|
2604
|
+
...(emptySparseCalendarSource.sourceType
|
|
2605
|
+
? { sourceType: emptySparseCalendarSource.sourceType }
|
|
2606
|
+
: {}),
|
|
2607
|
+
});
|
|
2608
|
+
}
|
|
2609
|
+
}
|
|
2610
|
+
if (!hasJunctionSnapshotRecords(timeseries) && emptySparseCalendarSource) {
|
|
2611
|
+
const [resource] = windowResources;
|
|
2612
|
+
if (!resource || !JUNCTION_SPARSE_CALENDAR_AGGREGATE_RESOURCE_SET.has(resource)) {
|
|
2613
|
+
throw deviceSyncError({
|
|
2614
|
+
code: JUNCTION_CALENDAR_REFRESH_EMPTY_IDENTITY_INVALID_CODE,
|
|
2615
|
+
message: "Junction empty calendar refresh lacked an admitted sparse identity.",
|
|
2616
|
+
retryable: false,
|
|
2617
|
+
});
|
|
2618
|
+
}
|
|
2619
|
+
timeseries[resource] = [buildJunctionEmptySparseCalendarAggregate({
|
|
2620
|
+
dayKey: window.windowStart.slice(0, 10),
|
|
2621
|
+
resource,
|
|
2622
|
+
...emptySparseCalendarSource,
|
|
2623
|
+
})];
|
|
2624
|
+
}
|
|
2625
|
+
else if (!hasJunctionSnapshotRecords(timeseries)) {
|
|
2626
|
+
continue;
|
|
2627
|
+
}
|
|
2628
|
+
const preparedImport = await prepareJunctionImportSnapshot(context, timeseries, sourceProviders, {
|
|
2629
|
+
projectAccountSourceIdentities: true,
|
|
2630
|
+
sourceIdentities: emptySparseCalendarSource
|
|
2631
|
+
? [{
|
|
2632
|
+
...(emptySparseCalendarSource.sourceInstanceId
|
|
2633
|
+
? { sourceInstanceId: emptySparseCalendarSource.sourceInstanceId }
|
|
2634
|
+
: {}),
|
|
2635
|
+
sourceProviderSlug: emptySparseCalendarSource.sourceProviderSlug,
|
|
2636
|
+
}]
|
|
2637
|
+
: [],
|
|
2638
|
+
});
|
|
2639
|
+
if (hasJunctionSnapshotRecords(preparedImport.snapshots)) {
|
|
2640
|
+
const receipt = await context.importSnapshot({
|
|
2641
|
+
provider: "junction",
|
|
2642
|
+
accountId: buildJunctionImportAccountId(context.account.externalAccountId),
|
|
2643
|
+
connectionId: context.account.id,
|
|
2644
|
+
importedAt: window.windowEnd,
|
|
2645
|
+
windowStart: window.windowStart,
|
|
2646
|
+
windowEnd: window.windowEnd,
|
|
2647
|
+
timeseriesWindowKind: "calendar_day",
|
|
2648
|
+
...(emptySparseCalendarSource
|
|
2649
|
+
? {
|
|
2650
|
+
strictSparseCalendarRepair: {
|
|
2651
|
+
dayKey: window.windowStart.slice(0, 10),
|
|
2652
|
+
resource: windowResources[0],
|
|
2653
|
+
...emptySparseCalendarSource,
|
|
2654
|
+
sourceProviderSlug: normalizeJunctionSourceProviderSlug(emptySparseCalendarSource.sourceProviderSlug) ?? emptySparseCalendarSource.sourceProviderSlug,
|
|
2655
|
+
},
|
|
2656
|
+
}
|
|
2657
|
+
: {}),
|
|
2658
|
+
connections: preparedImport.connections,
|
|
2659
|
+
summaries: {},
|
|
2660
|
+
timeseries: preparedImport.snapshots,
|
|
2661
|
+
});
|
|
2662
|
+
for (const resourceId of readProviderSnapshotCanonicalEventExternalRefResourceIds(receipt) ?? []) {
|
|
2663
|
+
appliedDailyAggregateResourceIds.add(resourceId);
|
|
2664
|
+
}
|
|
2665
|
+
}
|
|
2666
|
+
}
|
|
2667
|
+
return {
|
|
2668
|
+
appliedDailyAggregateResourceIds: [...appliedDailyAggregateResourceIds],
|
|
2669
|
+
yieldedAt: null,
|
|
2670
|
+
};
|
|
2671
|
+
}
|
|
2672
|
+
async function importTimeseriesDailySnapshots(context, sourceProviders, windowStart, windowEnd, skippedOptionalResources, resource, sourceProviderSlug, completedWorkoutStreamIdentities = new Set()) {
|
|
2673
|
+
let resumeWorkoutStreamIdentities = new Set(completedWorkoutStreamIdentities);
|
|
2674
|
+
let madeProgress = false;
|
|
2675
|
+
for (const window of buildClosedDailyWindows(windowStart, windowEnd)) {
|
|
2676
|
+
let workoutStreamCursor = resource === "workout_stream"
|
|
2677
|
+
? encodeJunctionWorkoutStreamCompletedIdentities(resumeWorkoutStreamIdentities)
|
|
2678
|
+
: null;
|
|
2679
|
+
if (context.shouldYield?.()) {
|
|
2680
|
+
if (madeProgress) {
|
|
2681
|
+
return {
|
|
2682
|
+
workoutStreamCursor,
|
|
2683
|
+
yieldedAt: window.windowStart,
|
|
2684
|
+
};
|
|
2685
|
+
}
|
|
2686
|
+
context.throwIfAborted?.();
|
|
2687
|
+
}
|
|
2688
|
+
if (resource === "workout_stream") {
|
|
2689
|
+
const workoutImport = await importJunctionWorkoutStreamWindow({
|
|
2690
|
+
allowImmediateYield: madeProgress,
|
|
2691
|
+
completedIdentities: resumeWorkoutStreamIdentities,
|
|
2692
|
+
context,
|
|
2693
|
+
skippedOptionalResources,
|
|
2694
|
+
sourceProviderSlug,
|
|
2695
|
+
sourceProviders,
|
|
2696
|
+
windowEnd: window.windowEnd,
|
|
2697
|
+
windowStart: window.windowStart,
|
|
2698
|
+
});
|
|
2699
|
+
workoutStreamCursor = workoutImport.workoutStreamCursor;
|
|
2700
|
+
madeProgress ||= workoutImport.madeProgress;
|
|
2701
|
+
if (workoutImport.yieldedAt) {
|
|
2702
|
+
return {
|
|
2703
|
+
workoutStreamCursor,
|
|
2704
|
+
yieldedAt: workoutImport.yieldedAt,
|
|
2705
|
+
};
|
|
2706
|
+
}
|
|
2707
|
+
madeProgress = true;
|
|
2708
|
+
}
|
|
2709
|
+
else {
|
|
2710
|
+
try {
|
|
2711
|
+
await importJunctionTimeseriesResourceSnapshot({
|
|
2712
|
+
context,
|
|
2713
|
+
dateQueryFormat: "date",
|
|
2714
|
+
resource,
|
|
2715
|
+
skippedOptionalResources,
|
|
2716
|
+
sourceProviderSlug,
|
|
2717
|
+
sourceProviders,
|
|
2718
|
+
windowEnd: window.windowEnd,
|
|
2719
|
+
windowStart: window.windowStart,
|
|
2720
|
+
});
|
|
2721
|
+
}
|
|
2722
|
+
catch (error) {
|
|
2723
|
+
if (isJunctionJobSignalAbort(error, context.signal)) {
|
|
2724
|
+
if (madeProgress) {
|
|
2725
|
+
return {
|
|
2726
|
+
workoutStreamCursor,
|
|
2727
|
+
yieldedAt: window.windowStart,
|
|
2728
|
+
};
|
|
2729
|
+
}
|
|
2730
|
+
throw error;
|
|
2731
|
+
}
|
|
2732
|
+
if (isRetryableDeviceSyncFailure(error)) {
|
|
2733
|
+
throw new JunctionTimeseriesProgressError(error, window.windowStart, workoutStreamCursor);
|
|
2734
|
+
}
|
|
2735
|
+
throw error;
|
|
2736
|
+
}
|
|
2737
|
+
madeProgress = true;
|
|
2738
|
+
}
|
|
2739
|
+
resumeWorkoutStreamIdentities = new Set();
|
|
2740
|
+
madeProgress = true;
|
|
2741
|
+
}
|
|
2742
|
+
return {
|
|
2743
|
+
workoutStreamCursor: null,
|
|
2744
|
+
yieldedAt: null,
|
|
2745
|
+
};
|
|
2746
|
+
}
|
|
2747
|
+
async function executeFullJobTimeseriesContinuation(context, job, skippedOptionalResources, completedWorkoutStreamIdentities) {
|
|
2748
|
+
const window = resolveJobWindow(job, context.now, job.kind === "backfill" ? summaryBackfillDays : reconcileDays);
|
|
2749
|
+
const baseTimeseriesWindowStart = job.kind === "backfill"
|
|
2750
|
+
? maxIsoTimestamp(window.windowStart, subtractDays(window.windowEnd, timeseriesBackfillDays))
|
|
2751
|
+
: window.windowStart;
|
|
2752
|
+
const resourceCursor = readFullJobTimeseriesResourceCursor(job, timeseriesResources);
|
|
2753
|
+
const persistedTimeseriesCursor = readFullJobTimeseriesCursor(job, {
|
|
2754
|
+
windowEnd: window.windowEnd,
|
|
2755
|
+
windowStart: baseTimeseriesWindowStart,
|
|
2756
|
+
});
|
|
2757
|
+
const persistedTimeseriesWindowHours = readFullJobTimeseriesWindowHours(job);
|
|
2758
|
+
if (!resourceCursor || !persistedTimeseriesCursor) {
|
|
2759
|
+
throw invalidJunctionTimeseriesResourceProgress();
|
|
2760
|
+
}
|
|
2761
|
+
const timeseriesCursor = resourceCursor.restartFromWindowStart
|
|
2762
|
+
? baseTimeseriesWindowStart
|
|
2763
|
+
: persistedTimeseriesCursor;
|
|
2764
|
+
const timeseriesWindowHours = resourceCursor.restartFromWindowStart
|
|
2765
|
+
? 24
|
|
2766
|
+
: persistedTimeseriesWindowHours;
|
|
2767
|
+
const resource = resourceCursor.resource;
|
|
2768
|
+
const policy = resolveJunctionTimeseriesResourcePolicy(resource);
|
|
2769
|
+
if ((timeseriesWindowHours === 1
|
|
2770
|
+
&& policy?.normalizationMode !== "hourly_or_session_feature")
|
|
2771
|
+
|| (!resourceCursor.restartFromWindowStart
|
|
2772
|
+
&& resource !== "workout_stream"
|
|
2773
|
+
&& job.payload.workoutStreamCursor !== undefined)) {
|
|
2774
|
+
throw invalidJunctionTimeseriesResourceProgress();
|
|
2775
|
+
}
|
|
2776
|
+
const executionWindowEnd = new Date(Math.min(Date.parse(timeseriesCursor) + timeseriesWindowHours * TIMESERIES_HOUR_MS, Date.parse(window.windowEnd))).toISOString();
|
|
2777
|
+
let workoutStreamCursor = null;
|
|
2778
|
+
if (resource === "workout_stream") {
|
|
2779
|
+
try {
|
|
2780
|
+
const workoutImport = await importJunctionWorkoutStreamWindow({
|
|
2781
|
+
allowImmediateYield: false,
|
|
2782
|
+
collectionWorkLimit: JUNCTION_FULL_JOB_TIMESERIES_COLLECTION_WORK_LIMIT,
|
|
2783
|
+
completedIdentities: completedWorkoutStreamIdentities,
|
|
2784
|
+
context,
|
|
2785
|
+
skippedOptionalResources,
|
|
2786
|
+
sourceProviders: [],
|
|
2787
|
+
windowEnd: executionWindowEnd,
|
|
2788
|
+
windowStart: timeseriesCursor,
|
|
2789
|
+
});
|
|
2790
|
+
workoutStreamCursor = workoutImport.workoutStreamCursor;
|
|
2791
|
+
if (workoutImport.yieldedAt) {
|
|
2792
|
+
return buildFullJobTimeseriesContinuationResult({
|
|
2793
|
+
context,
|
|
2794
|
+
job,
|
|
2795
|
+
skippedOptionalResources,
|
|
2796
|
+
continuation: {
|
|
2797
|
+
timeseriesCursor,
|
|
2798
|
+
timeseriesResourceCursor: resource,
|
|
2799
|
+
timeseriesWindowHours,
|
|
2800
|
+
workoutStreamCursor,
|
|
2801
|
+
},
|
|
2802
|
+
window,
|
|
2803
|
+
});
|
|
2804
|
+
}
|
|
2805
|
+
}
|
|
2806
|
+
catch (error) {
|
|
2807
|
+
if (error instanceof JunctionTimeseriesProgressError) {
|
|
2808
|
+
if (!error.workoutStreamCursor
|
|
2809
|
+
|| error.workoutStreamCursor === job.payload.workoutStreamCursor) {
|
|
2810
|
+
throw error.failure;
|
|
2811
|
+
}
|
|
2812
|
+
return buildFullJobTimeseriesContinuationResult({
|
|
2813
|
+
context,
|
|
2814
|
+
job,
|
|
2815
|
+
skippedOptionalResources,
|
|
2816
|
+
continuation: {
|
|
2817
|
+
timeseriesCursor,
|
|
2818
|
+
timeseriesResourceCursor: resource,
|
|
2819
|
+
timeseriesWindowHours,
|
|
2820
|
+
workoutStreamCursor: error.workoutStreamCursor,
|
|
2821
|
+
},
|
|
2822
|
+
window,
|
|
2823
|
+
});
|
|
2824
|
+
}
|
|
2825
|
+
throw error;
|
|
2826
|
+
}
|
|
2827
|
+
}
|
|
2828
|
+
else {
|
|
2829
|
+
try {
|
|
2830
|
+
const calendarDayAggregate = JUNCTION_CALENDAR_DAY_AGGREGATE_RESOURCE_SET.has(resource);
|
|
2831
|
+
const importWindow = calendarDayAggregate
|
|
2832
|
+
? {
|
|
2833
|
+
windowEnd: floorUtcDayTimestamp(executionWindowEnd),
|
|
2834
|
+
windowStart: floorUtcDayTimestamp(timeseriesCursor),
|
|
2835
|
+
}
|
|
2836
|
+
: {
|
|
2837
|
+
windowEnd: executionWindowEnd,
|
|
2838
|
+
windowStart: timeseriesCursor,
|
|
2839
|
+
};
|
|
2840
|
+
if (Date.parse(importWindow.windowStart) < Date.parse(importWindow.windowEnd)) {
|
|
2841
|
+
await importJunctionTimeseriesResourceSnapshot({
|
|
2842
|
+
collectionWorkLimit: JUNCTION_FULL_JOB_TIMESERIES_COLLECTION_WORK_LIMIT,
|
|
2843
|
+
context,
|
|
2844
|
+
dateQueryFormat: timeseriesWindowHours === 1 ? "datetime" : "date",
|
|
2845
|
+
resource,
|
|
2846
|
+
skippedOptionalResources,
|
|
2847
|
+
sourceProviders: [],
|
|
2848
|
+
windowEnd: importWindow.windowEnd,
|
|
2849
|
+
windowStart: importWindow.windowStart,
|
|
2850
|
+
});
|
|
2851
|
+
}
|
|
2852
|
+
}
|
|
2853
|
+
catch (error) {
|
|
2854
|
+
if (isJunctionTimeseriesWindowTooLarge(error)
|
|
2855
|
+
&& timeseriesWindowHours === 24
|
|
2856
|
+
&& policy?.normalizationMode === "hourly_or_session_feature") {
|
|
2857
|
+
return buildFullJobTimeseriesContinuationResult({
|
|
2858
|
+
context,
|
|
2859
|
+
job,
|
|
2860
|
+
skippedOptionalResources,
|
|
2861
|
+
continuation: {
|
|
2862
|
+
timeseriesCursor,
|
|
2863
|
+
timeseriesResourceCursor: resource,
|
|
2864
|
+
timeseriesWindowHours: 1,
|
|
2865
|
+
workoutStreamCursor: null,
|
|
2866
|
+
},
|
|
2867
|
+
window,
|
|
2868
|
+
});
|
|
2869
|
+
}
|
|
2870
|
+
throw error;
|
|
2871
|
+
}
|
|
2872
|
+
}
|
|
2873
|
+
return buildFullJobTimeseriesContinuationResult({
|
|
2874
|
+
context,
|
|
2875
|
+
job,
|
|
2876
|
+
skippedOptionalResources,
|
|
2877
|
+
continuation: resolveNextFullJobTimeseriesContinuation({
|
|
2878
|
+
baseTimeseriesWindowStart,
|
|
2879
|
+
executionWindowEnd,
|
|
2880
|
+
resource,
|
|
2881
|
+
resources: timeseriesResources,
|
|
2882
|
+
timeseriesWindowHours,
|
|
1482
2883
|
windowEnd: window.windowEnd,
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
2884
|
+
}),
|
|
2885
|
+
window,
|
|
2886
|
+
});
|
|
2887
|
+
}
|
|
2888
|
+
async function importJunctionTimeseriesResourceSnapshot(input) {
|
|
2889
|
+
const calendarDayAggregate = JUNCTION_CALENDAR_DAY_AGGREGATE_RESOURCE_SET.has(input.resource);
|
|
2890
|
+
if (calendarDayAggregate) {
|
|
2891
|
+
const windowEndMs = Date.parse(input.windowEnd);
|
|
2892
|
+
const globallyClosedProviderDayEnd = resolveGloballyClosedProviderDayEnd(input.windowEnd, input.context.now);
|
|
2893
|
+
if (!Number.isFinite(windowEndMs)
|
|
2894
|
+
|| !Number.isFinite(globallyClosedProviderDayEnd)
|
|
2895
|
+
|| windowEndMs > globallyClosedProviderDayEnd) {
|
|
2896
|
+
return;
|
|
2897
|
+
}
|
|
2898
|
+
}
|
|
2899
|
+
const records = await fetchTimeseriesResourceInChunks(input.context, input.resource, input.windowStart, input.windowEnd, input.skippedOptionalResources, input.sourceProviderSlug, {
|
|
2900
|
+
collectionWorkLimit: input.collectionWorkLimit,
|
|
2901
|
+
dateQueryFormat: input.dateQueryFormat,
|
|
2902
|
+
});
|
|
2903
|
+
if (records.length === 0) {
|
|
2904
|
+
return;
|
|
2905
|
+
}
|
|
2906
|
+
const preparedImport = await prepareJunctionImportSnapshot(input.context, { [input.resource]: records }, input.sourceProviders, { projectAccountSourceIdentities: calendarDayAggregate });
|
|
2907
|
+
if (!hasJunctionSnapshotRecords(preparedImport.snapshots)) {
|
|
2908
|
+
return;
|
|
2909
|
+
}
|
|
2910
|
+
await input.context.importSnapshot({
|
|
2911
|
+
provider: "junction",
|
|
2912
|
+
accountId: buildJunctionImportAccountId(input.context.account.externalAccountId),
|
|
2913
|
+
connectionId: input.context.account.id,
|
|
2914
|
+
importedAt: input.windowEnd,
|
|
2915
|
+
windowStart: input.windowStart,
|
|
2916
|
+
windowEnd: input.windowEnd,
|
|
2917
|
+
...(calendarDayAggregate ? { timeseriesWindowKind: "calendar_day" } : {}),
|
|
2918
|
+
connections: preparedImport.connections,
|
|
2919
|
+
summaries: {},
|
|
2920
|
+
timeseries: preparedImport.snapshots,
|
|
2921
|
+
});
|
|
2922
|
+
}
|
|
2923
|
+
async function importJunctionWorkoutStreamWindow(input) {
|
|
2924
|
+
const policy = resolveJunctionTimeseriesResourcePolicy("workout_stream");
|
|
2925
|
+
const maxWorkouts = policy?.maxRecordsPerWindow;
|
|
2926
|
+
const maxSamples = policy?.maxSamplesPerRecord;
|
|
2927
|
+
if (!maxWorkouts || !maxSamples) {
|
|
2928
|
+
throw new TypeError("Junction workout_stream policy did not define bounded limits.");
|
|
2929
|
+
}
|
|
2930
|
+
let completedIdentities = new Set(input.completedIdentities);
|
|
2931
|
+
let madeProgress = false;
|
|
2932
|
+
const carryTerminalProgressOrThrow = (error) => {
|
|
2933
|
+
if (isJunctionJobSignalAbort(error, input.context.signal)) {
|
|
2934
|
+
if (input.allowImmediateYield || madeProgress) {
|
|
2935
|
+
return {
|
|
2936
|
+
madeProgress,
|
|
2937
|
+
workoutStreamCursor: encodeJunctionWorkoutStreamCompletedIdentities(completedIdentities),
|
|
2938
|
+
yieldedAt: input.windowStart,
|
|
2939
|
+
};
|
|
2940
|
+
}
|
|
2941
|
+
throw error;
|
|
2942
|
+
}
|
|
2943
|
+
if (isRetryableDeviceSyncFailure(error)) {
|
|
2944
|
+
throw new JunctionTimeseriesProgressError(error, input.windowStart, encodeJunctionWorkoutStreamCompletedIdentities(completedIdentities));
|
|
2945
|
+
}
|
|
2946
|
+
throw error;
|
|
2947
|
+
};
|
|
2948
|
+
let candidates;
|
|
2949
|
+
try {
|
|
2950
|
+
candidates = await listJunctionWorkoutStreamCandidates(client, {
|
|
2951
|
+
collectionWorkLimit: input.collectionWorkLimit,
|
|
2952
|
+
resource: "workout_stream",
|
|
2953
|
+
signal: input.context.signal ?? null,
|
|
2954
|
+
sourceProviderSlug: input.sourceProviderSlug,
|
|
2955
|
+
userId: input.context.account.externalAccountId,
|
|
2956
|
+
windowEnd: input.windowEnd,
|
|
2957
|
+
windowStart: input.windowStart,
|
|
1486
2958
|
});
|
|
1487
2959
|
}
|
|
2960
|
+
catch (error) {
|
|
2961
|
+
return carryTerminalProgressOrThrow(error);
|
|
2962
|
+
}
|
|
2963
|
+
const candidateIdentities = new Set(candidates.map((candidate) => candidate.identity));
|
|
2964
|
+
completedIdentities = new Set([...completedIdentities].filter((identity) => candidateIdentities.has(identity)));
|
|
2965
|
+
for (const [candidateIndex, candidate] of candidates.entries()) {
|
|
2966
|
+
if (completedIdentities.has(candidate.identity)) {
|
|
2967
|
+
continue;
|
|
2968
|
+
}
|
|
2969
|
+
if (input.context.shouldYield?.()) {
|
|
2970
|
+
if (input.allowImmediateYield || madeProgress) {
|
|
2971
|
+
return {
|
|
2972
|
+
madeProgress,
|
|
2973
|
+
workoutStreamCursor: encodeJunctionWorkoutStreamCompletedIdentities(completedIdentities),
|
|
2974
|
+
yieldedAt: input.windowStart,
|
|
2975
|
+
};
|
|
2976
|
+
}
|
|
2977
|
+
input.context.throwIfAborted?.();
|
|
2978
|
+
}
|
|
2979
|
+
let feature;
|
|
2980
|
+
try {
|
|
2981
|
+
feature = await fetchJunctionWorkoutStreamFeature(client, candidate, maxSamples, input.context.signal ?? null, input.collectionWorkLimit);
|
|
2982
|
+
}
|
|
2983
|
+
catch (error) {
|
|
2984
|
+
const failure = classifyOptionalJunctionResourceFailure(error, "timeseries", "workout_stream", input.context.account.externalAccountId);
|
|
2985
|
+
if (!failure) {
|
|
2986
|
+
return carryTerminalProgressOrThrow(addJunctionWorkoutStreamCandidateFailureContext(error, {
|
|
2987
|
+
aliasSource: candidate.workoutIdAliasSource,
|
|
2988
|
+
candidateCount: candidates.length,
|
|
2989
|
+
candidateOrdinal: candidateIndex + 1,
|
|
2990
|
+
}));
|
|
2991
|
+
}
|
|
2992
|
+
logSkippedOptionalJunctionResource(input.context, "timeseries", "workout_stream", failure);
|
|
2993
|
+
input.skippedOptionalResources.push({
|
|
2994
|
+
...failure,
|
|
2995
|
+
resource: "workout_stream",
|
|
2996
|
+
resourceCategory: "timeseries",
|
|
2997
|
+
});
|
|
2998
|
+
completedIdentities.add(candidate.identity);
|
|
2999
|
+
madeProgress = true;
|
|
3000
|
+
continue;
|
|
3001
|
+
}
|
|
3002
|
+
if (feature === undefined) {
|
|
3003
|
+
input.context.logger.warn?.("Skipping Junction workout with unaligned metric cardinality.", {
|
|
3004
|
+
errorCode: "JUNCTION_WORKOUT_STREAM_CARDINALITY_MISMATCH",
|
|
3005
|
+
provider: "junction",
|
|
3006
|
+
resource: "workout_stream",
|
|
3007
|
+
resourceCategory: "timeseries",
|
|
3008
|
+
});
|
|
3009
|
+
completedIdentities.add(candidate.identity);
|
|
3010
|
+
madeProgress = true;
|
|
3011
|
+
continue;
|
|
3012
|
+
}
|
|
3013
|
+
try {
|
|
3014
|
+
const preparedImport = await prepareJunctionImportSnapshot(input.context, { workout_stream: [feature] }, input.sourceProviders);
|
|
3015
|
+
if (hasJunctionSnapshotRecords(preparedImport.snapshots)) {
|
|
3016
|
+
await input.context.importSnapshot({
|
|
3017
|
+
provider: "junction",
|
|
3018
|
+
accountId: buildJunctionImportAccountId(input.context.account.externalAccountId),
|
|
3019
|
+
connectionId: input.context.account.id,
|
|
3020
|
+
importedAt: input.windowEnd,
|
|
3021
|
+
windowStart: input.windowStart,
|
|
3022
|
+
windowEnd: input.windowEnd,
|
|
3023
|
+
connections: preparedImport.connections,
|
|
3024
|
+
summaries: {},
|
|
3025
|
+
timeseries: preparedImport.snapshots,
|
|
3026
|
+
});
|
|
3027
|
+
}
|
|
3028
|
+
}
|
|
3029
|
+
catch (error) {
|
|
3030
|
+
return carryTerminalProgressOrThrow(error);
|
|
3031
|
+
}
|
|
3032
|
+
completedIdentities.add(candidate.identity);
|
|
3033
|
+
madeProgress = true;
|
|
3034
|
+
}
|
|
1488
3035
|
return {
|
|
3036
|
+
madeProgress,
|
|
3037
|
+
workoutStreamCursor: encodeJunctionWorkoutStreamCompletedIdentities(completedIdentities),
|
|
1489
3038
|
yieldedAt: null,
|
|
1490
3039
|
};
|
|
1491
3040
|
}
|
|
1492
3041
|
async function importJunctionDirectResourceSnapshot(context, sourceProviders, windowStart, windowEnd, resource, records, historicalEvidenceWindow) {
|
|
1493
3042
|
const snapshots = { [resource]: [...records] };
|
|
1494
|
-
const
|
|
1495
|
-
const summaries = sanitizeJunctionImportSnapshots(snapshots, sourceProviders, {
|
|
3043
|
+
const preparedImport = await prepareJunctionImportSnapshot(context, snapshots, sourceProviders, {
|
|
1496
3044
|
blockedStringValues: [context.account.externalAccountId],
|
|
1497
3045
|
});
|
|
3046
|
+
const connections = preparedImport.connections;
|
|
3047
|
+
const summaries = preparedImport.snapshots;
|
|
1498
3048
|
const normalizationEvidence = classifyJunctionSummaryNormalizationEvidence({
|
|
1499
3049
|
connections,
|
|
1500
3050
|
importedAt: context.now,
|
|
@@ -1502,6 +3052,12 @@ export function createJunctionDeviceSyncProvider(config) {
|
|
|
1502
3052
|
windowEnd,
|
|
1503
3053
|
windowStart,
|
|
1504
3054
|
}, historicalEvidenceWindow);
|
|
3055
|
+
if (!hasJunctionSnapshotRecords(summaries)) {
|
|
3056
|
+
return {
|
|
3057
|
+
durableDeliveryAccepted: false,
|
|
3058
|
+
normalizationEvidence,
|
|
3059
|
+
};
|
|
3060
|
+
}
|
|
1505
3061
|
const receipt = await context.importSnapshot({
|
|
1506
3062
|
provider: "junction",
|
|
1507
3063
|
accountId: buildJunctionImportAccountId(context.account.externalAccountId),
|
|
@@ -1574,98 +3130,218 @@ export function createJunctionDeviceSyncProvider(config) {
|
|
|
1574
3130
|
function buildYieldedJunctionJobResult(input) {
|
|
1575
3131
|
const followUp = buildYieldedJunctionFollowUpJob(input);
|
|
1576
3132
|
return {
|
|
1577
|
-
...(followUp
|
|
3133
|
+
...(followUp
|
|
3134
|
+
? {
|
|
3135
|
+
scheduledJobs: [{
|
|
3136
|
+
...followUp,
|
|
3137
|
+
...(input.job.kind === "resource"
|
|
3138
|
+
? {}
|
|
3139
|
+
: { availableAt: input.context.now }),
|
|
3140
|
+
...(input.workoutStreamCursor !== undefined
|
|
3141
|
+
? {
|
|
3142
|
+
maxAttempts: input.job.maxAttempts - Math.max(input.job.attempts - 1, 0),
|
|
3143
|
+
}
|
|
3144
|
+
: {}),
|
|
3145
|
+
}],
|
|
3146
|
+
}
|
|
3147
|
+
: {}),
|
|
1578
3148
|
nextReconcileAt: input.job.kind === "resource"
|
|
1579
3149
|
? clampWebhookJobNextReconcileAt(input.context)
|
|
1580
3150
|
: addMilliseconds(input.context.now, reconcileIntervalMs),
|
|
1581
3151
|
};
|
|
1582
3152
|
}
|
|
1583
|
-
function
|
|
1584
|
-
|
|
3153
|
+
function buildDeferredNonConnectHistoricalBackfillRetry(input) {
|
|
3154
|
+
const emptyBackfillAttempts = readHistoricalBackfillJobEmptyAttempts(input.job);
|
|
3155
|
+
if (input.job.kind !== "backfill"
|
|
3156
|
+
|| emptyBackfillAttempts === 0
|
|
3157
|
+
|| isConnectHistoricalBackfillWindow(input.account, input.window)) {
|
|
1585
3158
|
return null;
|
|
1586
3159
|
}
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
return null;
|
|
1591
|
-
}
|
|
1592
|
-
const emptyBackfillAttempts = readHistoricalBackfillJobEmptyAttempts(input.job);
|
|
1593
|
-
const followUp = buildExactWindowJob({
|
|
1594
|
-
kind: "backfill",
|
|
1595
|
-
priority: input.job.priority,
|
|
1596
|
-
windowEnd: input.windowEnd,
|
|
1597
|
-
windowStart: input.windowStart,
|
|
1598
|
-
});
|
|
1599
|
-
return {
|
|
1600
|
-
...followUp,
|
|
1601
|
-
payload: {
|
|
1602
|
-
...followUp.payload,
|
|
1603
|
-
...(emptyBackfillAttempts > 0 ? { emptyBackfillAttempts } : {}),
|
|
1604
|
-
timeseriesCursor: cursor,
|
|
1605
|
-
},
|
|
1606
|
-
};
|
|
3160
|
+
const retryDelayMs = EMPTY_HISTORICAL_BACKFILL_RETRY_DELAYS_MS[emptyBackfillAttempts - 1] ?? null;
|
|
3161
|
+
if (retryDelayMs === null) {
|
|
3162
|
+
return null;
|
|
1607
3163
|
}
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
3164
|
+
const retryJob = buildExactWindowJob({
|
|
3165
|
+
kind: "backfill",
|
|
3166
|
+
priority: Math.max(input.job.priority, JUNCTION_HISTORICAL_BACKFILL_RETRY_PRIORITY),
|
|
3167
|
+
windowEnd: input.window.windowEnd,
|
|
3168
|
+
windowStart: input.window.windowStart,
|
|
3169
|
+
});
|
|
3170
|
+
return {
|
|
3171
|
+
...retryJob,
|
|
3172
|
+
availableAt: addMilliseconds(input.now, retryDelayMs),
|
|
3173
|
+
payload: {
|
|
3174
|
+
...(retryJob.payload ?? {}),
|
|
3175
|
+
emptyBackfillAttempts,
|
|
3176
|
+
},
|
|
3177
|
+
};
|
|
3178
|
+
}
|
|
3179
|
+
function buildFullJobTimeseriesContinuationResult(input) {
|
|
3180
|
+
const continuationJob = input.continuation
|
|
3181
|
+
? buildFullJobTimeseriesContinuationJob({
|
|
3182
|
+
deferredEmptyBackfillAttempts: readHistoricalBackfillJobEmptyAttempts(input.job),
|
|
3183
|
+
job: input.job,
|
|
3184
|
+
...input.continuation,
|
|
3185
|
+
window: input.window,
|
|
3186
|
+
})
|
|
3187
|
+
: null;
|
|
3188
|
+
const scheduledJob = continuationJob
|
|
3189
|
+
? { ...continuationJob, availableAt: input.context.now }
|
|
3190
|
+
: buildDeferredNonConnectHistoricalBackfillRetry({
|
|
3191
|
+
account: input.context.account,
|
|
3192
|
+
job: input.job,
|
|
3193
|
+
now: input.context.now,
|
|
3194
|
+
window: input.window,
|
|
1614
3195
|
});
|
|
3196
|
+
return withJunctionSkippedResourceMetadata(input.context, {
|
|
3197
|
+
...(scheduledJob ? { scheduledJobs: [scheduledJob] } : {}),
|
|
3198
|
+
nextReconcileAt: resolveJunctionNextReconcileAt(input.context.account, input.context.now, addMilliseconds(input.context.now, reconcileIntervalMs)),
|
|
3199
|
+
}, input.skippedOptionalResources);
|
|
3200
|
+
}
|
|
3201
|
+
function buildFullJobTimeseriesContinuationJob(input) {
|
|
3202
|
+
if (input.job.kind !== "backfill" && input.job.kind !== "reconcile") {
|
|
3203
|
+
return null;
|
|
3204
|
+
}
|
|
3205
|
+
const timeseriesResourceCursor = normalizeFullJobTimeseriesResourceCursor(input.timeseriesResourceCursor, timeseriesResources);
|
|
3206
|
+
if (!timeseriesResourceCursor
|
|
3207
|
+
|| !isTimestampInHalfOpenWindow(input.timeseriesCursor, {
|
|
3208
|
+
windowEnd: input.window.windowEnd,
|
|
3209
|
+
windowStart: input.job.kind === "backfill"
|
|
3210
|
+
? maxIsoTimestamp(input.window.windowStart, subtractDays(input.window.windowEnd, timeseriesBackfillDays))
|
|
3211
|
+
: input.window.windowStart,
|
|
3212
|
+
})) {
|
|
3213
|
+
return null;
|
|
3214
|
+
}
|
|
3215
|
+
const sourceProviderSlug = normalizeProviderSlug(input.job.payload.sourceProviderSlug);
|
|
3216
|
+
return buildExactWindowJob({
|
|
3217
|
+
kind: input.job.kind,
|
|
3218
|
+
payload: {
|
|
3219
|
+
...(input.deferredEmptyBackfillAttempts > 0
|
|
3220
|
+
? { emptyBackfillAttempts: input.deferredEmptyBackfillAttempts }
|
|
3221
|
+
: {}),
|
|
3222
|
+
...(sourceProviderSlug ? { sourceProviderSlug } : {}),
|
|
3223
|
+
timeseriesCursor: input.timeseriesCursor,
|
|
3224
|
+
timeseriesResourceCursor,
|
|
3225
|
+
...(input.timeseriesWindowHours === 1 ? { timeseriesWindowHours: 1 } : {}),
|
|
3226
|
+
...(input.workoutStreamCursor
|
|
3227
|
+
? { workoutStreamCursor: input.workoutStreamCursor }
|
|
3228
|
+
: {}),
|
|
3229
|
+
},
|
|
3230
|
+
priority: input.job.priority,
|
|
3231
|
+
windowEnd: input.window.windowEnd,
|
|
3232
|
+
windowStart: input.window.windowStart,
|
|
3233
|
+
});
|
|
3234
|
+
}
|
|
3235
|
+
function buildYieldedJunctionFollowUpJob(input) {
|
|
3236
|
+
if (Date.parse(input.windowStart) >= Date.parse(input.windowEnd)) {
|
|
3237
|
+
return null;
|
|
1615
3238
|
}
|
|
3239
|
+
const sourceProviderSlug = normalizeProviderSlug(input.job.payload.sourceProviderSlug);
|
|
1616
3240
|
if (input.job.kind !== "resource") {
|
|
1617
3241
|
return null;
|
|
1618
3242
|
}
|
|
1619
|
-
const payload = {
|
|
3243
|
+
const payload = stripUndefined({
|
|
1620
3244
|
...input.job.payload,
|
|
3245
|
+
emptyBackfillAttempts: input.emptyBackfillAttempts === undefined
|
|
3246
|
+
? input.job.payload.emptyBackfillAttempts
|
|
3247
|
+
: input.emptyBackfillAttempts > 0
|
|
3248
|
+
? input.emptyBackfillAttempts
|
|
3249
|
+
: undefined,
|
|
3250
|
+
...(input.historicalProviderRecordsSeen === undefined
|
|
3251
|
+
? {}
|
|
3252
|
+
: { historicalProviderRecordsSeen: input.historicalProviderRecordsSeen }),
|
|
3253
|
+
...(input.historicalRecordsSeen === undefined
|
|
3254
|
+
? {}
|
|
3255
|
+
: { historicalRecordsSeen: input.historicalRecordsSeen }),
|
|
3256
|
+
historicalUnresolvedProviderRecordIdentitiesJson: input.historicalUnresolvedProviderRecordIdentitiesJson === undefined
|
|
3257
|
+
? input.job.payload.historicalUnresolvedProviderRecordIdentitiesJson
|
|
3258
|
+
: input.historicalUnresolvedProviderRecordIdentitiesJson,
|
|
3259
|
+
historicalUnresolvedProviderRecordCount: input.historicalUnresolvedProviderRecordCount === undefined
|
|
3260
|
+
? input.job.payload.historicalUnresolvedProviderRecordCount
|
|
3261
|
+
: input.historicalUnresolvedProviderRecordCount > 0
|
|
3262
|
+
? input.historicalUnresolvedProviderRecordCount
|
|
3263
|
+
: undefined,
|
|
1621
3264
|
windowEnd: input.windowEnd,
|
|
1622
3265
|
windowStart: input.windowStart,
|
|
1623
|
-
|
|
3266
|
+
workoutStreamCursor: input.workoutStreamCursor || undefined,
|
|
3267
|
+
});
|
|
1624
3268
|
return {
|
|
1625
3269
|
kind: "resource",
|
|
1626
3270
|
payload,
|
|
1627
3271
|
priority: input.job.priority,
|
|
1628
|
-
dedupeKey:
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
3272
|
+
dedupeKey: input.job.dedupeKey
|
|
3273
|
+
?? buildJunctionExtendedTimeseriesBackfillDedupeKey(payload)
|
|
3274
|
+
?? sha256Text(JSON.stringify([
|
|
3275
|
+
"junction",
|
|
3276
|
+
"yield-follow-up",
|
|
3277
|
+
input.windowStart,
|
|
3278
|
+
input.windowEnd,
|
|
3279
|
+
normalizeString(payload.eventType),
|
|
3280
|
+
normalizeString(payload.objectId),
|
|
3281
|
+
normalizeString(payload.occurredAt),
|
|
3282
|
+
normalizeString(payload.resource),
|
|
3283
|
+
normalizeString(payload.resourceCategory),
|
|
3284
|
+
normalizeString(payload.sourceProviderSlug),
|
|
3285
|
+
])),
|
|
3286
|
+
};
|
|
3287
|
+
}
|
|
3288
|
+
function buildExtendedTimeseriesBackfillWindow(input) {
|
|
3289
|
+
const windowEnd = floorUtcDayTimestamp(input.anchorAt);
|
|
3290
|
+
return {
|
|
3291
|
+
windowEnd,
|
|
3292
|
+
windowStart: floorUtcDayTimestamp(subtractDays(windowEnd, input.days)),
|
|
1640
3293
|
};
|
|
1641
3294
|
}
|
|
1642
|
-
function
|
|
3295
|
+
function hasTerminalJunctionHistoricalBackfill(account) {
|
|
3296
|
+
const status = readJunctionHistoricalBackfillStatus(account.metadata[JUNCTION_HISTORICAL_BACKFILL_METADATA_KEYS.status]);
|
|
3297
|
+
const connectWindow = buildConnectHistoricalBackfillWindow(account, summaryBackfillDays);
|
|
3298
|
+
return status?.coverageVersion === JUNCTION_HISTORICAL_BACKFILL_COVERAGE_VERSION
|
|
3299
|
+
&& (status.status === "complete" || status.status === "exhausted")
|
|
3300
|
+
&& normalizeString(account.metadata[JUNCTION_HISTORICAL_BACKFILL_METADATA_KEYS.windowStart]) === connectWindow.windowStart
|
|
3301
|
+
&& normalizeString(account.metadata[JUNCTION_HISTORICAL_BACKFILL_METADATA_KEYS.windowEnd]) === connectWindow.windowEnd;
|
|
3302
|
+
}
|
|
3303
|
+
function buildInitialJobs(now, sourceProviderSlug) {
|
|
3304
|
+
const normalizedSourceProviderSlug = normalizeProviderSlug(sourceProviderSlug);
|
|
3305
|
+
const payload = normalizedSourceProviderSlug
|
|
3306
|
+
? { sourceProviderSlug: normalizedSourceProviderSlug }
|
|
3307
|
+
: undefined;
|
|
1643
3308
|
return [
|
|
1644
3309
|
buildWindowJob({
|
|
1645
3310
|
kind: "backfill",
|
|
1646
3311
|
now,
|
|
3312
|
+
payload,
|
|
1647
3313
|
windowStart: subtractDays(now, summaryBackfillDays),
|
|
1648
|
-
priority:
|
|
3314
|
+
priority: JUNCTION_HISTORICAL_BACKFILL_PRIORITY,
|
|
1649
3315
|
}),
|
|
1650
3316
|
buildWindowJob({
|
|
1651
3317
|
kind: "reconcile",
|
|
1652
3318
|
now,
|
|
3319
|
+
payload,
|
|
1653
3320
|
windowStart: subtractDays(now, reconcileDays),
|
|
1654
|
-
priority:
|
|
3321
|
+
priority: JUNCTION_SCHEDULED_RECONCILE_PRIORITY,
|
|
1655
3322
|
}),
|
|
1656
3323
|
];
|
|
1657
3324
|
}
|
|
3325
|
+
function buildSourceConnectionWork(input) {
|
|
3326
|
+
return {
|
|
3327
|
+
initialJobs: buildInitialJobs(input.now, input.sourceProviderSlug),
|
|
3328
|
+
nextReconcileAt: addMilliseconds(input.now, reconcileIntervalMs),
|
|
3329
|
+
};
|
|
3330
|
+
}
|
|
1658
3331
|
return {
|
|
1659
3332
|
provider: "junction",
|
|
1660
|
-
descriptor:
|
|
3333
|
+
descriptor: buildJunctionDeviceSyncRuntimeDescriptor(config),
|
|
1661
3334
|
credentialPolicy: {
|
|
1662
3335
|
kind: "provider_config",
|
|
1663
3336
|
providerConfigKey: JUNCTION_PROVIDER_CONFIG_KEY,
|
|
1664
3337
|
},
|
|
1665
3338
|
connectionHandler: {
|
|
1666
3339
|
beginConnection,
|
|
3340
|
+
buildSourceConnectionWork,
|
|
1667
3341
|
completeConnection,
|
|
3342
|
+
isSourceAccessActive,
|
|
1668
3343
|
revokeAccess,
|
|
3344
|
+
revokeSourceAccess,
|
|
1669
3345
|
},
|
|
1670
3346
|
sdkConnectionHandler: {
|
|
1671
3347
|
ensureConnection: ensureSdkConnection,
|
|
@@ -1684,6 +3360,80 @@ export function createJunctionDeviceSyncProvider(config) {
|
|
|
1684
3360
|
},
|
|
1685
3361
|
};
|
|
1686
3362
|
}
|
|
3363
|
+
async function fetchJunctionTimeseriesWindow(junctionClient, input) {
|
|
3364
|
+
const policy = resolveJunctionTimeseriesResourcePolicy(input.resource);
|
|
3365
|
+
if (!policy) {
|
|
3366
|
+
throw new TypeError(`Unknown Junction timeseries resource: ${input.resource}.`);
|
|
3367
|
+
}
|
|
3368
|
+
if (policy.fetchMode === "workout_stream") {
|
|
3369
|
+
const maxSamples = policy.maxSamplesPerRecord;
|
|
3370
|
+
if (!maxSamples) {
|
|
3371
|
+
throw new TypeError("Junction workout_stream policy did not define bounded limits.");
|
|
3372
|
+
}
|
|
3373
|
+
const candidates = await listJunctionWorkoutStreamCandidates(junctionClient, input);
|
|
3374
|
+
const features = [];
|
|
3375
|
+
for (const candidate of candidates) {
|
|
3376
|
+
const feature = await fetchJunctionWorkoutStreamFeature(junctionClient, candidate, maxSamples, input.signal ?? null);
|
|
3377
|
+
if (feature !== undefined) {
|
|
3378
|
+
features.push(feature);
|
|
3379
|
+
}
|
|
3380
|
+
}
|
|
3381
|
+
return features;
|
|
3382
|
+
}
|
|
3383
|
+
const records = await junctionClient.listTimeseries({
|
|
3384
|
+
...input,
|
|
3385
|
+
maxRecords: input.maxRecords ?? policy.maxSamplesPerWindow,
|
|
3386
|
+
});
|
|
3387
|
+
if (policy.normalizationMode !== "ecg_recording_feature") {
|
|
3388
|
+
return records;
|
|
3389
|
+
}
|
|
3390
|
+
if (!policy.maxRecordsPerWindow || !policy.maxSamplesPerWindow) {
|
|
3391
|
+
throw new TypeError("Junction ECG voltage policy did not define bounded limits.");
|
|
3392
|
+
}
|
|
3393
|
+
return reduceJunctionElectrocardiogramVoltageRecords(records, {
|
|
3394
|
+
maxRecordings: policy.maxRecordsPerWindow,
|
|
3395
|
+
maxSamples: policy.maxSamplesPerWindow,
|
|
3396
|
+
});
|
|
3397
|
+
}
|
|
3398
|
+
async function listJunctionWorkoutStreamCandidates(junctionClient, input) {
|
|
3399
|
+
const maxWorkouts = resolveJunctionTimeseriesResourcePolicy("workout_stream")
|
|
3400
|
+
?.maxRecordsPerWindow;
|
|
3401
|
+
if (!maxWorkouts) {
|
|
3402
|
+
throw new TypeError("Junction workout_stream policy did not define a workout limit.");
|
|
3403
|
+
}
|
|
3404
|
+
const indexRecords = await junctionClient.listSummary({
|
|
3405
|
+
collectionWorkLimit: input.collectionWorkLimit,
|
|
3406
|
+
resource: "workouts",
|
|
3407
|
+
signal: input.signal ?? null,
|
|
3408
|
+
sourceProviderSlug: input.sourceProviderSlug,
|
|
3409
|
+
userId: input.userId,
|
|
3410
|
+
windowStart: input.windowStart,
|
|
3411
|
+
windowEnd: input.windowEnd,
|
|
3412
|
+
maxRecords: maxWorkouts + 1,
|
|
3413
|
+
});
|
|
3414
|
+
const summaries = indexRecords.map((record) => withJunctionSourceProviderFallback(record, input.sourceProviderSlug));
|
|
3415
|
+
return selectJunctionWorkoutStreamCandidates(summaries, maxWorkouts);
|
|
3416
|
+
}
|
|
3417
|
+
async function fetchJunctionWorkoutStreamFeature(junctionClient, candidate, maxSamples, signal, collectionWorkLimit) {
|
|
3418
|
+
const stream = await junctionClient.getWorkoutStream({
|
|
3419
|
+
collectionWorkLimit,
|
|
3420
|
+
signal,
|
|
3421
|
+
workoutId: candidate.workoutId,
|
|
3422
|
+
});
|
|
3423
|
+
return reduceJunctionWorkoutStreamPayload({
|
|
3424
|
+
maxSamples,
|
|
3425
|
+
stream,
|
|
3426
|
+
summary: candidate.summary,
|
|
3427
|
+
});
|
|
3428
|
+
}
|
|
3429
|
+
function withJunctionSourceProviderFallback(value, sourceProviderSlug) {
|
|
3430
|
+
const record = readPlainObject(value);
|
|
3431
|
+
const normalizedSource = normalizeProviderSlug(sourceProviderSlug);
|
|
3432
|
+
if (!record || !normalizedSource || resolveJunctionOrigin(record).sourceProviderSlug) {
|
|
3433
|
+
return value;
|
|
3434
|
+
}
|
|
3435
|
+
return { ...record, sourceProviderSlug: normalizedSource };
|
|
3436
|
+
}
|
|
1687
3437
|
function withJunctionSkippedResourceMetadata(context, result, skippedOptionalResources) {
|
|
1688
3438
|
if (skippedOptionalResources.length === 0) {
|
|
1689
3439
|
return result;
|
|
@@ -1711,6 +3461,7 @@ function withJunctionMetadataPatch(result, metadataPatch) {
|
|
|
1711
3461
|
function buildJunctionProfileSummaryCheckedMetadataPatch(context) {
|
|
1712
3462
|
return {
|
|
1713
3463
|
[JUNCTION_PROFILE_SUMMARY_CHECKED_AT_METADATA_KEY]: context.now,
|
|
3464
|
+
[JUNCTION_PROFILE_SUMMARY_NORMALIZATION_REVISION_METADATA_KEY]: JUNCTION_PROFILE_SUMMARY_NORMALIZATION_REVISION,
|
|
1714
3465
|
};
|
|
1715
3466
|
}
|
|
1716
3467
|
function buildJunctionSkippedResourceMetadataPatch(context, skippedOptionalResources) {
|
|
@@ -1740,7 +3491,29 @@ function isJunctionProfileSummaryResource(resource) {
|
|
|
1740
3491
|
}
|
|
1741
3492
|
function hasCheckedJunctionProfileSummary(metadata) {
|
|
1742
3493
|
const checkedAt = normalizeString(metadata[JUNCTION_PROFILE_SUMMARY_CHECKED_AT_METADATA_KEY]);
|
|
1743
|
-
return checkedAt !== undefined
|
|
3494
|
+
return checkedAt !== undefined
|
|
3495
|
+
&& Number.isFinite(Date.parse(checkedAt))
|
|
3496
|
+
&& metadata[JUNCTION_PROFILE_SUMMARY_NORMALIZATION_REVISION_METADATA_KEY]
|
|
3497
|
+
=== JUNCTION_PROFILE_SUMMARY_NORMALIZATION_REVISION;
|
|
3498
|
+
}
|
|
3499
|
+
function addJunctionWorkoutStreamCandidateFailureContext(error, input) {
|
|
3500
|
+
if (!isDeviceSyncError(error) || error.code !== "JUNCTION_API_REQUEST_FAILED") {
|
|
3501
|
+
return error;
|
|
3502
|
+
}
|
|
3503
|
+
return deviceSyncError({
|
|
3504
|
+
accountStatus: error.accountStatus,
|
|
3505
|
+
cause: error.cause,
|
|
3506
|
+
code: error.code,
|
|
3507
|
+
details: {
|
|
3508
|
+
...error.details,
|
|
3509
|
+
requestCandidateAliasSource: input.aliasSource,
|
|
3510
|
+
requestCandidateCount: input.candidateCount,
|
|
3511
|
+
requestCandidateOrdinal: input.candidateOrdinal,
|
|
3512
|
+
},
|
|
3513
|
+
httpStatus: error.httpStatus,
|
|
3514
|
+
message: error.message,
|
|
3515
|
+
retryable: error.retryable,
|
|
3516
|
+
});
|
|
1744
3517
|
}
|
|
1745
3518
|
function classifyOptionalJunctionResourceFailure(error, resourceCategory, resource, accountExternalId) {
|
|
1746
3519
|
if (!isDeviceSyncError(error) || error.code !== "JUNCTION_API_REQUEST_FAILED") {
|
|
@@ -1785,6 +3558,22 @@ function classifyOptionalJunctionResourceFailure(error, resourceCategory, resour
|
|
|
1785
3558
|
...(responseDetail ? { responseDetail } : {}),
|
|
1786
3559
|
};
|
|
1787
3560
|
}
|
|
3561
|
+
function isRetryableDeviceSyncFailure(error) {
|
|
3562
|
+
return isDeviceSyncError(error) && error.retryable;
|
|
3563
|
+
}
|
|
3564
|
+
function isJunctionJobSignalAbort(error, signal, depth = 0) {
|
|
3565
|
+
if (!signal?.aborted) {
|
|
3566
|
+
return false;
|
|
3567
|
+
}
|
|
3568
|
+
if (error === signal.reason) {
|
|
3569
|
+
return true;
|
|
3570
|
+
}
|
|
3571
|
+
if (depth >= 4 || typeof error !== "object" || error === null) {
|
|
3572
|
+
return false;
|
|
3573
|
+
}
|
|
3574
|
+
const cause = "cause" in error ? error.cause : undefined;
|
|
3575
|
+
return cause !== undefined && isJunctionJobSignalAbort(cause, signal, depth + 1);
|
|
3576
|
+
}
|
|
1788
3577
|
function buildJunctionOptionalResourceResponseDetail(input) {
|
|
1789
3578
|
// The generic redactor does not know the current Junction user id; strip it
|
|
1790
3579
|
// explicitly before the shared sanitizer so provider prose that embeds the
|
|
@@ -2201,7 +3990,7 @@ function resolveJunctionDiagnosticMatrixResources(input) {
|
|
|
2201
3990
|
}
|
|
2202
3991
|
async function runJunctionDiagnosticMatrixRead(input) {
|
|
2203
3992
|
const response = await runJunctionDiagnosticCall(() => input.category === "timeseries"
|
|
2204
|
-
? input.client
|
|
3993
|
+
? fetchJunctionTimeseriesWindow(input.client, {
|
|
2205
3994
|
resource: input.resource,
|
|
2206
3995
|
sourceProviderSlug: input.sourceProviderSlug,
|
|
2207
3996
|
userId: input.account.externalAccountId,
|
|
@@ -2219,9 +4008,7 @@ async function runJunctionDiagnosticMatrixRead(input) {
|
|
|
2219
4008
|
request: {
|
|
2220
4009
|
configuredResource: input.configuredResource,
|
|
2221
4010
|
endpoint: input.category,
|
|
2222
|
-
endpointKind: input.category
|
|
2223
|
-
? "junction_timeseries_collection"
|
|
2224
|
-
: "junction_summary_collection",
|
|
4011
|
+
endpointKind: resolveJunctionDiagnosticEndpointKind(input.category, input.resource),
|
|
2225
4012
|
queryParameterNames: resolveJunctionDiagnosticResourceQueryParameterNames(input.category, input.resource, input.sourceProviderSlug),
|
|
2226
4013
|
resource: input.resource,
|
|
2227
4014
|
resourceCategory: input.category,
|
|
@@ -2231,6 +4018,14 @@ async function runJunctionDiagnosticMatrixRead(input) {
|
|
|
2231
4018
|
response: describeJunctionDiagnosticRecords(response),
|
|
2232
4019
|
};
|
|
2233
4020
|
}
|
|
4021
|
+
function resolveJunctionDiagnosticEndpointKind(category, resource) {
|
|
4022
|
+
if (category === "summary") {
|
|
4023
|
+
return "junction_summary_collection";
|
|
4024
|
+
}
|
|
4025
|
+
return resolveJunctionTimeseriesResourcePolicy(resource)?.fetchMode === "workout_stream"
|
|
4026
|
+
? "junction_workout_stream"
|
|
4027
|
+
: "junction_timeseries_collection";
|
|
4028
|
+
}
|
|
2234
4029
|
function resolveJunctionDiagnosticResourceQueryParameterNames(category, resource, sourceProviderSlug) {
|
|
2235
4030
|
if (category === "summary" && isJunctionProfileSummaryResource(resource)) {
|
|
2236
4031
|
return sourceProviderSlug ? ["provider"] : [];
|
|
@@ -2645,10 +4440,12 @@ function normalizeDiagnosticTimeseriesProbeDays(value) {
|
|
|
2645
4440
|
}
|
|
2646
4441
|
return Math.min(value, JUNCTION_MAX_DIAGNOSTIC_TIMESERIES_PROBE_DAYS);
|
|
2647
4442
|
}
|
|
2648
|
-
export function buildJunctionClientUserId(secret, ownerId) {
|
|
4443
|
+
export function buildJunctionClientUserId(secret, ownerId, namespace) {
|
|
2649
4444
|
const normalizedSecret = assertValidJunctionClientUserIdSecret(secret);
|
|
4445
|
+
const normalizedNamespace = normalizeJunctionClientUserIdNamespace(namespace);
|
|
2650
4446
|
const digest = createHmac("sha256", normalizedSecret).update(ownerId).digest();
|
|
2651
|
-
|
|
4447
|
+
const prefix = normalizedNamespace ? `murph_${normalizedNamespace}_` : "murph_";
|
|
4448
|
+
return `${prefix}${base32UrlEncode(digest)}`.slice(0, 32);
|
|
2652
4449
|
}
|
|
2653
4450
|
function resolveJunctionLinkDirectProvider(providerFilter, sourceProviderSlug) {
|
|
2654
4451
|
const requested = normalizeString(sourceProviderSlug);
|
|
@@ -2671,6 +4468,7 @@ function toClientConfig(config) {
|
|
|
2671
4468
|
apiKey: config.apiKey,
|
|
2672
4469
|
environment: config.environment,
|
|
2673
4470
|
region: config.region,
|
|
4471
|
+
apiBaseUrl: config.apiBaseUrl,
|
|
2674
4472
|
allowedLinkHosts: config.allowedLinkHosts,
|
|
2675
4473
|
requestTimeoutMs: config.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS,
|
|
2676
4474
|
fetchImpl: config.fetchImpl,
|
|
@@ -2680,14 +4478,153 @@ function normalizeProviderSlug(value) {
|
|
|
2680
4478
|
const normalized = normalizeString(value)?.toLowerCase().replace(/[^a-z0-9_]+/gu, "_").replace(/^_+|_+$/gu, "");
|
|
2681
4479
|
return normalized || null;
|
|
2682
4480
|
}
|
|
4481
|
+
function resolveJunctionProviderRouteSlug(value) {
|
|
4482
|
+
const normalized = normalizeProviderSlug(value);
|
|
4483
|
+
if (!normalized) {
|
|
4484
|
+
return null;
|
|
4485
|
+
}
|
|
4486
|
+
return resolveJunctionDeviceConnectRouteByProviderSlug(normalized)?.route.sourceProviderSlug
|
|
4487
|
+
?? normalized;
|
|
4488
|
+
}
|
|
4489
|
+
function areJunctionProviderSlugsRouteEquivalent(left, right) {
|
|
4490
|
+
const normalizedLeft = normalizeProviderSlug(left);
|
|
4491
|
+
const normalizedRight = normalizeProviderSlug(right);
|
|
4492
|
+
return normalizedLeft !== null
|
|
4493
|
+
&& normalizedRight !== null
|
|
4494
|
+
&& areJunctionDeviceConnectProviderSlugsEquivalent(normalizedLeft, normalizedRight);
|
|
4495
|
+
}
|
|
4496
|
+
function resolveJunctionAccountSourceIdentities(sources) {
|
|
4497
|
+
const identities = [];
|
|
4498
|
+
for (const source of sources) {
|
|
4499
|
+
const identity = resolveJunctionAccountSourceIdentity(sources, source.sourceProviderSlug);
|
|
4500
|
+
if (identity
|
|
4501
|
+
&& !identities.some((candidate) => candidate.sourceProviderSlug === identity.sourceProviderSlug)) {
|
|
4502
|
+
identities.push(identity);
|
|
4503
|
+
}
|
|
4504
|
+
}
|
|
4505
|
+
return identities;
|
|
4506
|
+
}
|
|
4507
|
+
function resolveJunctionAccountSourceStates(sources) {
|
|
4508
|
+
const states = [];
|
|
4509
|
+
for (const source of sources) {
|
|
4510
|
+
if (states.some((state) => areJunctionProviderSlugsRouteEquivalent(state.identitySource.sourceProviderSlug, source.sourceProviderSlug))) {
|
|
4511
|
+
continue;
|
|
4512
|
+
}
|
|
4513
|
+
const state = resolveJunctionAccountSourceState(sources, source.sourceProviderSlug);
|
|
4514
|
+
if (state) {
|
|
4515
|
+
states.push(state);
|
|
4516
|
+
}
|
|
4517
|
+
}
|
|
4518
|
+
return states;
|
|
4519
|
+
}
|
|
4520
|
+
function mergeJunctionAccountSourceIdentities(accountSourceIdentities, requestedSourceIdentities) {
|
|
4521
|
+
return [
|
|
4522
|
+
...accountSourceIdentities,
|
|
4523
|
+
...requestedSourceIdentities.filter((requestedIdentity) => !accountSourceIdentities.some((accountIdentity) => areJunctionProviderSlugsRouteEquivalent(requestedIdentity.sourceProviderSlug, accountIdentity.sourceProviderSlug))),
|
|
4524
|
+
];
|
|
4525
|
+
}
|
|
4526
|
+
function resolveJunctionAccountSourceIdentity(sources, sourceProviderSlug, allowUnlistedSource = false) {
|
|
4527
|
+
const normalizedSourceProviderSlug = normalizeProviderSlug(sourceProviderSlug);
|
|
4528
|
+
if (!normalizedSourceProviderSlug) {
|
|
4529
|
+
return null;
|
|
4530
|
+
}
|
|
4531
|
+
const matchingSource = findJunctionAccountSource(sources, normalizedSourceProviderSlug);
|
|
4532
|
+
if (!matchingSource) {
|
|
4533
|
+
return allowUnlistedSource
|
|
4534
|
+
? { sourceProviderSlug: normalizedSourceProviderSlug }
|
|
4535
|
+
: null;
|
|
4536
|
+
}
|
|
4537
|
+
const establishedSourceProviderSlug = normalizeProviderSlug(matchingSource.sourceProviderSlug);
|
|
4538
|
+
if (!establishedSourceProviderSlug) {
|
|
4539
|
+
return null;
|
|
4540
|
+
}
|
|
4541
|
+
const sourceInstanceId = matchingSource.sourceInstanceKey
|
|
4542
|
+
? resolveJunctionOrigin({
|
|
4543
|
+
sourceInstanceId: matchingSource.sourceInstanceKey,
|
|
4544
|
+
sourceProviderSlug: establishedSourceProviderSlug,
|
|
4545
|
+
}).sourceInstanceId
|
|
4546
|
+
: undefined;
|
|
4547
|
+
return {
|
|
4548
|
+
...(matchingSource.sourceInstanceKey
|
|
4549
|
+
? {
|
|
4550
|
+
...(sourceInstanceId ? { sourceInstanceId } : {}),
|
|
4551
|
+
sourceInstanceKey: matchingSource.sourceInstanceKey,
|
|
4552
|
+
}
|
|
4553
|
+
: {}),
|
|
4554
|
+
sourceProviderSlug: establishedSourceProviderSlug,
|
|
4555
|
+
};
|
|
4556
|
+
}
|
|
4557
|
+
function findJunctionAccountSource(sources, sourceProviderSlug) {
|
|
4558
|
+
return resolveJunctionAccountSourceState(sources, sourceProviderSlug)
|
|
4559
|
+
?.identitySource;
|
|
4560
|
+
}
|
|
4561
|
+
function findJunctionAccountSources(sources, sourceProviderSlug) {
|
|
4562
|
+
return sources.filter((source) => areJunctionProviderSlugsRouteEquivalent(source.sourceProviderSlug, sourceProviderSlug));
|
|
4563
|
+
}
|
|
4564
|
+
function resolveJunctionAccountSourceState(sources, sourceProviderSlug) {
|
|
4565
|
+
const [first, ...rest] = findJunctionAccountSources(sources, sourceProviderSlug);
|
|
4566
|
+
if (!first) {
|
|
4567
|
+
return null;
|
|
4568
|
+
}
|
|
4569
|
+
return resolveDeviceSyncSourceState([first, ...rest], junctionSourceStateUnavailableError);
|
|
4570
|
+
}
|
|
2683
4571
|
function stripUndefined(value) {
|
|
2684
4572
|
return Object.fromEntries(Object.entries(value).filter(([, entry]) => entry !== undefined));
|
|
2685
4573
|
}
|
|
2686
|
-
function sanitizeJunctionImportConnections(providers) {
|
|
2687
|
-
return providers.map((provider) =>
|
|
2688
|
-
sourceProviderSlug
|
|
2689
|
-
|
|
2690
|
-
|
|
4574
|
+
function sanitizeJunctionImportConnections(providers, sourceIdentities = []) {
|
|
4575
|
+
return providers.map((provider) => {
|
|
4576
|
+
const sourceProviderSlug = provider.origin.sourceProviderSlug ?? provider.slug;
|
|
4577
|
+
const projectedSourceIdentity = sourceIdentities.find((identity) => areJunctionProviderSlugsRouteEquivalent(sourceProviderSlug, identity.sourceProviderSlug));
|
|
4578
|
+
return stripUndefined({
|
|
4579
|
+
sourceProviderSlug: projectedSourceIdentity?.sourceProviderSlug ?? sourceProviderSlug,
|
|
4580
|
+
sourceInstanceId: projectedSourceIdentity?.sourceInstanceId ?? provider.origin.sourceInstanceId,
|
|
4581
|
+
});
|
|
4582
|
+
});
|
|
4583
|
+
}
|
|
4584
|
+
async function prepareJunctionImportSnapshot(context, snapshots, providers, options = {}, sourceStatusRequirement = "not_disconnected") {
|
|
4585
|
+
const currentSources = context.listConnectionSources
|
|
4586
|
+
? await context.listConnectionSources()
|
|
4587
|
+
: context.account.sources ?? [];
|
|
4588
|
+
const sourceIdentities = options.projectAccountSourceIdentities
|
|
4589
|
+
? mergeJunctionAccountSourceIdentities(resolveJunctionAccountSourceIdentities(currentSources), options.sourceIdentities ?? [])
|
|
4590
|
+
: options.sourceIdentities;
|
|
4591
|
+
return prepareJunctionImportSnapshotForSources(snapshots, providers, currentSources, { ...options, sourceIdentities }, {
|
|
4592
|
+
allowUnlistedSources: context.connectionSourceAdmissionMode !== "listed_only",
|
|
4593
|
+
sourceStatusRequirement,
|
|
4594
|
+
});
|
|
4595
|
+
}
|
|
4596
|
+
function prepareJunctionImportSnapshotForSources(snapshots, providers, currentSources, options = {}, admission = {}) {
|
|
4597
|
+
const allowUnlistedSources = admission.allowUnlistedSources ?? true;
|
|
4598
|
+
const sourceStatusRequirement = admission.sourceStatusRequirement ?? "not_disconnected";
|
|
4599
|
+
const sourceProviders = providers.filter((provider) => isJunctionSourceAdmittedForImport(currentSources, provider.origin.sourceProviderSlug ?? provider.slug, allowUnlistedSources, sourceStatusRequirement));
|
|
4600
|
+
return {
|
|
4601
|
+
connections: sanitizeJunctionImportConnections(sourceProviders, options.sourceIdentities),
|
|
4602
|
+
sourceProviders,
|
|
4603
|
+
snapshots: sanitizeJunctionImportSnapshots(filterJunctionImportSnapshots(snapshots, providers, currentSources, allowUnlistedSources, sourceStatusRequirement), providers, options),
|
|
4604
|
+
};
|
|
4605
|
+
}
|
|
4606
|
+
function filterJunctionImportSnapshots(snapshots, providers, sources, allowUnlistedSources = true, sourceStatusRequirement = "not_disconnected") {
|
|
4607
|
+
const sourceReferences = buildJunctionSourceReferenceMap(providers);
|
|
4608
|
+
const hasPendingSourceAdmission = resolveJunctionAccountSourceStates(sources).some(({ lifecycleSource }) => sourceStatusRequirement === "connected"
|
|
4609
|
+
? !isDeviceSyncSourceAdmitted([lifecycleSource], lifecycleSource.sourceProviderSlug)
|
|
4610
|
+
: lifecycleSource.status === "disconnected"
|
|
4611
|
+
|| isDeviceSyncSourceDisconnectFenced(lifecycleSource));
|
|
4612
|
+
return Object.fromEntries(Object.entries(snapshots).map(([resource, records]) => [
|
|
4613
|
+
resource,
|
|
4614
|
+
records.filter((record) => isJunctionImportRecordAdmitted(record, sourceReferences, sources, hasPendingSourceAdmission, allowUnlistedSources, sourceStatusRequirement)),
|
|
4615
|
+
]));
|
|
4616
|
+
}
|
|
4617
|
+
function isJunctionImportRecordAdmitted(value, sourceReferences, sources, hasPendingSourceAdmission, allowUnlistedSources, sourceStatusRequirement) {
|
|
4618
|
+
const record = readPlainObject(value);
|
|
4619
|
+
if (!record) {
|
|
4620
|
+
return true;
|
|
4621
|
+
}
|
|
4622
|
+
const fallback = readJunctionSourceReference(record, sourceReferences);
|
|
4623
|
+
const sourceProviderSlug = normalizeProviderSlug(resolveJunctionOrigin(record, fallback).sourceProviderSlug);
|
|
4624
|
+
if (sourceProviderSlug) {
|
|
4625
|
+
return isJunctionSourceAdmittedForImport(sources, sourceProviderSlug, allowUnlistedSources, sourceStatusRequirement);
|
|
4626
|
+
}
|
|
4627
|
+
return !hasPendingSourceAdmission || !hasJunctionSourceReferenceIdentity(record);
|
|
2691
4628
|
}
|
|
2692
4629
|
function sanitizeJunctionImportSnapshots(snapshots, providers, options = {}) {
|
|
2693
4630
|
const sourceReferences = buildJunctionSourceReferenceMap(providers);
|
|
@@ -2723,6 +4660,9 @@ function sanitizeJunctionImportSnapshotValue(value, sourceReferences, options =
|
|
|
2723
4660
|
if (typeof value === "string") {
|
|
2724
4661
|
return redactJunctionBlockedStringValue(value, options.blockedStringValues ?? []);
|
|
2725
4662
|
}
|
|
4663
|
+
if (value instanceof Date) {
|
|
4664
|
+
return Number.isFinite(value.getTime()) ? value.toISOString() : null;
|
|
4665
|
+
}
|
|
2726
4666
|
const record = readPlainObject(value);
|
|
2727
4667
|
if (!record) {
|
|
2728
4668
|
return value;
|
|
@@ -2736,11 +4676,18 @@ function sanitizeJunctionImportSnapshotValue(value, sourceReferences, options =
|
|
|
2736
4676
|
hasJunctionSourceReferenceIdentity(record);
|
|
2737
4677
|
const sourceInstanceId = fallbackSourceInstanceId ??
|
|
2738
4678
|
(unresolvedPreservedSourceReference ? undefined : origin.sourceInstanceId);
|
|
4679
|
+
const sourceProviderSlug = normalizeProviderSlug(origin.sourceProviderSlug);
|
|
4680
|
+
const projectedSourceIdentity = options.sourceIdentities
|
|
4681
|
+
?.find((identity) => areJunctionProviderSlugsRouteEquivalent(sourceProviderSlug, identity.sourceProviderSlug));
|
|
2739
4682
|
return stripUndefined({
|
|
2740
4683
|
...sanitized,
|
|
2741
|
-
sourceProviderSlug:
|
|
4684
|
+
sourceProviderSlug: projectedSourceIdentity?.sourceProviderSlug
|
|
4685
|
+
?? sourceProviderSlug
|
|
4686
|
+
?? sanitized.sourceProviderSlug,
|
|
2742
4687
|
sourceType: origin.sourceType ?? sanitized.sourceType,
|
|
2743
|
-
sourceInstanceId: sourceInstanceId
|
|
4688
|
+
sourceInstanceId: projectedSourceIdentity?.sourceInstanceId
|
|
4689
|
+
?? sourceInstanceId
|
|
4690
|
+
?? sanitized.sourceInstanceId,
|
|
2744
4691
|
});
|
|
2745
4692
|
}
|
|
2746
4693
|
function readJunctionSourceReference(record, sourceReferences) {
|
|
@@ -2838,17 +4785,39 @@ function isBlockedJunctionImportSourceIdentityContainerKey(key) {
|
|
|
2838
4785
|
|| normalized === "owner";
|
|
2839
4786
|
}
|
|
2840
4787
|
function dedupeJunctionTimeseriesRecords(resource, records) {
|
|
4788
|
+
const candidates = records.map((record) => ({
|
|
4789
|
+
contentKey: buildJunctionTimeseriesRecordContentKey(resource, record),
|
|
4790
|
+
key: buildJunctionTimeseriesRecordKey(resource, record),
|
|
4791
|
+
providerRowKey: buildJunctionTimeseriesProviderRowKey(resource, record),
|
|
4792
|
+
record,
|
|
4793
|
+
}));
|
|
4794
|
+
const contentKeysByProviderRow = new Map();
|
|
4795
|
+
for (const candidate of candidates) {
|
|
4796
|
+
if (!candidate.providerRowKey || !candidate.contentKey) {
|
|
4797
|
+
continue;
|
|
4798
|
+
}
|
|
4799
|
+
const contentKeys = contentKeysByProviderRow.get(candidate.providerRowKey)
|
|
4800
|
+
?? new Set();
|
|
4801
|
+
contentKeys.add(candidate.contentKey);
|
|
4802
|
+
contentKeysByProviderRow.set(candidate.providerRowKey, contentKeys);
|
|
4803
|
+
}
|
|
4804
|
+
const conflictingProviderRows = new Set([...contentKeysByProviderRow.entries()]
|
|
4805
|
+
.filter(([, contentKeys]) => contentKeys.size > 1)
|
|
4806
|
+
.map(([providerRowKey]) => providerRowKey));
|
|
2841
4807
|
const seen = new Set();
|
|
2842
4808
|
const deduped = [];
|
|
2843
|
-
for (const
|
|
2844
|
-
|
|
2845
|
-
|
|
4809
|
+
for (const candidate of candidates) {
|
|
4810
|
+
if (candidate.providerRowKey
|
|
4811
|
+
&& conflictingProviderRows.has(candidate.providerRowKey)) {
|
|
4812
|
+
continue;
|
|
4813
|
+
}
|
|
4814
|
+
if (candidate.key && seen.has(candidate.key)) {
|
|
2846
4815
|
continue;
|
|
2847
4816
|
}
|
|
2848
|
-
if (key) {
|
|
2849
|
-
seen.add(key);
|
|
4817
|
+
if (candidate.key) {
|
|
4818
|
+
seen.add(candidate.key);
|
|
2850
4819
|
}
|
|
2851
|
-
deduped.push(record);
|
|
4820
|
+
deduped.push(candidate.record);
|
|
2852
4821
|
}
|
|
2853
4822
|
return deduped;
|
|
2854
4823
|
}
|
|
@@ -2859,21 +4828,38 @@ function dedupeJunctionTimeseriesSnapshotRecords(snapshot) {
|
|
|
2859
4828
|
}
|
|
2860
4829
|
return deduped;
|
|
2861
4830
|
}
|
|
2862
|
-
function filterJunctionTimeseriesRecordsToWindow(records, windowStart, windowEnd) {
|
|
4831
|
+
function filterJunctionTimeseriesRecordsToWindow(resource, records, windowStart, windowEnd, dateQueryFormat) {
|
|
2863
4832
|
const startMs = Date.parse(windowStart);
|
|
2864
4833
|
const endMs = Date.parse(windowEnd);
|
|
2865
4834
|
if (!Number.isFinite(startMs) || !Number.isFinite(endMs) || startMs >= endMs) {
|
|
2866
4835
|
return [...records];
|
|
2867
4836
|
}
|
|
4837
|
+
const policy = resolveJunctionTimeseriesResourcePolicy(resource);
|
|
4838
|
+
const preferIntervalStart = usesJunctionTimeseriesIntervalStartOwnership(policy);
|
|
2868
4839
|
return records.filter((record) => {
|
|
2869
4840
|
const entry = readPlainObject(record);
|
|
2870
4841
|
if (!entry) {
|
|
2871
4842
|
return true;
|
|
2872
4843
|
}
|
|
2873
|
-
const
|
|
2874
|
-
if (!
|
|
4844
|
+
const rawTimestamp = resolveJunctionTimeseriesRecordRawTimestamp(entry, preferIntervalStart);
|
|
4845
|
+
if (!rawTimestamp) {
|
|
2875
4846
|
return true;
|
|
2876
4847
|
}
|
|
4848
|
+
if (dateQueryFormat === "date"
|
|
4849
|
+
&& policy?.normalizationMode === "daily_aggregate") {
|
|
4850
|
+
if (JUNCTION_CALENDAR_DAY_AGGREGATE_RESOURCE_SET.has(resource)
|
|
4851
|
+
|| resolveJunctionExtendedTimeseriesBackfillPolicy(resource)?.completion
|
|
4852
|
+
=== "daily_aggregate") {
|
|
4853
|
+
// Junction's date-mode response owns the provider calendar day. Keep
|
|
4854
|
+
// every interval together even when an explicit offset crosses UTC
|
|
4855
|
+
// midnight; the importer owns provider-local day resolution.
|
|
4856
|
+
return true;
|
|
4857
|
+
}
|
|
4858
|
+
if (isJunctionFloatingCalendarTimestamp(rawTimestamp)) {
|
|
4859
|
+
return rawTimestamp.slice(0, 10) === windowStart.slice(0, 10);
|
|
4860
|
+
}
|
|
4861
|
+
}
|
|
4862
|
+
const timestamp = toIsoTimestampIfValid(rawTimestamp) ?? rawTimestamp;
|
|
2877
4863
|
const recordedMs = Date.parse(timestamp);
|
|
2878
4864
|
if (!Number.isFinite(recordedMs)) {
|
|
2879
4865
|
return true;
|
|
@@ -2882,10 +4868,22 @@ function filterJunctionTimeseriesRecordsToWindow(records, windowStart, windowEnd
|
|
|
2882
4868
|
});
|
|
2883
4869
|
}
|
|
2884
4870
|
function buildJunctionTimeseriesRecordKey(resource, record) {
|
|
4871
|
+
const providerRowKey = buildJunctionTimeseriesProviderRowKey(resource, record);
|
|
4872
|
+
if (providerRowKey) {
|
|
4873
|
+
return providerRowKey;
|
|
4874
|
+
}
|
|
2885
4875
|
const entry = readPlainObject(record);
|
|
2886
4876
|
if (!entry) {
|
|
2887
4877
|
return null;
|
|
2888
4878
|
}
|
|
4879
|
+
if ((resource === "electrocardiogram_voltage" && entry.schema === JUNCTION_ECG_VOLTAGE_FEATURE_SCHEMA)
|
|
4880
|
+
|| (resource === "workout_stream" && entry.schema === JUNCTION_WORKOUT_STREAM_FEATURE_SCHEMA)) {
|
|
4881
|
+
return JSON.stringify([
|
|
4882
|
+
"junction-bounded-timeseries-feature",
|
|
4883
|
+
resource,
|
|
4884
|
+
buildJunctionBoundedFeatureIdentity(resource, entry),
|
|
4885
|
+
]);
|
|
4886
|
+
}
|
|
2889
4887
|
const origin = resolveJunctionOrigin(entry);
|
|
2890
4888
|
const sourceProviderSlug = normalizeProviderSlug(origin.sourceProviderSlug);
|
|
2891
4889
|
const timestamp = resolveJunctionTimeseriesRecordTimestamp(entry);
|
|
@@ -2902,26 +4900,237 @@ function buildJunctionTimeseriesRecordKey(resource, record) {
|
|
|
2902
4900
|
...junctionTimeseriesRecordValueIdentity(resource, entry),
|
|
2903
4901
|
]);
|
|
2904
4902
|
}
|
|
2905
|
-
|
|
2906
|
-
//
|
|
2907
|
-
//
|
|
2908
|
-
//
|
|
2909
|
-
|
|
2910
|
-
|
|
2911
|
-
|
|
4903
|
+
function buildJunctionTimeseriesProviderRowKey(resource, record) {
|
|
4904
|
+
// The bounded fidelity importer owns same-row revision arbitration for these
|
|
4905
|
+
// resources. Keep each distinct semantic body in transport so it can select
|
|
4906
|
+
// an explicit newer revision or reject an ambiguous provider conflict.
|
|
4907
|
+
if (JUNCTION_CALENDAR_DAY_AGGREGATE_RESOURCE_SET.has(resource)) {
|
|
4908
|
+
return null;
|
|
4909
|
+
}
|
|
4910
|
+
const entry = readPlainObject(record);
|
|
4911
|
+
if (!entry) {
|
|
4912
|
+
return null;
|
|
4913
|
+
}
|
|
4914
|
+
const providerRowId = readJunctionTimeseriesProviderRowId(resource, entry);
|
|
4915
|
+
if (!providerRowId) {
|
|
4916
|
+
return null;
|
|
4917
|
+
}
|
|
4918
|
+
const origin = resolveJunctionOrigin(entry);
|
|
4919
|
+
const sourceProviderSlug = normalizeProviderSlug(origin.sourceProviderSlug);
|
|
4920
|
+
if (!sourceProviderSlug) {
|
|
4921
|
+
return null;
|
|
4922
|
+
}
|
|
4923
|
+
return JSON.stringify([
|
|
4924
|
+
"junction-timeseries-provider-row",
|
|
4925
|
+
resource,
|
|
4926
|
+
sourceProviderSlug,
|
|
4927
|
+
normalizeString(origin.sourceType) ?? "",
|
|
4928
|
+
normalizeString(origin.sourceInstanceId) ?? "",
|
|
4929
|
+
providerRowId,
|
|
4930
|
+
]);
|
|
4931
|
+
}
|
|
4932
|
+
function buildJunctionTimeseriesRecordContentKey(resource, record) {
|
|
4933
|
+
const entry = readPlainObject(record);
|
|
4934
|
+
if (!entry) {
|
|
4935
|
+
return null;
|
|
4936
|
+
}
|
|
4937
|
+
return JSON.stringify([
|
|
4938
|
+
"junction-timeseries-content",
|
|
4939
|
+
resolveJunctionTimeseriesRecordTimestamp(entry) ?? "",
|
|
4940
|
+
normalizeString(entry.recordedAt ?? entry.recorded_at ?? entry.updatedAt ?? entry.updated_at)
|
|
4941
|
+
?? "",
|
|
4942
|
+
String(entry.timeZoneOffsetMinutes
|
|
4943
|
+
?? entry.time_zone_offset_minutes
|
|
4944
|
+
?? entry.timezoneOffsetMinutes
|
|
4945
|
+
?? entry.timezone_offset_minutes
|
|
4946
|
+
?? entry.timezone_offset
|
|
4947
|
+
?? entry.timezoneOffset
|
|
4948
|
+
?? ""),
|
|
4949
|
+
normalizeString(entry.timestampSemantics ?? entry.timestamp_semantics) ?? "",
|
|
4950
|
+
normalizeString(entry.originConfidence ?? entry.origin_confidence) ?? "",
|
|
4951
|
+
...junctionTimeseriesRecordValueIdentity(resource, entry, false),
|
|
4952
|
+
]);
|
|
4953
|
+
}
|
|
4954
|
+
function junctionTimeseriesRecordNeedsSemanticIdentity(resource) {
|
|
4955
|
+
const policy = resolveJunctionTimeseriesResourcePolicy(resource);
|
|
4956
|
+
return resource === "blood_pressure"
|
|
4957
|
+
|| resource === "note"
|
|
4958
|
+
|| JUNCTION_CALENDAR_DAY_AGGREGATE_RESOURCE_SET.has(resource)
|
|
4959
|
+
|| policy?.normalizationMode === "sparse_alert"
|
|
4960
|
+
|| policy?.normalizationMode === "sparse_intervention"
|
|
4961
|
+
|| policy?.normalizationMode === "sparse_observation"
|
|
4962
|
+
|| policy?.normalizationMode === "sparse_reading";
|
|
4963
|
+
}
|
|
4964
|
+
function readJunctionTimeseriesProviderRowId(resource, entry) {
|
|
4965
|
+
if (!junctionTimeseriesRecordNeedsSemanticIdentity(resource)) {
|
|
4966
|
+
return null;
|
|
2912
4967
|
}
|
|
2913
|
-
|
|
2914
|
-
|
|
2915
|
-
|
|
4968
|
+
const providerRowIdKeys = [
|
|
4969
|
+
"id",
|
|
4970
|
+
"resourceId",
|
|
4971
|
+
"resource_id",
|
|
4972
|
+
"externalId",
|
|
4973
|
+
"external_id",
|
|
4974
|
+
"providerId",
|
|
4975
|
+
"provider_id",
|
|
4976
|
+
...(JUNCTION_CALENDAR_DAY_AGGREGATE_RESOURCE_SET.has(resource)
|
|
4977
|
+
? ["recordId", "record_id", "sampleId", "sample_id"]
|
|
4978
|
+
: []),
|
|
4979
|
+
];
|
|
4980
|
+
for (const key of providerRowIdKeys) {
|
|
2916
4981
|
const rowId = normalizeString(entry[key]);
|
|
2917
4982
|
if (rowId) {
|
|
2918
|
-
return
|
|
4983
|
+
return rowId;
|
|
4984
|
+
}
|
|
4985
|
+
}
|
|
4986
|
+
return null;
|
|
4987
|
+
}
|
|
4988
|
+
// Sparse records without stable provider row ids retain their semantic tuple
|
|
4989
|
+
// identity so same-time rows remain distinct when their canonical bodies differ.
|
|
4990
|
+
function junctionTimeseriesRecordValueIdentity(resource, entry, includeProviderRowId = true) {
|
|
4991
|
+
if (!junctionTimeseriesRecordNeedsSemanticIdentity(resource)) {
|
|
4992
|
+
return [];
|
|
4993
|
+
}
|
|
4994
|
+
const providerRowId = readJunctionTimeseriesProviderRowId(resource, entry) ?? "";
|
|
4995
|
+
if (resource === "weight") {
|
|
4996
|
+
if (includeProviderRowId && providerRowId) {
|
|
4997
|
+
return [providerRowId];
|
|
4998
|
+
}
|
|
4999
|
+
const { weightKilograms } = resolveJunctionWeightProviderRecordIdentity(entry);
|
|
5000
|
+
return weightKilograms === undefined ? [] : [`kg:${weightKilograms}`];
|
|
5001
|
+
}
|
|
5002
|
+
if (resource === "note") {
|
|
5003
|
+
if (includeProviderRowId && providerRowId) {
|
|
5004
|
+
return [providerRowId];
|
|
2919
5005
|
}
|
|
5006
|
+
return [
|
|
5007
|
+
...(Array.isArray(entry.tags) ? entry.tags : [])
|
|
5008
|
+
.flatMap((tag) => {
|
|
5009
|
+
const normalized = normalizeString(tag);
|
|
5010
|
+
return normalized ? [normalized] : [];
|
|
5011
|
+
})
|
|
5012
|
+
.sort(),
|
|
5013
|
+
];
|
|
5014
|
+
}
|
|
5015
|
+
const fidelityPointResource = resource === "glucose"
|
|
5016
|
+
|| resource === "blood_oxygen"
|
|
5017
|
+
|| resource === "stress_level";
|
|
5018
|
+
const fidelityIntervalResource = resource === "caffeine"
|
|
5019
|
+
|| resource === "water"
|
|
5020
|
+
|| resource === "mindfulness_minutes";
|
|
5021
|
+
const rowId = includeProviderRowId ? providerRowId : "";
|
|
5022
|
+
const fidelitySourceRevision = String(entry.recordedAt
|
|
5023
|
+
?? entry.recorded_at
|
|
5024
|
+
?? entry.updatedAt
|
|
5025
|
+
?? entry.updated_at
|
|
5026
|
+
?? "");
|
|
5027
|
+
const timeZoneIdentity = [
|
|
5028
|
+
String(entry.timeZone ?? entry.timezone ?? entry.time_zone ?? ""),
|
|
5029
|
+
String(entry.timeZoneOffsetMinutes
|
|
5030
|
+
?? entry.time_zone_offset_minutes
|
|
5031
|
+
?? entry.timezoneOffsetMinutes
|
|
5032
|
+
?? entry.timezone_offset_minutes
|
|
5033
|
+
?? entry.utcOffsetMinutes
|
|
5034
|
+
?? entry.utc_offset_minutes
|
|
5035
|
+
?? ""),
|
|
5036
|
+
String(entry.timezone_offset
|
|
5037
|
+
?? entry.timezoneOffset
|
|
5038
|
+
?? entry.timeZoneOffset
|
|
5039
|
+
?? entry.time_zone_offset
|
|
5040
|
+
?? entry.timezoneOffsetSeconds
|
|
5041
|
+
?? entry.timezone_offset_seconds
|
|
5042
|
+
?? entry.timeZoneOffsetSeconds
|
|
5043
|
+
?? entry.time_zone_offset_seconds
|
|
5044
|
+
?? entry.utcOffsetSeconds
|
|
5045
|
+
?? entry.utc_offset_seconds
|
|
5046
|
+
?? ""),
|
|
5047
|
+
];
|
|
5048
|
+
const providerDayIdentity = [
|
|
5049
|
+
String(entry.calendarDate
|
|
5050
|
+
?? entry.calendar_date
|
|
5051
|
+
?? entry.localDate
|
|
5052
|
+
?? entry.local_date
|
|
5053
|
+
?? ""),
|
|
5054
|
+
String(entry.timestampSemantics ?? entry.timestamp_semantics ?? ""),
|
|
5055
|
+
];
|
|
5056
|
+
if (fidelityIntervalResource) {
|
|
5057
|
+
const intervalValue = resource === "mindfulness_minutes"
|
|
5058
|
+
? entry.value ?? entry.mindfulnessMinutes ?? entry.mindfulness_minutes
|
|
5059
|
+
: resource === "caffeine"
|
|
5060
|
+
? entry.value ?? entry.caffeine
|
|
5061
|
+
: entry.value ?? entry.water;
|
|
5062
|
+
return [
|
|
5063
|
+
rowId,
|
|
5064
|
+
String(entry.start ?? entry.startAt ?? entry.start_at ?? entry.timeStart ?? entry.time_start ?? ""),
|
|
5065
|
+
String(entry.end ?? entry.endAt ?? entry.end_at ?? entry.timeEnd ?? entry.time_end ?? ""),
|
|
5066
|
+
String(entry.unit ?? entry.valueUnit ?? entry.value_unit ?? ""),
|
|
5067
|
+
String(intervalValue ?? ""),
|
|
5068
|
+
...providerDayIdentity,
|
|
5069
|
+
...timeZoneIdentity,
|
|
5070
|
+
fidelitySourceRevision,
|
|
5071
|
+
];
|
|
5072
|
+
}
|
|
5073
|
+
if (fidelityPointResource) {
|
|
5074
|
+
return [
|
|
5075
|
+
rowId,
|
|
5076
|
+
String(entry.observedAt
|
|
5077
|
+
?? entry.observed_at
|
|
5078
|
+
?? entry.observed_at_utc
|
|
5079
|
+
?? entry.timestamp
|
|
5080
|
+
?? entry.time
|
|
5081
|
+
?? entry.date
|
|
5082
|
+
?? entry.day
|
|
5083
|
+
?? ""),
|
|
5084
|
+
String(entry.value ?? (resource === "glucose"
|
|
5085
|
+
? entry.glucose ?? entry.bloodGlucose ?? entry.blood_glucose
|
|
5086
|
+
: resource === "blood_oxygen"
|
|
5087
|
+
? entry.spo2
|
|
5088
|
+
?? entry.spO2
|
|
5089
|
+
?? entry.bloodOxygen
|
|
5090
|
+
?? entry.blood_oxygen
|
|
5091
|
+
?? entry.oxygenSaturation
|
|
5092
|
+
?? entry.oxygen_saturation
|
|
5093
|
+
: entry.stressLevel
|
|
5094
|
+
?? entry.stress_level
|
|
5095
|
+
?? entry.averageStressLevel
|
|
5096
|
+
?? entry.average_stress_level
|
|
5097
|
+
?? readPlainObject(entry.stress)?.average
|
|
5098
|
+
?? entry.stressLevelValue
|
|
5099
|
+
?? entry.stress_level_value
|
|
5100
|
+
?? entry.score) ?? ""),
|
|
5101
|
+
String(entry.unit ?? entry.valueUnit ?? entry.value_unit ?? ""),
|
|
5102
|
+
...providerDayIdentity,
|
|
5103
|
+
...timeZoneIdentity,
|
|
5104
|
+
fidelitySourceRevision,
|
|
5105
|
+
];
|
|
2920
5106
|
}
|
|
2921
|
-
|
|
2922
|
-
|
|
5107
|
+
if (resource === "blood_pressure") {
|
|
5108
|
+
return includeProviderRowId && providerRowId
|
|
5109
|
+
? [providerRowId]
|
|
5110
|
+
: [String(entry.systolic ?? ""), String(entry.diastolic ?? "")];
|
|
5111
|
+
}
|
|
5112
|
+
return [
|
|
5113
|
+
...(includeProviderRowId ? [providerRowId] : []),
|
|
5114
|
+
String(entry.start ?? ""),
|
|
5115
|
+
String(entry.end ?? ""),
|
|
5116
|
+
String(entry.value ?? ""),
|
|
5117
|
+
String(entry.unit ?? ""),
|
|
5118
|
+
String(entry.type ?? ""),
|
|
5119
|
+
String(entry.bolus_purpose ?? entry.bolusPurpose ?? ""),
|
|
5120
|
+
String(entry.delivery_form ?? entry.deliveryForm ?? ""),
|
|
5121
|
+
String(entry.delivery_mode ?? entry.deliveryMode ?? ""),
|
|
5122
|
+
];
|
|
5123
|
+
}
|
|
5124
|
+
function resolveJunctionTimeseriesRecordTimestamp(record, preferIntervalStart = false) {
|
|
5125
|
+
const rawTimestamp = resolveJunctionTimeseriesRecordRawTimestamp(record, preferIntervalStart);
|
|
5126
|
+
return rawTimestamp
|
|
5127
|
+
? toIsoTimestampIfValid(rawTimestamp) ?? rawTimestamp
|
|
5128
|
+
: null;
|
|
2923
5129
|
}
|
|
2924
|
-
function
|
|
5130
|
+
function resolveJunctionTimeseriesRecordRawTimestamp(record, preferIntervalStart = false) {
|
|
5131
|
+
const intervalKeys = preferIntervalStart
|
|
5132
|
+
? ["sessionStart", "session_start", "timeStart", "time_start", "start", "startAt", "start_at", "sessionEnd", "session_end", "timeEnd", "time_end", "end", "endAt", "end_at"]
|
|
5133
|
+
: ["sessionEnd", "session_end", "timeEnd", "time_end", "end", "endAt", "end_at", "sessionStart", "session_start", "timeStart", "time_start", "start", "startAt", "start_at"];
|
|
2925
5134
|
for (const key of [
|
|
2926
5135
|
"observedAt",
|
|
2927
5136
|
"observed_at",
|
|
@@ -2930,21 +5139,26 @@ function resolveJunctionTimeseriesRecordTimestamp(record) {
|
|
|
2930
5139
|
"time",
|
|
2931
5140
|
"date",
|
|
2932
5141
|
"day",
|
|
2933
|
-
|
|
2934
|
-
"endAt",
|
|
2935
|
-
"end_at",
|
|
2936
|
-
"start",
|
|
2937
|
-
"startAt",
|
|
2938
|
-
"start_at",
|
|
5142
|
+
...intervalKeys,
|
|
2939
5143
|
]) {
|
|
2940
|
-
const
|
|
5144
|
+
const value = record[key];
|
|
5145
|
+
const normalized = value instanceof Date
|
|
5146
|
+
? Number.isFinite(value.getTime()) ? value.toISOString() : null
|
|
5147
|
+
: normalizeString(value);
|
|
2941
5148
|
if (!normalized) {
|
|
2942
5149
|
continue;
|
|
2943
5150
|
}
|
|
2944
|
-
return
|
|
5151
|
+
return normalized;
|
|
2945
5152
|
}
|
|
2946
5153
|
return null;
|
|
2947
5154
|
}
|
|
5155
|
+
function isJunctionFloatingCalendarTimestamp(value) {
|
|
5156
|
+
const normalized = value.trim();
|
|
5157
|
+
if (/z$/iu.test(normalized) || /[+-]\d{2}:?\d{2}$/u.test(normalized)) {
|
|
5158
|
+
return false;
|
|
5159
|
+
}
|
|
5160
|
+
return /^\d{4}-\d{2}-\d{2}(?:$|[ t]\d{2}:\d{2})/iu.test(normalized);
|
|
5161
|
+
}
|
|
2948
5162
|
function buildJunctionRedirectUrl(callbackUrl, state) {
|
|
2949
5163
|
const url = new URL(callbackUrl);
|
|
2950
5164
|
url.searchParams.set("murph_state", state);
|
|
@@ -3016,6 +5230,115 @@ function resolveJobWindow(job, now, fallbackDays) {
|
|
|
3016
5230
|
windowEnd,
|
|
3017
5231
|
};
|
|
3018
5232
|
}
|
|
5233
|
+
function readFullJobTimeseriesCursor(job, ownerWindow) {
|
|
5234
|
+
const cursor = toIsoTimestampIfValid(job.payload.timeseriesCursor);
|
|
5235
|
+
return cursor && isTimestampInHalfOpenWindow(cursor, ownerWindow)
|
|
5236
|
+
? cursor
|
|
5237
|
+
: null;
|
|
5238
|
+
}
|
|
5239
|
+
function readFullJobTimeseriesWindowHours(job) {
|
|
5240
|
+
if (job.payload.timeseriesWindowHours === undefined) {
|
|
5241
|
+
return 24;
|
|
5242
|
+
}
|
|
5243
|
+
if (job.payload.timeseriesWindowHours !== 1) {
|
|
5244
|
+
throw invalidJunctionTimeseriesResourceProgress();
|
|
5245
|
+
}
|
|
5246
|
+
return 1;
|
|
5247
|
+
}
|
|
5248
|
+
function readFullJobTimeseriesResourceCursor(job, resources) {
|
|
5249
|
+
const configuredResource = normalizeFullJobTimeseriesResourceCursor(job.payload.timeseriesResourceCursor, resources);
|
|
5250
|
+
if (configuredResource) {
|
|
5251
|
+
return {
|
|
5252
|
+
resource: configuredResource,
|
|
5253
|
+
restartFromWindowStart: false,
|
|
5254
|
+
};
|
|
5255
|
+
}
|
|
5256
|
+
const previouslyConfiguredResource = normalizeFullJobTimeseriesResourceCursor(job.payload.timeseriesResourceCursor, JUNCTION_ALLOWED_TIMESERIES_RESOURCES);
|
|
5257
|
+
const firstConfiguredResource = resources[0];
|
|
5258
|
+
return previouslyConfiguredResource && firstConfiguredResource
|
|
5259
|
+
? {
|
|
5260
|
+
resource: firstConfiguredResource,
|
|
5261
|
+
restartFromWindowStart: true,
|
|
5262
|
+
}
|
|
5263
|
+
: null;
|
|
5264
|
+
}
|
|
5265
|
+
function normalizeFullJobTimeseriesResourceCursor(value, resources) {
|
|
5266
|
+
const cursor = normalizeJunctionResourceName(value);
|
|
5267
|
+
if (cursor && resources.includes(cursor)) {
|
|
5268
|
+
return cursor;
|
|
5269
|
+
}
|
|
5270
|
+
if (typeof value !== "string") {
|
|
5271
|
+
return null;
|
|
5272
|
+
}
|
|
5273
|
+
let parsedValue;
|
|
5274
|
+
try {
|
|
5275
|
+
parsedValue = JSON.parse(value);
|
|
5276
|
+
}
|
|
5277
|
+
catch {
|
|
5278
|
+
return null;
|
|
5279
|
+
}
|
|
5280
|
+
const parsed = readPlainObject(parsedValue);
|
|
5281
|
+
const activeResource = normalizeJunctionResourceName(parsed?.a);
|
|
5282
|
+
const completedResources = parsed?.i;
|
|
5283
|
+
if (!parsed
|
|
5284
|
+
|| parsed.v !== JUNCTION_DEPLOYED_FULL_JOB_PROGRESS_VERSION
|
|
5285
|
+
|| Object.keys(parsed).some((key) => key !== "a" && key !== "i" && key !== "v")
|
|
5286
|
+
|| !activeResource
|
|
5287
|
+
|| !resources.includes(activeResource)
|
|
5288
|
+
|| !Array.isArray(completedResources)
|
|
5289
|
+
|| completedResources.length > JUNCTION_ALLOWED_TIMESERIES_RESOURCES.length
|
|
5290
|
+
|| !completedResources.every((resource) => normalizeJunctionResourceName(resource) === resource
|
|
5291
|
+
&& JUNCTION_ALLOWED_TIMESERIES_RESOURCE_SET.has(resource))) {
|
|
5292
|
+
return null;
|
|
5293
|
+
}
|
|
5294
|
+
const sortedCompletedResources = [...completedResources].sort();
|
|
5295
|
+
if (new Set(sortedCompletedResources).size !== sortedCompletedResources.length
|
|
5296
|
+
|| sortedCompletedResources.includes(activeResource)
|
|
5297
|
+
|| JSON.stringify({
|
|
5298
|
+
v: JUNCTION_DEPLOYED_FULL_JOB_PROGRESS_VERSION,
|
|
5299
|
+
a: activeResource,
|
|
5300
|
+
i: sortedCompletedResources,
|
|
5301
|
+
}) !== value) {
|
|
5302
|
+
return null;
|
|
5303
|
+
}
|
|
5304
|
+
return activeResource;
|
|
5305
|
+
}
|
|
5306
|
+
function isFullJobTimeseriesContinuation(job) {
|
|
5307
|
+
return (job.kind === "backfill" || job.kind === "reconcile")
|
|
5308
|
+
&& Object.prototype.hasOwnProperty.call(job.payload, "timeseriesResourceCursor");
|
|
5309
|
+
}
|
|
5310
|
+
function isJunctionTimeseriesWindowTooLarge(error) {
|
|
5311
|
+
return isDeviceSyncError(error)
|
|
5312
|
+
&& error.code === "JUNCTION_API_WINDOW_TOO_LARGE";
|
|
5313
|
+
}
|
|
5314
|
+
function resolveNextFullJobTimeseriesContinuation(input) {
|
|
5315
|
+
if (Date.parse(input.executionWindowEnd) < Date.parse(input.windowEnd)) {
|
|
5316
|
+
return {
|
|
5317
|
+
timeseriesCursor: input.executionWindowEnd,
|
|
5318
|
+
timeseriesResourceCursor: input.resource,
|
|
5319
|
+
timeseriesWindowHours: input.timeseriesWindowHours,
|
|
5320
|
+
workoutStreamCursor: null,
|
|
5321
|
+
};
|
|
5322
|
+
}
|
|
5323
|
+
const nextResource = input.resources[input.resources.indexOf(input.resource) + 1] ?? null;
|
|
5324
|
+
return nextResource
|
|
5325
|
+
? {
|
|
5326
|
+
timeseriesCursor: input.baseTimeseriesWindowStart,
|
|
5327
|
+
timeseriesResourceCursor: nextResource,
|
|
5328
|
+
timeseriesWindowHours: 24,
|
|
5329
|
+
workoutStreamCursor: null,
|
|
5330
|
+
}
|
|
5331
|
+
: null;
|
|
5332
|
+
}
|
|
5333
|
+
function readDeferredEmptyBackfillAttempts(followUp) {
|
|
5334
|
+
for (const job of followUp.scheduledJobs ?? []) {
|
|
5335
|
+
const attempts = job.payload?.emptyBackfillAttempts;
|
|
5336
|
+
if (typeof attempts === "number" && Number.isSafeInteger(attempts) && attempts > 0) {
|
|
5337
|
+
return attempts;
|
|
5338
|
+
}
|
|
5339
|
+
}
|
|
5340
|
+
return 0;
|
|
5341
|
+
}
|
|
3019
5342
|
function readBackfillTimeseriesCursor(job, ownerWindow) {
|
|
3020
5343
|
const cursor = toIsoTimestampIfValid(job.payload.timeseriesCursor);
|
|
3021
5344
|
return cursor && isTimestampInHalfOpenWindow(cursor, ownerWindow)
|
|
@@ -3059,6 +5382,19 @@ function shouldImportClosedTimeseriesForReconcile(lastSyncCompletedAt, windowEnd
|
|
|
3059
5382
|
|| !Number.isFinite(windowEndMs)
|
|
3060
5383
|
|| lastCompletedClosedDayMs < windowEndMs;
|
|
3061
5384
|
}
|
|
5385
|
+
function resolveLatestGloballyClosedProviderDayWindow(windowStart, windowEnd, asOf) {
|
|
5386
|
+
const flooredWindowStartMs = Date.parse(floorUtcDayTimestamp(windowStart));
|
|
5387
|
+
const globallyClosedEndMs = resolveGloballyClosedProviderDayEnd(windowEnd, asOf);
|
|
5388
|
+
if (!Number.isFinite(flooredWindowStartMs)
|
|
5389
|
+
|| !Number.isFinite(globallyClosedEndMs)
|
|
5390
|
+
|| flooredWindowStartMs >= globallyClosedEndMs) {
|
|
5391
|
+
return null;
|
|
5392
|
+
}
|
|
5393
|
+
return {
|
|
5394
|
+
windowStart: new Date(globallyClosedEndMs - TIMESERIES_CHUNK_MS).toISOString(),
|
|
5395
|
+
windowEnd: new Date(globallyClosedEndMs).toISOString(),
|
|
5396
|
+
};
|
|
5397
|
+
}
|
|
3062
5398
|
function buildClosedDailyWindows(windowStart, windowEnd) {
|
|
3063
5399
|
const startMs = Date.parse(windowStart);
|
|
3064
5400
|
const endMs = Date.parse(windowEnd);
|
|
@@ -3086,7 +5422,16 @@ function buildClosedDailyWindows(windowStart, windowEnd) {
|
|
|
3086
5422
|
}
|
|
3087
5423
|
return windows;
|
|
3088
5424
|
}
|
|
3089
|
-
function
|
|
5425
|
+
function resolveGloballyClosedProviderDayEnd(windowEnd, asOf) {
|
|
5426
|
+
const requestedClosedEndMs = Date.parse(floorUtcDayTimestamp(windowEnd));
|
|
5427
|
+
const asOfMs = Date.parse(asOf);
|
|
5428
|
+
if (!Number.isFinite(requestedClosedEndMs) || !Number.isFinite(asOfMs)) {
|
|
5429
|
+
return Number.NaN;
|
|
5430
|
+
}
|
|
5431
|
+
const globallyClosedEndMs = Date.parse(floorUtcDayTimestamp(new Date(asOfMs - JUNCTION_PROVIDER_CALENDAR_DAY_CLOSE_LAG_MS).toISOString()));
|
|
5432
|
+
return Math.min(requestedClosedEndMs, globallyClosedEndMs);
|
|
5433
|
+
}
|
|
5434
|
+
function buildPreciseTimeseriesWindows(windowStart, windowEnd, chunkMs = TIMESERIES_CHUNK_MS) {
|
|
3090
5435
|
const startMs = Date.parse(windowStart);
|
|
3091
5436
|
const endMs = Date.parse(windowEnd);
|
|
3092
5437
|
if (!Number.isFinite(startMs) || !Number.isFinite(endMs) || startMs >= endMs) {
|
|
@@ -3095,7 +5440,7 @@ function buildPreciseTimeseriesWindows(windowStart, windowEnd) {
|
|
|
3095
5440
|
const windows = [];
|
|
3096
5441
|
let chunkStartMs = startMs;
|
|
3097
5442
|
while (chunkStartMs < endMs) {
|
|
3098
|
-
const chunkEndMs = Math.min(chunkStartMs +
|
|
5443
|
+
const chunkEndMs = Math.min(chunkStartMs + chunkMs, endMs);
|
|
3099
5444
|
if (chunkEndMs <= chunkStartMs) {
|
|
3100
5445
|
break;
|
|
3101
5446
|
}
|
|
@@ -3107,6 +5452,16 @@ function buildPreciseTimeseriesWindows(windowStart, windowEnd) {
|
|
|
3107
5452
|
}
|
|
3108
5453
|
return windows;
|
|
3109
5454
|
}
|
|
5455
|
+
function resolveJunctionTimeseriesFetchChunkMs(resource) {
|
|
5456
|
+
const fetchChunkDays = resolveJunctionTimeseriesResourcePolicy(resource)?.fetchChunkDays ?? 1;
|
|
5457
|
+
return Math.max(1, fetchChunkDays) * TIMESERIES_CHUNK_MS;
|
|
5458
|
+
}
|
|
5459
|
+
function resolveJunctionTimeseriesImportChunkMs(resources) {
|
|
5460
|
+
if (resources.length === 0) {
|
|
5461
|
+
return TIMESERIES_CHUNK_MS;
|
|
5462
|
+
}
|
|
5463
|
+
return resources.reduce((smallest, resource) => Math.min(smallest, resolveJunctionTimeseriesFetchChunkMs(resource)), Number.POSITIVE_INFINITY);
|
|
5464
|
+
}
|
|
3110
5465
|
function floorUtcDayTimestamp(timestamp) {
|
|
3111
5466
|
const parsed = Date.parse(timestamp);
|
|
3112
5467
|
if (!Number.isFinite(parsed)) {
|
|
@@ -3118,9 +5473,39 @@ function floorUtcDayTimestamp(timestamp) {
|
|
|
3118
5473
|
function hasJunctionSnapshotRecords(snapshot) {
|
|
3119
5474
|
return Object.values(snapshot).some((records) => records.length > 0);
|
|
3120
5475
|
}
|
|
5476
|
+
function countJunctionSnapshotRecords(snapshot) {
|
|
5477
|
+
return Object.values(snapshot).reduce((recordCount, records) => recordCount + records.length, 0);
|
|
5478
|
+
}
|
|
3121
5479
|
function hasJunctionHistoricalBackfillSummaryRecords(evidence) {
|
|
3122
5480
|
return evidence.some(({ resource }) => isJunctionHistoricalBackfillCompletionSummaryResource(resource));
|
|
3123
5481
|
}
|
|
5482
|
+
function resolveJunctionHistoricalPullReadiness(input) {
|
|
5483
|
+
const sourceProviderSlug = canonicalizeJunctionHistoricalProviderSlug(input.sourceProviderSlug)
|
|
5484
|
+
?? normalizeProviderSlug(input.sourceProviderSlug);
|
|
5485
|
+
if (!sourceProviderSlug || !input.snapshot?.matchedUser) {
|
|
5486
|
+
return "unavailable";
|
|
5487
|
+
}
|
|
5488
|
+
const source = input.snapshot.sources.find((entry) => (canonicalizeJunctionHistoricalProviderSlug(entry.sourceProviderSlug)
|
|
5489
|
+
?? normalizeProviderSlug(entry.sourceProviderSlug)) === sourceProviderSlug);
|
|
5490
|
+
if (!source) {
|
|
5491
|
+
return "unavailable";
|
|
5492
|
+
}
|
|
5493
|
+
const pulled = source.pulledResources.find((entry) => normalizeJunctionResourceName(entry.resource) === input.resource);
|
|
5494
|
+
if (pulled) {
|
|
5495
|
+
if (pulled.status === "success") {
|
|
5496
|
+
return "ready";
|
|
5497
|
+
}
|
|
5498
|
+
if (pulled.status === "failure") {
|
|
5499
|
+
return "terminal_failure";
|
|
5500
|
+
}
|
|
5501
|
+
return ["in_progress", "retrying", "scheduled"].includes(pulled.status)
|
|
5502
|
+
? "pending"
|
|
5503
|
+
: "unavailable";
|
|
5504
|
+
}
|
|
5505
|
+
return source.notPulledResources.some((resource) => normalizeJunctionResourceName(resource) === input.resource)
|
|
5506
|
+
? "no_obligation"
|
|
5507
|
+
: "unavailable";
|
|
5508
|
+
}
|
|
3124
5509
|
function evaluateJunctionHistoricalBackfillCoverage(summaryEvidence, sourceProviders, configuredSummaryResources, providerFilter, historicalPullSnapshot, historicalPushEvidence, window) {
|
|
3125
5510
|
const configuredResources = new Set(configuredSummaryResources.filter((resource) => JUNCTION_HISTORICAL_BACKFILL_REQUIRED_SUMMARY_RESOURCE_SET.has(resource)));
|
|
3126
5511
|
const advertisedResourcesByProvider = new Map();
|
|
@@ -3273,6 +5658,22 @@ function isJunctionResourceAdvertisedAvailable(value) {
|
|
|
3273
5658
|
return record.available === true
|
|
3274
5659
|
|| normalizeString(record.status)?.toLowerCase() === "available";
|
|
3275
5660
|
}
|
|
5661
|
+
function isJunctionResourceAvailableInSummary(availabilitySummary, resource) {
|
|
5662
|
+
const normalizedResource = normalizeJunctionResourceName(resource);
|
|
5663
|
+
if (!normalizedResource || !availabilitySummary) {
|
|
5664
|
+
return false;
|
|
5665
|
+
}
|
|
5666
|
+
return Object.entries(availabilitySummary).some(([candidate, availability]) => normalizeJunctionResourceName(candidate) === normalizedResource
|
|
5667
|
+
&& isJunctionResourceAdvertisedAvailable(availability));
|
|
5668
|
+
}
|
|
5669
|
+
function isJunctionSourceResourceCurrentlyAvailable(input) {
|
|
5670
|
+
if (!input.sourceProviderSlug) {
|
|
5671
|
+
return false;
|
|
5672
|
+
}
|
|
5673
|
+
return projectJunctionSourcesByProviderSlug(input.connectionId, input.providers).some((source) => source.sourceProviderSlug === input.sourceProviderSlug
|
|
5674
|
+
&& source.status === "connected"
|
|
5675
|
+
&& isJunctionResourceAvailableInSummary(source.resourceAvailabilitySummary, input.resource));
|
|
5676
|
+
}
|
|
3276
5677
|
function isJunctionHistoricalBackfillCompletionSummaryResource(resource) {
|
|
3277
5678
|
return JUNCTION_HISTORICAL_BACKFILL_COMPLETION_SUMMARY_RESOURCE_SET.has(resource);
|
|
3278
5679
|
}
|
|
@@ -3416,6 +5817,155 @@ function readHistoricalBackfillJobEmptyAttempts(job) {
|
|
|
3416
5817
|
const rawAttempts = job.payload.emptyBackfillAttempts;
|
|
3417
5818
|
return typeof rawAttempts === "number" && Number.isInteger(rawAttempts) && rawAttempts > 0 ? rawAttempts : 0;
|
|
3418
5819
|
}
|
|
5820
|
+
function readJunctionWorkoutStreamCompletedIdentities(job) {
|
|
5821
|
+
const encoded = job.payload.workoutStreamCursor;
|
|
5822
|
+
if (encoded === undefined) {
|
|
5823
|
+
return new Set();
|
|
5824
|
+
}
|
|
5825
|
+
const maxWorkouts = resolveJunctionTimeseriesResourcePolicy("workout_stream")
|
|
5826
|
+
?.maxRecordsPerWindow;
|
|
5827
|
+
if (!maxWorkouts || typeof encoded !== "string" || encoded.length === 0) {
|
|
5828
|
+
throw invalidJunctionWorkoutStreamProgress();
|
|
5829
|
+
}
|
|
5830
|
+
let parsedValue;
|
|
5831
|
+
try {
|
|
5832
|
+
parsedValue = JSON.parse(encoded);
|
|
5833
|
+
}
|
|
5834
|
+
catch {
|
|
5835
|
+
throw invalidJunctionWorkoutStreamProgress();
|
|
5836
|
+
}
|
|
5837
|
+
const parsed = readPlainObject(parsedValue);
|
|
5838
|
+
const identities = parsed?.i;
|
|
5839
|
+
if (!parsed
|
|
5840
|
+
|| parsed.v !== JUNCTION_WORKOUT_STREAM_PROGRESS_VERSION
|
|
5841
|
+
|| Object.keys(parsed).some((key) => key !== "i" && key !== "v")
|
|
5842
|
+
|| !Array.isArray(identities)
|
|
5843
|
+
|| identities.length === 0
|
|
5844
|
+
|| identities.length > maxWorkouts
|
|
5845
|
+
|| !identities.every(isCanonicalJunctionWorkoutStreamCandidateIdentity)) {
|
|
5846
|
+
throw invalidJunctionWorkoutStreamProgress();
|
|
5847
|
+
}
|
|
5848
|
+
const sortedIdentities = [...identities].sort();
|
|
5849
|
+
if (new Set(sortedIdentities).size !== sortedIdentities.length
|
|
5850
|
+
|| JSON.stringify({ v: JUNCTION_WORKOUT_STREAM_PROGRESS_VERSION, i: sortedIdentities })
|
|
5851
|
+
!== encoded) {
|
|
5852
|
+
throw invalidJunctionWorkoutStreamProgress();
|
|
5853
|
+
}
|
|
5854
|
+
return new Set(sortedIdentities);
|
|
5855
|
+
}
|
|
5856
|
+
function encodeJunctionWorkoutStreamCompletedIdentities(identities) {
|
|
5857
|
+
if (identities.size === 0) {
|
|
5858
|
+
return null;
|
|
5859
|
+
}
|
|
5860
|
+
const maxWorkouts = resolveJunctionTimeseriesResourcePolicy("workout_stream")
|
|
5861
|
+
?.maxRecordsPerWindow;
|
|
5862
|
+
const sortedIdentities = [...identities].sort();
|
|
5863
|
+
if (!maxWorkouts
|
|
5864
|
+
|| sortedIdentities.length > maxWorkouts
|
|
5865
|
+
|| !sortedIdentities.every(isCanonicalJunctionWorkoutStreamCandidateIdentity)) {
|
|
5866
|
+
throw new TypeError("Junction workout stream progress exceeded its identity contract.");
|
|
5867
|
+
}
|
|
5868
|
+
return JSON.stringify({
|
|
5869
|
+
v: JUNCTION_WORKOUT_STREAM_PROGRESS_VERSION,
|
|
5870
|
+
i: sortedIdentities,
|
|
5871
|
+
});
|
|
5872
|
+
}
|
|
5873
|
+
function isCanonicalJunctionWorkoutStreamCandidateIdentity(value) {
|
|
5874
|
+
if (typeof value !== "string" || value.length === 0) {
|
|
5875
|
+
return false;
|
|
5876
|
+
}
|
|
5877
|
+
let identity;
|
|
5878
|
+
try {
|
|
5879
|
+
identity = JSON.parse(value);
|
|
5880
|
+
}
|
|
5881
|
+
catch {
|
|
5882
|
+
return false;
|
|
5883
|
+
}
|
|
5884
|
+
if (!Array.isArray(identity) || identity.length !== 4) {
|
|
5885
|
+
return false;
|
|
5886
|
+
}
|
|
5887
|
+
const [sourceProviderSlug, sourceType, sourceInstanceId, stableId] = identity;
|
|
5888
|
+
return isNonEmptyCanonicalIdentityPart(sourceProviderSlug)
|
|
5889
|
+
&& (sourceType === null || isNonEmptyCanonicalIdentityPart(sourceType))
|
|
5890
|
+
&& (sourceInstanceId === null || isNonEmptyCanonicalIdentityPart(sourceInstanceId))
|
|
5891
|
+
&& isNonEmptyCanonicalIdentityPart(stableId)
|
|
5892
|
+
&& JSON.stringify(identity) === value;
|
|
5893
|
+
}
|
|
5894
|
+
function isNonEmptyCanonicalIdentityPart(value) {
|
|
5895
|
+
return typeof value === "string" && value.length > 0 && value.trim() === value;
|
|
5896
|
+
}
|
|
5897
|
+
function invalidJunctionTimeseriesResourceProgress() {
|
|
5898
|
+
return deviceSyncError({
|
|
5899
|
+
code: "DEVICE_SYNC_JOB_PAYLOAD_INVALID",
|
|
5900
|
+
message: "Junction timeseries resource continuation metadata was invalid.",
|
|
5901
|
+
retryable: false,
|
|
5902
|
+
});
|
|
5903
|
+
}
|
|
5904
|
+
function invalidJunctionWorkoutStreamProgress() {
|
|
5905
|
+
return deviceSyncError({
|
|
5906
|
+
code: "DEVICE_SYNC_JOB_PAYLOAD_INVALID",
|
|
5907
|
+
message: "Junction workout stream continuation metadata was invalid.",
|
|
5908
|
+
retryable: false,
|
|
5909
|
+
});
|
|
5910
|
+
}
|
|
5911
|
+
function readJunctionHistoricalUnresolvedProviderRecords(job) {
|
|
5912
|
+
const encoded = job.payload.historicalUnresolvedProviderRecordIdentitiesJson;
|
|
5913
|
+
if (typeof encoded === "string") {
|
|
5914
|
+
try {
|
|
5915
|
+
const parsed = readPlainObject(JSON.parse(encoded));
|
|
5916
|
+
const rawIdentities = parsed?.i;
|
|
5917
|
+
const version = parsed?.v;
|
|
5918
|
+
if (version !== JUNCTION_HISTORICAL_UNRESOLVED_PROVIDER_RECORD_IDENTITIES_VERSION
|
|
5919
|
+
|| !Array.isArray(rawIdentities)) {
|
|
5920
|
+
return { identities: [], withoutStableIdentity: true };
|
|
5921
|
+
}
|
|
5922
|
+
const validIdentities = rawIdentities.filter((identity) => typeof identity === "string"
|
|
5923
|
+
&& JUNCTION_BLOOD_PRESSURE_PROVIDER_RECORD_IDENTITY_PATTERN.test(identity));
|
|
5924
|
+
const identities = [...new Set(validIdentities)].sort();
|
|
5925
|
+
return {
|
|
5926
|
+
identities,
|
|
5927
|
+
withoutStableIdentity: parsed?.u === true
|
|
5928
|
+
|| validIdentities.length !== rawIdentities.length,
|
|
5929
|
+
};
|
|
5930
|
+
}
|
|
5931
|
+
catch {
|
|
5932
|
+
return { identities: [], withoutStableIdentity: true };
|
|
5933
|
+
}
|
|
5934
|
+
}
|
|
5935
|
+
const legacyUnresolvedEvidence = job.payload.historicalProviderRecordsSeen === true
|
|
5936
|
+
|| (typeof job.payload.historicalUnresolvedProviderRecordCount === "number"
|
|
5937
|
+
&& Number.isSafeInteger(job.payload.historicalUnresolvedProviderRecordCount)
|
|
5938
|
+
&& job.payload.historicalUnresolvedProviderRecordCount > 0);
|
|
5939
|
+
return {
|
|
5940
|
+
identities: [],
|
|
5941
|
+
withoutStableIdentity: legacyUnresolvedEvidence,
|
|
5942
|
+
};
|
|
5943
|
+
}
|
|
5944
|
+
function resolveJunctionHistoricalUnresolvedProviderRecords(job, importResult) {
|
|
5945
|
+
const carried = readJunctionHistoricalUnresolvedProviderRecords(job);
|
|
5946
|
+
const identities = new Set(carried.identities);
|
|
5947
|
+
for (const identity of importResult.canonicalProviderRecordIdentities) {
|
|
5948
|
+
identities.delete(identity);
|
|
5949
|
+
}
|
|
5950
|
+
for (const identity of importResult.unresolvedProviderRecordIdentities) {
|
|
5951
|
+
identities.add(identity);
|
|
5952
|
+
}
|
|
5953
|
+
return {
|
|
5954
|
+
identities: [...identities].sort(),
|
|
5955
|
+
withoutStableIdentity: carried.withoutStableIdentity
|
|
5956
|
+
|| importResult.unresolvedProviderRecordsWithoutStableIdentity,
|
|
5957
|
+
};
|
|
5958
|
+
}
|
|
5959
|
+
function countJunctionHistoricalUnresolvedProviderRecords(unresolved) {
|
|
5960
|
+
return unresolved.identities.length + (unresolved.withoutStableIdentity ? 1 : 0);
|
|
5961
|
+
}
|
|
5962
|
+
function encodeJunctionHistoricalUnresolvedProviderRecords(unresolved) {
|
|
5963
|
+
return JSON.stringify({
|
|
5964
|
+
v: JUNCTION_HISTORICAL_UNRESOLVED_PROVIDER_RECORD_IDENTITIES_VERSION,
|
|
5965
|
+
i: unresolved.identities,
|
|
5966
|
+
...(unresolved.withoutStableIdentity ? { u: true } : {}),
|
|
5967
|
+
});
|
|
5968
|
+
}
|
|
3419
5969
|
function buildConnectHistoricalBackfillWindow(account, summaryBackfillDays) {
|
|
3420
5970
|
return {
|
|
3421
5971
|
windowStart: floorUtcDayTimestamp(subtractDays(account.connectedAt, summaryBackfillDays)),
|
|
@@ -3427,6 +5977,7 @@ function buildWindowJob(input) {
|
|
|
3427
5977
|
const windowStart = floorUtcDayTimestamp(input.windowStart);
|
|
3428
5978
|
return buildExactWindowJob({
|
|
3429
5979
|
kind: input.kind,
|
|
5980
|
+
payload: input.payload,
|
|
3430
5981
|
windowStart,
|
|
3431
5982
|
windowEnd,
|
|
3432
5983
|
availableAt: input.now,
|
|
@@ -3434,6 +5985,15 @@ function buildWindowJob(input) {
|
|
|
3434
5985
|
});
|
|
3435
5986
|
}
|
|
3436
5987
|
function buildExactWindowJob(input) {
|
|
5988
|
+
const windowPayload = input.payload;
|
|
5989
|
+
const sourceProviderSlug = normalizeString(windowPayload?.sourceProviderSlug);
|
|
5990
|
+
const dedupeIdentity = [
|
|
5991
|
+
"junction",
|
|
5992
|
+
input.kind,
|
|
5993
|
+
input.windowStart,
|
|
5994
|
+
input.windowEnd,
|
|
5995
|
+
...(sourceProviderSlug ? [sourceProviderSlug] : []),
|
|
5996
|
+
];
|
|
3437
5997
|
return {
|
|
3438
5998
|
kind: input.kind,
|
|
3439
5999
|
payload: {
|
|
@@ -3443,9 +6003,261 @@ function buildExactWindowJob(input) {
|
|
|
3443
6003
|
},
|
|
3444
6004
|
priority: input.priority,
|
|
3445
6005
|
...(input.availableAt ? { availableAt: input.availableAt } : {}),
|
|
3446
|
-
dedupeKey: sha256Text(JSON.stringify(
|
|
6006
|
+
dedupeKey: sha256Text(JSON.stringify(dedupeIdentity)),
|
|
6007
|
+
};
|
|
6008
|
+
}
|
|
6009
|
+
function buildJunctionSparseCalendarRefreshJobs(input) {
|
|
6010
|
+
const targets = [...new Map(input.targets.map((target) => [
|
|
6011
|
+
JSON.stringify([
|
|
6012
|
+
target.dayKey,
|
|
6013
|
+
target.sourceProviderSlug,
|
|
6014
|
+
target.sourceType ?? null,
|
|
6015
|
+
target.sourceInstanceId ?? null,
|
|
6016
|
+
]),
|
|
6017
|
+
target,
|
|
6018
|
+
])).values()];
|
|
6019
|
+
const dayKeys = [...new Set(targets.map((target) => target.dayKey))].sort();
|
|
6020
|
+
if (dayKeys.length > JUNCTION_MAX_SPARSE_CALENDAR_REFRESH_DAYS
|
|
6021
|
+
|| targets.length > JUNCTION_MAX_SPARSE_CALENDAR_REFRESH_DAYS) {
|
|
6022
|
+
throw deviceSyncError({
|
|
6023
|
+
code: "JUNCTION_CALENDAR_REFRESH_DAY_LIMIT_EXCEEDED",
|
|
6024
|
+
message: "Junction sparse import exceeded the calendar refresh day limit.",
|
|
6025
|
+
retryable: false,
|
|
6026
|
+
details: {
|
|
6027
|
+
affectedDayCount: dayKeys.length,
|
|
6028
|
+
affectedTargetCount: targets.length,
|
|
6029
|
+
maxAllowed: JUNCTION_MAX_SPARSE_CALENDAR_REFRESH_DAYS,
|
|
6030
|
+
},
|
|
6031
|
+
});
|
|
6032
|
+
}
|
|
6033
|
+
return targets
|
|
6034
|
+
.filter((target) => isGloballyClosedJunctionProviderDay(target.dayKey, input.asOf))
|
|
6035
|
+
.map((target) => buildJunctionSparseCalendarRefreshJob({
|
|
6036
|
+
dayKey: target.dayKey,
|
|
6037
|
+
priority: input.priority,
|
|
6038
|
+
resource: input.resource,
|
|
6039
|
+
sourceInstanceId: target.sourceInstanceId,
|
|
6040
|
+
sourceProviderSlug: target.sourceProviderSlug,
|
|
6041
|
+
sourceType: target.sourceType,
|
|
6042
|
+
}));
|
|
6043
|
+
}
|
|
6044
|
+
function buildJunctionSparseCalendarRefreshJob(input) {
|
|
6045
|
+
const windowStart = `${input.dayKey}T00:00:00.000Z`;
|
|
6046
|
+
const windowEnd = addMilliseconds(windowStart, TIMESERIES_CHUNK_MS);
|
|
6047
|
+
const sourceProviderSlug = normalizeProviderSlug(input.sourceProviderSlug);
|
|
6048
|
+
const sourceInstanceId = normalizeString(input.sourceInstanceId);
|
|
6049
|
+
const sourceType = normalizeString(input.sourceType);
|
|
6050
|
+
return {
|
|
6051
|
+
kind: "resource",
|
|
6052
|
+
payload: {
|
|
6053
|
+
calendarRefreshDay: input.dayKey,
|
|
6054
|
+
resource: input.resource,
|
|
6055
|
+
resourceCategory: "timeseries",
|
|
6056
|
+
...(sourceInstanceId ? { sourceInstanceId } : {}),
|
|
6057
|
+
...(sourceProviderSlug ? { sourceProviderSlug } : {}),
|
|
6058
|
+
...(sourceType ? { sourceType } : {}),
|
|
6059
|
+
windowEnd,
|
|
6060
|
+
windowStart,
|
|
6061
|
+
},
|
|
6062
|
+
priority: input.priority,
|
|
6063
|
+
dedupeKey: sha256Text(JSON.stringify([
|
|
6064
|
+
"junction",
|
|
6065
|
+
"sparse-calendar-refresh",
|
|
6066
|
+
sourceProviderSlug,
|
|
6067
|
+
sourceType,
|
|
6068
|
+
sourceInstanceId,
|
|
6069
|
+
input.resource,
|
|
6070
|
+
input.dayKey,
|
|
6071
|
+
])),
|
|
6072
|
+
};
|
|
6073
|
+
}
|
|
6074
|
+
function readJunctionSparseCalendarRefreshDay(job) {
|
|
6075
|
+
if (!("calendarRefreshDay" in job.payload)) {
|
|
6076
|
+
return null;
|
|
6077
|
+
}
|
|
6078
|
+
const dayKey = job.payload.calendarRefreshDay;
|
|
6079
|
+
if (!isCanonicalEventDayKey(dayKey)) {
|
|
6080
|
+
throw deviceSyncError({
|
|
6081
|
+
code: JUNCTION_CALENDAR_REFRESH_JOB_INVALID_CODE,
|
|
6082
|
+
message: "Junction calendar refresh job had an invalid provider day.",
|
|
6083
|
+
retryable: false,
|
|
6084
|
+
});
|
|
6085
|
+
}
|
|
6086
|
+
return dayKey;
|
|
6087
|
+
}
|
|
6088
|
+
function readJunctionSparseCalendarSourceIdentity(job) {
|
|
6089
|
+
const sourceProviderSlug = normalizeProviderSlug(job.payload.sourceProviderSlug);
|
|
6090
|
+
if (!sourceProviderSlug) {
|
|
6091
|
+
throw deviceSyncError({
|
|
6092
|
+
code: JUNCTION_CALENDAR_REFRESH_JOB_INVALID_CODE,
|
|
6093
|
+
message: "Junction calendar refresh job lacked its source provider identity.",
|
|
6094
|
+
retryable: false,
|
|
6095
|
+
});
|
|
6096
|
+
}
|
|
6097
|
+
const sourceInstanceId = normalizeString(job.payload.sourceInstanceId);
|
|
6098
|
+
const sourceType = normalizeString(job.payload.sourceType);
|
|
6099
|
+
return {
|
|
6100
|
+
...(sourceInstanceId ? { sourceInstanceId } : {}),
|
|
6101
|
+
sourceProviderSlug,
|
|
6102
|
+
...(sourceType ? { sourceType } : {}),
|
|
6103
|
+
};
|
|
6104
|
+
}
|
|
6105
|
+
function filterJunctionSparseCalendarRecordsToSource(records, source) {
|
|
6106
|
+
const sourceProviderSlug = normalizeProviderSlug(source.sourceProviderSlug);
|
|
6107
|
+
const sourceInstanceId = normalizeString(source.sourceInstanceId);
|
|
6108
|
+
const sourceType = normalizeString(source.sourceType);
|
|
6109
|
+
return records.flatMap((record) => {
|
|
6110
|
+
const entry = readPlainObject(record);
|
|
6111
|
+
if (!entry) {
|
|
6112
|
+
throw incompleteJunctionSparseCalendarCollectionError();
|
|
6113
|
+
}
|
|
6114
|
+
const origin = resolveJunctionOrigin(entry);
|
|
6115
|
+
const recordSourceProviderSlug = normalizeProviderSlug(origin.sourceProviderSlug);
|
|
6116
|
+
if (!recordSourceProviderSlug) {
|
|
6117
|
+
throw incompleteJunctionSparseCalendarCollectionError();
|
|
6118
|
+
}
|
|
6119
|
+
if (!areJunctionProviderSlugsRouteEquivalent(recordSourceProviderSlug, sourceProviderSlug)) {
|
|
6120
|
+
return [];
|
|
6121
|
+
}
|
|
6122
|
+
const recordSourceType = normalizeString(origin.sourceType);
|
|
6123
|
+
if (sourceType && !recordSourceType) {
|
|
6124
|
+
throw incompleteJunctionSparseCalendarCollectionError();
|
|
6125
|
+
}
|
|
6126
|
+
if (sourceType && recordSourceType !== sourceType) {
|
|
6127
|
+
return [];
|
|
6128
|
+
}
|
|
6129
|
+
const recordSourceInstanceId = normalizeString(origin.sourceInstanceId);
|
|
6130
|
+
if (sourceInstanceId && !recordSourceInstanceId) {
|
|
6131
|
+
throw incompleteJunctionSparseCalendarCollectionError();
|
|
6132
|
+
}
|
|
6133
|
+
if (sourceInstanceId && recordSourceInstanceId !== sourceInstanceId) {
|
|
6134
|
+
return [];
|
|
6135
|
+
}
|
|
6136
|
+
return [{
|
|
6137
|
+
...entry,
|
|
6138
|
+
sourceProviderSlug,
|
|
6139
|
+
...(sourceType ? { sourceType } : {}),
|
|
6140
|
+
...(sourceInstanceId ? { sourceInstanceId } : {}),
|
|
6141
|
+
}];
|
|
6142
|
+
});
|
|
6143
|
+
}
|
|
6144
|
+
function incompleteJunctionSparseCalendarCollectionError() {
|
|
6145
|
+
return deviceSyncError({
|
|
6146
|
+
code: "JUNCTION_CALENDAR_REFRESH_INCOMPLETE_NORMALIZATION",
|
|
6147
|
+
message: "Junction calendar refresh response was not structurally complete.",
|
|
6148
|
+
retryable: true,
|
|
6149
|
+
httpStatus: 502,
|
|
6150
|
+
});
|
|
6151
|
+
}
|
|
6152
|
+
function buildJunctionEmptySparseCalendarAggregate(input) {
|
|
6153
|
+
return stripUndefined({
|
|
6154
|
+
authoritativeEmptyCalendarSet: true,
|
|
6155
|
+
calendarDate: input.dayKey,
|
|
6156
|
+
date: input.dayKey,
|
|
6157
|
+
sourceInstanceId: input.sourceInstanceId,
|
|
6158
|
+
sourceProviderSlug: input.sourceProviderSlug,
|
|
6159
|
+
sourceType: input.sourceType,
|
|
6160
|
+
value: 0,
|
|
6161
|
+
});
|
|
6162
|
+
}
|
|
6163
|
+
function isGloballyClosedJunctionProviderDay(dayKey, asOf) {
|
|
6164
|
+
if (!isCanonicalEventDayKey(dayKey)) {
|
|
6165
|
+
return false;
|
|
6166
|
+
}
|
|
6167
|
+
const windowEnd = addMilliseconds(`${dayKey}T00:00:00.000Z`, TIMESERIES_CHUNK_MS);
|
|
6168
|
+
return Date.parse(windowEnd) <= resolveGloballyClosedProviderDayEnd(windowEnd, asOf);
|
|
6169
|
+
}
|
|
6170
|
+
function buildJunctionExtendedTimeseriesBackfillDedupeKey(payload) {
|
|
6171
|
+
if (payload.historicalBackfill !== true) {
|
|
6172
|
+
return null;
|
|
6173
|
+
}
|
|
6174
|
+
const historicalWindowStart = toIsoTimestampIfValid(normalizeString(payload.historicalWindowStart));
|
|
6175
|
+
const resource = normalizeJunctionResourceName(payload.resource);
|
|
6176
|
+
const windowEnd = toIsoTimestampIfValid(normalizeString(payload.windowEnd));
|
|
6177
|
+
const policy = resource
|
|
6178
|
+
? resolveJunctionExtendedTimeseriesBackfillPolicy(resource)
|
|
6179
|
+
: null;
|
|
6180
|
+
if (!historicalWindowStart
|
|
6181
|
+
|| !resource
|
|
6182
|
+
|| !windowEnd
|
|
6183
|
+
|| !policy) {
|
|
6184
|
+
return null;
|
|
6185
|
+
}
|
|
6186
|
+
if (!["blood_pressure", "weight"].includes(resource)) {
|
|
6187
|
+
const coverageVersion = resource === "note"
|
|
6188
|
+
? readJunctionNoteHistoryBackfillVersion(payload)
|
|
6189
|
+
: policy.version;
|
|
6190
|
+
return sha256Text(JSON.stringify([
|
|
6191
|
+
"junction",
|
|
6192
|
+
"extended-timeseries-backfill",
|
|
6193
|
+
normalizeProviderSlug(payload.sourceProviderSlug),
|
|
6194
|
+
resource,
|
|
6195
|
+
coverageVersion,
|
|
6196
|
+
]));
|
|
6197
|
+
}
|
|
6198
|
+
return sha256Text(JSON.stringify([
|
|
6199
|
+
"junction",
|
|
6200
|
+
"extended-timeseries-backfill",
|
|
6201
|
+
normalizeProviderSlug(payload.sourceProviderSlug),
|
|
6202
|
+
resource,
|
|
6203
|
+
historicalWindowStart,
|
|
6204
|
+
windowEnd,
|
|
6205
|
+
]));
|
|
6206
|
+
}
|
|
6207
|
+
function buildExtendedTimeseriesBackfillJob(input) {
|
|
6208
|
+
const payload = {
|
|
6209
|
+
...(input.emptyBackfillAttempts && input.emptyBackfillAttempts > 0
|
|
6210
|
+
? { emptyBackfillAttempts: input.emptyBackfillAttempts }
|
|
6211
|
+
: {}),
|
|
6212
|
+
historicalBackfill: true,
|
|
6213
|
+
...(input.historicalBackfillVersion === undefined
|
|
6214
|
+
? {}
|
|
6215
|
+
: { historicalBackfillVersion: input.historicalBackfillVersion }),
|
|
6216
|
+
...(input.historicalProviderRecordsSeen
|
|
6217
|
+
? { historicalProviderRecordsSeen: true }
|
|
6218
|
+
: {}),
|
|
6219
|
+
...(input.historicalRecordsSeen
|
|
6220
|
+
? { historicalRecordsSeen: true }
|
|
6221
|
+
: {}),
|
|
6222
|
+
...(input.historicalUnresolvedProviderRecordIdentitiesJson
|
|
6223
|
+
? {
|
|
6224
|
+
historicalUnresolvedProviderRecordIdentitiesJson: input.historicalUnresolvedProviderRecordIdentitiesJson,
|
|
6225
|
+
}
|
|
6226
|
+
: {}),
|
|
6227
|
+
...(input.historicalUnresolvedProviderRecordCount
|
|
6228
|
+
&& input.historicalUnresolvedProviderRecordCount > 0
|
|
6229
|
+
? {
|
|
6230
|
+
historicalUnresolvedProviderRecordCount: input.historicalUnresolvedProviderRecordCount,
|
|
6231
|
+
}
|
|
6232
|
+
: {}),
|
|
6233
|
+
historicalWindowStart: input.historicalWindowStart,
|
|
6234
|
+
resource: input.resource,
|
|
6235
|
+
resourceCategory: "timeseries",
|
|
6236
|
+
...(input.sourceProviderSlug
|
|
6237
|
+
? { sourceProviderSlug: input.sourceProviderSlug }
|
|
6238
|
+
: {}),
|
|
6239
|
+
windowEnd: input.windowEnd,
|
|
6240
|
+
windowStart: input.windowStart,
|
|
6241
|
+
};
|
|
6242
|
+
const dedupeKey = input.dedupeKey
|
|
6243
|
+
?? buildJunctionExtendedTimeseriesBackfillDedupeKey(payload);
|
|
6244
|
+
if (!dedupeKey) {
|
|
6245
|
+
throw new TypeError("Junction extended timeseries backfill identity was invalid.");
|
|
6246
|
+
}
|
|
6247
|
+
return {
|
|
6248
|
+
kind: "resource",
|
|
6249
|
+
payload,
|
|
6250
|
+
availableAt: input.availableAt,
|
|
6251
|
+
priority: JUNCTION_HISTORICAL_BACKFILL_PRIORITY,
|
|
6252
|
+
dedupeKey,
|
|
3447
6253
|
};
|
|
3448
6254
|
}
|
|
6255
|
+
function readJunctionNoteHistoryBackfillVersion(payload) {
|
|
6256
|
+
const version = payload.historicalBackfillVersion;
|
|
6257
|
+
return typeof version === "number" && Number.isSafeInteger(version) && version >= 1
|
|
6258
|
+
? version
|
|
6259
|
+
: 1;
|
|
6260
|
+
}
|
|
3449
6261
|
function buildJunctionWebhookJobs(input) {
|
|
3450
6262
|
if (isJunctionProviderConnectionEvent(input.eventType)) {
|
|
3451
6263
|
const backfillWindowStart = subtractDays(input.window.windowEnd, input.summaryBackfillDays);
|
|
@@ -3538,8 +6350,7 @@ function isJunctionHistoricalDataEvent(eventType) {
|
|
|
3538
6350
|
return eventType.startsWith("historical.data.");
|
|
3539
6351
|
}
|
|
3540
6352
|
function isJunctionHistoricalPullCompletedWebhookData(data, externalAccountId) {
|
|
3541
|
-
|
|
3542
|
-
if (completed && normalizeJunctionWebhookSourceProviderCandidate(completed.provider)) {
|
|
6353
|
+
if (isJunctionSdkHistoricalPullCompletedWebhookData(data, externalAccountId)) {
|
|
3543
6354
|
return true;
|
|
3544
6355
|
}
|
|
3545
6356
|
if (hasJunctionHistoricalInlineRecordCarrierFields(data)) {
|
|
@@ -3547,14 +6358,19 @@ function isJunctionHistoricalPullCompletedWebhookData(data, externalAccountId) {
|
|
|
3547
6358
|
}
|
|
3548
6359
|
return isDocumentedJunctionHistoricalPullCompletedWebhookData(data, externalAccountId);
|
|
3549
6360
|
}
|
|
3550
|
-
function
|
|
3551
|
-
const
|
|
3552
|
-
|
|
3553
|
-
|
|
3554
|
-
|
|
3555
|
-
|
|
3556
|
-
|
|
3557
|
-
|
|
6361
|
+
function isJunctionSdkHistoricalPullCompletedWebhookData(data, externalAccountId) {
|
|
6362
|
+
const userId = normalizeString(data[JUNCTION_WEBHOOK_ROOT_FIELDS.userId])
|
|
6363
|
+
?? externalAccountId;
|
|
6364
|
+
const startDate = data.start_date;
|
|
6365
|
+
const endDate = data.end_date;
|
|
6366
|
+
return typeof userId === "string"
|
|
6367
|
+
&& typeof startDate === "string"
|
|
6368
|
+
&& JUNCTION_SDK_ISO_8601_DATE_PATTERN.test(startDate)
|
|
6369
|
+
&& typeof endDate === "string"
|
|
6370
|
+
&& JUNCTION_SDK_ISO_8601_DATE_PATTERN.test(endDate)
|
|
6371
|
+
&& data.is_final === true
|
|
6372
|
+
&& typeof data.provider === "string"
|
|
6373
|
+
&& normalizeJunctionWebhookSourceProviderCandidate(data.provider) !== null;
|
|
3558
6374
|
}
|
|
3559
6375
|
const JUNCTION_HISTORICAL_INLINE_RECORD_CARRIER_FIELDS = new Set([
|
|
3560
6376
|
"activities",
|
|
@@ -3975,6 +6791,7 @@ function verifyAndParseJunctionWebhookEnvelope(input) {
|
|
|
3975
6791
|
return {
|
|
3976
6792
|
messageId,
|
|
3977
6793
|
payload,
|
|
6794
|
+
providerSentAt: new Date(timestampMs).toISOString(),
|
|
3978
6795
|
};
|
|
3979
6796
|
}
|
|
3980
6797
|
function requireJunctionWebhookHeader(headers, name) {
|
|
@@ -4248,12 +7065,30 @@ async function projectJunctionSources(context, providers, options = {}) {
|
|
|
4248
7065
|
const preserveHistoricalReconnectProviderSlugs = options.preserveHistoricalReconnectProviderSlugs === undefined
|
|
4249
7066
|
? null
|
|
4250
7067
|
: new Set(options.preserveHistoricalReconnectProviderSlugs);
|
|
7068
|
+
const projectedSources = projectJunctionSourcesByProviderSlug(context.account.id, providers);
|
|
7069
|
+
if (projectedSources.length > JUNCTION_MAX_USER_PROVIDERS) {
|
|
7070
|
+
throw deviceSyncError({
|
|
7071
|
+
code: "JUNCTION_USER_PROVIDER_LIMIT",
|
|
7072
|
+
message: "Junction projected sources exceeded the supported provider bound.",
|
|
7073
|
+
retryable: true,
|
|
7074
|
+
httpStatus: 502,
|
|
7075
|
+
});
|
|
7076
|
+
}
|
|
4251
7077
|
const existingSources = context.listConnectionSources
|
|
4252
|
-
? await context.listConnectionSources()
|
|
7078
|
+
? [...await context.listConnectionSources()]
|
|
4253
7079
|
: [];
|
|
4254
|
-
const
|
|
4255
|
-
|
|
4256
|
-
|
|
7080
|
+
const admissionSources = context.listConnectionSources
|
|
7081
|
+
? existingSources
|
|
7082
|
+
: context.account.sources ?? [];
|
|
7083
|
+
for (const source of projectedSources) {
|
|
7084
|
+
const listedOnly = context.connectionSourceAdmissionMode === "listed_only";
|
|
7085
|
+
if ((listedOnly
|
|
7086
|
+
&& !hasJunctionSourceListing(admissionSources, source.sourceProviderSlug))
|
|
7087
|
+
|| isJunctionSourceProjectionFenced(admissionSources, source.sourceProviderSlug)) {
|
|
7088
|
+
continue;
|
|
7089
|
+
}
|
|
7090
|
+
const accountSourceIdentity = resolveJunctionAccountSourceIdentity(existingSources, source.sourceProviderSlug, true);
|
|
7091
|
+
const existing = findJunctionAccountSource(existingSources, source.sourceProviderSlug);
|
|
4257
7092
|
const keepHistoricalReconnect = preserveHistoricalReconnect
|
|
4258
7093
|
&& (preserveHistoricalReconnectProviderSlugs === null
|
|
4259
7094
|
|| preserveHistoricalReconnectProviderSlugs.has(source.sourceProviderSlug))
|
|
@@ -4264,11 +7099,14 @@ async function projectJunctionSources(context, providers, options = {}) {
|
|
|
4264
7099
|
&& existing.lastErrorCode === DEVICE_SYNC_HISTORICAL_DATA_RECONNECT_REQUIRED_ERROR_CODE
|
|
4265
7100
|
: requiresHistoricalResetDeviceSyncSource(existing));
|
|
4266
7101
|
const historicalReconnectError = keepHistoricalReconnect ? existing : null;
|
|
4267
|
-
await context.upsertConnectionSource({
|
|
4268
|
-
sourceInstanceKey:
|
|
4269
|
-
sourceProviderSlug: source.sourceProviderSlug,
|
|
7102
|
+
const persistedSource = await context.upsertConnectionSource({
|
|
7103
|
+
sourceInstanceKey: accountSourceIdentity?.sourceInstanceKey ?? source.sourceInstanceKey,
|
|
7104
|
+
sourceProviderSlug: accountSourceIdentity?.sourceProviderSlug ?? source.sourceProviderSlug,
|
|
4270
7105
|
displayName: existing?.displayName ?? null,
|
|
4271
|
-
|
|
7106
|
+
...(existing?.firstSeenAt ? { firstSeenAt: existing.firstSeenAt } : {}),
|
|
7107
|
+
status: keepHistoricalReconnect
|
|
7108
|
+
? "error"
|
|
7109
|
+
: source.status,
|
|
4272
7110
|
resourceAvailabilitySummary: source.resourceAvailabilitySummary,
|
|
4273
7111
|
// Only assert error fields when this projection saw an errored entry;
|
|
4274
7112
|
// omitting the keys lets the store preserve existing detail while the
|
|
@@ -4283,7 +7121,118 @@ async function projectJunctionSources(context, providers, options = {}) {
|
|
|
4283
7121
|
: {}),
|
|
4284
7122
|
lastSeenAt: context.now,
|
|
4285
7123
|
});
|
|
7124
|
+
const persistedIndex = existingSources.findIndex((candidate) => candidate.sourceInstanceKey === persistedSource.sourceInstanceKey);
|
|
7125
|
+
if (persistedIndex >= 0) {
|
|
7126
|
+
existingSources[persistedIndex] = persistedSource;
|
|
7127
|
+
}
|
|
7128
|
+
else {
|
|
7129
|
+
existingSources.push(persistedSource);
|
|
7130
|
+
}
|
|
7131
|
+
}
|
|
7132
|
+
}
|
|
7133
|
+
function isJunctionSourceAdmittedForImport(sources, sourceProviderSlug, allowUnlistedSources = true, sourceStatusRequirement = "not_disconnected") {
|
|
7134
|
+
const normalizedSourceProviderSlug = normalizeProviderSlug(sourceProviderSlug);
|
|
7135
|
+
if (!normalizedSourceProviderSlug) {
|
|
7136
|
+
return true;
|
|
7137
|
+
}
|
|
7138
|
+
const accountSourceIdentity = resolveJunctionAccountSourceIdentity(sources, normalizedSourceProviderSlug, allowUnlistedSources);
|
|
7139
|
+
if (!accountSourceIdentity) {
|
|
7140
|
+
return false;
|
|
7141
|
+
}
|
|
7142
|
+
const sourceState = resolveJunctionAccountSourceState(sources, accountSourceIdentity.sourceProviderSlug);
|
|
7143
|
+
if (!sourceState) {
|
|
7144
|
+
return allowUnlistedSources;
|
|
7145
|
+
}
|
|
7146
|
+
const lifecycleSource = sourceState.lifecycleSource;
|
|
7147
|
+
return sourceStatusRequirement === "connected"
|
|
7148
|
+
? isDeviceSyncSourceAdmitted([lifecycleSource], lifecycleSource.sourceProviderSlug)
|
|
7149
|
+
: lifecycleSource.status !== "disconnected"
|
|
7150
|
+
&& !isDeviceSyncSourceDisconnectFenced(lifecycleSource);
|
|
7151
|
+
}
|
|
7152
|
+
function isJunctionSourceProjectionFenced(sources, sourceProviderSlug) {
|
|
7153
|
+
const normalizedSourceProviderSlug = normalizeProviderSlug(sourceProviderSlug);
|
|
7154
|
+
if (!normalizedSourceProviderSlug) {
|
|
7155
|
+
return false;
|
|
7156
|
+
}
|
|
7157
|
+
const accountSourceIdentity = resolveJunctionAccountSourceIdentity(sources, normalizedSourceProviderSlug);
|
|
7158
|
+
if (!accountSourceIdentity) {
|
|
7159
|
+
return false;
|
|
7160
|
+
}
|
|
7161
|
+
const sourceState = resolveJunctionAccountSourceState(sources, accountSourceIdentity.sourceProviderSlug);
|
|
7162
|
+
return sourceState !== null
|
|
7163
|
+
&& isDeviceSyncSourceDisconnectFenced(sourceState.lifecycleSource);
|
|
7164
|
+
}
|
|
7165
|
+
function hasJunctionSourceListing(sources, sourceProviderSlug) {
|
|
7166
|
+
const normalizedSourceProviderSlug = normalizeProviderSlug(sourceProviderSlug);
|
|
7167
|
+
if (!normalizedSourceProviderSlug) {
|
|
7168
|
+
return true;
|
|
7169
|
+
}
|
|
7170
|
+
return sources.some((source) => areJunctionProviderSlugsRouteEquivalent(source.sourceProviderSlug, normalizedSourceProviderSlug));
|
|
7171
|
+
}
|
|
7172
|
+
async function resolveJunctionCurrentSourceAdmission(context, sourceProviderSlug) {
|
|
7173
|
+
const sources = context.listConnectionSources
|
|
7174
|
+
? await context.listConnectionSources()
|
|
7175
|
+
: context.account.sources ?? [];
|
|
7176
|
+
return resolveJunctionCurrentSourceAdmissionFromSources(sources, sourceProviderSlug, context.connectionSourceAdmissionMode !== "listed_only");
|
|
7177
|
+
}
|
|
7178
|
+
function resolveJunctionCurrentSourceAdmissionFromSources(sources, sourceProviderSlug, allowUnlistedSources) {
|
|
7179
|
+
if (isJunctionSourceProjectionFenced(sources, sourceProviderSlug)) {
|
|
7180
|
+
return "fenced";
|
|
7181
|
+
}
|
|
7182
|
+
return isJunctionSourceAdmittedForImport(sources, sourceProviderSlug, allowUnlistedSources, "connected")
|
|
7183
|
+
? "admitted"
|
|
7184
|
+
: "pending";
|
|
7185
|
+
}
|
|
7186
|
+
async function isJunctionCompanionSourceCurrentlyAdmitted(context, sourceProviderSlug) {
|
|
7187
|
+
const normalizedSourceProviderSlug = normalizeProviderSlug(sourceProviderSlug);
|
|
7188
|
+
if (!context.listConnectionSources) {
|
|
7189
|
+
throw junctionCompanionSourceStateUnavailableError();
|
|
7190
|
+
}
|
|
7191
|
+
if (!normalizedSourceProviderSlug) {
|
|
7192
|
+
throw junctionCompanionSourceStateUnavailableError();
|
|
7193
|
+
}
|
|
7194
|
+
let sources;
|
|
7195
|
+
try {
|
|
7196
|
+
sources = await context.listConnectionSources({
|
|
7197
|
+
sourceProviderSlug: normalizedSourceProviderSlug,
|
|
7198
|
+
});
|
|
7199
|
+
}
|
|
7200
|
+
catch (error) {
|
|
7201
|
+
if (isDeviceSyncError(error) && error.retryable) {
|
|
7202
|
+
throw error;
|
|
7203
|
+
}
|
|
7204
|
+
throw junctionCompanionSourceStateUnavailableError(error);
|
|
7205
|
+
}
|
|
7206
|
+
if (isDeviceSyncSourceAdmitted(sources, normalizedSourceProviderSlug)) {
|
|
7207
|
+
return true;
|
|
7208
|
+
}
|
|
7209
|
+
if (sources.some((source) => source.lastErrorCode === DEVICE_SYNC_SOURCE_USER_DISCONNECTED_ERROR_CODE)) {
|
|
7210
|
+
return false;
|
|
4286
7211
|
}
|
|
7212
|
+
throw deviceSyncError({
|
|
7213
|
+
code: "JUNCTION_COMPANION_SOURCE_NOT_READY",
|
|
7214
|
+
message: "Current companion source authorization is not ready. Retry shortly.",
|
|
7215
|
+
retryable: true,
|
|
7216
|
+
httpStatus: 503,
|
|
7217
|
+
});
|
|
7218
|
+
}
|
|
7219
|
+
function junctionSourceStateUnavailableError(cause) {
|
|
7220
|
+
return deviceSyncError({
|
|
7221
|
+
code: "JUNCTION_SOURCE_STATE_UNAVAILABLE",
|
|
7222
|
+
message: "Current Junction source state is unavailable. Retry shortly.",
|
|
7223
|
+
retryable: true,
|
|
7224
|
+
httpStatus: 503,
|
|
7225
|
+
...(cause === undefined ? {} : { cause }),
|
|
7226
|
+
});
|
|
7227
|
+
}
|
|
7228
|
+
function junctionCompanionSourceStateUnavailableError(cause) {
|
|
7229
|
+
return deviceSyncError({
|
|
7230
|
+
code: "JUNCTION_COMPANION_SOURCE_STATE_UNAVAILABLE",
|
|
7231
|
+
message: "Current companion source authorization is unavailable. Retry shortly.",
|
|
7232
|
+
retryable: true,
|
|
7233
|
+
httpStatus: 503,
|
|
7234
|
+
...(cause === undefined ? {} : { cause }),
|
|
7235
|
+
});
|
|
4287
7236
|
}
|
|
4288
7237
|
function projectJunctionSourcesByProviderSlug(connectionId, providers) {
|
|
4289
7238
|
const projected = new Map();
|
|
@@ -4489,6 +7438,102 @@ function readPlainObject(value) {
|
|
|
4489
7438
|
function readProviderSnapshotDurableDeliveryAccepted(value) {
|
|
4490
7439
|
return readPlainObject(value)?.durableDeliveryAccepted === true;
|
|
4491
7440
|
}
|
|
7441
|
+
function readProviderSnapshotCanonicalEventCount(value) {
|
|
7442
|
+
const canonicalEventCount = readPlainObject(value)?.canonicalEventCount;
|
|
7443
|
+
return typeof canonicalEventCount === "number"
|
|
7444
|
+
&& Number.isSafeInteger(canonicalEventCount)
|
|
7445
|
+
&& canonicalEventCount >= 0
|
|
7446
|
+
? canonicalEventCount
|
|
7447
|
+
: 0;
|
|
7448
|
+
}
|
|
7449
|
+
function readProviderSnapshotCanonicalEventDayKeys(value) {
|
|
7450
|
+
const dayKeys = readPlainObject(value)?.canonicalEventDayKeys;
|
|
7451
|
+
if (!Array.isArray(dayKeys)) {
|
|
7452
|
+
return [];
|
|
7453
|
+
}
|
|
7454
|
+
return [...new Set(dayKeys.filter((dayKey) => isCanonicalEventDayKey(dayKey)))].sort();
|
|
7455
|
+
}
|
|
7456
|
+
function readProviderSnapshotCanonicalSparseCalendarTargets(value) {
|
|
7457
|
+
const rawTargets = readPlainObject(value)?.canonicalSparseCalendarTargets;
|
|
7458
|
+
if (!Array.isArray(rawTargets)) {
|
|
7459
|
+
return [];
|
|
7460
|
+
}
|
|
7461
|
+
return rawTargets.flatMap((rawTarget) => {
|
|
7462
|
+
const target = readPlainObject(rawTarget);
|
|
7463
|
+
if (!target) {
|
|
7464
|
+
return [];
|
|
7465
|
+
}
|
|
7466
|
+
const sourceProviderSlug = normalizeProviderSlug(target.sourceProviderSlug);
|
|
7467
|
+
if (!isCanonicalEventDayKey(target.dayKey) || !sourceProviderSlug) {
|
|
7468
|
+
return [];
|
|
7469
|
+
}
|
|
7470
|
+
const sourceType = normalizeString(target.sourceType);
|
|
7471
|
+
return [{
|
|
7472
|
+
dayKey: target.dayKey,
|
|
7473
|
+
...(typeof target.sourceInstanceId === "string" || target.sourceInstanceId === null
|
|
7474
|
+
? { sourceInstanceId: target.sourceInstanceId }
|
|
7475
|
+
: {}),
|
|
7476
|
+
sourceProviderSlug,
|
|
7477
|
+
...(sourceType ? { sourceType } : {}),
|
|
7478
|
+
}];
|
|
7479
|
+
});
|
|
7480
|
+
}
|
|
7481
|
+
function isCanonicalEventDayKey(value) {
|
|
7482
|
+
if (typeof value !== "string" || !/^\d{4}-\d{2}-\d{2}$/u.test(value)) {
|
|
7483
|
+
return false;
|
|
7484
|
+
}
|
|
7485
|
+
const parsed = new Date(`${value}T00:00:00.000Z`);
|
|
7486
|
+
return Number.isFinite(parsed.getTime()) && parsed.toISOString().slice(0, 10) === value;
|
|
7487
|
+
}
|
|
7488
|
+
function readProviderSnapshotCanonicalEventExternalRefResourceIds(value) {
|
|
7489
|
+
const record = readPlainObject(value);
|
|
7490
|
+
if (!record || !("canonicalEventExternalRefResourceIds" in record)) {
|
|
7491
|
+
return null;
|
|
7492
|
+
}
|
|
7493
|
+
const resourceIds = record.canonicalEventExternalRefResourceIds;
|
|
7494
|
+
return Array.isArray(resourceIds)
|
|
7495
|
+
&& resourceIds.every((resourceId) => typeof resourceId === "string")
|
|
7496
|
+
? resourceIds
|
|
7497
|
+
: null;
|
|
7498
|
+
}
|
|
7499
|
+
function uniqueJunctionProviderRecordIdentities(identities) {
|
|
7500
|
+
return [...new Set(identities.filter((identity) => identity !== null && JUNCTION_BLOOD_PRESSURE_PROVIDER_RECORD_IDENTITY_PATTERN.test(identity)))].sort();
|
|
7501
|
+
}
|
|
7502
|
+
function resolveJunctionBloodPressureProviderRecordResolutionEvidence(input) {
|
|
7503
|
+
const rawIdentities = input.providerRecordIdentityEvidence.repairStableExternalRefResourceIds;
|
|
7504
|
+
const stableIdentities = uniqueJunctionProviderRecordIdentities(rawIdentities);
|
|
7505
|
+
const identityEvidenceIncomplete = input.providerRecordIdentityEvidence.providerRecordCount !== input.providerRecordCount
|
|
7506
|
+
|| rawIdentities.some((identity) => identity !== null
|
|
7507
|
+
&& !JUNCTION_BLOOD_PRESSURE_PROVIDER_RECORD_IDENTITY_PATTERN.test(identity));
|
|
7508
|
+
// Older unit seams may only expose the aggregate count. They can prove an
|
|
7509
|
+
// all-canonical current scan, but never clear an exact carried obligation.
|
|
7510
|
+
if (input.canonicalEventExternalRefResourceIds === null) {
|
|
7511
|
+
const allCurrentRecordsCanonical = !identityEvidenceIncomplete
|
|
7512
|
+
&& input.canonicalEventCount >= input.providerRecordCount;
|
|
7513
|
+
return {
|
|
7514
|
+
canonicalProviderRecordIdentities: [],
|
|
7515
|
+
unresolvedProviderRecordIdentities: allCurrentRecordsCanonical
|
|
7516
|
+
? []
|
|
7517
|
+
: stableIdentities,
|
|
7518
|
+
unresolvedProviderRecordsWithoutStableIdentity: !allCurrentRecordsCanonical
|
|
7519
|
+
&& (identityEvidenceIncomplete
|
|
7520
|
+
|| rawIdentities.some((identity) => identity === null)),
|
|
7521
|
+
};
|
|
7522
|
+
}
|
|
7523
|
+
const canonicalResourceIds = new Set(input.canonicalEventExternalRefResourceIds.filter((resourceId) => JUNCTION_BLOOD_PRESSURE_PROVIDER_RECORD_IDENTITY_PATTERN.test(resourceId)));
|
|
7524
|
+
const stableIdentitySet = new Set(stableIdentities);
|
|
7525
|
+
const canonicalProviderRecordIdentities = stableIdentities.filter((identity) => canonicalResourceIds.has(identity));
|
|
7526
|
+
const unresolvedProviderRecordIdentities = stableIdentities.filter((identity) => !canonicalResourceIds.has(identity));
|
|
7527
|
+
const providerRecordsWithoutStableIdentity = rawIdentities.filter((identity) => identity === null).length;
|
|
7528
|
+
const canonicalRecordsWithoutStableIdentity = input.canonicalEventExternalRefResourceIds.filter((resourceId) => !stableIdentitySet.has(resourceId)).length;
|
|
7529
|
+
return {
|
|
7530
|
+
canonicalProviderRecordIdentities,
|
|
7531
|
+
unresolvedProviderRecordIdentities,
|
|
7532
|
+
unresolvedProviderRecordsWithoutStableIdentity: identityEvidenceIncomplete
|
|
7533
|
+
|| input.canonicalEventExternalRefResourceIds.length !== input.canonicalEventCount
|
|
7534
|
+
|| canonicalRecordsWithoutStableIdentity < providerRecordsWithoutStableIdentity,
|
|
7535
|
+
};
|
|
7536
|
+
}
|
|
4492
7537
|
function base32UrlEncode(input) {
|
|
4493
7538
|
const alphabet = "abcdefghijklmnopqrstuvwxyz234567";
|
|
4494
7539
|
let bits = 0;
|