Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
246 commits
Select commit Hold shift + click to select a range
a28eace
feat: surface and document metadata production
Mandyx22 Jul 1, 2026
b0fa96e
feat: cross-link Getting Started to the metadata FAQ
Mandyx22 Jul 1, 2026
2c600bf
fix(metadata): re-vendor @jspsych/metadata from upstream main + sync …
htsukamoto5 Jul 1, 2026
5b53084
fix(ci): drop obsolete metadata build step from workflows
htsukamoto5 Jul 2, 2026
d392ec5
fix(test): stop base64 and data emulator suites sharing one log doc
htsukamoto5 Jul 2, 2026
a558583
refactor(metadata): make the metadata transaction Firestore-only
htsukamoto5 Jul 2, 2026
5b299d7
feat(metadata): write sidecar CSVs for nested array/object columns
htsukamoto5 Jul 2, 2026
9208d43
refactor(metadata): delegate sidecar CSVs to buildPsychDSDataFiles + …
htsukamoto5 Jul 3, 2026
0dbe4bc
feat(osf): walk arbitrary-depth paths in putFileOSF (data/raw/)
htsukamoto5 Jul 3, 2026
92dd9eb
feat(metadata): ship the Psych-DS layout to OSF (raw under data/raw/,…
htsukamoto5 Jul 6, 2026
627f173
Merge pull request #151 from jspsych/fix/metadata-version-drift
htsukamoto5 Jul 6, 2026
04a4fea
Merge pull request #152 from jspsych/feat/metadata-sidecars
htsukamoto5 Jul 6, 2026
3ff8be6
Merge remote-tracking branch 'origin/test' into feature/metadata-disc…
Mandyx22 Jul 6, 2026
c4edeca
feat: metadata popover docs link + status-label tooltips
Mandyx22 Jul 6, 2026
342062f
Merge pull request #150 from jspsych/feature/metadata-discoverability
Mandyx22 Jul 6, 2026
3f4621a
fix(recovery): make crash recovery layout-aware
htsukamoto5 Jul 6, 2026
f7dd079
fix(metadata): stop widened metadata failures from destroying data
htsukamoto5 Jul 6, 2026
79016a6
fix(metadata): collision-proof flattened filenames (D1: encode)
htsukamoto5 Jul 6, 2026
1ade20f
fix(metadata): stop the create-only queue from dropping dataset_descr…
htsukamoto5 Jul 6, 2026
73bda2d
perf(metadata): parallelize derived uploads, resolve data/ once
htsukamoto5 Jul 6, 2026
76b6804
perf(metadata): parse each payload exactly once
htsukamoto5 Jul 6, 2026
7b4d00a
refactor(metadata): replace the sentinel-abort transaction with a pre…
htsukamoto5 Jul 6, 2026
a756618
fix(faq): make deep-link scroll robust to Chakra internals and in-pag…
htsukamoto5 Jul 6, 2026
56f281c
fix(metadata): restore metadataMessage on the pre-read download path
htsukamoto5 Jul 6, 2026
891312a
test(recovery): fix expected path in the emulator test for D1 encoding
htsukamoto5 Jul 6, 2026
76d1b95
fix(metadata): keep up-front data/ resolution from failing the submis…
htsukamoto5 Jul 6, 2026
509e848
fix(queue): don't lose a refreshed payload when the doc races to comp…
htsukamoto5 Jul 6, 2026
1c72ef6
refactor(metadata): mark the not-an-array case with a class, not a me…
htsukamoto5 Jul 6, 2026
22735ec
refactor(metadata): make MetadataBlockResult a discriminated union
htsukamoto5 Jul 7, 2026
5349776
Merge pull request #153 from jspsych/fix/metadata-followups
htsukamoto5 Jul 7, 2026
e4adf10
docs: add storage provider migration design doc
jodeleeuw Jul 21, 2026
ab334cd
docs: harden provider-migration design after review
jodeleeuw Jul 21, 2026
e7fc792
feat: add storage-provider interface, registry, and additive schema t…
jodeleeuw Jul 22, 2026
f6304d8
refactor: route all OSF writes through the storage-provider interface
jodeleeuw Jul 22, 2026
0c336f8
feat: Firestore collision cache with claim lifecycle and OSF dual-run
jodeleeuw Jul 22, 2026
4e889f3
feat: track metadata file by provider ref instead of listing on every…
jodeleeuw Jul 22, 2026
bc3c8a3
feat: Google Drive adapter and full provider generalization of the wr…
jodeleeuw Jul 22, 2026
8f70d23
fix: write dual-run disagreement logs before responding
jodeleeuw Jul 23, 2026
c653732
feat: provider OAuth connect flow (gdrive) alongside the OSF identity…
jodeleeuw Jul 23, 2026
6b9eb59
feat: server-side experiment creation for provider-backed experiments
jodeleeuw Jul 23, 2026
be36c94
feat: provider selector, connect UI, and provider-aware dashboard
jodeleeuw Jul 23, 2026
564012a
docs: deployment checklist for gdrive launch; cap CI jest workers
jodeleeuw Jul 23, 2026
7bdbe21
fix: address Copilot review findings on PR #154
jodeleeuw Jul 23, 2026
f7e1d82
fix: address review findings on PR #154 (minor items)
jodeleeuw Jul 24, 2026
154d4d8
Merge branch 'test' into provider-migration
jodeleeuw Jul 24, 2026
974afc4
Merge pull request #154 from jspsych/provider-migration
jodeleeuw Jul 24, 2026
33545db
fix: point deployed gdrive OAuth at real Google creds, not emulator m…
jodeleeuw Jul 24, 2026
cfaa303
Merge pull request #155 from jspsych/provider-migration
jodeleeuw Jul 24, 2026
022c24a
feat: let experiments target a chosen gdrive folder (backend)
jodeleeuw Jul 25, 2026
3e0a773
feat: Google Drive folder picker for experiment creation (front-end)
jodeleeuw Jul 25, 2026
ec8380d
Merge pull request #156 from jspsych/provider-migration
jodeleeuw Jul 25, 2026
947d9ce
fix: make Drive folder picker navigable with breadcrumb path
jodeleeuw Jul 25, 2026
e7243bd
feat: shared-drive support + picker button contrast for gdrive folders
jodeleeuw Jul 25, 2026
e2612c4
Merge pull request #157 from jspsych/provider-migration
jodeleeuw Jul 25, 2026
0664bd5
refactor: move token resolution onto the StorageProvider interface
jodeleeuw Jul 25, 2026
313abbf
refactor: fold OAuth config into the provider registry
jodeleeuw Jul 25, 2026
9008f67
refactor: move the scheduled refresh pass onto the provider interface
jodeleeuw Jul 25, 2026
419c4b9
refactor: thread ResolvedAuth through the provider write path
jodeleeuw Jul 25, 2026
16a5cd0
feat: Dataverse storage adapter (backend only, not yet exposed)
jodeleeuw Jul 25, 2026
25f1e9d
feat: static-token connect path, with an SSRF gate on serverUrl
jodeleeuw Jul 25, 2026
55b95a3
docs: record source-verified Dataverse spike findings
jodeleeuw Jul 25, 2026
ddef109
test: fix the cross-suite race in the pending-recovery and queue suites
jodeleeuw Jul 26, 2026
37f244e
feat: connect UI for static-token providers, and the Dataverse rewrite
jodeleeuw Jul 26, 2026
e72a8b8
feat: providers declare their container input; create-experiment vali…
jodeleeuw Jul 26, 2026
c98603b
feat: provider-generic new-experiment form, driven by containerInput
jodeleeuw Jul 26, 2026
193e3cd
test: add the Dataverse gating-spike script
jodeleeuw Jul 26, 2026
e6b8a60
fix: Dataverse create accepts 201; record live spike result (GATE A F…
jodeleeuw Jul 26, 2026
ff5d805
feat: fast retry tier for transient provider contention
jodeleeuw Jul 26, 2026
835821f
docs: revise the Dataverse gate to CONDITIONAL PASS
jodeleeuw Jul 26, 2026
b1f0a3b
feat: warn at experiment setup when a Dataverse install predates 5.11
jodeleeuw Jul 26, 2026
903ac97
fix: classify queue failures by provider taxonomy, not HTTP status
jodeleeuw Jul 26, 2026
0c08f29
feat: read and warn on Dataverse API token expiry
jodeleeuw Jul 26, 2026
2f42ad4
docs: audit the pre-spike claims; several were wrong or stale
jodeleeuw Jul 27, 2026
1b3fe3a
feat: Zenodo storage adapter
jodeleeuw Aug 11, 2026
85b133e
test: add the Zenodo gating-spike script
jodeleeuw Aug 11, 2026
1bdabd2
docs: record the Zenodo spike result (all five gates PASS)
jodeleeuw Aug 11, 2026
34e1f69
feat: warn at experiment setup about Zenodo's 100-file cap
jodeleeuw Aug 11, 2026
4c442af
fix: apply the PR 158 review findings
jodeleeuw Aug 11, 2026
9d8dc6b
build: migrate lint to ESLint flat config
jodeleeuw Aug 11, 2026
1df5082
fix: clear the react-hooks findings and enforce the rules
jodeleeuw Aug 12, 2026
ccdf0f3
Merge pull request #158 from jspsych/provider-migration
jodeleeuw Aug 12, 2026
a391cb1
feat: close OSF to new experiments
jodeleeuw Aug 12, 2026
697546e
feat: pluggable sign-in providers (Google, ORCID, GitHub)
jodeleeuw Aug 12, 2026
fd5e389
feat: announce the OSF sunset and keep re-authorization working
jodeleeuw Aug 12, 2026
6ff21d0
feat: migrate OSF-era accounts onto a durable sign-in method
jodeleeuw Aug 12, 2026
32a893f
Merge pull request #159 from jspsych/provider-migration
jodeleeuw Aug 12, 2026
ecedc5b
fix: outline buttons rendered near-black on the dark background
jodeleeuw Aug 12, 2026
0c4b021
Merge pull request #160 from jspsych/provider-migration
jodeleeuw Aug 12, 2026
31a200d
fix: re-point the gray palette for this app's dark surface
jodeleeuw Aug 12, 2026
b47218b
Merge pull request #161 from jspsych/provider-migration
jodeleeuw Aug 12, 2026
29f45c5
fix: give account-linking failures their own wording
jodeleeuw Aug 12, 2026
2b40584
fix: give account-linking failures their own wording (#162)
jodeleeuw Aug 12, 2026
2a3864a
fix: delete accounts server-side, and purge everything they own
jodeleeuw Aug 12, 2026
20ca7a1
fix: delete accounts server-side, and purge everything they own (#163)
jodeleeuw Aug 12, 2026
c394a09
feat: seal sessions into archives so capped providers stop breaking s…
jodeleeuw Aug 20, 2026
f1f606c
fix: don't let a still-building index fail the compaction trigger
jodeleeuw Aug 20, 2026
7cc9ebd
Merge branch 'test' into provider-migration
jodeleeuw Aug 20, 2026
5a09619
Merge pull request #164 from jspsych/provider-migration
jodeleeuw Aug 20, 2026
de0636d
feat: point the test deployment at the Zenodo sandbox
jodeleeuw Aug 20, 2026
9dd602e
Merge pull request #165 from jspsych/zenodo-sandbox-in-test
jodeleeuw Aug 20, 2026
cd3c866
test: add spike gates for the three adapter methods never run live
jodeleeuw Aug 20, 2026
f7e8ae8
fix: verify Zenodo deletes instead of trusting the status
jodeleeuw Aug 20, 2026
1a01947
Merge pull request #166 from jspsych/zenodo-spike-gates
jodeleeuw Aug 20, 2026
be12412
test: add a live end-to-end check against a deployed DataPipe
jodeleeuw Aug 20, 2026
d515d39
fix: do not hold the compaction lease while deciding there is no work
jodeleeuw Aug 20, 2026
09098a0
Merge pull request #167 from jspsych/live-check-script
jodeleeuw Aug 20, 2026
7126c0c
test: a 202 during compaction is correct, not a load failure
jodeleeuw Aug 20, 2026
db99cf3
Merge pull request #168 from jspsych/live-check-202
jodeleeuw Aug 20, 2026
f26cd68
fix: put dataset_description.json inside the finalized archive
jodeleeuw Aug 20, 2026
eda7547
fix: finalize to a single self-contained archive
jodeleeuw Aug 20, 2026
b78f429
Merge pull request #169 from jspsych/live-check-202
jodeleeuw Aug 20, 2026
635e860
fix: queue derived Psych-DS files when a submission is diverted
jodeleeuw Aug 20, 2026
ff01e68
Merge pull request #170 from jspsych/fix-derived-files-on-divert
jodeleeuw Aug 21, 2026
7723681
test: count derived tables across the whole dataset, not just loose f…
jodeleeuw Aug 21, 2026
395357e
Merge pull request #171 from jspsych/live-check-pacing
jodeleeuw Aug 21, 2026
20eb922
fix: keep the real error code when a nested Drive folder walk fails
jodeleeuw Aug 21, 2026
baad592
fix: stop concurrent Drive writes from fragmenting the folder tree
jodeleeuw Aug 21, 2026
152edcd
Merge pull request #172 from jspsych/gdrive-spike-and-coverage
jodeleeuw Aug 21, 2026
a70c380
feat: move Zenodo storage from pasted tokens to OAuth2
jodeleeuw Aug 21, 2026
c10eb93
feat: give self-healing failures one early retry before the long wait
jodeleeuw Aug 21, 2026
0ac9c6e
Merge pull request #173 from jspsych/zenodo-oauth
jodeleeuw Aug 21, 2026
5d8dd3e
fix: say which token exchange failed, and why
jodeleeuw Aug 22, 2026
828d5b5
Merge pull request #174 from jspsych/zenodo-connect-diagnostics
jodeleeuw Aug 22, 2026
31ed699
fix: never merge a loose original that is already sealed in a batch
jodeleeuw Aug 22, 2026
cd3bdfd
Merge pull request #176 from jspsych/zenodo-finalization-dedup
jodeleeuw Aug 22, 2026
267570f
docs: add PRODUCT.md — strategic design context for the site-wide des…
jodeleeuw Aug 22, 2026
9f51065
docs: retire OSF from the researcher-facing guides
jodeleeuw Aug 22, 2026
75b8831
Merge pull request #178 from jspsych/docs/multi-backend-guides
jodeleeuw Aug 22, 2026
e98be90
feat(ui): shared primitives — SettingsSection, StatusIndicator, FormE…
jodeleeuw Aug 22, 2026
4fdf735
fix(account): close both P0s — guard provider disconnect, surface eve…
jodeleeuw Aug 22, 2026
f6f7fae
docs: DESIGN.md — dual-mode design contract; version the |> logo handoff
jodeleeuw Aug 22, 2026
9c0d78d
feat(theme): adopt the logo's green — brandGreen replaces brandTeal a…
jodeleeuw Aug 22, 2026
3d33f69
feat(brand): implement the |> mark — LogoMark, navbar lockup, favicon…
jodeleeuw Aug 22, 2026
c5bc0da
refactor(index): retire Rubik, finish the brandGreen rename
jodeleeuw Aug 22, 2026
801654e
feat(account): assemble the settings page on the shared primitives
jodeleeuw Aug 22, 2026
cc2ce4f
feat(theme): Phase 1 foundation — real light/dark token divergence, n…
jodeleeuw Aug 22, 2026
38f2659
fix(theme): light-safe primitives; code.*, status.*, logo.mark tokens
jodeleeuw Aug 22, 2026
07fb142
fix(account): retire the last pre-rebuild surface remnants
jodeleeuw Aug 22, 2026
1c08cd6
feat(chrome): mode-aware navbar and footer, banner guard fix
jodeleeuw Aug 22, 2026
72cb60f
feat(landing): sell the shipped product, on the mode-invariant code d…
jodeleeuw Aug 22, 2026
b7b4840
feat(auth): every failure path lands somewhere, in a real form
jodeleeuw Aug 22, 2026
b47c420
fix(ui): ConfirmDialog speaks brandRed and FormErrorAlert; close smal…
jodeleeuw Aug 22, 2026
948ed15
feat(dashboard): writes that can't lie, status you can read, a way back
jodeleeuw Aug 22, 2026
1ae5d59
feat(landing): commit to the green — full-bleed brand bands, hero scale
jodeleeuw Aug 22, 2026
e3d7a79
fix(landing): clarify pass — every string earns its place
jodeleeuw Aug 22, 2026
dfef8c0
feat(theme): the mode control, built and gated
jodeleeuw Aug 22, 2026
6e640bf
Merge pull request #179 from jspsych/account-settings-design
jodeleeuw Aug 22, 2026
de4c7d3
feat(chrome): the pipe fires on hover — logo emit animation
jodeleeuw Aug 22, 2026
dc19e61
fix(chrome): make the logo emit read as emission, owner-tuned
jodeleeuw Aug 22, 2026
c30471c
feat(theme): ship light mode — final pages converted, alias retired, …
jodeleeuw Aug 22, 2026
d9dbe12
fix(landing): two-column hero with the code specimen, arrivals panel out
jodeleeuw Aug 22, 2026
1253b07
feat(storage): encrypt pending payloads at rest
jodeleeuw Aug 23, 2026
383b4c0
Merge pull request #180 from jspsych/logo-emit-animation
jodeleeuw Aug 23, 2026
5835ac9
Merge pull request #181 from jspsych/light-mode-ship
jodeleeuw Aug 23, 2026
9a8fc59
Merge pull request #182 from jspsych/homepage-cleanup
jodeleeuw Aug 23, 2026
bb75c35
fix(layout): declare the navbar gap once, put spacing back on the ladder
jodeleeuw Aug 22, 2026
1efded2
Merge pull request #183 from jspsych/spacing-pass
jodeleeuw Aug 23, 2026
0eb7f2f
Merge pull request #185 from jspsych/payload-encryption
jodeleeuw Aug 23, 2026
1b3671f
feat(email): contact-email schema, adversarial rules, mail primitive …
jodeleeuw Aug 23, 2026
2659093
feat(email): the contact-email wall and signup seeding (P1)
jodeleeuw Aug 23, 2026
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
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.

65 changes: 59 additions & 6 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 @@ -20,6 +34,20 @@ env:
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 +69,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,6 +84,34 @@ 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: |
Expand Down
31 changes: 25 additions & 6 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 @@ -20,6 +28,9 @@ env:
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: ""

jobs:
build:
Expand All @@ -41,16 +52,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,6 +67,17 @@ 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
# 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: |
Expand Down
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
16 changes: 9 additions & 7 deletions .github/workflows/node.js.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,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 +61,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'
1 change: 1 addition & 0 deletions .github/workflows/run-migration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ on:
options:
- 2025-09-29-osf-integration.cjs
- encrypt-tokens.cjs
- 2026-08-contact-email-backfill.cjs
dry_run:
description: 'Dry run (no changes applied)'
required: true
Expand Down
10 changes: 8 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,8 @@ yarn-error.log*

# local env files
.env*.local
# ...except the committed emulator/CI overrides (never deployed by Firebase)
!functions/.env.local

# vercel
.vercel
Expand All @@ -157,7 +159,11 @@ functions/lib/
#vscode local testing
.vscode/settings.json

#metadata build artifacts
functions/metadata/dist
# metadata build artifacts — the vendored @jspsych/metadata dist is intentionally
# COMMITTED (populated by functions/scripts/sync-metadata.mjs) so deploys need no
# metadata build step. See functions/metadata/README.md. These negations override the
# broad `dist` rule above; both the dir and its contents must be re-included.
!functions/metadata/dist/
!functions/metadata/dist/**

CLAUDE.md
Loading