Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
410 commits
Select commit Hold shift + click to select a range
b06e0e3
feat(email): first-failure notification state machine (P2)
jodeleeuw Aug 23, 2026
f01cc95
feat(email): verification round trip (P3)
jodeleeuw Aug 23, 2026
6225e43
feat(email): backfill migration, purge coverage, deploy runbook (P4)
jodeleeuw Aug 23, 2026
4780514
Merge pull request #184 from jspsych/required-email
jodeleeuw Aug 23, 2026
a5a141a
feat(docs): skeleton — nav source of truth, DocsLayout, 16 anchored r…
jodeleeuw Aug 23, 2026
14df6f2
feat(docs): providers, account, about — package B content
jodeleeuw Aug 23, 2026
b053f33
feat(docs): collecting data — package C content
jodeleeuw Aug 23, 2026
a062b26
feat(docs): your data + API reference — package D content
jodeleeuw Aug 23, 2026
20c6141
fix(docs): clarify sweep — one voice, one term per concept
jodeleeuw Aug 23, 2026
4ed6a5a
feat(docs): wiring — nav, redirects, shim; no route left behind
jodeleeuw Aug 23, 2026
893cc83
Merge pull request #186 from jspsych/docs-restructure
jodeleeuw Aug 23, 2026
070e3a5
fix(ci): notify suite survives the live trigger; backfill runs via wo…
jodeleeuw Aug 23, 2026
7affa1f
feat(mail): own the delivery — SES trigger replaces the deprecated ex…
jodeleeuw Aug 23, 2026
5119c85
fix: ignore empty entries in required-fields validation (#95)
jodeleeuw Aug 23, 2026
f9bfca3
feat: add branded 404 page (#42)
jodeleeuw Aug 23, 2026
85a5e8b
ci: run ESLint on every PR and test push (#109)
jodeleeuw Aug 23, 2026
37ae401
docs: describe the observable failure when a request exceeds 32 MB
jodeleeuw Aug 23, 2026
c1e59fe
fix(deps): clear all runtime advisories in the Next.js lockfile
jodeleeuw Aug 23, 2026
de196eb
fix(deps): clear all advisories in the Cloud Functions lockfile
jodeleeuw Aug 23, 2026
b69e6c0
feat(deps): upgrade firebase-admin to v14
jodeleeuw Aug 23, 2026
76aa0d3
build(deps): pin CI's firebase-tools to the audited 15.28.1
jodeleeuw Aug 23, 2026
9751807
Merge pull request #187 from jspsych/dependabot-fixes
jodeleeuw Aug 23, 2026
30030b2
fix: address Copilot review findings on #188
jodeleeuw Aug 23, 2026
07d428d
feat(theme): retire light mode — dark is the only mode
jodeleeuw Aug 23, 2026
b19b6a0
Merge branch 'pr188-review-fixes' into test
jodeleeuw Aug 23, 2026
b23f6eb
Merge branch 'remove-light-mode' into test
jodeleeuw Aug 23, 2026
421bbf4
docs: copy-level fixes from Diátaxis review of /docs
jodeleeuw Aug 23, 2026
9cd6d7f
feat(docs): add draft Privacy & Information for IRBs page (#53)
jodeleeuw Aug 24, 2026
3f6f54c
fix(privacy): address review comments on #190
jodeleeuw Aug 24, 2026
38dc09f
fix(privacy): clarity pass for non-technical IRB readers
jodeleeuw Aug 24, 2026
31aba9e
fix(metadata): readable, collision-free flattening of researcher subf…
jodeleeuw Aug 24, 2026
8ff81c2
fix(gdrive): claim collisions on the full path, not the bare leaf
jodeleeuw Aug 24, 2026
54680c0
feat(metadata): freeze the Psych-DS setting once an experiment has data
jodeleeuw Aug 24, 2026
cf4c06b
Merge pull request #191 from jspsych/flatten-name-hash
jodeleeuw Aug 24, 2026
1b35df0
Merge branch 'test' into docs-diataxis-copyedits
jodeleeuw Aug 24, 2026
d832a7f
Merge branch 'test' into irb-privacy-page
jodeleeuw Aug 24, 2026
978bbc4
Merge branch 'test' into gdrive-path-claims
jodeleeuw Aug 24, 2026
a130560
Merge pull request #189 from jspsych/docs-diataxis-copyedits
jodeleeuw Aug 24, 2026
308417f
Merge pull request #190 from jspsych/irb-privacy-page
jodeleeuw Aug 24, 2026
d43e29d
Merge pull request #192 from jspsych/gdrive-path-claims
jodeleeuw Aug 24, 2026
b82632d
Merge branch 'test' into lock-metadata-after-first-submission
jodeleeuw Aug 24, 2026
119312c
Merge pull request #193 from jspsych/lock-metadata-after-first-submis…
jodeleeuw Aug 24, 2026
3cf19f8
Move privacy & IRB page into the docs section
jodeleeuw Aug 24, 2026
a086506
Standardize the new-experiment form across providers
jodeleeuw Aug 24, 2026
e8c90fc
Merge pull request #194 from jspsych/privacy-page-into-docs
jodeleeuw Aug 24, 2026
a42edce
Update the no-carry-over test for the contact email prefill
jodeleeuw Aug 24, 2026
c7a52cc
Merge pull request #195 from jspsych/standardize-new-experiment-form
jodeleeuw Aug 24, 2026
60190fc
Paint the link focus ring on :focus-visible, not :focus
jodeleeuw Aug 24, 2026
d18fc88
Merge pull request #196 from jspsych/fix-link-focus-ring
jodeleeuw Aug 24, 2026
d9553d1
Send mail from datapipe-notifications@jspsych.org
jodeleeuw Aug 24, 2026
432b609
Home: ration the green, drop the hover lift, fix step alignment and t…
jodeleeuw Aug 24, 2026
6406491
Test site: gate the environment banner on NEXT_PUBLIC_DEPLOY_ENV and …
jodeleeuw Aug 24, 2026
00b1fa7
Account: heading hierarchy and a dismissible link-success alert
jodeleeuw Aug 24, 2026
3d4c53e
New experiment: pre-select the first connected provider and add provi…
jodeleeuw Aug 24, 2026
9244efd
Experiment page: bordered sections, a switch table, and a Danger zone
jodeleeuw Aug 24, 2026
a2831b1
Merge pull request #197 from jspsych/design-feedback-pass
jodeleeuw Aug 24, 2026
955a50e
New experiment: use the providers' real marks (Simple Icons via react…
jodeleeuw Aug 24, 2026
c3f0990
Merge pull request #198 from jspsych/provider-brand-icons
jodeleeuw Aug 24, 2026
cd43426
New experiment: drop the provider icons
jodeleeuw Aug 24, 2026
4f4e435
Merge pull request #199 from jspsych/remove-provider-icons
jodeleeuw Aug 24, 2026
b418d0c
Zenodo test OAuth app: move to the datapipe@jspsych.org registration
jodeleeuw Aug 24, 2026
ef12b4a
Merge pull request #200 from jspsych/zenodo-oauth-app-org-account
jodeleeuw Aug 25, 2026
f9fed45
Experiment page: one ordered column, width allocated per section
jodeleeuw Aug 25, 2026
92389dd
docs: plainer provider copy, a citation page, quieter footer links
jodeleeuw Aug 25, 2026
63fe4b9
Merge pull request #201 from jspsych/experiment-page-single-column
jodeleeuw Aug 25, 2026
13a2eaa
Merge pull request #202 from jspsych/worktree-connect-account-copy
jodeleeuw Aug 25, 2026
d47a90c
ci: serialize deploys to each Firebase project
jodeleeuw Aug 25, 2026
4e7acd6
Merge pull request #203 from jspsych/deploy-concurrency-and-fail-loud
jodeleeuw Aug 25, 2026
fce6470
Experiment page: one column, one width
jodeleeuw Aug 25, 2026
1be4248
Merge pull request #204 from jspsych/experiment-page-uniform-width
jodeleeuw Aug 25, 2026
405d81f
Saved confirmation: move it out of the layout flow
jodeleeuw Aug 25, 2026
5f114ea
Merge pull request #205 from jspsych/saved-message-no-layout-shift
jodeleeuw Aug 25, 2026
042e371
Finalizing an experiment closes it, visibly
jodeleeuw Aug 26, 2026
faef584
Offer finalizing only where it works; name each experiment's provider
jodeleeuw Aug 26, 2026
f3e7149
Merge pull request #206 from jspsych/finalize-stops-collection
jodeleeuw Aug 26, 2026
41d2e57
Required fields: show the parsed list, don't ask them to imagine it
jodeleeuw Aug 26, 2026
63a8dfb
Merge pull request #207 from jspsych/required-fields-pills
jodeleeuw Aug 26, 2026
51c7399
Experiment logs: make them readable, bounded, and queryable
jodeleeuw Aug 26, 2026
e17a3b8
Merge pull request #208 from jspsych/logs-upgrade
jodeleeuw Aug 26, 2026
b582946
Stop a validation checkbox from flipping the switch above it
jodeleeuw Aug 27, 2026
7a08ab0
Merge pull request #209 from jspsych/fix/validation-checkbox-id-colli…
jodeleeuw Aug 27, 2026
c08fe82
Refuse to untick the last allowed submission format
jodeleeuw Aug 27, 2026
7267841
Merge pull request #210 from jspsych/fix/validation-require-one-format
jodeleeuw Aug 27, 2026
0041d8c
Send transactional mail through Resend, not SES (#211)
jodeleeuw Aug 29, 2026
f0aafe0
Keep the mail TTL policy from being deleted by every deploy (#212)
jodeleeuw Aug 29, 2026
efb07b4
Make transactional mail fail safely, and keep data until the research…
jodeleeuw Aug 29, 2026
0ec3197
Merge branch 'main' into test
jodeleeuw Sep 1, 2026
0eeec4b
docs: design for incremental session upload without per-trial functions
jodeleeuw Sep 2, 2026
7917e49
Add the RTDB staging tier's rules, wiring and access module
jodeleeuw Sep 2, 2026
174c1c0
Add the session endpoint, completion handling and abandonment sweep
jodeleeuw Sep 2, 2026
9e87516
Cover the staging tier end to end, and fix a discard-ordering hazard
jodeleeuw Sep 2, 2026
16158f7
Document incremental upload, and correct the privacy page's encryptio…
jodeleeuw Sep 2, 2026
c3c7bb6
Fix the streaming code sample and resolve the staging database's real…
jodeleeuw Sep 10, 2026
4f76565
Record abandonment per connection, in capped write-once slots
jodeleeuw Sep 11, 2026
50eca19
Mirror in-progress streaming sessions into Firestore for the dashboard
jodeleeuw Sep 11, 2026
5ad0166
Show sessions in progress on the experiment dashboard, live
jodeleeuw Sep 11, 2026
8447e55
Merge pull request #214 from jspsych/feat/streaming-ingest
jodeleeuw Sep 11, 2026
83cd456
Merge pull request #215 from jspsych/feat/live-sessions
jodeleeuw Sep 11, 2026
7ff1f30
Fix a sessionId path-injection hole that could wipe every open session
jodeleeuw Sep 11, 2026
944acc4
Close the dataverse SSRF bypass through providerContainer.serverUrl
jodeleeuw Sep 11, 2026
ce69831
Add a narrow test-only seam for dataverse-emulator.test.js's mock origin
jodeleeuw Sep 11, 2026
0b7d327
Fix recovered base64 uploads landing in storage as literal base64 text
jodeleeuw Sep 11, 2026
cec4157
Merge pull request #216 from jspsych/fix/session-id-validation
jodeleeuw Sep 11, 2026
ba3ec25
Merge pull request #217 from jspsych/fix/dataverse-server-url-allowlist
jodeleeuw Sep 11, 2026
d078197
Merge pull request #218 from jspsych/fix/pending-recovery-base64-data…
jodeleeuw Sep 11, 2026
e5c0c41
Revoke the Google grant on Drive disconnect/account deletion, and fix…
jodeleeuw Sep 12, 2026
ce5e3d1
Merge pull request #219 from jspsych/fix/revoke-gdrive-on-disconnect
jodeleeuw Sep 12, 2026
c1541dd
Give production its Google Drive OAuth and Picker configuration
jodeleeuw Sep 12, 2026
8ae4f9d
Merge pull request #220 from jspsych/config/production-gdrive
jodeleeuw Sep 12, 2026
9eaec3c
Give production its Zenodo OAuth configuration
jodeleeuw Sep 12, 2026
291105b
Merge pull request #221 from jspsych/config/production-zenodo
jodeleeuw Sep 12, 2026
b345b9b
Delete upload-queue Storage payloads and sweep every experiment subco…
jodeleeuw Sep 12, 2026
3aaabee
Extend retention when a terminal mail failure or rate-limit never tel…
jodeleeuw Sep 12, 2026
d266190
Point mail-delivery-emulator.test.js at its own breaker document
jodeleeuw Sep 12, 2026
d8d2824
Strengthen cleanupOldEntries and base64 upload tests
jodeleeuw Sep 13, 2026
9a7d133
Make the upload-retry backoff tests exercise the real formula
jodeleeuw Sep 13, 2026
8eeb0d0
Add emulator coverage for the OSF OAuth callback, regenerate, and ema…
jodeleeuw Sep 13, 2026
9df78dd
Merge pull request #222 from jspsych/fix/purge-queued-payloads
jodeleeuw Sep 13, 2026
54799f1
Merge pull request #223 from jspsych/fix/retention-on-terminal-mail-f…
jodeleeuw Sep 13, 2026
fc7e83e
Merge pull request #224 from jspsych/test-retention-sweep-assertions
jodeleeuw Sep 13, 2026
07adf58
Merge pull request #225 from jspsych/test-real-backoff-arithmetic
jodeleeuw Sep 13, 2026
5f2bad4
Merge pull request #226 from jspsych/test-oauth2-callback-coverage
jodeleeuw Sep 13, 2026
0cea1e3
Stop the live-sessions reconciler deleting genuinely open sessions
jodeleeuw Sep 13, 2026
8d0a426
Harden the streaming-ingest tier's bounds and add a kill switch
jodeleeuw Sep 13, 2026
fbad446
Harden the abandoned-session sweep against starvation, mis-reported d…
jodeleeuw Sep 13, 2026
9d59c79
Fix flaky concurrency-cap tests: direct discard, realistic reconcile …
jodeleeuw Sep 13, 2026
b53c7ad
Merge origin/harden-staging-sweep into harden-streaming-bounds
jodeleeuw Sep 13, 2026
4795bb6
Prove a real /api/data completion releases the concurrency-cap slot
jodeleeuw Sep 13, 2026
bf278c8
Document the streaming-ingest tier's hard limits for researchers
jodeleeuw Sep 14, 2026
2f52b46
Register the remaining rendered-but-unlisted docs section ids
jodeleeuw Sep 14, 2026
6e03b62
Merge pull request #227 from jspsych/fix-live-sessions-reconcile
jodeleeuw Sep 14, 2026
86f4c49
Merge pull request #228 from jspsych/harden-staging-sweep
jodeleeuw Sep 14, 2026
85fb0e1
Merge pull request #229 from jspsych/harden-streaming-bounds
jodeleeuw Sep 14, 2026
90300b1
Extract the DataPipe browser client into its own package
jodeleeuw Sep 15, 2026
a37b965
Recommend the extension, and let plain JavaScript stream too
jodeleeuw Sep 15, 2026
d970b31
Manage the client's releases with changesets
jodeleeuw Sep 15, 2026
0342b6a
Point the docs prose at the extension
jodeleeuw Sep 15, 2026
ca9d257
Remove the unauthenticated metadataOptions write channel from /api/data
jodeleeuw Sep 15, 2026
d17bc68
Deploy storage.rules to both projects; document its Admin-SDK-only pr…
jodeleeuw Sep 15, 2026
b7dbab5
Add the missing uploadQueue composite index and declare the filenameC…
jodeleeuw Sep 15, 2026
eed788b
Raise apiData/apiBase64 instance ceiling and rehydration lease
jodeleeuw Sep 15, 2026
3d77aba
Ship a license with the client package
jodeleeuw Sep 15, 2026
a9ea103
Publish the client with npm trusted publishing, not a stored token
jodeleeuw Sep 15, 2026
25a5bf9
Register the trusted publisher with npm trust, not the website
jodeleeuw Sep 15, 2026
9e2f703
Fix rehydration heartbeat leaving Jest unable to exit
jodeleeuw Sep 15, 2026
ac2379d
Give datapipe-client an entry point on the site
jodeleeuw Sep 15, 2026
da6885c
Merge remote-tracking branch 'origin/remove-metadata-options-param' i…
jodeleeuw Sep 15, 2026
3430f0b
Keep the app's Jest run out of packages/
jodeleeuw Sep 15, 2026
c910468
Merge pull request #234 from jspsych/feat/datapipe-client
jodeleeuw Sep 15, 2026
d08437c
Merge pull request #235 from jspsych/docs/recommend-extension
jodeleeuw Sep 15, 2026
2c57c1f
Bootstrap users/{uid} on password sign-in to stop a contact-email loc…
jodeleeuw Sep 15, 2026
30ae293
Merge pull request #230 from jspsych/remove-metadata-options-param
jodeleeuw Sep 15, 2026
12c8208
Merge pull request #231 from jspsych/deploy-storage-rules
jodeleeuw Sep 15, 2026
f4ec5d8
Merge pull request #232 from jspsych/firestore-index-and-claims-ttl
jodeleeuw Sep 15, 2026
ec0ce66
Merge pull request #233 from jspsych/raise-submission-capacity
jodeleeuw Sep 15, 2026
db67b79
Strip trailing slashes without a backtracking regex, and fix the fall…
jodeleeuw Sep 15, 2026
deb6696
Cap apidata at 200 instances, the Cloud Run quota ceiling
jodeleeuw Sep 15, 2026
a35c8a8
Tighten the docs prose
jodeleeuw Sep 15, 2026
ccd260d
Merge pull request #236 from jspsych/ensure-user-doc-on-password-signin
jodeleeuw Sep 15, 2026
5d85f19
Merge pull request #237 from jspsych/fix/client-redos
jodeleeuw Sep 15, 2026
ca31706
Merge pull request #238 from jspsych/apidata-max-instances-quota
jodeleeuw Sep 15, 2026
e3d6716
Merge pull request #239 from jspsych/docs/clarity-pass
jodeleeuw Sep 15, 2026
efe1258
Use datapipe-client in the plain JavaScript examples and docs
jodeleeuw Sep 15, 2026
e1a915a
Merge pull request #240 from jspsych/docs/datapipe-client-examples
jodeleeuw Sep 15, 2026
1d30c5f
Bump the version before the first publish, not after
jodeleeuw Sep 15, 2026
ddfba6a
Say to install packages/client before running changesets
jodeleeuw Sep 15, 2026
17cde18
Release datapipe-client 0.1.0
jodeleeuw Sep 15, 2026
ae64e5e
Put the manual publish first, and name the traps that bite
jodeleeuw Sep 15, 2026
e79d1ec
Randomize the Drive adapter's multipart boundary per request
jodeleeuw Sep 15, 2026
b6dee43
Merge pull request #243 from jspsych/gdrive-random-multipart-boundary
jodeleeuw Sep 15, 2026
5180365
Queue a submission on a recoverable credential failure instead of rej…
jodeleeuw Sep 15, 2026
927cde6
Merge pull request #241 from jspsych/docs/fix-release-runbook
jodeleeuw Sep 16, 2026
cebabe7
Merge pull request #242 from jspsych/release/client-0.1.0
jodeleeuw Sep 16, 2026
f7d1154
Drop the arrow-function filename from the homepage hero example
jodeleeuw Sep 16, 2026
086f31b
Claim the filename before queueing a token-failure submission
jodeleeuw Sep 16, 2026
619594d
Tag queued token failures AUTH_EXPIRED; stop tagging resolution excep…
jodeleeuw Sep 16, 2026
c4c4145
Stop naming OSF in error messages that every provider returns
jodeleeuw Sep 16, 2026
6a77934
Drop the OSF_ prefix from the provider-neutral error codes
jodeleeuw Sep 16, 2026
754b4b7
Humanize and reorganize the docs
jodeleeuw Sep 16, 2026
6d944b6
Merge pull request #247 from jspsych/docs/humanize-pass
jodeleeuw Sep 16, 2026
647c6ae
Merge branch 'test' into fix/provider-neutral-api-messages
jodeleeuw Sep 16, 2026
a747217
Merge pull request #245 from jspsych/fix/provider-neutral-api-messages
jodeleeuw Sep 16, 2026
06c44cb
Merge branch 'test' into queue-on-token-failure
jodeleeuw Sep 16, 2026
017c2ce
Merge pull request #244 from jspsych/queue-on-token-failure
jodeleeuw Sep 16, 2026
6b50c71
Fix the contact-email backfill for firebase-admin v14
jodeleeuw Sep 16, 2026
065c5d9
Merge pull request #248 from jspsych/fix/backfill-admin-v14
jodeleeuw Sep 16, 2026
8f436aa
Create the Psych-DS folders when metadata is switched on
jodeleeuw Sep 19, 2026
8b7371b
Merge pull request #249 from jspsych/gdrive-derived-paths-on-toggle
jodeleeuw Sep 19, 2026
f3ab755
Fix a log-write race in the base64 token-failure test
jodeleeuw Sep 19, 2026
f5f2fbb
Stop the zenodo provider suite making a live request to sandbox.zenod…
jodeleeuw Sep 19, 2026
a5e0425
Merge 16 low-traffic dashboard endpoints into one Cloud Function
jodeleeuw Sep 19, 2026
a5a4f00
Update emulator tests for the dashboardapi consolidation
jodeleeuw Sep 19, 2026
0033bd4
Delete the two OSF token endpoints the browser no longer calls
jodeleeuw Sep 19, 2026
133a8a6
Move apiFinalize into dashboardapi
jodeleeuw Sep 19, 2026
34c7220
Add consolidated participant-facing routing, keep every old function …
jodeleeuw Sep 19, 2026
490098d
Consolidate the four frequent scheduled functions into one scheduleds…
jodeleeuw Sep 19, 2026
a58c8e1
Update a stale scheduledPendingRecovery comment in purge-user-data.ts
jodeleeuw Sep 19, 2026
d2d4d33
Keep the gated sweep jobs running on an unparseable scheduleTime
jodeleeuw Sep 19, 2026
8c0ace7
Drop the mail-retry comment left dangling in index.ts
jodeleeuw Sep 19, 2026
b3ea8ce
Move compaction execution off the hot triggers into a dedicated Cloud…
jodeleeuw Sep 19, 2026
2a6686d
Update and add tests for the compaction Cloud Task consolidation
jodeleeuw Sep 19, 2026
cd0facc
Remove the standalone apisessionstart/apicondition/apibase64 functions
jodeleeuw Sep 19, 2026
a10464c
Merge pull request #254 from jspsych/refactor/participantapi-cleanup
jodeleeuw Sep 19, 2026
c9011dc
Add an e2e-testbed skill that is the driver, not a description of one
jodeleeuw Sep 19, 2026
a1572c6
Fold the 2026-09-19 run into the runbook
jodeleeuw Sep 19, 2026
be5e4bb
Drop the validation setup step, and get SKILL.md back under 250 lines
jodeleeuw Sep 19, 2026
caebcef
Say eight scenarios are marked full, matching the manifest
jodeleeuw Sep 19, 2026
264547d
Merge pull request #259 from jspsych/e2e-testbed-skill
jodeleeuw Sep 19, 2026
f20551e
Add a clearErrors dashboard route to reset the rejected-submissions w…
jodeleeuw Sep 19, 2026
73d2b0e
Add shared relative-time and since-last-clear helpers for ErrorPanel
jodeleeuw Sep 19, 2026
1f87eb3
Quiet ErrorPanel down and add a Clear this list button
jodeleeuw Sep 19, 2026
611ad30
Merge pull request #260 from jspsych/error-panel-clear
jodeleeuw Sep 19, 2026
aa0b1ec
Say what a metadata failure means, and that its data was kept
jodeleeuw Sep 19, 2026
0cededd
Merge pull request #261 from jspsych/error-panel-copy
jodeleeuw Sep 19, 2026
3cda559
Label WHY a pending copy was kept, so recovery can say so
jodeleeuw Sep 19, 2026
d02a67b
Tell held-and-unattempted uploads apart from ones that actually failed
jodeleeuw Sep 19, 2026
fc8305f
Update queue-panel docs for the waiting/retrying/failed split
jodeleeuw Sep 19, 2026
3a5d43e
Keep a held queue entry 'waiting' until a retry has actually failed
jodeleeuw Sep 19, 2026
e1a6862
Merge pull request #262 from jspsych/queue-panel-states
jodeleeuw Sep 19, 2026
352abbb
Polish the upload-queue panel's table: retention field, labels, layout
jodeleeuw Sep 19, 2026
45a286c
Give 'waiting' its own status icon: a clock, in the neutral hue
jodeleeuw Sep 19, 2026
67e3cb6
Teach the driver about ready, the trial counter, and today's dashboard
jodeleeuw Sep 19, 2026
579e545
Correct the trailing-slash note: a live endpoint does not redirect
jodeleeuw Sep 19, 2026
be5fca6
Merge pull request #263 from jspsych/queue-panel-polish
jodeleeuw Sep 19, 2026
0077cab
Merge pull request #264 from jspsych/e2e-skill-contract-v2
jodeleeuw Sep 19, 2026
0783ec7
Fold the 2026-09-20 run into the runbook
jodeleeuw Sep 20, 2026
cb979eb
Say plainly that the dashboard is dark-only
jodeleeuw Sep 20, 2026
2732383
Scrub run history out of the e2e runbook and reports guidance
jodeleeuw Sep 20, 2026
c801a85
Move the e2e runbook out: end-to-end testing lives in datapipe-testbed
jodeleeuw Sep 20, 2026
2f7c01d
Give a recovered partial its first upload attempt right away
jodeleeuw Sep 20, 2026
7554560
Claim .psychds-ignore once per experiment, not once per submission
jodeleeuw Sep 20, 2026
1cb5323
Keep the rejections table's Time column on one line
jodeleeuw Sep 20, 2026
aa1fc83
Never let the .psychds-ignore claim fail a submission; leave e2e docs…
jodeleeuw Sep 20, 2026
1c475f8
Merge pull request #265 from jspsych/e2e-runbook-run2
jodeleeuw Sep 20, 2026
d58bb67
Merge pull request #266 from jspsych/partials-now-and-ignore-once
jodeleeuw Sep 20, 2026
76bedcf
Add a What's changed documentation page for the September 2026 release
jodeleeuw Sep 20, 2026
f2c7521
Add a one-time homepage modal pointing at What's changed
jodeleeuw Sep 20, 2026
536e34f
Test the What's changed page, its nav entry, and the homepage modal
jodeleeuw Sep 20, 2026
6736623
Say what is true about running studies and the contact-email gate
jodeleeuw Sep 20, 2026
34016d7
Validation docs: the dashboard now keeps one format allowed
jodeleeuw Sep 20, 2026
b559795
Merge pull request #267 from jspsych/whats-changed
jodeleeuw Sep 20, 2026
dcf5176
Copyedit the What's changed page
jodeleeuw Sep 21, 2026
9034947
Keep the modal's Dismiss button in the footer
jodeleeuw Sep 21, 2026
a6ec80b
Reorder What's changed from the largest change to the smallest
jodeleeuw Sep 21, 2026
303c219
Merge pull request #269 from jspsych/fix/whats-changed-modal-dismiss
jodeleeuw Sep 21, 2026
3740942
Merge pull request #268 from jspsych/whats-changed-copy
jodeleeuw Sep 21, 2026
74a9fd2
Strip WaterButler's osfstorage/ prefix before building OSF file URLs
jodeleeuw Sep 21, 2026
bda67d0
Update the OSF downloadFile test that asserted the doubled URL
jodeleeuw Sep 21, 2026
dabd7cd
Merge pull request #270 from jspsych/fix/osf-file-id-prefix
jodeleeuw Sep 21, 2026
7914293
Lower apidata's maxInstances from 200 to 40
jodeleeuw Sep 21, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
6 changes: 0 additions & 6 deletions .eslintrc.json

This file was deleted.

47 changes: 47 additions & 0 deletions .github/workflows/client-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Test datapipe-client on its own.
#
# Separate from node.js.yml because that workflow builds the Next.js app and
# the Cloud Functions, and carries a page of NEXT_PUBLIC_* configuration that
# this package has no use for. packages/client has no Firebase project, no
# emulators, and no secrets -- it is a browser library with a mocked fetch.
#
# This exists so that a broken client cannot reach main and first fail at
# release time, when npm's refusal to republish a version makes a bad publish
# awkward to undo.

name: Test datapipe-client

on:
pull_request:
branches: ["main", "test"]
paths:
- "packages/client/**"
- ".github/workflows/client-test.yml"
push:
branches: ["test"]
paths:
- "packages/client/**"
- ".github/workflows/client-test.yml"

jobs:
test:
runs-on: ubuntu-latest
defaults:
run:
working-directory: packages/client

steps:
- uses: actions/checkout@v6
- name: Use Node.js
uses: actions/setup-node@v6
with:
node-version: 22.x
- run: npm ci
- run: npm run typecheck
- run: npm test
- run: npm run build
# The browser bundle carries the Firebase SDK, so its size is the whole
# reason streaming lives here rather than in the jsPsych plugin. Print it
# on every run, so a jump is visible in the log rather than discovered by
# a researcher on a slow connection.
- run: npm run size
74 changes: 66 additions & 8 deletions .github/workflows/firebase-deploy-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,20 @@ on:
branches: ["test"]
workflow_dispatch:

# Deploys to one Firebase project must not overlap. Two merges landing within
# a few minutes of each other used to start two deploys at once; the second
# one's update of the SSR function was rejected with a 409 ("unable to queue
# the operation") because the first was still mid-flight, and the site kept
# serving the previous build. Note that firebase deploy reports that failure
# as a warning and still exits 0, so the collision does not show up as a red
# check -- keeping deploys serialized is what prevents it, not the exit code.
# cancel-in-progress stays false on purpose --
# a deploy that is already updating functions should be allowed to finish,
# not killed halfway through. Later runs queue behind it instead.
concurrency:
group: deploy-test
cancel-in-progress: false

env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
#FIREBASE_TOKEN: ${{ secrets.FIREBASE_TOKEN }}
Expand All @@ -16,10 +30,23 @@ env:
NEXT_PUBLIC_REDIRECT_URI: "https://datapipe-test.web.app/oauth2/callback"
NEXT_PUBLIC_OAUTH_CALLBACK: "https://datapipe-test.web.app/api/oauth2callback"
NEXT_PUBLIC_OAUTH_FINAL: "/admin"
NEXT_PUBLIC_OAUTH_REGENERATE: "https://datapipe-test.web.app/api/oauth2regenerate"
NEXT_PUBLIC_GENERATE_STATE: "https://datapipe-test.web.app/api/generateoauthstate"
NEXT_PUBLIC_BASE_URL: "https://datapipe-test.web.app"
NEXT_PUBLIC_OSF_ENV: ""
# Frontend-only: drives the TestEnvironmentWarning banner gate (see
# components/TestEnvironmentWarning.js). Distinct from NEXT_PUBLIC_OSF_ENV
# above, which is being retired as OSF is deprecated and was left "" here
# -- that meant the banner stopped rendering on this site once OSF_ENV
# went empty. Not echoed into functions/.env; functions has no use for it.
NEXT_PUBLIC_DEPLOY_ENV: "test"
# sandbox.zenodo.org. Without this the TEST site creates real
# depositions on the live Zenodo using the researcher's real account.
NEXT_PUBLIC_ZENODO_ENV: "sandbox."
# Google Picker (folder selection for gdrive experiments). The API key is
# restricted to the Picker API + our domains, so it is safe in the browser
# bundle -- not a secret. The project number is public.
NEXT_PUBLIC_GOOGLE_PICKER_API_KEY: "AIzaSyDLg6uprrY5BPjY4ClVZGSvy7sd_ug0t9M"
NEXT_PUBLIC_GDRIVE_PROJECT_NUMBER: "699904257039"

jobs:
deploy:
Expand All @@ -41,16 +68,13 @@ jobs:
with:
credentials_json: '${{ secrets.GOOGLE_TEST_CREDENTIALS }}' # Replace with the name of your GitHub Actions secret
- name: Install firebase tools
run: npm install -g firebase-tools@15.8.0
run: npm install -g firebase-tools@15.28.1
- name: Enable firebase webframeworks
run: firebase experiments:enable webframeworks
- name: Install dependencies
run: npm ci
- name: Install dependencies and build metadata
working-directory: functions/metadata
run: |
npm ci
npm run build
# functions/metadata is a pre-built vendored dist (see functions/metadata/README.md);
# it is installed as a file: dependency by the functions npm ci below.
- name: Create functions environment file
working-directory: functions
run: |
Expand All @@ -59,12 +83,46 @@ jobs:
echo "REDIRECT_URI=https://datapipe-test.web.app/oauth2/callback" >> .env
echo "TOKEN_ENCRYPTION_KEY=${{ secrets.FIRESTORE_KEY_TEST }}" >> .env
echo "NEXT_PUBLIC_OSF_ENV=" >> .env
# Google Drive client secret for the deployed test site. Client id and
# redirect uri are non-secret and live in functions/.env.datapipe-test.
echo "GDRIVE_CLIENT_SECRET=${{ secrets.TEST_GDRIVE_CLIENT_SECRET }}" >> .env
# Zenodo OAuth client secret for the deployed test site. Client id,
# redirect uri and ZENODO_ENV are non-secret and live in
# functions/.env.datapipe-test.
echo "ZENODO_CLIENT_SECRET=${{ secrets.TEST_ZENODO_CLIENT_SECRET }}" >> .env
# Resend for the deployed test site (functions/src/mail-delivery.ts).
# SET this one. The test site is the only place mail DELIVERY is
# exercised before production -- the emulator short-circuits before
# sending and the unit suites mock the transport -- so it is where a
# mail change is proved to pass DKIM/SPF and reach an inbox. Use a
# SEPARATE sending-only key from prod, on the same Resend account
# (the From domain is the same, so it has to be the same account).
# Unset is still safe rather than silent: the onmailcreated trigger
# records a terminal MailConfigMissingError on each mail document and
# sends nothing. Reputation and daily quota are shared with prod --
# see docs/deploy-contact-email.md §2(d).
echo "RESEND_API_KEY=${{ secrets.TEST_RESEND_API_KEY }}" >> .env
# Not secret, so literals here, the same way REDIRECT_URI above is.
# Same sender as production: Resend verifies the DOMAIN
# (jspsych.org), not the deployment, and datapipe-test.web.app is not
# a verified domain -- sending from it is a 403 validation_error,
# which is why contact-email codes never arrived on the test site.
# Only the display name differs, so test mail is recognisable in an
# inbox.
echo "MAIL_FROM=DataPipe (test) <datapipe-notifications@jspsych.org>" >> .env
echo "MAIL_REPLY_TO=datapipe@jspsych.org" >> .env
- name: Install dependencies and build functions
working-directory: functions
run: |
npm ci
npm run build
- name: Use test firebase project
run: firebase use test
# storage deploys storage.rules to the project's default bucket
# (datapipe-test.appspot.com, which already exists). It is listed
# before functions because firebase-tools deploys --only targets in
# the order given, and the deny-all rules should be in place before
# functions keep writing participant data under pending-data/,
# upload-queue/ and finalization/ in that bucket.
- name: Deploy firebase project
run: firebase deploy --only firestore,functions,hosting --force
run: firebase deploy --only firestore,database,storage,functions,hosting --force
54 changes: 46 additions & 8 deletions .github/workflows/firebase-deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,14 @@ on:
branches: ["main"]
workflow_dispatch:

# See the matching block in firebase-deploy-test.yml: concurrent deploys to the
# same Firebase project collide on the SSR function update and leave the site
# on the old build. Separate group from the test deploy -- they target
# different projects and have no reason to queue behind each other.
concurrency:
group: deploy-production
cancel-in-progress: false

env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
#FIREBASE_TOKEN: ${{ secrets.FIREBASE_TOKEN }}
Expand All @@ -16,10 +24,19 @@ env:
NEXT_PUBLIC_REDIRECT_URI: "https://pipe.jspsych.org/oauth2/callback"
NEXT_PUBLIC_OAUTH_CALLBACK: "https://pipe.jspsych.org/api/oauth2callback"
NEXT_PUBLIC_OAUTH_FINAL: "/admin"
NEXT_PUBLIC_OAUTH_REGENERATE: "https://pipe.jspsych.org/api/oauth2regenerate"
NEXT_PUBLIC_GENERATE_STATE: "https://pipe.jspsych.org/api/generateoauthstate"
NEXT_PUBLIC_BASE_URL: "https://pipe.jspsych.org"
NEXT_PUBLIC_OSF_ENV: ""
# Empty = the real zenodo.org. Set explicitly rather than relying on the
# default, so production never inherits a sandbox value by accident.
NEXT_PUBLIC_ZENODO_ENV: ""
# Google Picker (folder selection for gdrive experiments). The key is
# restricted to the Picker API and to the https://pipe.jspsych.org/* referrer
# (API key "DataPipe Picker – production" in the osf-relay GCP project), so
# it is safe in the browser bundle -- not a secret. The project number is
# osf-relay's; the Picker's setAppId wants the number, not the id.
NEXT_PUBLIC_GOOGLE_PICKER_API_KEY: "AIzaSyDNGwbzk4qwjhq_jJZVIg8ajxXtqi2A3wQ"
NEXT_PUBLIC_GDRIVE_PROJECT_NUMBER: "54492763028"

jobs:
build:
Expand All @@ -41,16 +58,13 @@ jobs:
with:
credentials_json: '${{ secrets.GOOGLE_PRODUCTION_CREDENTIALS }}'
- name: Install firebase tools
run: npm install -g firebase-tools@15.8.0
run: npm install -g firebase-tools@15.28.1
- name: Enable firebase webframeworks
run: firebase experiments:enable webframeworks
- name: Install dependencies
run: npm ci
- name: Install dependencies and build metadata
working-directory: functions/metadata
run: |
npm ci
npm run build
# functions/metadata is a pre-built vendored dist (see functions/metadata/README.md);
# it is installed as a file: dependency by the functions npm ci below.
- name: Create functions environment file
working-directory: functions
run: |
Expand All @@ -59,12 +73,36 @@ jobs:
echo "REDIRECT_URI=https://pipe.jspsych.org/oauth2/callback" >> .env
echo "TOKEN_ENCRYPTION_KEY=${{ secrets.FIRESTORE_KEY_PRODUCTION }}" >> .env
echo "NEXT_PUBLIC_OSF_ENV=" >> .env
# Google Drive client secret for production. Client id and redirect
# uri are non-secret and live in functions/.env.osf-relay.
echo "GDRIVE_CLIENT_SECRET=${{ secrets.PROD_GDRIVE_CLIENT_SECRET }}" >> .env
# Zenodo OAuth client secret for production. Client id and redirect
# uri are non-secret and live in functions/.env.osf-relay; ZENODO_ENV
# stays unset there so the flow runs against the real zenodo.org.
echo "ZENODO_CLIENT_SECRET=${{ secrets.PROD_ZENODO_CLIENT_SECRET }}" >> .env
# Resend. functions/src/mail-delivery.ts delivers everything mail.ts
# queues into the `mail` collection; without this key the
# onmailcreated trigger writes a terminal MailConfigMissingError on
# every notification and sends nothing. Scope the key to Sending
# access only -- see docs/deploy-contact-email.md §2, which also
# covers domain verification.
echo "RESEND_API_KEY=${{ secrets.PROD_RESEND_API_KEY }}" >> .env
# Not secret, so literals here, the same way REDIRECT_URI above is.
# MAIL_FROM must be an address on a domain verified in Resend.
echo "MAIL_FROM=DataPipe <datapipe-notifications@jspsych.org>" >> .env
echo "MAIL_REPLY_TO=datapipe@jspsych.org" >> .env
- name: Install dependencies and build functions
working-directory: functions
run: |
npm ci
npm run build
- name: Use default firebase project
run: firebase use default
# storage deploys storage.rules to the project's default bucket
# (osf-relay.appspot.com, which already exists). It is listed before
# functions because firebase-tools deploys --only targets in the order
# given, and the deny-all rules should be in place before functions
# keep writing participant data under pending-data/, upload-queue/ and
# finalization/ in that bucket.
- name: Deploy firebase project
run: firebase deploy --only firestore,functions,hosting --force
run: firebase deploy --only firestore,database,storage,functions,hosting --force
74 changes: 74 additions & 0 deletions .github/workflows/metadata-drift-check.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# Nudge (never an auto-merge): flags when upstream @jspsych/metadata main has moved past
# the commit DataPipe currently vendors. The vendored copy is pinned + built by
# functions/scripts/sync-metadata.mjs; this job just tells a human it's time to re-sync.
name: Metadata vendor drift check

on:
schedule:
- cron: "0 12 * * 1" # Mondays 12:00 UTC
workflow_dispatch:

permissions:
contents: read
issues: write

jobs:
drift-check:
runs-on: ubuntu-latest
env:
UPSTREAM: jspsych/metadata
ISSUE_TITLE: "[metadata-sync] Vendored @jspsych/metadata is behind upstream main"
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- uses: actions/checkout@v6

- name: Compare pinned commit against upstream main
id: compare
run: |
PINNED=$(jq -r .commit functions/metadata/VENDORED_FROM.json)
echo "Pinned commit: $PINNED"
if [ -z "$PINNED" ] || [ "$PINNED" = "null" ]; then
echo "::error::Could not read pinned commit from functions/metadata/VENDORED_FROM.json"
exit 1
fi
UPSTREAM_MAIN=$(gh api "repos/$UPSTREAM/commits/main" --jq .sha)
echo "Upstream main: $UPSTREAM_MAIN"
if [ "$PINNED" = "$UPSTREAM_MAIN" ]; then
echo "in_sync=true" >> "$GITHUB_OUTPUT"
echo "Vendored copy is up to date with upstream main."
exit 0
fi
# ahead_by = how many commits upstream main is ahead of our pinned commit.
AHEAD=$(gh api "repos/$UPSTREAM/compare/$PINNED...main" --jq .ahead_by)
echo "in_sync=false" >> "$GITHUB_OUTPUT"
echo "ahead=$AHEAD" >> "$GITHUB_OUTPUT"
echo "pinned=$PINNED" >> "$GITHUB_OUTPUT"
echo "upstream=$UPSTREAM_MAIN" >> "$GITHUB_OUTPUT"

- name: Open or update tracking issue
if: steps.compare.outputs.in_sync == 'false'
run: |
BODY=$(cat <<EOF
Upstream \`$UPSTREAM\` \`main\` is **${{ steps.compare.outputs.ahead }} commit(s) ahead** of the version DataPipe vendors.

- Pinned: \`${{ steps.compare.outputs.pinned }}\`
- Upstream: \`${{ steps.compare.outputs.upstream }}\`
- Diff: https://github.com/$UPSTREAM/compare/${{ steps.compare.outputs.pinned }}...main

To re-sync (nothing is automatic):
\`\`\`
cd functions && npm run sync:metadata
\`\`\`
Then review the diff, run the tests, and open a PR. See \`functions/metadata/README.md\`.

_This issue is updated automatically by \`.github/workflows/metadata-drift-check.yml\`._
EOF
)
EXISTING=$(gh issue list --state open --search "$ISSUE_TITLE in:title" --json number --jq '.[0].number')
if [ -n "$EXISTING" ]; then
echo "Updating existing issue #$EXISTING"
gh issue edit "$EXISTING" --body "$BODY"
else
echo "Creating new tracking issue"
gh issue create --title "$ISSUE_TITLE" --body "$BODY"
fi
17 changes: 9 additions & 8 deletions .github/workflows/node.js.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ env:
NEXT_PUBLIC_REDIRECT_URI: "https://datapipe-test.web.app/oauth2/callback"
NEXT_PUBLIC_OAUTH_CALLBACK: "https://datapipe-test.web.app/api/oauth2callback"
NEXT_PUBLIC_OAUTH_FINAL: "/admin"
NEXT_PUBLIC_OAUTH_REGENERATE: "https://datapipe-test.web.app/api/oauth2regenerate"
NEXT_PUBLIC_OSF_ENV: ""

jobs:
Expand Down Expand Up @@ -45,15 +44,14 @@ jobs:
with:
credentials_json: '${{ secrets.GOOGLE_TEST_CREDENTIALS }}' # Replace with the name of your GitHub Actions secret
- name: Install firebase tools
run: npm install -g firebase-tools@15.8.0
run: npm install -g firebase-tools@15.28.1
- name: Enable firebase webframeworks
run: firebase experiments:enable webframeworks
- run: npm ci
- name: Install dependencies and build metadata
working-directory: functions/metadata
run: |
npm ci
npm run build
- name: Lint
run: npm run lint
# functions/metadata is a pre-built vendored dist (see functions/metadata/README.md);
# it is installed as a file: dependency by the functions npm ci below.
- name: Install dependencies and build functions
working-directory: functions
run: |
Expand All @@ -62,4 +60,7 @@ jobs:
- name: Select project
run: firebase use test
- name: Launch firestore emulator and test
run: firebase emulators:exec 'npm run test-ci'
# maxWorkers=2: the emulator-backed suites contend under full
# parallel load (pre-existing data-emulator timing flake); capping
# workers reproduces consistently-green runs.
run: firebase emulators:exec 'npm run test-ci -- --maxWorkers=2'
Loading
Loading